aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2017-01-27 16:00:45 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-01-27 16:00:45 -0500
commit030305d69fc6963c16003f50d7e8d74b02d0a143 (patch)
tree363a4e34d199178769b7e7eeb26ea2620a55847b
parent4d191b1b63c209e37bf27938ef365244d3c41084 (diff)
PCI/ASPM: Handle PCI-to-PCIe bridges as roots of PCIe hierarchies
In a struct pcie_link_state, link->root points to the pcie_link_state of the root of the PCIe hierarchy. For the topmost link, this points to itself (link->root = link). For others, we copy the pointer from the parent (link->root = link->parent->root). Previously we recognized that Root Ports originated PCIe hierarchies, but we treated PCI/PCI-X to PCIe Bridges as being in the middle of the hierarchy, and when we tried to copy the pointer from link->parent->root, there was no parent, and we dereferenced a NULL pointer: BUG: unable to handle kernel NULL pointer dereference at 0000000000000090 IP: [<ffffffff9e424350>] pcie_aspm_init_link_state+0x170/0x820 Recognize that PCI/PCI-X to PCIe Bridges originate PCIe hierarchies just like Root Ports do, so link->root for these devices should also point to itself. Fixes: 51ebfc92b72b ("PCI: Enumerate switches below PCI-to-PCIe bridges") Link: https://bugzilla.kernel.org/show_bug.cgi?id=193411 Link: https://bugzilla.opensuse.org/show_bug.cgi?id=1022181 Tested-by: lists@ssl-mail.com Tested-by: Jayachandran C. <jnair@caviumnetworks.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> CC: stable@vger.kernel.org # v4.2+
-rw-r--r--drivers/pci/pcie/aspm.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 17ac1dce3286..3dd8bcbb3011 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -532,25 +532,32 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
532 link = kzalloc(sizeof(*link), GFP_KERNEL); 532 link = kzalloc(sizeof(*link), GFP_KERNEL);
533 if (!link) 533 if (!link)
534 return NULL; 534 return NULL;
535
535 INIT_LIST_HEAD(&link->sibling); 536 INIT_LIST_HEAD(&link->sibling);
536 INIT_LIST_HEAD(&link->children); 537 INIT_LIST_HEAD(&link->children);
537 INIT_LIST_HEAD(&link->link); 538 INIT_LIST_HEAD(&link->link);
538 link->pdev = pdev; 539 link->pdev = pdev;
539 if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) { 540
541 /*
542 * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
543 * hierarchies.
544 */
545 if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
546 pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) {
547 link->root = link;
548 } else {
540 struct pcie_link_state *parent; 549 struct pcie_link_state *parent;
550
541 parent = pdev->bus->parent->self->link_state; 551 parent = pdev->bus->parent->self->link_state;
542 if (!parent) { 552 if (!parent) {
543 kfree(link); 553 kfree(link);
544 return NULL; 554 return NULL;
545 } 555 }
556
546 link->parent = parent; 557 link->parent = parent;
558 link->root = link->parent->root;
547 list_add(&link->link, &parent->children); 559 list_add(&link->link, &parent->children);
548 } 560 }
549 /* Setup a pointer to the root port link */
550 if (!link->parent)
551 link->root = link;
552 else
553 link->root = link->parent->root;
554 561
555 list_add(&link->sibling, &link_list); 562 list_add(&link->sibling, &link_list);
556 pdev->link_state = link; 563 pdev->link_state = link;