Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Feb 2018 18:41:56 +0000 (UTC)
From:      Bryan Venteicher <bryanv@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329598 - in head: share/man/man9 sys/dev/pci
Message-ID:  <201802191841.w1JIfutv071319@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bryanv
Date: Mon Feb 19 18:41:56 2018
New Revision: 329598
URL: https://svnweb.freebsd.org/changeset/base/329598

Log:
  Add PCI methods to iterate over the PCI capabilities
  
  VirtIO V1 provides configuration in multiple VENDOR capabilities so this
  allows all of the configuration to be discovered.
  
  Reviewed by:	jhb
  MFC after:	2 weeks
  Differential Revision:	https://reviews.freebsd.org/D14325

Modified:
  head/share/man/man9/pci.9
  head/sys/dev/pci/hostb_pci.c
  head/sys/dev/pci/pci.c
  head/sys/dev/pci/pci_if.m
  head/sys/dev/pci/pci_private.h
  head/sys/dev/pci/pcivar.h
  head/sys/dev/pci/vga_pci.c

Modified: head/share/man/man9/pci.9
==============================================================================
--- head/share/man/man9/pci.9	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/share/man/man9/pci.9	Mon Feb 19 18:41:56 2018	(r329598)
@@ -42,6 +42,9 @@
 .Nm pci_find_device ,
 .Nm pci_find_extcap ,
 .Nm pci_find_htcap ,
+.Nm pci_find_next_cap ,
+.Nm pci_find_next_extcap ,
+.Nm pci_find_next_htcap ,
 .Nm pci_find_pcie_root_port ,
 .Nm pci_get_id ,
 .Nm pci_get_max_payload ,
@@ -100,6 +103,12 @@
 .Fn pci_find_extcap "device_t dev" "int capability" "int *capreg"
 .Ft int
 .Fn pci_find_htcap "device_t dev" "int capability" "int *capreg"
+.Ft int
+.Fn pci_find_next_cap "device_t dev" "int capability" "int start" "int *capreg"
+.Ft int
+.Fn pci_find_next_extcap "device_t dev" "int capability" "int start" "int *capreg"
+.Ft int
+.Fn pci_find_next_htcap "device_t dev" "int capability" "int start" "int *capreg"
 .Ft device_t
 .Fn pci_find_pcie_root_port "device_t dev"
 .Ft int
@@ -330,6 +339,22 @@ returns zero.
 If the capability is not found or the device does not support capabilities,
 .Fn pci_find_cap
 returns an error.
+The
+.Fn pci_find_next_cap
+function is used to locate the next instance of a PCI capability
+register set for the device
+.Fa dev .
+The
+.Fa start
+should be the
+.Fa *capreg
+returned by a prior
+.Fn pci_find_cap
+or
+.Fn pci_find_next_cap .
+When no more instances are located
+.Fn pci_find_next_cap
+returns an error.
 .Pp
 The
 .Fn pci_find_extcap
@@ -352,6 +377,22 @@ If the extended capability is not found or the device 
 PCI-express device,
 .Fn pci_find_extcap
 returns an error.
+The
+.Fn pci_find_next_extcap
+function is used to locate the next instance of a PCI-express
+extended capability register set for the device
+.Fa dev .
+The
+.Fa start
+should be the
+.Fa *capreg
+returned by a prior
+.Fn pci_find_extcap
+or
+.Fn pci_find_next_extcap .
+When no more instances are located
+.Fn pci_find_next_extcap
+returns an error.
 .Pp
 The
 .Fn pci_find_htcap
@@ -372,6 +413,22 @@ and
 returns zero.
 If the capability is not found or the device is not a HyperTransport device,
 .Fn pci_find_htcap
+returns an error.
+The
+.Fn pci_find_next_htcap
+function is used to locate the next instance of a HyperTransport capability
+register set for the device
+.Fa dev .
+The
+.Fa start
+should be the
+.Fa *capreg
+returned by a prior
+.Fn pci_find_htcap
+or
+.Fn pci_find_next_htcap .
+When no more instances are located
+.Fn pci_find_next_htcap
 returns an error.
 .Pp
 The

Modified: head/sys/dev/pci/hostb_pci.c
==============================================================================
--- head/sys/dev/pci/hostb_pci.c	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/sys/dev/pci/hostb_pci.c	Mon Feb 19 18:41:56 2018	(r329598)
@@ -207,6 +207,14 @@ pci_hostb_find_cap(device_t dev, device_t child, int c
 }
 
 static int
