| From 4ac5927972ea1d8a2a389928710c5c12911dd358 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 8 Jun 2021 10:04:09 +0200 |
| Subject: PCI: rockchip: Register IRQ handlers after device and data are ready |
| |
| From: Javier Martinez Canillas <javierm@redhat.com> |
| |
| [ Upstream commit 3cf5f7ab230e2b886e493c7a8449ed50e29d2b98 ] |
| |
| An IRQ handler may be called at any time after it is registered, so |
| anything it relies on must be ready before registration. |
| |
| rockchip_pcie_subsys_irq_handler() and rockchip_pcie_client_irq_handler() |
| read registers in the PCIe controller, but we registered them before |
| turning on clocks to the controller. If either is called before the clocks |
| are turned on, the register reads fail and the machine hangs. |
| |
| Similarly, rockchip_pcie_legacy_int_handler() uses rockchip->irq_domain, |
| but we installed it before initializing irq_domain. |
| |
| Register IRQ handlers after their data structures are initialized and |
| clocks are enabled. |
| |
| Found by enabling CONFIG_DEBUG_SHIRQ, which calls the IRQ handler when it |
| is being unregistered. An error during the probe path might cause this |
| unregistration and IRQ handler execution before the device or data |
| structure init has finished. |
| |
| [bhelgaas: commit log] |
| Link: https://lore.kernel.org/r/20210608080409.1729276-1-javierm@redhat.com |
| Reported-by: Peter Robinson <pbrobinson@gmail.com> |
| Tested-by: Peter Robinson <pbrobinson@gmail.com> |
| Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> |
| Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> |
| Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
| Acked-by: Shawn Lin <shawn.lin@rock-chips.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/pci/controller/pcie-rockchip-host.c | 12 ++++++------ |
| 1 file changed, 6 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c |
| index f1d08a1b1591..78d04ac29cd5 100644 |
| --- a/drivers/pci/controller/pcie-rockchip-host.c |
| +++ b/drivers/pci/controller/pcie-rockchip-host.c |
| @@ -592,10 +592,6 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip) |
| if (err) |
| return err; |
| |
| - err = rockchip_pcie_setup_irq(rockchip); |
| - if (err) |
| - return err; |
| - |
| rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v"); |
| if (IS_ERR(rockchip->vpcie12v)) { |
| if (PTR_ERR(rockchip->vpcie12v) != -ENODEV) |
| @@ -973,8 +969,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev) |
| if (err) |
| goto err_vpcie; |
| |
| - rockchip_pcie_enable_interrupts(rockchip); |
| - |
| err = rockchip_pcie_init_irq_domain(rockchip); |
| if (err < 0) |
| goto err_deinit_port; |
| @@ -992,6 +986,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev) |
| bridge->sysdata = rockchip; |
| bridge->ops = &rockchip_pcie_ops; |
| |
| + err = rockchip_pcie_setup_irq(rockchip); |
| + if (err) |
| + goto err_remove_irq_domain; |
| + |
| + rockchip_pcie_enable_interrupts(rockchip); |
| + |
| err = pci_host_probe(bridge); |
| if (err < 0) |
| goto err_remove_irq_domain; |
| -- |
| 2.30.2 |
| |