iPXE
pciextra.c
Go to the documentation of this file.
00001 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00002 
00003 #include <stdint.h>
00004 #include <ipxe/pci.h>
00005 
00006 static int pci_find_capability_common ( struct pci_device *pci,
00007                                         uint8_t pos, int cap ) {
00008         uint8_t id;
00009         int ttl = 48;
00010 
00011         while ( ttl-- && pos >= 0x40 ) {
00012                 pos &= ~3;
00013                 pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id );
00014                 DBG ( "PCI Capability: %d\n", id );
00015                 if ( id == 0xff )
00016                         break;
00017                 if ( id == cap )
00018                         return pos;
00019                 pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos );
00020         }
00021         return 0;
00022 }
00023 
00024 /**
00025  * Look for a PCI capability
00026  *
00027  * @v pci               PCI device to query
00028  * @v cap               Capability code
00029  * @ret address         Address of capability, or 0 if not found
00030  *
00031  * Determine whether or not a device supports a given PCI capability.
00032  * Returns the address of the requested capability structure within
00033  * the device's PCI configuration space, or 0 if the device does not
00034  * support it.
00035  */
00036 int pci_find_capability ( struct pci_device *pci, int cap ) {
00037         uint16_t status;
00038         uint8_t pos;
00039         uint8_t hdr_type;
00040 
00041         pci_read_config_word ( pci, PCI_STATUS, &status );
00042         if ( ! ( status & PCI_STATUS_CAP_LIST ) )
00043                 return 0;
00044 
00045         pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type );
00046         switch ( hdr_type & PCI_HEADER_TYPE_MASK ) {
00047         case PCI_HEADER_TYPE_NORMAL:
00048         case PCI_HEADER_TYPE_BRIDGE:
00049         default:
00050                 pci_read_config_byte ( pci, PCI_CAPABILITY_LIST, &pos );
00051                 break;
00052         case PCI_HEADER_TYPE_CARDBUS:
00053                 pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos );
00054                 break;
00055         }
00056         return pci_find_capability_common ( pci, pos, cap );
00057 }
00058 
00059 /**
00060  * Look for another PCI capability
00061  *
00062  * @v pci               PCI device to query
00063  * @v pos               Address of the current capability
00064  * @v cap               Capability code
00065  * @ret address         Address of capability, or 0 if not found
00066  *
00067  * Determine whether or not a device supports a given PCI capability
00068  * starting the search at a given address within the device's PCI
00069  * configuration space. Returns the address of the next capability
00070  * structure within the device's PCI configuration space, or 0 if the
00071  * device does not support another such capability.
00072  */
00073 int pci_find_next_capability ( struct pci_device *pci, int pos, int cap ) {
00074         uint8_t new_pos;
00075 
00076         pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &new_pos );
00077         return pci_find_capability_common ( pci, new_pos, cap );
00078 }
00079 
00080 /**
00081  * Find the size of a PCI BAR
00082  *
00083  * @v pci               PCI device
00084  * @v reg               PCI register number
00085  * @ret size            BAR size
00086  *
00087  * It should not be necessary for any Etherboot code to call this
00088  * function.
00089  */
00090 unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
00091         uint16_t cmd;
00092         uint32_t start, size;
00093 
00094         /* Save the original command register */
00095         pci_read_config_word ( pci, PCI_COMMAND, &cmd );
00096         /* Save the original bar */
00097         pci_read_config_dword ( pci, reg, &start );
00098         /* Compute which bits can be set */
00099         pci_write_config_dword ( pci, reg, ~0 );
00100         pci_read_config_dword ( pci, reg, &size );
00101         /* Restore the original size */
00102         pci_write_config_dword ( pci, reg, start );
00103         /* Find the significant bits */
00104         /* Restore the original command register. This reenables decoding. */
00105         pci_write_config_word ( pci, PCI_COMMAND, cmd );
00106         if ( start & PCI_BASE_ADDRESS_SPACE_IO ) {
00107                 size &= ~PCI_BASE_ADDRESS_IO_MASK;
00108         } else {
00109                 size &= ~PCI_BASE_ADDRESS_MEM_MASK;
00110         }
00111         /* Find the lowest bit set */
00112         size = size & ~( size - 1 );
00113         return size;
00114 }