Commit d31587eb92 for qemu.org
commit d31587eb925e4ab646b4e01ce985406b839595f2
Author: Bibo Mao <maobibo@loongson.cn>
Date: Wed Sep 23 11:10:29 2026 +0800
target/loongarch: Set CPU_INTERRUPT_HARD unless no pending irq
On LoongArch CPU_INTERRUPT_HARD is set only when interrupt is injected
at the first time. Function cpu_interrupt() is not called if there is
pending irq already, this will not set CPU_INTERRUPT_HARD bit and kick
dest CPU, however QEMU TCG framework will clear exception_index when
handling IRQ flow. There will be new interrupt lost issue when handling
old one, the similar with other architectures call cpu_interrupt() always
if there is pending interrupt.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index f22f64efb8..54c2699897 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -58,20 +58,16 @@ static vaddr loongarch_cpu_get_pc(CPUState *cs)
#ifndef CONFIG_USER_ONLY
#include "hw/loongarch/virt.h"
-void loongarch_cpu_update_irq(LoongArchCPU *cpu, uint64_t old)
+void loongarch_cpu_update_irq(LoongArchCPU *cpu)
{
CPULoongArchState *env = &cpu->env;
CPUState *cs = CPU(cpu);
CPUSysState *sys = env_sys(env);
if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) {
- if (!FIELD_EX64(old, CSR_ESTAT, IS)) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- }
+ cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
- if (FIELD_EX64(old, CSR_ESTAT, IS)) {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
@@ -81,13 +77,11 @@ static void loongarch_cpu_self_set_irq(CPUState *cs, run_on_cpu_data data)
CPULoongArchState *env = cpu_env(cs);
CPUSysState *sys = env_sys(env);
int irq, level;
- uint64_t old;
irq = data.host_int & ~BIT(31);
level = (data.host_int >> 31) & 1;
- old = sys->CSR_ESTAT;
sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, irq, 1, level != 0);
- loongarch_cpu_update_irq(cpu, old);
+ loongarch_cpu_update_irq(cpu);
}
void loongarch_cpu_set_irq(void *opaque, int irq, int level)
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index f9a0680fe0..ff956823fd 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -31,7 +31,7 @@ void restore_fp_status(CPULoongArchState *env);
#ifndef CONFIG_USER_ONLY
extern const VMStateDescription vmstate_loongarch_cpu;
-void loongarch_cpu_update_irq(LoongArchCPU *cpu, uint64_t old);
+void loongarch_cpu_update_irq(LoongArchCPU *cpu);
void loongarch_cpu_set_irq(void *opaque, int irq, int level);
void cpu_loongarch_timer_cb(void *opaque);
diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
index 88656b5344..1a6919417f 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -111,7 +111,7 @@ target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
*/
if (sys->CSR_ESTAT != old_v) {
bql_lock();
- loongarch_cpu_update_irq(env_archcpu(env), old_v);
+ loongarch_cpu_update_irq(env_archcpu(env));
bql_unlock();
}