Skip to content

Commit

Permalink
PCI: Tolerate hierarchies with no Root Port
Browse files Browse the repository at this point in the history
We should not assume any particular hardware topology.  Commit d0751b9
("PCI: Add dev->has_secondary_link to track downstream PCIe links") relied
on the assumption that every PCIe hierarchy is rooted at a Root Port.  But
we can't rely on any assumption about what hardware we will find; we just
have to deal with the world as it is.

On some platforms, PCIe devices (endpoints, switch upstream ports, etc.)
appear directly on the root bus, and there is no Root Port in the PCI bus
hierarchy.  For example, Meelis observed these top-level devices on a
Sparc V245:

  0000:02:00.0 PCI bridge to [bus 03-0d]    Switch Upstream Port
  0001:02:00.0 PCI bridge to [bus 03]       PCIe to PCI/PCI-X Bridge

These devices *look* like they have links going upstream, but there really
are no upstream devices.

In set_pcie_port_type(), we used the parent device to figure out which side
of a switch port has a link, so if the parent device did not exist, we
dereferenced a NULL parent pointer.

Check whether the parent device exists before dereferencing it.

Meelis observed this oops on Sparc V245 and T2000.  Ben Herrenschmidt says
this is also possible on IBM PowerVM guests on PowerPC.

[bhelgaas: changelog, comment]
Link: http://lkml.kernel.org/r/alpine.LRH.2.20.1508122118210.18637@math.ut.ee
Reported-by: Meelis Roos <mroos@linux.ee>
Tested-by: Meelis Roos <mroos@linux.ee>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Yijing Wang authored and Bjorn Helgaas committed Aug 19, 2015
1 parent c9ddbac commit b35b1df
Showing 1 changed file with 6 additions and 1 deletion.
7 changes: 6 additions & 1 deletion drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,12 @@ void set_pcie_port_type(struct pci_dev *pdev)
else if (type == PCI_EXP_TYPE_UPSTREAM ||
type == PCI_EXP_TYPE_DOWNSTREAM) {
parent = pci_upstream_bridge(pdev);
if (!parent->has_secondary_link)

/*
* Usually there's an upstream device (Root Port or Switch
* Downstream Port), but we can't assume one exists.
*/
if (parent && !parent->has_secondary_link)
pdev->has_secondary_link = 1;
}
}
Expand Down

0 comments on commit b35b1df

Please sign in to comment.