PCI: iproc: Save host bridge window resource in struct iproc_pcie
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: c3245a5664
("PCI: iproc: Request host bridge window resources")
Reported-and-tested-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: stable@vger.kernel.org # v4.8+
This commit is contained in:
parent
3bd7db63a8
commit
6e347b5e05
|
@ -44,8 +44,7 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &bdev->dev;
|
struct device *dev = &bdev->dev;
|
||||||
struct iproc_pcie *pcie;
|
struct iproc_pcie *pcie;
|
||||||
LIST_HEAD(res);
|
LIST_HEAD(resources);
|
||||||
struct resource res_mem;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
||||||
|
@ -63,22 +62,23 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev)
|
||||||
|
|
||||||
pcie->base_addr = bdev->addr;
|
pcie->base_addr = bdev->addr;
|
||||||
|
|
||||||
res_mem.start = bdev->addr_s[0];
|
pcie->mem.start = bdev->addr_s[0];
|
||||||
res_mem.end = bdev->addr_s[0] + SZ_128M - 1;
|
pcie->mem.end = bdev->addr_s[0] + SZ_128M - 1;
|
||||||
res_mem.name = "PCIe MEM space";
|
pcie->mem.name = "PCIe MEM space";
|
||||||
res_mem.flags = IORESOURCE_MEM;
|
pcie->mem.flags = IORESOURCE_MEM;
|
||||||
pci_add_resource(&res, &res_mem);
|
pci_add_resource(&resources, &pcie->mem);
|
||||||
|
|
||||||
pcie->map_irq = iproc_pcie_bcma_map_irq;
|
pcie->map_irq = iproc_pcie_bcma_map_irq;
|
||||||
|
|
||||||
ret = iproc_pcie_setup(pcie, &res);
|
ret = iproc_pcie_setup(pcie, &resources);
|
||||||
if (ret)
|
if (ret) {
|
||||||
dev_err(dev, "PCIe controller setup failed\n");
|
dev_err(dev, "PCIe controller setup failed\n");
|
||||||
|
pci_free_resource_list(&resources);
|
||||||
pci_free_resource_list(&res);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bcma_set_drvdata(bdev, pcie);
|
bcma_set_drvdata(bdev, pcie);
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iproc_pcie_bcma_remove(struct bcma_device *bdev)
|
static void iproc_pcie_bcma_remove(struct bcma_device *bdev)
|
||||||
|
|
|
@ -51,7 +51,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
struct resource reg;
|
struct resource reg;
|
||||||
resource_size_t iobase = 0;
|
resource_size_t iobase = 0;
|
||||||
LIST_HEAD(res);
|
LIST_HEAD(resources);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
||||||
|
@ -96,10 +96,10 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
|
||||||
pcie->phy = NULL;
|
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) {
|
if (ret) {
|
||||||
dev_err(dev,
|
dev_err(dev, "unable to get PCI host bridge resources\n");
|
||||||
"unable to get PCI host bridge resources\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,14 +112,15 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
|
||||||
pcie->map_irq = of_irq_parse_and_map_pci;
|
pcie->map_irq = of_irq_parse_and_map_pci;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = iproc_pcie_setup(pcie, &res);
|
ret = iproc_pcie_setup(pcie, &resources);
|
||||||
if (ret)
|
if (ret) {
|
||||||
dev_err(dev, "PCIe controller setup failed\n");
|
dev_err(dev, "PCIe controller setup failed\n");
|
||||||
|
pci_free_resource_list(&resources);
|
||||||
pci_free_resource_list(&res);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, pcie);
|
platform_set_drvdata(pdev, pcie);
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iproc_pcie_pltfm_remove(struct platform_device *pdev)
|
static int iproc_pcie_pltfm_remove(struct platform_device *pdev)
|
||||||
|
|
|
@ -90,6 +90,7 @@ struct iproc_pcie {
|
||||||
#ifdef CONFIG_ARM
|
#ifdef CONFIG_ARM
|
||||||
struct pci_sys_data sysdata;
|
struct pci_sys_data sysdata;
|
||||||
#endif
|
#endif
|
||||||
|
struct resource mem;
|
||||||
struct pci_bus *root_bus;
|
struct pci_bus *root_bus;
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
int (*map_irq)(const struct pci_dev *, u8, u8);
|
int (*map_irq)(const struct pci_dev *, u8, u8);
|
||||||
|
|
Loading…
Reference in New Issue