| From 9b641e276c3cfdf34fbbc3d9134c5c49a68d4062 Mon Sep 17 00:00:00 2001 |
| From: Bjorn Helgaas <bhelgaas@google.com> |
| 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 |
| |
| commit 6e347b5e05ea2ac4ac467a5a1cfaebb2c7f06f80 upstream. |
| |
| 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 <zajec5@gmail.com> |
| Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
| CC: stable@vger.kernel.org # v4.8+ |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c |
| index 0d7bee4a0d26..54bd3bafc1f9 100644 |
| --- a/drivers/pci/host/pcie-iproc-bcma.c |
| +++ b/drivers/pci/host/pcie-iproc-bcma.c |
| @@ -43,8 +43,7 @@ static int iproc_pcie_bcma_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
| static int iproc_pcie_bcma_probe(struct bcma_device *bdev) |
| { |
| struct iproc_pcie *pcie; |
| - LIST_HEAD(res); |
| - struct resource res_mem; |
| + LIST_HEAD(resources); |
| int ret; |
| |
| pcie = devm_kzalloc(&bdev->dev, sizeof(*pcie), GFP_KERNEL); |
| @@ -57,21 +56,22 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) |
| pcie->base = bdev->io_addr; |
| 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(pcie->dev, "PCIe controller setup failed\n"); |
| + pci_free_resource_list(&resources); |
| + return ret; |
| + } |
| |
| - pci_free_resource_list(&res); |
| - |
| - return ret; |
| + return 0; |
| } |
| |
| static void iproc_pcie_bcma_remove(struct bcma_device *bdev) |
| diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c |
| index 1738c5288eb6..48480d56823d 100644 |
| --- a/drivers/pci/host/pcie-iproc-platform.c |
| +++ b/drivers/pci/host/pcie-iproc-platform.c |
| @@ -45,7 +45,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) |
| struct device_node *np = pdev->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, &pdev->dev); |
| @@ -108,22 +108,23 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) |
| 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(pcie->dev, |
| - "unable to get PCI host bridge resources\n"); |
| + dev_err(pcie->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(pcie->dev, "PCIe controller setup failed\n"); |
| + pci_free_resource_list(&resources); |
| + return ret; |
| + } |
| |
| - pci_free_resource_list(&res); |
| - |
| - return ret; |
| + return 0; |
| } |
| |
| static int iproc_pcie_pltfm_remove(struct platform_device *pdev) |
| diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h |
| index e84d93c53c7b..fa4226742bcd 100644 |
| --- 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); |
| -- |
| 2.12.0 |
| |