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