176d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h> 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Look for a PCI capability 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v pci PCI device to query 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v cap Capability code 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret address Address of capability, or 0 if not found 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Determine whether or not a device supports a given PCI capability. 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns the address of the requested capability structure within 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the device's PCI configuration space, or 0 if the device does not 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * support it. 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint pci_find_capability ( struct pci_device *pci, int cap ) { 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t status; 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t pos, id; 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t hdr_type; 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ttl = 48; 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_word ( pci, PCI_STATUS, &status ); 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! ( status & PCI_STATUS_CAP_LIST ) ) 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type ); 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch ( hdr_type & 0x7F ) { 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PCI_HEADER_TYPE_NORMAL: 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PCI_HEADER_TYPE_BRIDGE: 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_byte ( pci, PCI_CAPABILITY_LIST, &pos ); 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PCI_HEADER_TYPE_CARDBUS: 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos ); 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( ttl-- && pos >= 0x40 ) { 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pos &= ~3; 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_byte ( pci, pos + PCI_CAP_LIST_ID, &id ); 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "PCI Capability: %d\n", id ); 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( id == 0xff ) 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( id == cap ) 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return pos; 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_byte ( pci, pos + PCI_CAP_LIST_NEXT, &pos ); 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Find the size of a PCI BAR 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v pci PCI device 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v reg PCI register number 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret size BAR size 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It should not be necessary for any Etherboot code to call this 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * function. 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanunsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) { 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t cmd; 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t start, size; 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Save the original command register */ 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_word ( pci, PCI_COMMAND, &cmd ); 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Save the original bar */ 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_dword ( pci, reg, &start ); 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Compute which bits can be set */ 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_write_config_dword ( pci, reg, ~0 ); 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_dword ( pci, reg, &size ); 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Restore the original size */ 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_write_config_dword ( pci, reg, start ); 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Find the significant bits */ 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Restore the original command register. This reenables decoding. */ 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_write_config_word ( pci, PCI_COMMAND, cmd ); 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( start & PCI_BASE_ADDRESS_SPACE_IO ) { 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size &= PCI_BASE_ADDRESS_IO_MASK; 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size &= PCI_BASE_ADDRESS_MEM_MASK; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Find the lowest bit set */ 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size = size & ~( size - 1 ); 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return size; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 87