forked from rpms/kernel
		
	
		
			
				
	
	
		
			56 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			56 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From patchwork Mon Oct  2 14:08:40 2017
 | 
						|
Content-Type: text/plain; charset="utf-8"
 | 
						|
MIME-Version: 1.0
 | 
						|
Content-Transfer-Encoding: 7bit
 | 
						|
Subject: PCI: aspm: deal with missing root ports in link state handling
 | 
						|
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
 | 
						|
X-Patchwork-Id: 9980861
 | 
						|
Message-Id: <20171002140840.7767-1-ard.biesheuvel@linaro.org>
 | 
						|
To: linux-pci@vger.kernel.org, bhelgaas@google.com
 | 
						|
Cc: graeme.gregory@linaro.org, leif.lindholm@linaro.org,
 | 
						|
 daniel.thompson@Linaro.org, Ard Biesheuvel <ard.biesheuvel@linaro.org>
 | 
						|
Date: Mon,  2 Oct 2017 15:08:40 +0100
 | 
						|
 | 
						|
Even though it is unconventional, some PCIe host implementations omit
 | 
						|
the root ports entirely, and simply consist of a host bridge (which
 | 
						|
is not modeled as a device in the PCI hierarchy) and a link.
 | 
						|
 | 
						|
When the downstream device is an endpoint, our current code does not
 | 
						|
seem to mind this unusual configuration. However, when PCIe switches
 | 
						|
are involved, the ASPM code assumes that any downstream switch port
 | 
						|
has a parent, and blindly derefences the bus->parent->self field of
 | 
						|
the pci_dev struct to chain the downstream link state to the link
 | 
						|
state of the root port. Given that the root port is missing, the link
 | 
						|
is not modeled at all, and nor is the link state, and attempting to
 | 
						|
access it results in a NULL pointer dereference and a crash.
 | 
						|
 | 
						|
So let's avoid this by allowing the link state chain to terminate at
 | 
						|
the downstream port if no root port exists.
 | 
						|
 | 
						|
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
 | 
						|
---
 | 
						|
 drivers/pci/pcie/aspm.c | 8 ++++++--
 | 
						|
 1 file changed, 6 insertions(+), 2 deletions(-)
 | 
						|
 | 
						|
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
 | 
						|
index 1dfa10cc566b..0bea8498b5a5 100644
 | 
						|
--- a/drivers/pci/pcie/aspm.c
 | 
						|
+++ b/drivers/pci/pcie/aspm.c
 | 
						|
@@ -802,10 +802,14 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
 | 
						|
 
 | 
						|
 	/*
 | 
						|
 	 * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
 | 
						|
-	 * hierarchies.
 | 
						|
+	 * hierarchies.  Note that some PCIe host implementations omit
 | 
						|
+	 * the root ports entirely, in which case a downstream port on
 | 
						|
+	 * a switch may become the root of the link state chain for all
 | 
						|
+	 * its subordinate endpoints.
 | 
						|
 	 */
 | 
						|
 	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
 | 
						|
-	    pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) {
 | 
						|
+	    pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE ||
 | 
						|
+	    !pdev->bus->parent->self) {
 | 
						|
 		link->root = link;
 | 
						|
 	} else {
 | 
						|
 		struct pcie_link_state *parent;
 |