* [PATCH v4] PCI: dw-rockchip: Move the INTx irq setup to probe
@ 2026-09-24 4:06 Shawn Lin
2026-09-24 8:51 ` Niklas Cassel
2026-09-24 10:17 ` Diederik de Haas
0 siblings, 2 replies; 3+ messages in thread
From: Shawn Lin @ 2026-09-24 4:06 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, Niklas Cassel, Diederik de Haas,
Shawn Lin
Since commit b376b3ff9cb0 ("PCI: dw-rockchip: Implement .reset_root_port()
and use for link down"), .reset_root_port() re-runs the host ops .init()
callback to reprogram the Root Complex after a controller reset. That
works for the register programming, but .init() is not re-entrant: it
also creates the INTx irq domain and installs the chained INTx handler.
Every root port reset therefore ends up with a second irq domain
registered for the same fwnode: the previous one is leaked, as it is
never removed, and worse, the INTx virqs of the downstream PCI devices
were allocated in the previous irq domain and are never re-mapped, while
the chained handler now looks up virqs in the new, empty domain. After a
link down recovery, INTx interrupts are silently lost.
Fix it by moving the of_irq_get_byname() lookup, the INTx irq domain
creation and the chained handler installation out of .init() and into
rockchip_pcie_configure_rc(), just before dw_pcie_host_init(). The
lookup has to happen before the host is initialized, because
dw_pcie_host_init() enumerates the bus and probes the downstream
devices, and pci_assign_irq() maps their INTx interrupts at that point:
if the domain does not exist yet, the mapping fails and the devices end
up without a usable INTx. This also mirrors how the qcom driver requests
its global IRQ, and leaves .init() with nothing but idempotent register
programming, so both .reset_root_port() and dw_pcie_resume_noirq() can
safely re-run it. Re-running of_irq_get_byname() on every resume is also
gone.
Fixes: b376b3ff9cb0 ("PCI: dw-rockchip: Implement .reset_root_port() and use for link down")
Suggested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---
Changes in v4:
- drop the code comment (Niklas)
- create the INTx irq domain before dw_pcie_host_init() instead of
after it. dw_pcie_host_init() enumerates the bus and probes the
downstream devices, and their INTx interrupts get mapped at that
point, so registering the domain afterwards left every downstream
device without a usable INTx (flagged by the Sashiko review).
- this also removes the failing steps behind dw_pcie_host_init(), so
there is no error path left that would return with the root bus
registered and the rockchip structure about to be freed (flagged by
the Sashiko review).
Changes in v3:
- split devm-managed part into a seperate patch
Changes in v2:
- Moved the of_irq_get_byname() lookup, the INTx irq domain creation
and the chained handler installation out of the host ops .init()
callback into rockchip_pcie_configure_rc(), right after
dw_pcie_host_init(), as suggested by Niklas Cassel. This supersedes
v1 patch 1/2, as .init() no longer creates the irq domain, and
removes the rockchip_pcie_host_hw_init() helper from v1.
- Made the INTx irq domain devm-managed with
devm_irq_domain_instantiate() and uninstall the chained handler
through a devres action, addressing the probe failure leak and
use-after-free flagged by the Sashiko review.
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 1497686..bd86e32c 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -422,23 +422,9 @@ static void rockchip_pcie_stop_link(struct dw_pcie *pci)
static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
- struct device *dev = rockchip->pci.dev;
- int irq, ret;
-
- irq = of_irq_get_byname(dev->of_node, "legacy");
- if (irq < 0)
- return irq;
pci->dbi_base2 = pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET;
- ret = rockchip_pcie_init_irq_domain(rockchip);
- if (ret < 0)
- dev_err(dev, "failed to init irq domain\n");
-
- irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
- rockchip);
-
rockchip_pcie_configure_l1ss(pci);
rockchip_pcie_enable_l0s(pci);
pp->bridge->reset_root_port = rockchip_pcie_rc_reset_root_port;
@@ -731,6 +717,19 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
PCIE_CLIENT_SET_MODE(PCIE_CLIENT_MODE_RC),
PCIE_CLIENT_GENERAL_CON);
+ irq = of_irq_get_byname(dev->of_node, "legacy");
+ if (irq < 0)
+ return irq;
+
+ ret = rockchip_pcie_init_irq_domain(rockchip);
+ if (ret < 0) {
+ dev_err(dev, "failed to init irq domain\n");
+ return ret;
+ }
+
+ irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
+ rockchip);
+
pp = &rockchip->pci.pp;
pp->ops = &rockchip_pcie_host_ops;
--
2.7.4
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v4] PCI: dw-rockchip: Move the INTx irq setup to probe
2026-09-24 4:06 [PATCH v4] PCI: dw-rockchip: Move the INTx irq setup to probe Shawn Lin
@ 2026-09-24 8:51 ` Niklas Cassel
2026-09-24 10:17 ` Diederik de Haas
1 sibling, 0 replies; 3+ messages in thread
From: Niklas Cassel @ 2026-09-24 8:51 UTC (permalink / raw)
To: Shawn Lin
Cc: Manivannan Sadhasivam, Bjorn Helgaas, linux-rockchip, linux-pci,
Diederik de Haas
On Thu, Sep 24, 2026 at 12:06:33PM +0800, Shawn Lin wrote:
> Since commit b376b3ff9cb0 ("PCI: dw-rockchip: Implement .reset_root_port()
> and use for link down"), .reset_root_port() re-runs the host ops .init()
> callback to reprogram the Root Complex after a controller reset. That
> works for the register programming, but .init() is not re-entrant: it
> also creates the INTx irq domain and installs the chained INTx handler.
> Every root port reset therefore ends up with a second irq domain
> registered for the same fwnode: the previous one is leaked, as it is
> never removed, and worse, the INTx virqs of the downstream PCI devices
> were allocated in the previous irq domain and are never re-mapped, while
> the chained handler now looks up virqs in the new, empty domain. After a
> link down recovery, INTx interrupts are silently lost.
>
> Fix it by moving the of_irq_get_byname() lookup, the INTx irq domain
> creation and the chained handler installation out of .init() and into
> rockchip_pcie_configure_rc(), just before dw_pcie_host_init(). The
> lookup has to happen before the host is initialized, because
> dw_pcie_host_init() enumerates the bus and probes the downstream
> devices, and pci_assign_irq() maps their INTx interrupts at that point:
> if the domain does not exist yet, the mapping fails and the devices end
> up without a usable INTx. This also mirrors how the qcom driver requests
> its global IRQ, and leaves .init() with nothing but idempotent register
> programming, so both .reset_root_port() and dw_pcie_resume_noirq() can
> safely re-run it. Re-running of_irq_get_byname() on every resume is also
> gone.
>
> Fixes: b376b3ff9cb0 ("PCI: dw-rockchip: Implement .reset_root_port() and use for link down")
> Suggested-by: Niklas Cassel <cassel@kernel.org>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v4] PCI: dw-rockchip: Move the INTx irq setup to probe
2026-09-24 4:06 [PATCH v4] PCI: dw-rockchip: Move the INTx irq setup to probe Shawn Lin
2026-09-24 8:51 ` Niklas Cassel
@ 2026-09-24 10:17 ` Diederik de Haas
1 sibling, 0 replies; 3+ messages in thread
From: Diederik de Haas @ 2026-09-24 10:17 UTC (permalink / raw)
To: Shawn Lin, Manivannan Sadhasivam, Bjorn Helgaas
Cc: linux-rockchip, linux-pci, Niklas Cassel, Diederik de Haas
On Thu Sep 24, 2026 at 6:06 AM CEST, Shawn Lin wrote:
> Since commit b376b3ff9cb0 ("PCI: dw-rockchip: Implement .reset_root_port()
> and use for link down"), .reset_root_port() re-runs the host ops .init()
> callback to reprogram the Root Complex after a controller reset. That
> works for the register programming, but .init() is not re-entrant: it
> also creates the INTx irq domain and installs the chained INTx handler.
> Every root port reset therefore ends up with a second irq domain
> registered for the same fwnode: the previous one is leaked, as it is
> never removed, and worse, the INTx virqs of the downstream PCI devices
> were allocated in the previous irq domain and are never re-mapped, while
> the chained handler now looks up virqs in the new, empty domain. After a
> link down recovery, INTx interrupts are silently lost.
>
> Fix it by moving the of_irq_get_byname() lookup, the INTx irq domain
> creation and the chained handler installation out of .init() and into
> rockchip_pcie_configure_rc(), just before dw_pcie_host_init(). The
> lookup has to happen before the host is initialized, because
> dw_pcie_host_init() enumerates the bus and probes the downstream
> devices, and pci_assign_irq() maps their INTx interrupts at that point:
> if the domain does not exist yet, the mapping fails and the devices end
> up without a usable INTx. This also mirrors how the qcom driver requests
> its global IRQ, and leaves .init() with nothing but idempotent register
> programming, so both .reset_root_port() and dw_pcie_resume_noirq() can
> safely re-run it. Re-running of_irq_get_byname() on every resume is also
> gone.
While with only patch 1 of v3 I still got (5x) this warning:
irq: no irq domain found for legacy-interrupt-controller !
but no more stack traces.
With v4 there are no stack traces and no more irq warnings.
My NVMe drive, Ethernet NIC (also PCIe based) and both MT7925 based Wi-Fi
and Bluetooth work fine, so feel free to include
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 Plus
Cheers,
Diederik
> Fixes: b376b3ff9cb0 ("PCI: dw-rockchip: Implement .reset_root_port() and use for link down")
> Suggested-by: Niklas Cassel <cassel@kernel.org>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> ---
>
> Changes in v4:
> - drop the code comment (Niklas)
> - create the INTx irq domain before dw_pcie_host_init() instead of
> after it. dw_pcie_host_init() enumerates the bus and probes the
> downstream devices, and their INTx interrupts get mapped at that
> point, so registering the domain afterwards left every downstream
> device without a usable INTx (flagged by the Sashiko review).
> - this also removes the failing steps behind dw_pcie_host_init(), so
> there is no error path left that would return with the root bus
> registered and the rockchip structure about to be freed (flagged by
> the Sashiko review).
>
> Changes in v3:
> - split devm-managed part into a seperate patch
>
> Changes in v2:
> - Moved the of_irq_get_byname() lookup, the INTx irq domain creation
> and the chained handler installation out of the host ops .init()
> callback into rockchip_pcie_configure_rc(), right after
> dw_pcie_host_init(), as suggested by Niklas Cassel. This supersedes
> v1 patch 1/2, as .init() no longer creates the irq domain, and
> removes the rockchip_pcie_host_hw_init() helper from v1.
> - Made the INTx irq domain devm-managed with
> devm_irq_domain_instantiate() and uninstall the chained handler
> through a devres action, addressing the probe failure leak and
> use-after-free flagged by the Sashiko review.
>
> drivers/pci/controller/dwc/pcie-dw-rockchip.c | 27 +++++++++++++--------------
> 1 file changed, 13 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> index 1497686..bd86e32c 100644
> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> @@ -422,23 +422,9 @@ static void rockchip_pcie_stop_link(struct dw_pcie *pci)
> static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
> {
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> - struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
> - struct device *dev = rockchip->pci.dev;
> - int irq, ret;
> -
> - irq = of_irq_get_byname(dev->of_node, "legacy");
> - if (irq < 0)
> - return irq;
>
> pci->dbi_base2 = pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET;
>
> - ret = rockchip_pcie_init_irq_domain(rockchip);
> - if (ret < 0)
> - dev_err(dev, "failed to init irq domain\n");
> -
> - irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
> - rockchip);
> -
> rockchip_pcie_configure_l1ss(pci);
> rockchip_pcie_enable_l0s(pci);
> pp->bridge->reset_root_port = rockchip_pcie_rc_reset_root_port;
> @@ -731,6 +717,19 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
> PCIE_CLIENT_SET_MODE(PCIE_CLIENT_MODE_RC),
> PCIE_CLIENT_GENERAL_CON);
>
> + irq = of_irq_get_byname(dev->of_node, "legacy");
> + if (irq < 0)
> + return irq;
> +
> + ret = rockchip_pcie_init_irq_domain(rockchip);
> + if (ret < 0) {
> + dev_err(dev, "failed to init irq domain\n");
> + return ret;
> + }
> +
> + irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
> + rockchip);
> +
> pp = &rockchip->pci.pp;
> pp->ops = &rockchip_pcie_host_ops;
>
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-24 10:18 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-24 4:06 [PATCH v4] PCI: dw-rockchip: Move the INTx irq setup to probe Shawn Lin
2026-09-24 8:51 ` Niklas Cassel
2026-09-24 10:17 ` Diederik de Haas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox