diff options
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/drivers/bus/pciextra.c')
-rw-r--r-- | contrib/syslinux-4.02/gpxe/src/drivers/bus/pciextra.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/drivers/bus/pciextra.c b/contrib/syslinux-4.02/gpxe/src/drivers/bus/pciextra.c new file mode 100644 index 0000000..74c4099 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/drivers/bus/pciextra.c @@ -0,0 +1,86 @@ +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <gpxe/pci.h> + +/** + * Look for a PCI capability + * + * @v pci PCI device to query + * @v cap Capability code + * @ret address Address of capability, or 0 if not found + * + * Determine whether or not a device supports a given PCI capability. + * Returns the address of the requested capability structure within + * the device's PCI configuration space, or 0 if the device does not + * support it. + */ +int pci_find_capability ( struct pci_device *pci, int cap ) { + uint16_t status; + uint8_t pos, id; + uint8_t hdr_type; + int ttl = 48; + + pci_read_config_word ( pci, PCI_STATUS, &status ); + if ( ! ( status & PCI_STATUS_CAP_LIST ) ) + return 0; + + pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type ); + switch ( hdr_type & 0x7F ) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + default: + pci_read_config_byte ( pci, PCI_CAPABILITY_LIST, &pos ); + break; + case PCI_HEADER_TYPE_CARDBUS: + pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos ); + break; + } + while ( ttl-- && pos >= 0x40 ) { + pos &= ~3; + pci_read_config_byte ( pci, pos + PCI_CAP_LIST_ID, &id ); + DBG ( "PCI Capability: %d\n", id ); + if ( id == 0xff ) + break; + if ( id == cap ) + return pos; + pci_read_config_byte ( pci, pos + PCI_CAP_LIST_NEXT, &pos ); + } + return 0; +} + +/** + * Find the size of a PCI BAR + * + * @v pci PCI device + * @v reg PCI register number + * @ret size BAR size + * + * It should not be necessary for any Etherboot code to call this + * function. + */ +unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) { + uint16_t cmd; + uint32_t start, size; + + /* Save the original command register */ + pci_read_config_word ( pci, PCI_COMMAND, &cmd ); + /* Save the original bar */ + pci_read_config_dword ( pci, reg, &start ); + /* Compute which bits can be set */ + pci_write_config_dword ( pci, reg, ~0 ); + pci_read_config_dword ( pci, reg, &size ); + /* Restore the original size */ + pci_write_config_dword ( pci, reg, start ); + /* Find the significant bits */ + /* Restore the original command register. This reenables decoding. */ + pci_write_config_word ( pci, PCI_COMMAND, cmd ); + if ( start & PCI_BASE_ADDRESS_SPACE_IO ) { + size &= PCI_BASE_ADDRESS_IO_MASK; + } else { + size &= PCI_BASE_ADDRESS_MEM_MASK; + } + /* Find the lowest bit set */ + size = size & ~( size - 1 ); + return size; +} |