LinuxKPI: pci: fix pcie_get_speed_cap()
pcie_get_speed_cap() has a hard coded skip of 3 devices at the beginning. It is either called on a pdev or on a result from pci_upstream_bridge(). In the latter case skipping another three devices might get us to acpi0 or nexus, neither of which is a PCI device still and pci_get_vendor() will panic() on that. Sponsored by: The FreeBSD Foundation (commit) GHI: https://github.com/freebsd/drm-kmod/issues/393 MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D53862
This commit is contained in:
@@ -1136,19 +1136,28 @@ pci_num_vf(struct pci_dev *dev)
|
||||
static inline enum pci_bus_speed
|
||||
pcie_get_speed_cap(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *pbus;
|
||||
device_t root;
|
||||
uint32_t lnkcap, lnkcap2;
|
||||
int error, pos;
|
||||
|
||||
root = device_get_parent(dev->dev.bsddev);
|
||||
if (root == NULL)
|
||||
return (PCI_SPEED_UNKNOWN);
|
||||
root = device_get_parent(root);
|
||||
if (root == NULL)
|
||||
return (PCI_SPEED_UNKNOWN);
|
||||
root = device_get_parent(root);
|
||||
if (root == NULL)
|
||||
return (PCI_SPEED_UNKNOWN);
|
||||
/*
|
||||
* We should always be called on a PCI device.
|
||||
* The only current consumer I could find was amdgpu which either
|
||||
* calls us directly on a pdev(drmn?) or with the result of
|
||||
* pci_upstream_bridge().
|
||||
*
|
||||
* Treat "drmn" as special again as it is not a PCI device.
|
||||
*/
|
||||
if (dev->pdrv != NULL && dev->pdrv->isdrm) {
|
||||
pbus = pci_upstream_bridge(dev);
|
||||
if (pbus == NULL)
|
||||
return (PCI_SPEED_UNKNOWN);
|
||||
} else
|
||||
pbus = dev;
|
||||
|
||||
/* "root" may be misleading as it may not be that. */
|
||||
root = pbus->dev.bsddev;
|
||||
|
||||
if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
|
||||
pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
|
||||
|
||||
Reference in New Issue
Block a user