[PATCH 3/3] PCI: rzg3s: Fix IRQ domain initialization error handling
Prabhakar <[email protected]>
| Newsgroups | org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
From: Lad Prabhakar <[email protected]> rzg3s_pcie_init_irqdomain() installs chained handlers for the INTx parent interrupts before creating the INTx irqdomain and initializing MSI support. If any subsequent step fails, such as obtaining an INTx IRQ, creating the irqdomain, or initializing MSI, the error path returns without removing any chained handlers that were already installed. This leaves stale handler and data pointers attached to the parent interrupts. Fix the error path by unwinding the chained handler registration before returning. Also clear the chained handlers during rzg3s_pcie_teardown_irqdomain() so that teardown fully mirrors the initialization sequence. Fixes: 7ef502fb35b28 ("PCI: Add Renesas RZ/G3S host controller driver") Cc: [email protected] Signed-off-by: Lad Prabhakar <[email protected]> --- drivers/pci/controller/pcie-rzg3s-host.c | 37 +++++++++++++++++------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c index f51b5d7c1998..5aeb030d43c8 100644 --- a/drivers/pci/controller/pcie-rzg3s-host.c +++ b/drivers/pci/controller/pcie-rzg3s-host.c @@ -1006,22 +1006,30 @@ static const struct irq_domain_ops rzg3s_pcie_intx_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; +static void rzg3s_pcie_clear_intx_handlers(struct rzg3s_pcie_host *host, int count) +{ + while (--count >= 0) + irq_set_chained_handler_and_data(host->intx_irqs[count], NULL, NULL); +} + static int rzg3s_pcie_init_irqdomain(struct rzg3s_pcie_host *host) { struct device *dev = host->dev; struct platform_device *pdev = to_platform_device(dev); + int i, ret; - for (int i = 0; i < PCI_NUM_INTX; i++) { + for (i = 0; i < PCI_NUM_INTX; i++) { char irq_name[5] = {0}; int irq; scnprintf(irq_name, ARRAY_SIZE(irq_name), "int%c", 'a' + i); irq = platform_get_irq_byname(pdev, irq_name); - if (irq < 0) - return dev_err_probe(dev, irq, - "Failed to parse and map INT%c IRQ\n", - 'A' + i); + if (irq < 0) { + ret = irq; + dev_err_probe(dev, ret, "Failed to parse and map INT%c IRQ\n", 'A' + i); + goto err_cleanup_intx; + } host->intx_irqs[i] = irq; irq_set_chained_handler_and_data(irq, @@ -1033,21 +1041,28 @@ static int rzg3s_pcie_init_irqdomain(struct rzg3s_pcie_host *host) PCI_NUM_INTX, &rzg3s_pcie_intx_domain_ops, host); - if (!host->intx_domain) - return dev_err_probe(dev, -EINVAL, - "Failed to add irq domain for INTx IRQs\n"); + if (!host->intx_domain) { + ret = -EINVAL; + dev_err_probe(dev, ret, "Failed to add irq domain for INTx IRQs\n"); + goto err_cleanup_intx; + } irq_domain_update_bus_token(host->intx_domain, DOMAIN_BUS_WIRED); if (IS_ENABLED(CONFIG_PCI_MSI)) { - int ret = rzg3s_pcie_init_msi(host); + ret = rzg3s_pcie_init_msi(host); if (ret) { irq_domain_remove(host->intx_domain); - return ret; + goto err_cleanup_intx; } } return 0; + +err_cleanup_intx: + rzg3s_pcie_clear_intx_handlers(host, i); + + return ret; } static void rzg3s_pcie_teardown_irqdomain(struct rzg3s_pcie_host *host) @@ -1055,6 +1070,8 @@ static void rzg3s_pcie_teardown_irqdomain(struct rzg3s_pcie_host *host) if (IS_ENABLED(CONFIG_PCI_MSI)) rzg3s_pcie_teardown_msi(host); + rzg3s_pcie_clear_intx_handlers(host, PCI_NUM_INTX); + irq_domain_remove(host->intx_domain); } -- 2.54.0