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 | |
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>
-rw-r--r-- | drivers/pci/pci.c | 46 | ||||
-rw-r--r-- | include/linux/pci.h | 2 |
2 files changed, 34 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 | /** |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 3596ac94ecff..7063241e34d9 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -338,6 +338,7 @@ struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const | |||
338 | struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from); | 338 | struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from); |
339 | struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); | 339 | struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); |
340 | int pci_find_capability (struct pci_dev *dev, int cap); | 340 | int pci_find_capability (struct pci_dev *dev, int cap); |
341 | int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); | ||
341 | int pci_find_ext_capability (struct pci_dev *dev, int cap); | 342 | int pci_find_ext_capability (struct pci_dev *dev, int cap); |
342 | struct pci_bus * pci_find_next_bus(const struct pci_bus *from); | 343 | struct pci_bus * pci_find_next_bus(const struct pci_bus *from); |
343 | 344 | ||
@@ -550,6 +551,7 @@ static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUS | |||
550 | static inline int pci_register_driver(struct pci_driver *drv) { return 0;} | 551 | static inline int pci_register_driver(struct pci_driver *drv) { return 0;} |
551 | static inline void pci_unregister_driver(struct pci_driver *drv) { } | 552 | static inline void pci_unregister_driver(struct pci_driver *drv) { } |
552 | static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } | 553 | static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } |
554 | static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; } | ||
553 | static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; } | 555 | static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; } |
554 | static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } | 556 | static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } |
555 | 557 | ||