From 6e347b5e05ea2ac4ac467a5a1cfaebb2c7f06f80 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas 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 Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # 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);