diff options
author | Roland Dreier <rolandd@cisco.com> | 2005-10-28 20:35:34 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-11-10 19:09:14 -0500 |
commit | 24a4e377068d15424cd6a921d41352f295548037 (patch) | |
tree | f6eb0e19f3828ca713d8151a63292de6d2287a90 /drivers/pci/pci.c | |
parent | 6d23c8bc7a6af4300b3c5244f4c21211f9adb960 (diff) |
[PATCH] PCI: add pci_find_next_capability()
Some devices have more than one capability of the same type. For
example, the PCI header for the PathScale InfiniPath looks like:
04:01.0 InfiniBand: Unknown device 1fc1:000d (rev 02)
Subsystem: Unknown device 1fc1:000d
Flags: bus master, fast devsel, latency 0, IRQ 193
Memory at fea00000 (64-bit, non-prefetchable) [size=2M]
Capabilities: [c0] HyperTransport: Slave or Primary Interface
Capabilities: [f8] HyperTransport: Interrupt Discovery and Configuration
There are _two_ HyperTransport capabilities, and the PathScale driver
wants to look at both of them.
The current pci_find_capability() API doesn't work for this, since it
only allows us to get to the first capability of a given type. The
patch below introduces a new pci_find_next_capability(), which can be
used in a loop like
for (pos = pci_find_capability(pdev, <ID>);
pos;
pos = pci_find_next_capability(pdev, pos, <ID>)) {
/* ... */
}
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Signed-off-by: Matthew Wilcox <matthew@wil.cx>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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 | /** |