[pci] Save and restore PCI command register
[gpxe.git] / src / drivers / bus / pciextra.c
blob74c40990efa61f9a5fe222ba243c9cbb552da486
1 FILE_LICENCE ( GPL2_OR_LATER );
3 #include <stdint.h>
4 #include <gpxe/pci.h>
6 /**
7 * Look for a PCI capability
9 * @v pci PCI device to query
10 * @v cap Capability code
11 * @ret address Address of capability, or 0 if not found
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.
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;
24 pci_read_config_word ( pci, PCI_STATUS, &status );
25 if ( ! ( status & PCI_STATUS_CAP_LIST ) )
26 return 0;
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;
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 );
49 return 0;
52 /**
53 * Find the size of a PCI BAR
55 * @v pci PCI device
56 * @v reg PCI register number
57 * @ret size BAR size
59 * It should not be necessary for any Etherboot code to call this
60 * function.
62 unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
63 uint16_t cmd;
64 uint32_t start, size;
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;
83 /* Find the lowest bit set */
84 size = size & ~( size - 1 );
85 return size;