[PATCH v3 2/3] PCI: dw-rockchip: Make the INTx irq setup devm-managed
Shawn Lin
shawn.lin at rock-chips.com
Mon Sep 21 19:37:01 PDT 2026
The irq domain and the chained handler set up by the previous commit
are resources owned by the device, but nothing releases them if probing
ever fails after they are set up, and they are not tied to the device
lifetime in any other way either.
Tie their lifetime to the device with devres: create the irq domain
with devm_irq_domain_instantiate() and uninstall the chained handler
through the rockchip_pcie_intx_chained_release() devres action. The
driver is builtin and cannot be unbound (suppress_bind_attrs), so probe
failure is the only path that ever needs this cleanup, and devres takes
care of it without sprinkling it over every error path.
Since the irq setup is the last step of rockchip_pcie_configure_rc(),
the only failure point left after the chained handler is installed is
devm_add_action_or_reset() itself, whose failure mode runs the action,
so the handler can never run against the devm-freed rockchip structure.
devres also unwinds in reverse registration order, so the handler is
always uninstalled before the domain is removed. There is no devm API
for chained handlers, hence the small devres action wrapper.
While at it, drop the now unused rockchip variable from
rockchip_pcie_host_init().
Suggested-by: Niklas Cassel <cassel at kernel.org>
Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---
This patch didn't find a suitable fix tag as it fixes an issue along with
patch 1/3, then patch 3/3 depends on it. So it might go with the whole series
into a fix branch.
Changes in v3: None
Changes in v2: None
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 46 ++++++++++++++++++++-------
1 file changed, 34 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 8788a10..f395a66 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -114,6 +114,7 @@ struct rockchip_pcie {
struct reset_control *rst;
struct gpio_desc *rst_gpio;
struct irq_domain *irq_domain;
+ int intx_irq;
const struct rockchip_pcie_of_data *data;
bool supports_clkreq;
struct delayed_work trace_work;
@@ -188,9 +189,16 @@ static const struct irq_domain_ops intx_domain_ops = {
.map = rockchip_pcie_intx_map,
};
-static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
+static void rockchip_pcie_intx_chained_release(void *data)
+{
+ struct rockchip_pcie *rockchip = data;
+
+ irq_set_chained_handler_and_data(rockchip->intx_irq, NULL, NULL);
+}
+
+static int rockchip_pcie_init_irq_domain(struct device *dev,
+ struct rockchip_pcie *rockchip)
{
- struct device *dev = rockchip->pci.dev;
struct device_node *intc;
intc = of_get_child_by_name(dev->of_node, "legacy-interrupt-controller");
@@ -199,12 +207,17 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
return -EINVAL;
}
- rockchip->irq_domain = irq_domain_create_linear(of_fwnode_handle(intc), PCI_NUM_INTX,
- &intx_domain_ops, rockchip);
+ rockchip->irq_domain = devm_irq_domain_instantiate(dev,
+ &(struct irq_domain_info){
+ .fwnode = of_fwnode_handle(intc),
+ .size = PCI_NUM_INTX,
+ .ops = &intx_domain_ops,
+ .host_data = rockchip,
+ });
of_node_put(intc);
- if (!rockchip->irq_domain) {
+ if (IS_ERR(rockchip->irq_domain)) {
dev_err(dev, "failed to get a INTx IRQ domain\n");
- return -EINVAL;
+ return PTR_ERR(rockchip->irq_domain);
}
return 0;
@@ -731,18 +744,27 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
* which is also re-run by .reset_root_port(), so that the INTx irq
* domain is only created once, at probe time.
*/
- irq = of_irq_get_byname(dev->of_node, "legacy");
- if (irq < 0)
- return irq;
+ rockchip->intx_irq = of_irq_get_byname(dev->of_node, "legacy");
+ if (rockchip->intx_irq < 0)
+ return rockchip->intx_irq;
- ret = rockchip_pcie_init_irq_domain(rockchip);
+ ret = rockchip_pcie_init_irq_domain(dev, 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);
+ irq_set_chained_handler_and_data(rockchip->intx_irq,
+ rockchip_pcie_intx_handler, rockchip);
+
+ /*
+ * Uninstall the chained handler on probe failure, so that it can
+ * never run against the devm-freed rockchip structure.
+ */
+ ret = devm_add_action_or_reset(dev, rockchip_pcie_intx_chained_release,
+ rockchip);
+ if (ret)
+ return ret;
/* unmask hot reset/link-down reset */
val = FIELD_PREP_WM16(PCIE_LINK_REQ_RST_NOT_INT, 0);
--
2.7.4
More information about the Linux-rockchip
mailing list