[e16e8f2] | 1 | FILE_LICENCE ( GPL2_OR_LATER ); |
---|
| 2 | |
---|
| 3 | #include <stdint.h> |
---|
| 4 | #include <gpxe/pci.h> |
---|
| 5 | |
---|
| 6 | /** |
---|
| 7 | * Look for a PCI capability |
---|
| 8 | * |
---|
| 9 | * @v pci PCI device to query |
---|
| 10 | * @v cap Capability code |
---|
| 11 | * @ret address Address of capability, or 0 if not found |
---|
| 12 | * |
---|
| 13 | * Determine whether or not a device supports a given PCI capability. |
---|
| 14 | * Returns the address of the requested capability structure within |
---|
| 15 | * the device's PCI configuration space, or 0 if the device does not |
---|
| 16 | * support it. |
---|
| 17 | */ |
---|
| 18 | int pci_find_capability ( struct pci_device *pci, int cap ) { |
---|
| 19 | uint16_t status; |
---|
| 20 | uint8_t pos, id; |
---|
| 21 | uint8_t hdr_type; |
---|
| 22 | int ttl = 48; |
---|
| 23 | |
---|
| 24 | pci_read_config_word ( pci, PCI_STATUS, &status ); |
---|
| 25 | if ( ! ( status & PCI_STATUS_CAP_LIST ) ) |
---|
| 26 | return 0; |
---|
| 27 | |
---|
| 28 | pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type ); |
---|
| 29 | switch ( hdr_type & 0x7F ) { |
---|
| 30 | case PCI_HEADER_TYPE_NORMAL: |
---|
| 31 | case PCI_HEADER_TYPE_BRIDGE: |
---|
| 32 | default: |
---|
| 33 | pci_read_config_byte ( pci, PCI_CAPABILITY_LIST, &pos ); |
---|
| 34 | break; |
---|
| 35 | case PCI_HEADER_TYPE_CARDBUS: |
---|
| 36 | pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos ); |
---|
| 37 | break; |
---|
| 38 | } |
---|
| 39 | while ( ttl-- && pos >= 0x40 ) { |
---|
| 40 | pos &= ~3; |
---|
| 41 | pci_read_config_byte ( pci, pos + PCI_CAP_LIST_ID, &id ); |
---|
| 42 | DBG ( "PCI Capability: %d\n", id ); |
---|
| 43 | if ( id == 0xff ) |
---|
| 44 | break; |
---|
| 45 | if ( id == cap ) |
---|
| 46 | return pos; |
---|
| 47 | pci_read_config_byte ( pci, pos + PCI_CAP_LIST_NEXT, &pos ); |
---|
| 48 | } |
---|
| 49 | return 0; |
---|
| 50 | } |
---|
| 51 | |
---|
| 52 | /** |
---|
| 53 | * Find the size of a PCI BAR |
---|
| 54 | * |
---|
| 55 | * @v pci PCI device |
---|
| 56 | * @v reg PCI register number |
---|
| 57 | * @ret size BAR size |
---|
| 58 | * |
---|
| 59 | * It should not be necessary for any Etherboot code to call this |
---|
| 60 | * function. |
---|
| 61 | */ |
---|
| 62 | unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) { |
---|
| 63 | uint16_t cmd; |
---|
| 64 | uint32_t start, size; |
---|
| 65 | |
---|
| 66 | /* Save the original command register */ |
---|
| 67 | pci_read_config_word ( pci, PCI_COMMAND, &cmd ); |
---|
| 68 | /* Save the original bar */ |
---|
| 69 | pci_read_config_dword ( pci, reg, &start ); |
---|
| 70 | /* Compute which bits can be set */ |
---|
| 71 | pci_write_config_dword ( pci, reg, ~0 ); |
---|
| 72 | pci_read_config_dword ( pci, reg, &size ); |
---|
| 73 | /* Restore the original size */ |
---|
| 74 | pci_write_config_dword ( pci, reg, start ); |
---|
| 75 | /* Find the significant bits */ |
---|
| 76 | /* Restore the original command register. This reenables decoding. */ |
---|
| 77 | pci_write_config_word ( pci, PCI_COMMAND, cmd ); |
---|
| 78 | if ( start & PCI_BASE_ADDRESS_SPACE_IO ) { |
---|
| 79 | size &= PCI_BASE_ADDRESS_IO_MASK; |
---|
| 80 | } else { |
---|
| 81 | size &= PCI_BASE_ADDRESS_MEM_MASK; |
---|
| 82 | } |
---|
| 83 | /* Find the lowest bit set */ |
---|
| 84 | size = size & ~( size - 1 ); |
---|
| 85 | return size; |
---|
| 86 | } |
---|