[PATCH] PCI: dw-rockchip: Enable INTx affinity support

Shawn Lin shawn.lin at rock-chips.com
Mon Sep 28 23:54:58 PDT 2026


Leverage the interrupt redirection infrastructure to enable CPU
affinity support for the legacy INTx interrupts. The INTx virqs are
demultiplexed by the chained handler of the "legacy" interrupt, whose
affinity cannot be changed, so affinity control for the INTx virqs is
achieved by redirecting the handler to run in IRQ work context on the
target CPU.

Mask the INTx source in .irq_pre_redirect() before the handler is
redirected: the legacy interrupt is level triggered, so an unmasked
line would keep re-firing the chained interrupt until the redirected
handler runs.

Same approach as the DesignWare core, commit eaf290c404f7c39f2 ("PCI:
dwc: Enable MSI affinity support").

Test was done on RK3588 EVB1 board with an NVMe with pci=nomsi
parameter. The /proc/interrupts columns are trimmed for brevity.

  # cat /proc/interrupts | grep INTx
  51:  137 0 0 0 0 0 0 0 INTx 0 Edge PCIe PME, nvme0q0, nvme0q1
  # echo 10 > /proc/irq/51/smp_affinity
  # dd if=/dev/nvme0n1p1 of=/dev/null bs=1M count=200
  200+0 records in
  200+0 records out
  209715200 bytes (210 MB, 200 MiB) copied, 0.182021 s, 1.2 GB/s
  # cat /proc/interrupts | grep INTx
  51:  137 0 0 0 946 0 0 0 INTx 0 Edge PCIe PME, nvme0q0, nvme0q1

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 1497686..af66142 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -149,7 +149,7 @@ static void rockchip_pcie_intx_handler(struct irq_desc *desc)
 	reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_LEGACY);
 
 	for_each_set_bit(hwirq, &reg, 4)
-		generic_handle_domain_irq(rockchip->irq_domain, hwirq);
+		generic_handle_demux_domain_irq(rockchip->irq_domain, hwirq);
 
 	chained_irq_exit(chip, desc);
 }
@@ -173,6 +173,16 @@ static struct irq_chip rockchip_intx_irq_chip = {
 	.irq_mask		= rockchip_intx_mask,
 	.irq_unmask		= rockchip_intx_unmask,
 	.flags			= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
+#ifdef CONFIG_SMP
+	/*
+	 * The legacy interrupt is level triggered. Mask the INTx source in
+	 * the parent's context before the handler is redirected, so that
+	 * the unmasked level line does not keep re-firing the chained
+	 * interrupt until the redirected handler runs.
+	 */
+	.irq_pre_redirect	= rockchip_intx_mask,
+	.irq_set_affinity	= irq_chip_redirect_set_affinity,
+#endif
 };
 
 static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-- 
2.7.4




More information about the Linux-rockchip mailing list