summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2005-10-28 17:35:34 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2005-11-10 16:09:14 -0800
commit24a4e377068d15424cd6a921d41352f295548037 (patch)
treef6eb0e19f3828ca713d8151a63292de6d2287a90
parent6d23c8bc7a6af4300b3c5244f4c21211f9adb960 (diff)
downloadlinux-24a4e377068d15424cd6a921d41352f295548037.tar.bz2
[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.c46
-rw-r--r--include/linux/pci.h2
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)
return max;
}
+static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
+{
+ u8 id;
+ int ttl = 48;
+
+ while (ttl--) {
+ pci_bus_read_config_byte(bus, devfn, pos, &pos);
+ if (pos < 0x40)
+ break;
+ pos &= ~3;
+ pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID,
+ &id);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pos += PCI_CAP_LIST_NEXT;
+ }
+ return 0;
+}
+
+int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
+{
+ return __pci_find_next_cap(dev->bus, dev->devfn,
+ pos + PCI_CAP_LIST_NEXT, cap);
+}
+EXPORT_SYMBOL_GPL(pci_find_next_capability);
+
static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap)
{
u16 status;
- u8 pos, id;
- int ttl = 48;
+ u8 pos;
pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
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
switch (hdr_type) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
- pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);
+ pos = PCI_CAPABILITY_LIST;
break;
case PCI_HEADER_TYPE_CARDBUS:
- pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);
+ pos = PCI_CB_CAPABILITY_LIST;
break;
default:
return 0;
}
- while (ttl-- && pos >= 0x40) {
- pos &= ~3;
- pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);
- if (id == 0xff)
- break;
- if (id == cap)
- return pos;
- pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);
- }
- return 0;
+ return __pci_find_next_cap(bus, devfn, pos, cap);
}
/**
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
struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from);
struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
int pci_find_capability (struct pci_dev *dev, int cap);
+int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
int pci_find_ext_capability (struct pci_dev *dev, int cap);
struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
@@ -550,6 +551,7 @@ static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUS
static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
static inline void pci_unregister_driver(struct pci_driver *drv) { }
static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
+static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; }
static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; }