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();
     }