public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] PCI: Add pci_find_next_capability() to deal with >1 caps of same type
@ 2005-10-17 23:08 Roland Dreier
  2005-10-18  2:10 ` Matthew Wilcox
  0 siblings, 1 reply; 4+ messages in thread
From: Roland Dreier @ 2005-10-17 23:08 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, linux-pci

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>)) {
		/* ... */
	}

I made this an EXPORT_SYMBOL() instead of an EXPORT_SYMBOL_GPL() since
it is a trivial wrapper around existing PCI functions, and I'd rather
see people use a nice wrapper instead of recreating the function.

Signed-off-by: Roland Dreier <rolandd@cisco.com>

---

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 259d247..b852959 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -120,6 +120,33 @@ int pci_find_capability(struct pci_dev *
 }
 
 /**
+ * pci_find_next_capability - Find next capability after current position
+ * @dev: PCI device to query
+ * @pos: Position to search from
+ * @cap: capability code
+ */
+int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
+{
+	u8 id;
+	int ttl = 48;
+
+	while (ttl--) {
+		pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
+		pos &= ~3;
+		if (pos < 0x40)
+			break;
+		pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pci_find_next_capability);
+
+/**
  * pci_bus_find_capability - query for devices' capabilities 
  * @bus:   the PCI bus to query
  * @devfn: PCI device to query
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7349058..8016d14 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -337,6 +337,7 @@ struct pci_dev *pci_find_device (unsigne
 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);
 
@@ -546,6 +547,7 @@ static inline int pci_assign_resource(st
 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; }
 

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] PCI: Add pci_find_next_capability() to deal with >1 caps of same type
  2005-10-17 23:08 [PATCH] PCI: Add pci_find_next_capability() to deal with >1 caps of same type Roland Dreier
@ 2005-10-18  2:10 ` Matthew Wilcox
  2005-10-18  3:17   ` Roland Dreier
  0 siblings, 1 reply; 4+ messages in thread
From: Matthew Wilcox @ 2005-10-18  2:10 UTC (permalink / raw)
  To: Roland Dreier; +Cc: gregkh, linux-kernel, linux-pci

On Mon, Oct 17, 2005 at 04:08:12PM -0700, Roland Dreier wrote:
> +	while (ttl--) {
> +		pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
> +		pos &= ~3;
> +		if (pos < 0x40)
> +			break;
> +		pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
> +		if (id == 0xff)
> +			break;
> +		if (id == cap)
> +			return pos;
> +	}

I don't like having this loop duplicated.  How about the following?

Index: ./drivers/pci/pci.c
===================================================================
RCS file: /var/lib/cvs/linux-2.6/drivers/pci/pci.c,v
retrieving revision 1.25
diff -u -p -r1.25 pci.c
--- ./drivers/pci/pci.c	24 Sep 2005 03:43:38 -0000	1.25
+++ ./drivers/pci/pci.c	18 Oct 2005 01:56:24 -0000
@@ -62,11 +62,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(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))
@@ -75,24 +102,15 @@ static int __pci_bus_find_cap(struct pci
 	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);
 }
 
 /**

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] PCI: Add pci_find_next_capability() to deal with >1 caps of same type
  2005-10-18  2:10 ` Matthew Wilcox
@ 2005-10-18  3:17   ` Roland Dreier
  2005-10-18  4:37     ` Greg KH
  0 siblings, 1 reply; 4+ messages in thread
From: Roland Dreier @ 2005-10-18  3:17 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: gregkh, linux-kernel, linux-pci

    Matthew> I don't like having this loop duplicated.  How about the
    Matthew> following?

Looks good to me -- I agree with wanting only one loop, but I wasn't
clever enough to see how to avoid the duplication.

Greg, want me to send a new patch including this along with required
the <linux/pci.h> changes again?

Thanks,
  Roland

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] PCI: Add pci_find_next_capability() to deal with >1 caps of same type
  2005-10-18  3:17   ` Roland Dreier
@ 2005-10-18  4:37     ` Greg KH
  0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2005-10-18  4:37 UTC (permalink / raw)
  To: Roland Dreier; +Cc: Matthew Wilcox, gregkh, linux-kernel, linux-pci

On Mon, Oct 17, 2005 at 08:17:15PM -0700, Roland Dreier wrote:
>     Matthew> I don't like having this loop duplicated.  How about the
>     Matthew> following?
> 
> Looks good to me -- I agree with wanting only one loop, but I wasn't
> clever enough to see how to avoid the duplication.
> 
> Greg, want me to send a new patch including this along with required
> the <linux/pci.h> changes again?

Yes, please do.  And all new PCI core exports should be _GPL please.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-10-18  4:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-10-17 23:08 [PATCH] PCI: Add pci_find_next_capability() to deal with >1 caps of same type Roland Dreier
2005-10-18  2:10 ` Matthew Wilcox
2005-10-18  3:17   ` Roland Dreier
2005-10-18  4:37     ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox