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>
This commit is contained in:
parent
64d6ea602c
commit
073d3dbe9a
@ -223,9 +223,11 @@ struct rockchip_pcie {
|
||||
int link_gen;
|
||||
struct device *dev;
|
||||
struct irq_domain *irq_domain;
|
||||
u32 io_size;
|
||||
int offset;
|
||||
struct pci_bus *root_bus;
|
||||
struct resource *io;
|
||||
phys_addr_t io_bus_addr;
|
||||
u32 io_size;
|
||||
void __iomem *msg_region;
|
||||
u32 mem_size;
|
||||
phys_addr_t msg_bus_addr;
|
||||
@ -1366,6 +1368,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
err, io);
|
||||
continue;
|
||||
}
|
||||
rockchip->io = io;
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
mem = win->res;
|
||||
@ -1397,6 +1400,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
||||
err = -ENOMEM;
|
||||
goto err_free_res;
|
||||
}
|
||||
rockchip->root_bus = bus;
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
@ -1427,6 +1431,34 @@ err_aclk_pcie:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rockchip_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
|
||||
|
||||
pci_stop_root_bus(rockchip->root_bus);
|
||||
pci_remove_root_bus(rockchip->root_bus);
|
||||
pci_unmap_iospace(rockchip->io);
|
||||
irq_domain_remove(rockchip->irq_domain);
|
||||
|
||||
phy_power_off(rockchip->phy);
|
||||
phy_exit(rockchip->phy);
|
||||
|
||||
clk_disable_unprepare(rockchip->clk_pcie_pm);
|
||||
clk_disable_unprepare(rockchip->hclk_pcie);
|
||||
clk_disable_unprepare(rockchip->aclk_perf_pcie);
|
||||
clk_disable_unprepare(rockchip->aclk_pcie);
|
||||
|
||||
if (!IS_ERR(rockchip->vpcie3v3))
|
||||
regulator_disable(rockchip->vpcie3v3);
|
||||
if (!IS_ERR(rockchip->vpcie1v8))
|
||||
regulator_disable(rockchip->vpcie1v8);
|
||||
if (!IS_ERR(rockchip->vpcie0v9))
|
||||
regulator_disable(rockchip->vpcie0v9);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rockchip_pcie_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq,
|
||||
rockchip_pcie_resume_noirq)
|
||||
@ -1444,6 +1476,6 @@ static struct platform_driver rockchip_pcie_driver = {
|
||||
.pm = &rockchip_pcie_pm_ops,
|
||||
},
|
||||
.probe = rockchip_pcie_probe,
|
||||
|
||||
.remove = rockchip_pcie_remove,
|
||||
};
|
||||
builtin_platform_driver(rockchip_pcie_driver);
|
||||
|
Loading…
Reference in New Issue
Block a user