[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251009155752.773732-84-sashal@kernel.org>
Date: Thu, 9 Oct 2025 11:55:50 -0400
From: Sasha Levin <sashal@...nel.org>
To: patches@...ts.linux.dev,
stable@...r.kernel.org
Cc: Bibo Mao <maobibo@...ngson.cn>,
Thomas Gleixner <tglx@...utronix.de>,
Sasha Levin <sashal@...nel.org>,
chenhuacai@...nel.org,
jiaxun.yang@...goat.com,
linux-mips@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH AUTOSEL 6.17-6.16] irqchip/loongson-eiointc: Route interrupt parsed from bios table
From: Bibo Mao <maobibo@...ngson.cn>
[ Upstream commit 7fb83eb664e9b3a0438dd28859e9f0fd49d4c165 ]
Interrupt controller eiointc routes interrupts to CPU interface IP0 - IP7.
It is currently hard-coded that eiointc routes interrupts to the CPU
starting from IP1, but it should base that decision on the parent
interrupt, which is provided by ACPI or DTS.
Retrieve the parent's hardware interrupt number and store it in the
descriptor of the eointc instance, so that the routing function can utilize
it for the correct route settings.
[ tglx: Massaged change log ]
Signed-off-by: Bibo Mao <maobibo@...ngson.cn>
Signed-off-by: Thomas Gleixner <tglx@...utronix.de>
Link: https://lore.kernel.org/all/20250804081946.1456573-2-maobibo@loongson.cn
Signed-off-by: Sasha Levin <sashal@...nel.org>
---
LLM Generated explanations, may be completely bogus:
Now let me compile my comprehensive analysis.
## COMPREHENSIVE ANALYSIS
Based on my extensive investigation of this commit, here is my
determination:
**Backport Status: YES**
## Detailed Analysis
### What This Commit Fixes
The Loongson eiointc (Extended I/O Interrupt Controller) driver was
**hardcoding interrupt routing** to CPU interface pins using the formula
`BIT(1 + index)`, which routes interrupts starting from IP1. However,
the **correct routing information is provided by ACPI/DTS** in the
`cascade` field (for ACPI) or parent interrupt hwirq (for device tree).
**Code Evidence:**
- Line 214 in drivers/irqchip/irq-loongson-eiointc.c (before fix): `bit
= BIT(1 + index); /* Route to IP[1 + index] */`
- After fix: `bit = BIT(eiointc_priv[index]->parent_hwirq - INT_HWI0);`
- The ACPI structure at include/acpi/actbl2.h:1479-1485 defines
`cascade` field (u8) which specifies the correct interrupt pin
- INT_HWI0 through INT_HWI7 are defined at
arch/loongarch/include/asm/loongarch.h:1462-1469
### Real-World Impact
1. **Incorrect Interrupt Routing:** On systems where ACPI/DTS specifies
a different CPU interrupt pin than the hardcoded value, interrupts
would be routed to the wrong pin. This could cause:
- Interrupts not being received at all
- System hangs or device malfunctions
- Hardware that doesn't work correctly
2. **Prerequisite for Optimization:** The follow-up commit
(8ff1c16c753e2) explains that correct routing enables an important VM
optimization: routing different interrupt vectors to different CPU
pins reduces VM exits by allowing the handler to read only one
EIOINTC_REG_ISR register instead of all four.
3. **Affected Systems:** All Loongson systems using eiointc:
- LS2K0500, LS2K2000 (device tree)
- Loongson-3A5000, Loongson-3C5000 (ACPI)
### Why This Bug Existed
The hardcoded routing was present **from the initial driver commit**
(dd281e1a1a937 from July 2022). It likely went undetected because:
- Reference/common platforms happened to use IP1, matching the hardcoded
value
- Limited deployment of Loongson architecture
- New hardware configurations or firmware changes exposed the issue
### Backporting Assessment
**✓ Fixes a bug affecting users:** Yes - incorrect hardware programming
that can cause device malfunctions
**✓ Small and contained:** Yes - adds one struct field, modifies routing
logic in one place, updates two init functions
**✓ No architectural changes:** Correct - just fixes the routing to
match hardware specification
**✓ Minimal risk:** Low risk because:
- Makes behavior match what ACPI/DTS specifies (hardware specification)
- Part of a tested two-commit series (both commits already merged and
backported)
- No subsequent fixes found (checked commits after 2025-08-04)
- Already successfully backported to 6.17 (ec1317ec5082f)
**✓ No explicit stable tag:** Commit lacks `Cc: stable` tag, but fits
stable tree criteria
**✗ Critical subsystem:** Yes, but the change is localized to Loongson-
specific driver
### Verification of Backport Quality
- Commit was authored: Mon Aug 4 16:19:45 2025
- Merged to mainline: Sun Aug 24 12:51:04 2025
- Already backported to 6.17 by Sasha Levin
- No fixes found targeting this commit (searched with git log
--grep="Fixes.*7fb83eb664e9b")
- Follow-up commit (8ff1c16c753e2) builds on this fix and should be
backported together
## Conclusion
**YES - This commit should be backported to stable kernel trees.**
This is a clear bugfix that corrects incorrect hardware programming. The
driver was routing interrupts to hardcoded CPU interrupt pins instead of
using the routing information from firmware (ACPI/DTS). This could cause
device malfunctions on systems where firmware specifies different
interrupt pins. The fix is small, contained, has no known regressions,
and is a prerequisite for important virtualization optimizations. It
meets all stable tree criteria for backporting.
drivers/irqchip/irq-loongson-eiointc.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
index b2860eb2d32c5..baa406904de55 100644
--- a/drivers/irqchip/irq-loongson-eiointc.c
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -68,6 +68,7 @@ struct eiointc_priv {
struct fwnode_handle *domain_handle;
struct irq_domain *eiointc_domain;
int flags;
+ irq_hw_number_t parent_hwirq;
};
static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
@@ -211,7 +212,12 @@ static int eiointc_router_init(unsigned int cpu)
}
for (i = 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) {
- bit = BIT(1 + index); /* Route to IP[1 + index] */
+ /*
+ * Route to interrupt pin, relative offset used here
+ * Offset 0 means routing to IP0 and so on
+ * Every 32 vector routing to one interrupt pin
+ */
+ bit = BIT(eiointc_priv[index]->parent_hwirq - INT_HWI0);
data = bit | (bit << 8) | (bit << 16) | (bit << 24);
iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
}
@@ -495,7 +501,7 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
priv->vec_count = VEC_COUNT;
priv->node = acpi_eiointc->node;
-
+ priv->parent_hwirq = acpi_eiointc->cascade;
parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
ret = eiointc_init(priv, parent_irq, acpi_eiointc->node_map);
@@ -527,8 +533,9 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
static int __init eiointc_of_init(struct device_node *of_node,
struct device_node *parent)
{
- int parent_irq, ret;
struct eiointc_priv *priv;
+ struct irq_data *irq_data;
+ int parent_irq, ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -544,6 +551,12 @@ static int __init eiointc_of_init(struct device_node *of_node,
if (ret < 0)
goto out_free_priv;
+ irq_data = irq_get_irq_data(parent_irq);
+ if (!irq_data) {
+ ret = -ENODEV;
+ goto out_free_priv;
+ }
+
/*
* In particular, the number of devices supported by the LS2K0500
* extended I/O interrupt vector is 128.
@@ -552,7 +565,7 @@ static int __init eiointc_of_init(struct device_node *of_node,
priv->vec_count = 128;
else
priv->vec_count = VEC_COUNT;
-
+ priv->parent_hwirq = irqd_to_hwirq(irq_data);
priv->node = 0;
priv->domain_handle = of_fwnode_handle(of_node);
--
2.51.0
Powered by blists - more mailing lists