]> xenbits.xensource.com Git - people/liuw/freebsd.git/commitdiff
Add a new helper function for PCI devices to locate the upstream
authorjhb <jhb@FreeBSD.org>
Thu, 5 Nov 2015 21:27:25 +0000 (21:27 +0000)
committerjhb <jhb@FreeBSD.org>
Thu, 5 Nov 2015 21:27:25 +0000 (21:27 +0000)
PCI-express root port of a given PCI device.

Reviewed by: kib, imp
MFC after: 1 week
Sponsored by: Chelsio
Differential Revision: https://reviews.freebsd.org/D4089

share/man/man9/Makefile
share/man/man9/pci.9
sys/dev/pci/pci.c
sys/dev/pci/pcivar.h

index 5ae857ed313e3c91a2dc5205f6f8c4d1f95074fd..b4af53d09188f101d71e472773d2bfa7f6f54fc4 100644 (file)
@@ -1274,6 +1274,7 @@ MLINKS+=pci.9 pci_alloc_msi.9 \
        pci.9 pci_find_device.9 \
        pci.9 pci_find_extcap.9 \
        pci.9 pci_find_htcap.9 \
+       pci.9 pci_find_pcie_root_port.9 \
        pci.9 pci_get_max_read_req.9 \
        pci.9 pci_get_powerstate.9 \
        pci.9 pci_get_vpd_ident.9 \
index 2321638a0e3e3c8823a21e3b5dac3cdb471a0390..4faa5f2a4a9dc7662dae0a974f5134e66b115c42 100644 (file)
@@ -42,6 +42,7 @@
 .Nm pci_find_device ,
 .Nm pci_find_extcap ,
 .Nm pci_find_htcap ,
+.Nm pci_find_pcie_root_port ,
 .Nm pci_get_max_read_req ,
 .Nm pci_get_powerstate ,
 .Nm pci_get_vpd_ident ,
@@ -91,6 +92,8 @@
 .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 device_t
+.Fn pci_find_pcie_root_port "device_t dev"
 .Ft int
 .Fn pci_get_max_read_req "device_t dev"
 .Ft int
@@ -338,6 +341,16 @@ If the capability is not found or the device is not a HyperTransport device,
 returns an error.
 .Pp
 The
+.Fn pci_find_pcie_root_port
+function walks up the PCI device hierarchy to locate the PCI-express root
+port upstream of
+.Fa dev .
+If a root port is not found,
+.Fn pci_find_pcie_root_port
+returns
+.Dv NULL .
+.Pp
+The
 .Fn pci_get_vpd_ident
 function is used to fetch a device's Vital Product Data
 .Pq VPD
index 5116a4fa579aa33b959b8adbb1dd32496ef9111a..f5e8470de3acab46558fcb7b446ea7499d90c4a8 100644 (file)
@@ -5431,3 +5431,44 @@ pci_get_rid_method(device_t dev, device_t child)
 
        return (PCIB_GET_RID(device_get_parent(dev), child));
 }
+
+/* Find the upstream port of a given PCI device in a root complex. */
+device_t
+pci_find_pcie_root_port(device_t dev)
+{
+       struct pci_devinfo *dinfo;
+       devclass_t pci_class;
+       device_t pcib, bus;
+
+       pci_class = devclass_find("pci");
+       KASSERT(device_get_devclass(device_get_parent(dev)) == pci_class,
+           ("%s: non-pci device %s", __func__, device_get_nameunit(dev)));
+
+       /*
+        * Walk the bridge hierarchy until we find a PCI-e root
+        * port or a non-PCI device.
+        */
+       for (;;) {
+               bus = device_get_parent(dev);
+               KASSERT(bus != NULL, ("%s: null parent of %s", __func__,
+                   device_get_nameunit(dev)));
+
+               pcib = device_get_parent(bus);
+               KASSERT(pcib != NULL, ("%s: null bridge of %s", __func__,
+                   device_get_nameunit(bus)));
+
+               /*
+                * pcib's parent must be a PCI bus for this to be a
+                * PCI-PCI bridge.
+                */
+               if (device_get_devclass(device_get_parent(pcib)) != pci_class)
+                       return (NULL);
+
+               dinfo = device_get_ivars(pcib);
+               if (dinfo->cfg.pcie.pcie_location != 0 &&
+                   dinfo->cfg.pcie.pcie_type == PCIEM_TYPE_ROOT_PORT)
+                       return (pcib);
+
+               dev = pcib;
+       }
+}
index 242201b13390014f987a829d324a573aee8ad5a3..b8f64c2d9793185acde73b2aa2a3ac3091341ca4 100644 (file)
@@ -547,6 +547,7 @@ int pci_msix_device_blacklisted(device_t dev);
 
 void   pci_ht_map_msi(device_t dev, uint64_t addr);
 
+device_t pci_find_pcie_root_port(device_t dev);
 int    pci_get_max_read_req(device_t dev);
 void   pci_restore_state(device_t dev);
 void   pci_save_state(device_t dev);