+pci_hostb_find_next_cap(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+
+	return (pci_find_next_cap(dev, capability, start, capreg));
+}
+
+static int
 pci_hostb_find_extcap(device_t dev, device_t child, int capability,
     int *capreg)
 {
@@ -215,6 +223,14 @@ pci_hostb_find_extcap(device_t dev, device_t child, in
 }
 
 static int
+pci_hostb_find_next_extcap(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+
+	return (pci_find_next_extcap(dev, capability, start, capreg));
+}
+
+static int
 pci_hostb_find_htcap(device_t dev, device_t child, int capability,
     int *capreg)
 {
@@ -222,6 +238,14 @@ pci_hostb_find_htcap(device_t dev, device_t child, int
 	return (pci_find_htcap(dev, capability, capreg));
 }
 
+static int
+pci_hostb_find_next_htcap(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+
+	return (pci_find_next_htcap(dev, capability, start, capreg));
+}
+
 static device_method_t pci_hostb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		pci_hostb_probe),
@@ -252,8 +276,11 @@ static device_method_t pci_hostb_methods[] = {
 	DEVMETHOD(pci_set_powerstate,	pci_hostb_set_powerstate),
 	DEVMETHOD(pci_assign_interrupt,	pci_hostb_assign_interrupt),
 	DEVMETHOD(pci_find_cap,		pci_hostb_find_cap),
+	DEVMETHOD(pci_find_next_cap,	pci_hostb_find_next_cap),
 	DEVMETHOD(pci_find_extcap,	pci_hostb_find_extcap),
+	DEVMETHOD(pci_find_next_extcap,	pci_hostb_find_next_extcap),
 	DEVMETHOD(pci_find_htcap,	pci_hostb_find_htcap),
+	DEVMETHOD(pci_find_next_htcap,	pci_hostb_find_next_htcap),
 
 	{ 0, 0 }
 };

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/sys/dev/pci/pci.c	Mon Feb 19 18:41:56 2018	(r329598)
@@ -183,8 +183,11 @@ static device_method_t pci_methods[] = {
 	DEVMETHOD(pci_set_powerstate,	pci_set_powerstate_method),
 	DEVMETHOD(pci_assign_interrupt,	pci_assign_interrupt_method),
 	DEVMETHOD(pci_find_cap,		pci_find_cap_method),
+	DEVMETHOD(pci_find_next_cap,	pci_find_next_cap_method),
 	DEVMETHOD(pci_find_extcap,	pci_find_extcap_method),
+	DEVMETHOD(pci_find_next_extcap,	pci_find_next_extcap_method),
 	DEVMETHOD(pci_find_htcap,	pci_find_htcap_method),
+	DEVMETHOD(pci_find_next_htcap,	pci_find_next_htcap_method),
 	DEVMETHOD(pci_alloc_msi,	pci_alloc_msi_method),
 	DEVMETHOD(pci_alloc_msix,	pci_alloc_msix_method),
 	DEVMETHOD(pci_enable_msi,	pci_enable_msi_method),
@@ -1377,7 +1380,7 @@ pci_find_htcap_method(device_t dev, device_t child, in
 	 * Traverse the capabilities list checking each HT capability
 	 * to see if it matches the requested HT capability.
 	 */
-	while (ptr != 0) {
+	for (;;) {
 		val = pci_read_config(child, ptr + PCIR_HT_COMMAND, 2);
 		if (capability == PCIM_HTCAP_SLAVE ||
 		    capability == PCIM_HTCAP_HOST)
@@ -1391,13 +1394,51 @@ pci_find_htcap_method(device_t dev, device_t child, in
 		}
 
 		/* Skip to the next HT capability. */
-		while (ptr != 0) {
-			ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1);
-			if (pci_read_config(child, ptr + PCICAP_ID, 1) ==
-			    PCIY_HT)
-				break;
+		if (pci_find_next_cap(child, PCIY_HT, ptr, &ptr) != 0)
+			break;
+	}
+
+	return (ENOENT);
+}
+
+/*
+ * Find the next requested HyperTransport capability after start and return
+ * the offset in configuration space via the pointer provided.  The function
+ * returns 0 on success and an error code otherwise.
+ */
+int
+pci_find_next_htcap_method(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+	int ptr;
+	uint16_t val;
+
+	KASSERT(pci_read_config(child, start + PCICAP_ID, 1) == PCIY_HT,
+	    ("start capability is not HyperTransport capability"));
+	ptr = start;
+
+	/*
+	 * Traverse the capabilities list checking each HT capability
+	 * to see if it matches the requested HT capability.
+	 */
+	for (;;) {
+		/* Skip to the next HT capability. */
+		if (pci_find_next_cap(child, PCIY_HT, ptr, &ptr) != 0)
+			break;
+
+		val = pci_read_config(child, ptr + PCIR_HT_COMMAND, 2);
+		if (capability == PCIM_HTCAP_SLAVE ||
+		    capability == PCIM_HTCAP_HOST)
+			val &= 0xe000;
+		else
+			val &= PCIM_HTCMD_CAP_MASK;
+		if (val == capability) {
+			if (capreg != NULL)
+				*capreg = ptr;
+			return (0);
 		}
 	}
+
 	return (ENOENT);
 }
 
@@ -1412,8 +1453,8 @@ pci_find_cap_method(device_t dev, device_t child, int 
 {
 	struct pci_devinfo *dinfo = device_get_ivars(child);
 	pcicfgregs *cfg = &dinfo->cfg;
-	u_int32_t status;
-	u_int8_t ptr;
+	uint32_t status;
+	uint8_t ptr;
 
 	/*
 	 * Check the CAP_LIST bit of the PCI status register first.
@@ -1455,6 +1496,33 @@ pci_find_cap_method(device_t dev, device_t child, int 
 }
 
 /*
+ * Find the next requested capability after start and return the offset in
+ * configuration space via the pointer provided.  The function returns
+ * 0 on success and an error code otherwise.
+ */
+int
+pci_find_next_cap_method(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+	uint8_t ptr;
+
+	KASSERT(pci_read_config(child, start + PCICAP_ID, 1) == capability,
+	    ("start capability is not expected capability"));
+
+	ptr = pci_read_config(child, start + PCICAP_NEXTPTR, 1);
+	while (ptr != 0) {
+		if (pci_read_config(child, ptr + PCICAP_ID, 1) == capability) {
+			if (capreg != NULL)
+				*capreg = ptr;
+			return (0);
+		}
+		ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1);
+	}
+
+	return (ENOENT);
+}
+
+/*
  * Find the requested extended capability and return the offset in
  * configuration space via the pointer provided.  The function returns
  * 0 on success and an error code otherwise.
@@ -1486,6 +1554,41 @@ pci_find_extcap_method(device_t dev, device_t child, i
 		if (ptr == 0)
 			break;
 		ecap = pci_read_config(child, ptr, 4);
+	}
+
+	return (ENOENT);
+}
+
+/*
+ * Find the next requested extended capability after start and return the
+ * offset in configuration space via the pointer provided.  The function
+ * returns 0 on success and an error code otherwise.
+ */
+int
+pci_find_next_extcap_method(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(child);
+	pcicfgregs *cfg = &dinfo->cfg;
+	uint32_t ecap;
+	uint16_t ptr;
+
+	/* Only supported for PCI-express devices. */
+	if (cfg->pcie.pcie_location == 0)
+		return (ENXIO);
+
+	ecap = pci_read_config(child, start, 4);
+	KASSERT(PCI_EXTCAP_ID(ecap) == capability,
+	    ("start extended capability is not expected capability"));
+	ptr = PCI_EXTCAP_NEXTPTR(ecap);
+	while (ptr != 0) {
+		ecap = pci_read_config(child, ptr, 4);
+		if (PCI_EXTCAP_ID(ecap) == capability) {
+			if (capreg != NULL)
+				*capreg = ptr;
+			return (0);
+		}
+		ptr = PCI_EXTCAP_NEXTPTR(ecap);
 	}
 
 	return (ENOENT);

Modified: head/sys/dev/pci/pci_if.m
==============================================================================
--- head/sys/dev/pci/pci_if.m	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/sys/dev/pci/pci_if.m	Mon Feb 19 18:41:56 2018	(r329598)
@@ -141,6 +141,14 @@ METHOD int find_cap {
 	int		*capreg;
 };
 
+METHOD int find_next_cap {
+	device_t	dev;
+	device_t	child;
+	int		capability;
+	int		start;
+	int		*capreg;
+};
+
 METHOD int find_extcap {
 	device_t	dev;
 	device_t	child;
@@ -148,10 +156,26 @@ METHOD int find_extcap {
 	int		*capreg;
 };
 
+METHOD int find_next_extcap {
+	device_t	dev;
+	device_t	child;
+	int		capability;
+	int		start;
+	int		*capreg;
+};
+
 METHOD int find_htcap {
 	device_t	dev;
 	device_t	child;
 	int		capability;
+	int		*capreg;
+};
+
+METHOD int find_next_htcap {
+	device_t	dev;
+	device_t	child;
+	int		capability;
+	int		start;
 	int		*capreg;
 };
 

Modified: head/sys/dev/pci/pci_private.h
==============================================================================
--- head/sys/dev/pci/pci_private.h	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/sys/dev/pci/pci_private.h	Mon Feb 19 18:41:56 2018	(r329598)
@@ -90,10 +90,16 @@ int		pci_enable_io_method(device_t dev, device_t child
 int		pci_disable_io_method(device_t dev, device_t child, int space);
 int		pci_find_cap_method(device_t dev, device_t child,
 		    int capability, int *capreg);
+int		pci_find_next_cap_method(device_t dev, device_t child,
+		    int capability, int start, int *capreg);
 int		pci_find_extcap_method(device_t dev, device_t child,
 		    int capability, int *capreg);
+int		pci_find_next_extcap_method(device_t dev, device_t child,
+		    int capability, int start, int *capreg);
 int		pci_find_htcap_method(device_t dev, device_t child,
 		    int capability, int *capreg);
+int		pci_find_next_htcap_method(device_t dev, device_t child,
+		    int capability, int start, int *capreg);
 int		pci_alloc_msi_method(device_t dev, device_t child, int *count);
 int		pci_alloc_msix_method(device_t dev, device_t child, int *count);
 void		pci_enable_msi_method(device_t dev, device_t child,

Modified: head/sys/dev/pci/pcivar.h
==============================================================================
--- head/sys/dev/pci/pcivar.h	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/sys/dev/pci/pcivar.h	Mon Feb 19 18:41:56 2018	(r329598)
@@ -468,15 +468,36 @@ pci_find_cap(device_t dev, int capability, int *capreg
 }
 
 static __inline int
+pci_find_next_cap(device_t dev, int capability, int start, int *capreg)
+{
+    return (PCI_FIND_NEXT_CAP(device_get_parent(dev), dev, capability, start,
+        capreg));
+}
+
+static __inline int
 pci_find_extcap(device_t dev, int capability, int *capreg)
 {
     return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
 }
 
 static __inline int
+pci_find_next_extcap(device_t dev, int capability, int start, int *capreg)
+{
+    return (PCI_FIND_NEXT_EXTCAP(device_get_parent(dev), dev, capability,
+        start, capreg));
+}
+
+static __inline int
 pci_find_htcap(device_t dev, int capability, int *capreg)
 {
     return (PCI_FIND_HTCAP(device_get_parent(dev), dev, capability, capreg));
+}
+
+static __inline int
+pci_find_next_htcap(device_t dev, int capability, int start, int *capreg)
+{
+    return (PCI_FIND_NEXT_HTCAP(device_get_parent(dev), dev, capability,
+        start, capreg));
 }
 
 static __inline int

Modified: head/sys/dev/pci/vga_pci.c
==============================================================================
--- head/sys/dev/pci/vga_pci.c	Mon Feb 19 18:14:12 2018	(r329597)
+++ head/sys/dev/pci/vga_pci.c	Mon Feb 19 18:41:56 2018	(r329598)
@@ -497,6 +497,14 @@ vga_pci_find_cap(device_t dev, device_t child, int cap
 }
 
 static int
+vga_pci_find_next_cap(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+
+	return (pci_find_next_cap(dev, capability, start, capreg));
+}
+
+static int
 vga_pci_find_extcap(device_t dev, device_t child, int capability,
     int *capreg)
 {
@@ -505,6 +513,14 @@ vga_pci_find_extcap(device_t dev, device_t child, int 
 }
 
 static int
+vga_pci_find_next_extcap(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+
+	return (pci_find_next_extcap(dev, capability, start, capreg));
+}
+
+static int
 vga_pci_find_htcap(device_t dev, device_t child, int capability,
     int *capreg)
 {
@@ -513,6 +529,14 @@ vga_pci_find_htcap(device_t dev, device_t child, int c
 }
 
 static int
+vga_pci_find_next_htcap(device_t dev, device_t child, int capability,
+    int start, int *capreg)
+{
+
+	return (pci_find_next_htcap(dev, capability, start, capreg));
+}
+
+static int
 vga_pci_alloc_msi(device_t dev, device_t child, int *count)
 {
 	struct vga_pci_softc *sc;
@@ -622,8 +646,11 @@ static device_method_t vga_pci_methods[] = {
 	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
 	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
 	DEVMETHOD(pci_find_cap,		vga_pci_find_cap),
+	DEVMETHOD(pci_find_next_cap,	vga_pci_find_next_cap),
 	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
+	DEVMETHOD(pci_find_next_extcap,	vga_pci_find_next_extcap),
 	DEVMETHOD(pci_find_htcap,	vga_pci_find_htcap),
+	DEVMETHOD(pci_find_next_htcap,	vga_pci_find_next_htcap),
 	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
 	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
 	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802191841.w1JIfutv071319>