aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Norris <briannorris@chromium.org>2017-03-09 21:46:15 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-04-21 11:54:35 -0400
commit073d3dbe9a7c38888d8dafe09df421b174a6cffa (patch)
treea5d31cfbe63c905a5954096b887e70f631a9a2f7
parent64d6ea602ce619633a6e0af979e2c73738f6aeba (diff)
PCI: rockchip: Add remove() support
Currently, if we try to unbind the platform device, the remove will succeed, but the removal won't undo most of the registration, leaving partially-configured PCI devices in the system. This allows, for example, a simple 'lspci' to crash the system, as it will try to touch the freed (via devm_*) driver structures, e.g., on RK3399: # echo f8000000.pcie > /sys/bus/platform/drivers/rockchip-pcie/unbind # lspci So let's implement device remove(). Signed-off-by: Brian Norris <briannorris@chromium.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Shawn Lin <shawn.lin@rock-chips.com>
-rw-r--r--drivers/pci/host/pcie-rockchip.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
index 94feb7dfd8f4..76f2edc93663 100644
--- a/drivers/pci/host/pcie-rockchip.c
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -223,9 +223,11 @@ struct rockchip_pcie {
223 int link_gen; 223 int link_gen;
224 struct device *dev; 224 struct device *dev;
225 struct irq_domain *irq_domain; 225 struct irq_domain *irq_domain;
226 u32 io_size;
227 int offset; 226 int offset;
227 struct pci_bus *root_bus;
228 struct resource *io;
228 phys_addr_t io_bus_addr; 229 phys_addr_t io_bus_addr;
230 u32 io_size;
229 void __iomem *msg_region; 231 void __iomem *msg_region;
230 u32 mem_size; 232 u32 mem_size;
231 phys_addr_t msg_bus_addr; 233 phys_addr_t msg_bus_addr;
@@ -1366,6 +1368,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
1366 err, io); 1368 err, io);
1367 continue; 1369 continue;
1368 } 1370 }
1371 rockchip->io = io;
1369 break; 1372 break;
1370 case IORESOURCE_MEM: 1373 case IORESOURCE_MEM:
1371 mem = win->res; 1374 mem = win->res;
@@ -1397,6 +1400,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
1397 err = -ENOMEM; 1400 err = -ENOMEM;
1398 goto err_free_res; 1401 goto err_free_res;
1399 } 1402 }
1403 rockchip->root_bus = bus;
1400 1404
1401 pci_bus_size_bridges(bus); 1405 pci_bus_size_bridges(bus);
1402 pci_bus_assign_resources(bus); 1406 pci_bus_assign_resources(bus);
@@ -1427,6 +1431,34 @@ err_aclk_pcie:
1427 return err; 1431 return err;
1428} 1432}
1429 1433
1434static int rockchip_pcie_remove(struct platform_device *pdev)
1435{
1436 struct device *dev = &pdev->dev;
1437 struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
1438
1439 pci_stop_root_bus(rockchip->root_bus);
1440 pci_remove_root_bus(rockchip->root_bus);
1441 pci_unmap_iospace(rockchip->io);
1442 irq_domain_remove(rockchip->irq_domain);
1443
1444 phy_power_off(rockchip->phy);
1445 phy_exit(rockchip->phy);
1446
1447 clk_disable_unprepare(rockchip->clk_pcie_pm);
1448 clk_disable_unprepare(rockchip->hclk_pcie);
1449 clk_disable_unprepare(rockchip->aclk_perf_pcie);
1450 clk_disable_unprepare(rockchip->aclk_pcie);
1451
1452 if (!IS_ERR(rockchip->vpcie3v3))
1453 regulator_disable(rockchip->vpcie3v3);
1454 if (!IS_ERR(rockchip->vpcie1v8))
1455 regulator_disable(rockchip->vpcie1v8);
1456 if (!IS_ERR(rockchip->vpcie0v9))
1457 regulator_disable(rockchip->vpcie0v9);
1458
1459 return 0;
1460}
1461
1430static const struct dev_pm_ops rockchip_pcie_pm_ops = { 1462static const struct dev_pm_ops rockchip_pcie_pm_ops = {
1431 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq, 1463 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq,
1432 rockchip_pcie_resume_noirq) 1464 rockchip_pcie_resume_noirq)
@@ -1444,6 +1476,6 @@ static struct platform_driver rockchip_pcie_driver = {
1444 .pm = &rockchip_pcie_pm_ops, 1476 .pm = &rockchip_pcie_pm_ops,
1445 }, 1477 },
1446 .probe = rockchip_pcie_probe, 1478 .probe = rockchip_pcie_probe,
1447 1479 .remove = rockchip_pcie_remove,
1448}; 1480};
1449builtin_platform_driver(rockchip_pcie_driver); 1481builtin_platform_driver(rockchip_pcie_driver);