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 } 87