|
@@ -0,0 +1,131 @@
|
|
|
+From 6e347b5e05ea2ac4ac467a5a1cfaebb2c7f06f80 Mon Sep 17 00:00:00 2001
|
|
|
+From: Bjorn Helgaas <[email protected]>
|
|
|
+Date: Thu, 9 Mar 2017 11:27:07 -0600
|
|
|
+Subject: [PATCH] PCI: iproc: Save host bridge window resource in struct
|
|
|
+ iproc_pcie
|
|
|
+MIME-Version: 1.0
|
|
|
+Content-Type: text/plain; charset=UTF-8
|
|
|
+Content-Transfer-Encoding: 8bit
|
|
|
+
|
|
|
+The host bridge memory window resource is inserted into the iomem_resource
|
|
|
+tree and cannot be deallocated until the host bridge itself is removed.
|
|
|
+
|
|
|
+Previously, the window was on the stack, which meant the iomem_resource
|
|
|
+entry pointed into the stack and was corrupted as soon as the probe
|
|
|
+function returned, which caused memory corruption and errors like this:
|
|
|
+
|
|
|
+ pcie_iproc_bcma bcma0:8: resource collision: [mem 0x40000000-0x47ffffff] conflicts with PCIe MEM space [mem 0x40000000-0x47ffffff]
|
|
|
+
|
|
|
+Move the memory window resource from the stack into struct iproc_pcie so
|
|
|
+its lifetime matches that of the host bridge.
|
|
|
+
|
|
|
+Fixes: c3245a566400 ("PCI: iproc: Request host bridge window resources")
|
|
|
+Reported-and-tested-by: Rafał Miłecki <[email protected]>
|
|
|
+Signed-off-by: Bjorn Helgaas <[email protected]>
|
|
|
+CC: [email protected] # v4.8+
|
|
|
+---
|
|
|
+ drivers/pci/host/pcie-iproc-bcma.c | 24 ++++++++++++------------
|
|
|
+ drivers/pci/host/pcie-iproc-platform.c | 19 ++++++++++---------
|
|
|
+ drivers/pci/host/pcie-iproc.h | 1 +
|
|
|
+ 3 files changed, 23 insertions(+), 21 deletions(-)
|
|
|
+
|
|
|
+--- a/drivers/pci/host/pcie-iproc-bcma.c
|
|
|
++++ b/drivers/pci/host/pcie-iproc-bcma.c
|
|
|
+@@ -44,8 +44,7 @@ static int iproc_pcie_bcma_probe(struct
|
|
|
+ {
|
|
|
+ struct device *dev = &bdev->dev;
|
|
|
+ struct iproc_pcie *pcie;
|
|
|
+- LIST_HEAD(res);
|
|
|
+- struct resource res_mem;
|
|
|
++ LIST_HEAD(resources);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
|
|
+@@ -62,22 +61,23 @@ static int iproc_pcie_bcma_probe(struct
|
|
|
+
|
|
|
+ pcie->base_addr = bdev->addr;
|
|
|
+
|
|
|
+- res_mem.start = bdev->addr_s[0];
|
|
|
+- res_mem.end = bdev->addr_s[0] + SZ_128M - 1;
|
|
|
+- res_mem.name = "PCIe MEM space";
|
|
|
+- res_mem.flags = IORESOURCE_MEM;
|
|
|
+- pci_add_resource(&res, &res_mem);
|
|
|
++ pcie->mem.start = bdev->addr_s[0];
|
|
|
++ pcie->mem.end = bdev->addr_s[0] + SZ_128M - 1;
|
|
|
++ pcie->mem.name = "PCIe MEM space";
|
|
|
++ pcie->mem.flags = IORESOURCE_MEM;
|
|
|
++ pci_add_resource(&resources, &pcie->mem);
|
|
|
+
|
|
|
+ pcie->map_irq = iproc_pcie_bcma_map_irq;
|
|
|
+
|
|
|
+- ret = iproc_pcie_setup(pcie, &res);
|
|
|
+- if (ret)
|
|
|
++ ret = iproc_pcie_setup(pcie, &resources);
|
|
|
++ if (ret) {
|
|
|
+ dev_err(dev, "PCIe controller setup failed\n");
|
|
|
+-
|
|
|
+- pci_free_resource_list(&res);
|
|
|
++ pci_free_resource_list(&resources);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
+
|
|
|
+ bcma_set_drvdata(bdev, pcie);
|
|
|
+- return ret;
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void iproc_pcie_bcma_remove(struct bcma_device *bdev)
|
|
|
+--- a/drivers/pci/host/pcie-iproc-platform.c
|
|
|
++++ b/drivers/pci/host/pcie-iproc-platform.c
|
|
|
+@@ -46,7 +46,7 @@ static int iproc_pcie_pltfm_probe(struct
|
|
|
+ struct device_node *np = dev->of_node;
|
|
|
+ struct resource reg;
|
|
|
+ resource_size_t iobase = 0;
|
|
|
+- LIST_HEAD(res);
|
|
|
++ LIST_HEAD(resources);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ of_id = of_match_device(iproc_pcie_of_match_table, dev);
|
|
|
+@@ -108,23 +108,24 @@ static int iproc_pcie_pltfm_probe(struct
|
|
|
+ pcie->phy = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+- ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &iobase);
|
|
|
++ ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &resources,
|
|
|
++ &iobase);
|
|
|
+ if (ret) {
|
|
|
+- dev_err(dev,
|
|
|
+- "unable to get PCI host bridge resources\n");
|
|
|
++ dev_err(dev, "unable to get PCI host bridge resources\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ pcie->map_irq = of_irq_parse_and_map_pci;
|
|
|
+
|
|
|
+- ret = iproc_pcie_setup(pcie, &res);
|
|
|
+- if (ret)
|
|
|
++ ret = iproc_pcie_setup(pcie, &resources);
|
|
|
++ if (ret) {
|
|
|
+ dev_err(dev, "PCIe controller setup failed\n");
|
|
|
+-
|
|
|
+- pci_free_resource_list(&res);
|
|
|
++ pci_free_resource_list(&resources);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
+
|
|
|
+ platform_set_drvdata(pdev, pcie);
|
|
|
+- return ret;
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int iproc_pcie_pltfm_remove(struct platform_device *pdev)
|
|
|
+--- a/drivers/pci/host/pcie-iproc.h
|
|
|
++++ b/drivers/pci/host/pcie-iproc.h
|
|
|
+@@ -68,6 +68,7 @@ struct iproc_pcie {
|
|
|
+ #ifdef CONFIG_ARM
|
|
|
+ struct pci_sys_data sysdata;
|
|
|
+ #endif
|
|
|
++ struct resource mem;
|
|
|
+ struct pci_bus *root_bus;
|
|
|
+ struct phy *phy;
|
|
|
+ int (*map_irq)(const struct pci_dev *, u8, u8);
|