Commit 1a8d26f623 for qemu.org

commit 1a8d26f623b18d7a5cc19b65b7052bf0d930a4ae
Author: Bibo Mao <maobibo@loongson.cn>
Date:   Thu Sep 10 15:46:13 2026 +0800

    target/loongarch: Add CPUTimerState structure

    Structure CPUTimerState is added in structure CPUSysState, QEMUTimer
    and IRQ number is included, so it is easy to add another separate
    timer if LVZ feature is supported.

    Signed-off-by: Bibo Mao <maobibo@loongson.cn>
    Reviewed-by:   Xianglai Li <lixianglai@loongson.cn>

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index ab37a9e2e6..b8e95750bb 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -727,11 +727,18 @@ static void loongarch_cpu_init(Object *obj)
 {
 #ifndef CONFIG_USER_ONLY
     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+#ifdef CONFIG_TCG
+    CPULoongArchState *env = &cpu->env;
+    CPUTimerState *timer;
+#endif

     qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
 #ifdef CONFIG_TCG
-    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
-                  &cpu_loongarch_timer_cb, cpu);
+    timer = env_timer(env);
+    timer->irq = IRQ_TIMER;
+    timer->cs  = CPU(obj);
+    timer_init_ns(&timer->timer, QEMU_CLOCK_VIRTUAL,
+                  &cpu_loongarch_timer_cb, timer);
 #endif
 #endif
 }
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index d83dcef6f8..c592f69885 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -315,6 +315,12 @@ typedef struct  LoongArchBT {
     uint32_t ftop;
 } lbt_t;

+typedef struct CPUTimerState {
+    QEMUTimer timer;
+    int irq;
+    CPUState *cs;
+} CPUTimerState;
+
 #define CPU_VENDOR_LOONGSON   "Loongson"
 #define CPU_MODEL_3A5000      "3A5000"
 #define CPU_MODEL_1C101       "1C101"
@@ -384,6 +390,9 @@ typedef struct CPUSysState {
     uint64_t CSR_PRCFG1;
     uint64_t CSR_PRCFG2;
     uint64_t CSR_PRCFG3;
+#ifdef CONFIG_TCG
+    CPUTimerState timer_state;
+#endif
 } CPUSysState;

 typedef struct CPUArchState {
@@ -446,7 +455,6 @@ struct ArchCPU {
     CPUState parent_obj;

     CPULoongArchState env;
-    QEMUTimer timer;
     uint32_t  phy_id;
     OnOffAuto lbt;
     OnOffAuto pmu;
@@ -504,6 +512,11 @@ static inline void set_sys_state(CPULoongArchState *env, CPUSysState *sys)
     env->sys_state = sys;
 }

+static inline CPUTimerState *env_timer(CPULoongArchState *env)
+{
+    return &env->sys_states[0].timer_state;
+}
+
 static inline bool is_la64(CPULoongArchState *env)
 {
     return FIELD_EX32(env->cpucfg[1], CPUCFG1, ARCH) == CPUCFG1_ARCH_LA64;
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 8c5f095782..f9a0680fe0 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -35,9 +35,9 @@ void loongarch_cpu_update_irq(LoongArchCPU *cpu, uint64_t old);
 void loongarch_cpu_set_irq(void *opaque, int irq, int level);

 void cpu_loongarch_timer_cb(void *opaque);
-uint64_t cpu_loongarch_get_timer_counter(LoongArchCPU *cpu);
-uint64_t cpu_loongarch_get_timer_ticks(LoongArchCPU *cpu);
-void cpu_loongarch_set_timer_config(LoongArchCPU *cpu, uint64_t value);
+uint64_t cpu_loongarch_get_timer_counter(CPUTimerState *timer);
+uint64_t cpu_loongarch_get_timer_ticks(CPUTimerState *timer);
+void cpu_loongarch_set_timer_config(CPUTimerState *timer, uint64_t value);
 bool loongarch_cpu_has_work(CPUState *cs);
 bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env);
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c
index b1a0b005e9..88656b5344 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -72,9 +72,7 @@ target_ulong helper_csrrd_cpuid(CPULoongArchState *env)

 target_ulong helper_csrrd_tval(CPULoongArchState *env)
 {
-    LoongArchCPU *cpu = env_archcpu(env);
-
-    return cpu_loongarch_get_timer_ticks(cpu);
+    return cpu_loongarch_get_timer_ticks(env_timer(env));
 }

 target_ulong helper_csrrd_msgir(CPULoongArchState *env)
@@ -135,23 +133,23 @@ target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val)

 target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val)
 {
-    LoongArchCPU *cpu = env_archcpu(env);
-    CPUSysState *sys = env_sys(env);
+    CPUTimerState *timer = env_timer(env);
+    CPUSysState *sys = container_of(timer, CPUSysState, timer_state);
     int64_t old_v = sys->CSR_TCFG;

-    cpu_loongarch_set_timer_config(cpu, val);
+    cpu_loongarch_set_timer_config(timer, val);

     return old_v;
 }

 target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
 {
-    LoongArchCPU *cpu = env_archcpu(env);
+    CPUTimerState *timer = env_timer(env);
     int64_t old_v = 0;

     if (val & 0x1) {
         bql_lock();
-        loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0);
+        loongarch_cpu_set_irq(LOONGARCH_CPU(timer->cs), timer->irq, 0);
         bql_unlock();
     }
     return old_v;
diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
index c090d5b12e..f98fe4d4a1 100644
--- a/target/loongarch/tcg/op_helper.c
+++ b/target/loongarch/tcg/op_helper.c
@@ -73,15 +73,15 @@ uint64_t helper_rdtime_d(CPULoongArchState *env)
     return cpu_get_host_ticks();
 #else
     uint64_t plv;
-    LoongArchCPU *cpu = env_archcpu(env);
-    CPUSysState *sys = env_sys(env);
+    CPUTimerState *timer = env_timer(env);
+    CPUSysState *sys = container_of(timer, CPUSysState, timer_state);

     plv = FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, PLV);
     if (extract64(sys->CSR_MISC, R_CSR_MISC_DRDTL_SHIFT + plv, 1)) {
         do_raise_exception(env, EXCCODE_IPE, GETPC());
     }

-    return cpu_loongarch_get_timer_counter(cpu);
+    return cpu_loongarch_get_timer_counter(timer);
 #endif
 }

diff --git a/target/loongarch/tcg/timer.c b/target/loongarch/tcg/timer.c
index a25312b9ab..6a96dfd429 100644
--- a/target/loongarch/tcg/timer.c
+++ b/target/loongarch/tcg/timer.c
@@ -15,60 +15,57 @@
 #define CONSTANT_TIMER_TICK_MASK    0xfffffffffffcUL
 #define CONSTANT_TIMER_ENABLE       0x1UL

-uint64_t cpu_loongarch_get_timer_counter(LoongArchCPU *cpu)
+uint64_t cpu_loongarch_get_timer_counter(CPUTimerState *timer)
 {
     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
 }

-uint64_t cpu_loongarch_get_timer_ticks(LoongArchCPU *cpu)
+uint64_t cpu_loongarch_get_timer_ticks(CPUTimerState *timer)
 {
-    CPULoongArchState *env = &cpu->env;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = container_of(timer, CPUSysState, timer_state);
     uint64_t now, expire;

     if ((sys->CSR_TCFG & CONSTANT_TIMER_ENABLE) &&
         (sys->CSR_TVAL < sys->CSR_TCFG)) {
         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-        expire = timer_expire_time_ns(&cpu->timer);
+        expire = timer_expire_time_ns(&timer->timer);
         sys->CSR_TVAL = (expire - now) / TIMER_PERIOD;
     }

     return sys->CSR_TVAL;
 }

-void cpu_loongarch_set_timer_config(LoongArchCPU *cpu, uint64_t value)
+void cpu_loongarch_set_timer_config(CPUTimerState *timer, uint64_t value)
 {
-    CPULoongArchState *env = &cpu->env;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = container_of(timer, CPUSysState, timer_state);
     uint64_t now, next;

     sys->CSR_TCFG = value;
     if (value & CONSTANT_TIMER_ENABLE) {
         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
         next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
-        timer_mod(&cpu->timer, next);
+        timer_mod(&timer->timer, next);
         sys->CSR_TVAL = sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK;
     } else {
-        timer_del(&cpu->timer);
+        timer_del(&timer->timer);
         sys->CSR_TVAL = 0;
     }
 }

 void cpu_loongarch_timer_cb(void *opaque)
 {
-    LoongArchCPU *cpu  = opaque;
-    CPULoongArchState *env = &cpu->env;
-    CPUSysState *sys = env_sys(env);
+    CPUTimerState *timer = opaque;
+    CPUSysState *sys = container_of(timer, CPUSysState, timer_state);
     uint64_t now, next;

     if (FIELD_EX64(sys->CSR_TCFG, CSR_TCFG, PERIODIC)) {
         now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
         next = now + (sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
-        timer_mod(&cpu->timer, next);
+        timer_mod(&timer->timer, next);
         sys->CSR_TVAL = sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK;
     } else {
         sys->CSR_TVAL = CONSTANT_TIMER_TICK_MASK;
     }

-    loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1);
+    loongarch_cpu_set_irq(LOONGARCH_CPU(timer->cs), timer->irq, 1);
 }