efi_io.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <assert.h>
00022 #include <gpxe/io.h>
00023 #include <gpxe/efi/efi.h>
00024 #include <gpxe/efi/Protocol/CpuIo.h>
00025 #include <gpxe/efi/efi_io.h>
00026 
00027 /** @file
00028  *
00029  * gPXE I/O API for EFI
00030  *
00031  */
00032 
00033 /** CPU I/O protocol */
00034 static EFI_CPU_IO_PROTOCOL *cpu_io;
00035 EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
00036 
00037 /** Maximum address that can be used for port I/O */
00038 #define MAX_PORT_ADDRESS 0xffff
00039 
00040 /**
00041  * Determine whether or not address is a port I/O address
00042  *
00043  * @v io_addr           I/O address
00044  * @v is_port           I/O address is a port I/O address
00045  */
00046 #define IS_PORT_ADDRESS(io_addr) \
00047         ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
00048 
00049 /**
00050  * Determine EFI CPU I/O width code
00051  *
00052  * @v size              Size of value
00053  * @ret width           EFI width code
00054  *
00055  * Someone at Intel clearly gets paid by the number of lines of code
00056  * they write.  No-one should ever be able to make I/O this
00057  * convoluted.  The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
00058  * idiocy.
00059  */
00060 static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
00061         switch ( size ) {
00062         case 1 :        return EfiCpuIoWidthFifoUint8;
00063         case 2 :        return EfiCpuIoWidthFifoUint16;
00064         case 4 :        return EfiCpuIoWidthFifoUint32;
00065         case 8 :        return EfiCpuIoWidthFifoUint64;
00066         default :
00067                 assert ( 0 );
00068                 /* I wonder what this will actually do... */
00069                 return EfiCpuIoWidthMaximum;
00070         }
00071 }
00072 
00073 /**
00074  * Read from device
00075  *
00076  * @v io_addr           I/O address
00077  * @v size              Size of value
00078  * @ret data            Value read
00079  */
00080 unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
00081         EFI_CPU_IO_PROTOCOL_IO_MEM read;
00082         unsigned long long data = 0;
00083         EFI_STATUS efirc;
00084 
00085         read = ( IS_PORT_ADDRESS ( io_addr ) ?
00086                  cpu_io->Io.Read : cpu_io->Mem.Read );
00087 
00088         if ( ( efirc = read ( cpu_io, efi_width ( size ),
00089                               ( intptr_t ) io_addr, 1,
00090                               ( void * ) &data ) ) != 0 ) {
00091                 DBG ( "EFI I/O read at %p failed: %s\n",
00092                       io_addr, efi_strerror ( efirc ) );
00093                 return -1ULL;
00094         }
00095 
00096         return data;
00097 }
00098 
00099 /**
00100  * Write to device
00101  *
00102  * @v data              Value to write
00103  * @v io_addr           I/O address
00104  * @v size              Size of value
00105  */
00106 void efi_iowrite ( unsigned long long data, volatile void *io_addr,
00107                    size_t size ) {
00108         EFI_CPU_IO_PROTOCOL_IO_MEM write;
00109         EFI_STATUS efirc;
00110 
00111         write = ( IS_PORT_ADDRESS ( io_addr ) ?
00112                   cpu_io->Io.Write : cpu_io->Mem.Write );
00113 
00114         if ( ( efirc = write ( cpu_io, efi_width ( size ),
00115                                ( intptr_t ) io_addr, 1,
00116                                ( void * ) &data ) ) != 0 ) {
00117                 DBG ( "EFI I/O write at %p failed: %s\n",
00118                       io_addr, efi_strerror ( efirc ) );
00119         }
00120 }
00121 
00122 /**
00123  * String read from device
00124  *
00125  * @v io_addr           I/O address
00126  * @v data              Data buffer
00127  * @v size              Size of values
00128  * @v count             Number of values to read
00129  */
00130 void efi_ioreads ( volatile void *io_addr, void *data,
00131                    size_t size, unsigned int count ) {
00132         EFI_CPU_IO_PROTOCOL_IO_MEM read;
00133         EFI_STATUS efirc;
00134 
00135         read = ( IS_PORT_ADDRESS ( io_addr ) ?
00136                  cpu_io->Io.Read : cpu_io->Mem.Read );
00137 
00138         if ( ( efirc = read ( cpu_io, efi_width ( size ),
00139                               ( intptr_t ) io_addr, count,
00140                               ( void * ) data ) ) != 0 ) {
00141                 DBG ( "EFI I/O string read at %p failed: %s\n",
00142                       io_addr, efi_strerror ( efirc ) );
00143         }
00144 }
00145 
00146 /**
00147  * String write to device
00148  *
00149  * @v io_addr           I/O address
00150  * @v data              Data buffer
00151  * @v size              Size of values
00152  * @v count             Number of values to write
00153  */
00154 void efi_iowrites ( volatile void *io_addr, const void *data,
00155                     size_t size, unsigned int count ) {
00156         EFI_CPU_IO_PROTOCOL_IO_MEM write;
00157         EFI_STATUS efirc;
00158 
00159         write = ( IS_PORT_ADDRESS ( io_addr ) ?
00160                  cpu_io->Io.Write : cpu_io->Mem.Write );
00161 
00162         if ( ( efirc = write ( cpu_io, efi_width ( size ),
00163                                ( intptr_t ) io_addr, count,
00164                                ( void * ) data ) ) != 0 ) {
00165                 DBG ( "EFI I/O write at %p failed: %s\n",
00166                       io_addr, efi_strerror ( efirc ) );
00167         }
00168 }
00169 
00170 /**
00171  * Wait for I/O-mapped operation to complete
00172  *
00173  */
00174 static void efi_iodelay ( void ) {
00175         /* Write to non-existent port.  Probably x86-only. */
00176         outb ( 0, 0x80 );
00177 }
00178 
00179 PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
00180 PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
00181 PROVIDE_IOAPI_INLINE ( efi, ioremap );
00182 PROVIDE_IOAPI_INLINE ( efi, iounmap );
00183 PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
00184 PROVIDE_IOAPI_INLINE ( efi, readb );
00185 PROVIDE_IOAPI_INLINE ( efi, readw );
00186 PROVIDE_IOAPI_INLINE ( efi, readl );
00187 PROVIDE_IOAPI_INLINE ( efi, readq );
00188 PROVIDE_IOAPI_INLINE ( efi, writeb );
00189 PROVIDE_IOAPI_INLINE ( efi, writew );
00190 PROVIDE_IOAPI_INLINE ( efi, writel );
00191 PROVIDE_IOAPI_INLINE ( efi, writeq );
00192 PROVIDE_IOAPI_INLINE ( efi, inb );
00193 PROVIDE_IOAPI_INLINE ( efi, inw );
00194 PROVIDE_IOAPI_INLINE ( efi, inl );
00195 PROVIDE_IOAPI_INLINE ( efi, outb );
00196 PROVIDE_IOAPI_INLINE ( efi, outw );
00197 PROVIDE_IOAPI_INLINE ( efi, outl );
00198 PROVIDE_IOAPI_INLINE ( efi, insb );
00199 PROVIDE_IOAPI_INLINE ( efi, insw );
00200 PROVIDE_IOAPI_INLINE ( efi, insl );
00201 PROVIDE_IOAPI_INLINE ( efi, outsb );
00202 PROVIDE_IOAPI_INLINE ( efi, outsw );
00203 PROVIDE_IOAPI_INLINE ( efi, outsl );
00204 PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
00205 PROVIDE_IOAPI_INLINE ( efi, mb );

Generated on Tue Apr 6 20:01:09 2010 for gPXE by  doxygen 1.5.7.1