From: Ming Wang wangming01@loongson.cn
[ Upstream commit c33c43f71bda362b292a6e57ac41b64342dc87b3 ]
On certain Loongson platforms, drivers attempting to request a legacy ISA IRQ directly via request_irq() (e.g., IRQ 4) may fail. The virtual IRQ descriptor is not fully initialized and lacks a valid irqchip.
This issue does not affect ACPI-enumerated devices described in DSDT, as their interrupts are properly mapped via the GSI translation path. This indicates the LPC irqdomain itself is functional but is not correctly handling direct VIRQ-to-HWIRQ mappings.
The root cause is the use of irq_domain_create_linear(). This API sets up a domain for dynamic, on-demand mapping, typically triggered by a GSI request. It does not pre-populate the mappings for the legacy VIRQ range (0-15). Consequently, if no ACPI device claims a specific GSI (e.g., GSI 4), the corresponding VIRQ (e.g., VIRQ 4) is never mapped to the LPC domain. A direct call to request_irq(4, ...) then fails because the kernel cannot resolve this VIRQ to a hardware interrupt managed by the LPC controller.
The PCH-LPC interrupt controller is an i8259-compatible legacy device that requires a deterministic, static 1-to-1 mapping for IRQs 0-15 to support legacy drivers.
Fix this by replacing irq_domain_create_linear() with irq_domain_create_legacy(). This API is specifically designed for such controllers. It establishes the required static 1-to-1 VIRQ-to-HWIRQ mapping for the entire legacy range (0-15) immediately upon domain creation. This ensures that any VIRQ in this range is always resolvable, making direct calls to request_irq() for legacy IRQs function correctly.
Signed-off-by: Ming Wang wangming01@loongson.cn Signed-off-by: Thomas Gleixner tglx@linutronix.de Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES: Switching the Loongson PCH-LPC domain from `irq_domain_create_linear()` to `irq_domain_create_legacy()` removes a long-standing bug that prevents legacy ISA interrupts from working when drivers call `request_irq()` directly.
- The current code at `drivers/irqchip/irq-loongson-pch-lpc.c:203` creates a linear domain, which only instantiates mappings on demand. That leaves IRQs 0‑15 unmapped unless an ACPI GSI translation happens first, so `request_irq(4, …)` sees an uninitialized descriptor and fails exactly as described in the commit message. - The fix replaces that call with `irq_domain_create_legacy(…, LPC_COUNT, 0, 0, …)` (same location) and adds a clarifying comment. Legacy domains eagerly map the whole 0‑15 range, invoking `pch_lpc_map()` for each slot so the chip/handler is set up before any driver requests the IRQ. This mirrors how other i8259-compatible controllers (e.g. `irq-i8259.c`) are wired. - The regression was introduced when the controller first landed (Fixes: ee73f14ee9eb7, v6.0), so every stable kernel carrying Loongson support can hit it. Impact is high: legacy ISA drivers or firmware that still rely on numeric IRQs can never bind on affected systems. - The change is tiny, localized to one driver, and does not alter the hardware programming model—only the domain helper is swapped. No new features, no ABI changes, and it parallels existing upstream practice, so regression risk is minimal.
Given the clear user-visible failure mode and the contained, well- understood fix, this is an excellent candidate for stable backporting.
drivers/irqchip/irq-loongson-pch-lpc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c index 2d4c3ec128b8f..912bf50a5c7ca 100644 --- a/drivers/irqchip/irq-loongson-pch-lpc.c +++ b/drivers/irqchip/irq-loongson-pch-lpc.c @@ -200,8 +200,13 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, goto iounmap_base; }
- priv->lpc_domain = irq_domain_create_linear(irq_handle, LPC_COUNT, - &pch_lpc_domain_ops, priv); + /* + * The LPC interrupt controller is a legacy i8259-compatible device, + * which requires a static 1:1 mapping for IRQs 0-15. + * Use irq_domain_create_legacy to establish this static mapping early. + */ + priv->lpc_domain = irq_domain_create_legacy(irq_handle, LPC_COUNT, 0, 0, + &pch_lpc_domain_ops, priv); if (!priv->lpc_domain) { pr_err("Failed to create IRQ domain\n"); goto free_irq_handle;