diff options
author | jhb <jhb@FreeBSD.org> | 2015-11-05 21:27:25 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2015-11-05 21:27:25 +0000 |
commit | fa7f239637c899b490a1463c23b0516030c79bc4 (patch) | |
tree | 5c0c3dd2265de647727b90524bf7ccdbbf094e85 /sys/dev | |
parent | 0c12e4753ba6951c7105eee5418f69cfda826f9c (diff) | |
download | FreeBSD-src-fa7f239637c899b490a1463c23b0516030c79bc4.zip FreeBSD-src-fa7f239637c899b490a1463c23b0516030c79bc4.tar.gz |
Add a new helper function for PCI devices to locate the upstream
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
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/pci.c | 41 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 1 |
2 files changed, 42 insertions, 0 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 5116a4f..f5e8470 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -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; + } +} diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 242201b..b8f64c2 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -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); |