【OS版本】openEuler-24.03-LTS
【内核版本】OLK-6.6
【硬件平台】SG2044(RISC-V,thead,c900-plic)
【故障描述】
中断亲和性迁移后偶发中断失效。该问题通过 IGB 驱动的 i210/i350 网卡使用观察到:先出现网卡异常,dmesg 报 WATCHDOG: TX queue xxx timeout → Reset adapter,且网卡reset后依旧无法正常使用;进一步通过/proc/interrupts 观察到异常后网卡对应的中断计数不再增长,设备无法正常上报和处理中断。
PLIC 1.0.0 规范(https://github.com/riscv/riscv-plic-spec)要求:
§8:"the gateway will not forward an additional interrupt request until it receives an interrupt completion message"
§9:"If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is silently ignored."
§5:"A pending bit in the PLIC core can be cleared by setting the associated enable bit then performing a claim."
即 completion 时源必须对本 context enabled,否则被硬件静默忽略;gateway 收不到 completion 不再转发该源(§8),pending 只能由 enabled+claim 清除(§5),故一次被忽略的 completion 会使该源中断永久无法正常触发和处理。
CPU-A PLIC CPU-B
|--- claim -------> | | t1 plic_handle_irq 取得 hwirq
| |<-- clr en[A] -------| t2 plic_set_affinity→plic_irq_toggle({A},0)
| |<-- eff -> B --------| t3
| |<-- en[B] -----------| t4
| run handler | | t5 handle_irq_event
|--- complete ----> X | t6 chained_irq_exit→plic_irq_eoi: ignored
| | | gateway 不再转发该源,中断永久失效
【问题复现步骤】
在网卡中断持续触发时反复高频修改亲和性:
echo 0 > /proc/irq/<N>/smp_affinity_list
echo 1 > /proc/irq/<N>/smp_affinity_list
【实际结果】
若干次后该中断计数停止增长,中断不再正常触发和处理,最终触发 TX watchdog timeout。
【期望结果】
亲和性迁移后中断正常触发和处理。
【修复思路】
修复涉及文件:drivers/irqchip/irq-sifive-plic.c。
给 plic_irq_eoi() 整段加 per-hart enable_lock,使「读 enable 位→(必要时临时使能)→写 completion→(恢复禁用)」与 plic_set_affinity 清 enable 互斥:
raw_spin_lock_irqsave(&handler->enable_lock, flags);
enabled = readl(reg) & BIT(d->hwirq % 32);
if (unlikely(!enabled)) {
plic_toggle(handler, d->hwirq, 1); // 临时使能
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); // completion
plic_toggle(handler, d->hwirq, 0); // 恢复禁用
} else {
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
}
raw_spin_unlock_irqrestore(&handler->enable_lock, flags);
enable_lock 与 plic_toggle(清 enable,持同一把锁)互斥:enable 清除要么先于 EOI(读到 0,走临时使能再 completion),要么阻塞在锁外至 EOI 释放,completion 不被忽略。enable_lock 为最内层锁,无 ABBA。
【OS版本】openEuler-24.03-LTS
【内核版本】OLK-6.6
【硬件平台】SG2044(RISC-V,
thead,c900-plic)【故障描述】
中断亲和性迁移后偶发中断失效。该问题通过 IGB 驱动的 i210/i350 网卡使用观察到:先出现网卡异常,dmesg 报
WATCHDOG: TX queue xxx timeout → Reset adapter,且网卡reset后依旧无法正常使用;进一步通过/proc/interrupts观察到异常后网卡对应的中断计数不再增长,设备无法正常上报和处理中断。PLIC 1.0.0 规范(https://github.com/riscv/riscv-plic-spec)要求:
即 completion 时源必须对本 context enabled,否则被硬件静默忽略;gateway 收不到 completion 不再转发该源(§8),pending 只能由 enabled+claim 清除(§5),故一次被忽略的 completion 会使该源中断永久无法正常触发和处理。
【问题复现步骤】
在网卡中断持续触发时反复高频修改亲和性:
【实际结果】
若干次后该中断计数停止增长,中断不再正常触发和处理,最终触发 TX watchdog timeout。
【期望结果】
亲和性迁移后中断正常触发和处理。
【修复思路】
修复涉及文件:
drivers/irqchip/irq-sifive-plic.c。给
plic_irq_eoi()整段加 per-hartenable_lock,使「读 enable 位→(必要时临时使能)→写 completion→(恢复禁用)」与plic_set_affinity清 enable 互斥:enable_lock与plic_toggle(清 enable,持同一把锁)互斥:enable 清除要么先于 EOI(读到 0,走临时使能再 completion),要么阻塞在锁外至 EOI 释放,completion 不被忽略。enable_lock为最内层锁,无 ABBA。