diff options
Diffstat (limited to 'drivers/pci/pci.c')
| -rw-r--r-- | drivers/pci/pci.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e74d75843047..8e287a828d5d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -63,11 +63,38 @@ pci_max_busnr(void) | |||
| 63 | return max; | 63 | return max; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) | ||
| 67 | { | ||
| 68 | u8 id; | ||
| 69 | int ttl = 48; | ||
| 70 | |||
| 71 | while (ttl--) { | ||
| 72 | pci_bus_read_config_byte(bus, devfn, pos, &pos); | ||
| 73 | if (pos < 0x40) | ||
| 74 | break; | ||
| 75 | pos &= ~3; | ||
| 76 | pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, | ||
| 77 | &id); | ||
| 78 | if (id == 0xff) | ||
| 79 | break; | ||
| 80 | if (id == cap) | ||
| 81 | return pos; | ||
| 82 | pos += PCI_CAP_LIST_NEXT; | ||
| 83 | } | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) | ||
| 88 | { | ||
| 89 | return __pci_find_next_cap(dev->bus, dev->devfn, | ||
| 90 | pos + PCI_CAP_LIST_NEXT, cap); | ||
| 91 | } | ||
| 92 | EXPORT_SYMBOL_GPL(pci_find_next_capability); | ||
| 93 | |||
| 66 | static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap) | 94 | static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap) |
| 67 | { | 95 | { |
| 68 | u16 status; | 96 | u16 status; |
| 69 | u8 pos, id; | 97 | u8 pos; |
| 70 | int ttl = 48; | ||
| 71 | 98 | ||
| 72 | pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status); | 99 | pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status); |
| 73 | if (!(status & PCI_STATUS_CAP_LIST)) | 100 | if (!(status & PCI_STATUS_CAP_LIST)) |
| @@ -76,24 +103,15 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty | |||
| 76 | switch (hdr_type) { | 103 | switch (hdr_type) { |
| 77 | case PCI_HEADER_TYPE_NORMAL: | 104 | case PCI_HEADER_TYPE_NORMAL: |
| 78 | case PCI_HEADER_TYPE_BRIDGE: | 105 | case PCI_HEADER_TYPE_BRIDGE: |
| 79 | pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos); | 106 | pos = PCI_CAPABILITY_LIST; |
| 80 | break; | 107 | break; |
| 81 | case PCI_HEADER_TYPE_CARDBUS: | 108 | case PCI_HEADER_TYPE_CARDBUS: |
| 82 | pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos); | 109 | pos = PCI_CB_CAPABILITY_LIST; |
| 83 | break; | 110 | break; |
| 84 | default: | 111 | default: |
| 85 | return 0; | 112 | return 0; |
| 86 | } | 113 | } |
| 87 | while (ttl-- && pos >= 0x40) { | 114 | return __pci_find_next_cap(bus, devfn, pos, cap); |
| 88 | pos &= ~3; | ||
| 89 | pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id); | ||
| 90 | if (id == 0xff) | ||
| 91 | break; | ||
| 92 | if (id == cap) | ||
| 93 | return pos; | ||
| 94 | pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos); | ||
| 95 | } | ||
| 96 | return 0; | ||
| 97 | } | 115 | } |
| 98 | 116 | ||
| 99 | /** | 117 | /** |
