diff mbox series

[RFC,v3,05/27] target/loongarch: Add stabletimer support

Message ID 1638619645-11283-6-git-send-email-yangxiaojuan@loongson.cn (mailing list archive)
State New, archived
Headers show
Series Add LoongArch softmmu support. | expand

Commit Message

Xiaojuan Yang Dec. 4, 2021, 12:07 p.m. UTC
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu.c         |  9 +++++
 target/loongarch/cpu.h         | 10 ++++++
 target/loongarch/meson.build   |  1 +
 target/loongarch/stabletimer.c | 63 ++++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+)
 create mode 100644 target/loongarch/stabletimer.c

Comments

chen huacai Dec. 6, 2021, 4:38 a.m. UTC | #1
Hi, Xiaojuan,

Maybe it is better to use "constant timer" instead of "stable timer",
which is more "native" in English.

Huacai

On Sat, Dec 4, 2021 at 8:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>  target/loongarch/cpu.c         |  9 +++++
>  target/loongarch/cpu.h         | 10 ++++++
>  target/loongarch/meson.build   |  1 +
>  target/loongarch/stabletimer.c | 63 ++++++++++++++++++++++++++++++++++
>  4 files changed, 83 insertions(+)
>  create mode 100644 target/loongarch/stabletimer.c
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 343632c644..f34e9763af 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -234,12 +234,21 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>      LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
>      Error *local_err = NULL;
>
> +#ifndef CONFIG_USER_ONLY
> +    LoongArchCPU *cpu = LOONGARCH_CPU(dev);
> +#endif
> +
>      cpu_exec_realizefn(cs, &local_err);
>      if (local_err != NULL) {
>          error_propagate(errp, local_err);
>          return;
>      }
>
> +#ifndef CONFIG_USER_ONLY
> +    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
> +                  &loongarch_stable_timer_cb, cpu);
> +#endif
> +
>      cpu_reset(cs);
>      qemu_init_vcpu(cs);
>
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index a4acd3b285..aeb8a5d397 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -12,6 +12,7 @@
>  #include "fpu/softfloat-types.h"
>  #include "hw/registerfields.h"
>  #include "cpu-csr.h"
> +#include "qemu/timer.h"
>
>  #define TCG_GUEST_DEFAULT_MO (0)
>
> @@ -148,6 +149,9 @@ FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
>  extern const char * const regnames[];
>  extern const char * const fregnames[];
>
> +#define N_IRQS      14
> +#define IRQ_TIMER   11
> +
>  typedef struct CPULoongArchState CPULoongArchState;
>  struct CPULoongArchState {
>      uint64_t gpr[32];
> @@ -242,6 +246,7 @@ struct LoongArchCPU {
>
>      CPUNegativeOffsetState neg;
>      CPULoongArchState env;
> +    QEMUTimer timer; /* Internal timer */
>  };
>
>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
> @@ -306,4 +311,9 @@ enum {
>  #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
>
> +void loongarch_stable_timer_cb(void *opaque);
> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu);
> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu);
> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
> +                                             uint64_t value);
>  #endif /* LOONGARCH_CPU_H */
> diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
> index 103f36ee15..bda9f47ae4 100644
> --- a/target/loongarch/meson.build
> +++ b/target/loongarch/meson.build
> @@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib)
>  loongarch_softmmu_ss = ss.source_set()
>  loongarch_softmmu_ss.add(files(
>    'machine.c',
> +  'stabletimer.c',
>  ))
>
>  loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
> diff --git a/target/loongarch/stabletimer.c b/target/loongarch/stabletimer.c
> new file mode 100644
> index 0000000000..151f5073f5
> --- /dev/null
> +++ b/target/loongarch/stabletimer.c
> @@ -0,0 +1,63 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU LoongArch timer support
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "qemu/timer.h"
> +#include "cpu.h"
> +
> +#define TIMER_PERIOD                10 /* 10 ns period for 100 Mhz frequency */
> +#define STABLETIMER_TICK_MASK       0xfffffffffffcUL
> +#define STABLETIMER_ENABLE          0x1UL
> +
> +/* LoongArch timer */
> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu)
> +{
> +    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
> +}
> +
> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu)
> +{
> +    uint64_t now, expire;
> +
> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    expire = timer_expire_time_ns(&cpu->timer);
> +
> +    return (expire - now) / TIMER_PERIOD;
> +}
> +
> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
> +                                             uint64_t value)
> +{
> +    CPULoongArchState *env = &cpu->env;
> +    uint64_t now, next;
> +
> +    env->CSR_TCFG = value;
> +    if (value & STABLETIMER_ENABLE) {
> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
> +        timer_mod(&cpu->timer, next);
> +    }
> +}
> +
> +void loongarch_stable_timer_cb(void *opaque)
> +{
> +    LoongArchCPU *cpu  = opaque;
> +    CPULoongArchState *env = &cpu->env;
> +    uint64_t now, next;
> +
> +    if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
> +        timer_mod(&cpu->timer, next);
> +    } else {
> +        env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
> +    }
> +
> +    env->CSR_ESTAT |= 1 << IRQ_TIMER;
> +    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
> +}
> --
> 2.27.0
>
>
maobibo Dec. 7, 2021, 7:04 a.m. UTC | #2
On 12/06/2021 12:38 PM, chen huacai wrote:
> Hi, Xiaojuan,
> 
> Maybe it is better to use "constant timer" instead of "stable timer",
> which is more "native" in English.

Yeap, maybe we need more investigation. On arm platform its name is ArchTimer
rather than "constant timer" in x86. And we will investigate the timer name
across different architecture.

regards
bibo, mao

> 
> Huacai
> 
> On Sat, Dec 4, 2021 at 8:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>  target/loongarch/cpu.c         |  9 +++++
>>  target/loongarch/cpu.h         | 10 ++++++
>>  target/loongarch/meson.build   |  1 +
>>  target/loongarch/stabletimer.c | 63 ++++++++++++++++++++++++++++++++++
>>  4 files changed, 83 insertions(+)
>>  create mode 100644 target/loongarch/stabletimer.c
>>
>> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
>> index 343632c644..f34e9763af 100644
>> --- a/target/loongarch/cpu.c
>> +++ b/target/loongarch/cpu.c
>> @@ -234,12 +234,21 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>>      LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
>>      Error *local_err = NULL;
>>
>> +#ifndef CONFIG_USER_ONLY
>> +    LoongArchCPU *cpu = LOONGARCH_CPU(dev);
>> +#endif
>> +
>>      cpu_exec_realizefn(cs, &local_err);
>>      if (local_err != NULL) {
>>          error_propagate(errp, local_err);
>>          return;
>>      }
>>
>> +#ifndef CONFIG_USER_ONLY
>> +    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
>> +                  &loongarch_stable_timer_cb, cpu);
>> +#endif
>> +
>>      cpu_reset(cs);
>>      qemu_init_vcpu(cs);
>>
>> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
>> index a4acd3b285..aeb8a5d397 100644
>> --- a/target/loongarch/cpu.h
>> +++ b/target/loongarch/cpu.h
>> @@ -12,6 +12,7 @@
>>  #include "fpu/softfloat-types.h"
>>  #include "hw/registerfields.h"
>>  #include "cpu-csr.h"
>> +#include "qemu/timer.h"
>>
>>  #define TCG_GUEST_DEFAULT_MO (0)
>>
>> @@ -148,6 +149,9 @@ FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
>>  extern const char * const regnames[];
>>  extern const char * const fregnames[];
>>
>> +#define N_IRQS      14
>> +#define IRQ_TIMER   11
>> +
>>  typedef struct CPULoongArchState CPULoongArchState;
>>  struct CPULoongArchState {
>>      uint64_t gpr[32];
>> @@ -242,6 +246,7 @@ struct LoongArchCPU {
>>
>>      CPUNegativeOffsetState neg;
>>      CPULoongArchState env;
>> +    QEMUTimer timer; /* Internal timer */
>>  };
>>
>>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
>> @@ -306,4 +311,9 @@ enum {
>>  #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
>>  #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
>>
>> +void loongarch_stable_timer_cb(void *opaque);
>> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu);
>> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu);
>> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
>> +                                             uint64_t value);
>>  #endif /* LOONGARCH_CPU_H */
>> diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
>> index 103f36ee15..bda9f47ae4 100644
>> --- a/target/loongarch/meson.build
>> +++ b/target/loongarch/meson.build
>> @@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib)
>>  loongarch_softmmu_ss = ss.source_set()
>>  loongarch_softmmu_ss.add(files(
>>    'machine.c',
>> +  'stabletimer.c',
>>  ))
>>
>>  loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
>> diff --git a/target/loongarch/stabletimer.c b/target/loongarch/stabletimer.c
>> new file mode 100644
>> index 0000000000..151f5073f5
>> --- /dev/null
>> +++ b/target/loongarch/stabletimer.c
>> @@ -0,0 +1,63 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU LoongArch timer support
>> + *
>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/loongarch/loongarch.h"
>> +#include "qemu/timer.h"
>> +#include "cpu.h"
>> +
>> +#define TIMER_PERIOD                10 /* 10 ns period for 100 Mhz frequency */
>> +#define STABLETIMER_TICK_MASK       0xfffffffffffcUL
>> +#define STABLETIMER_ENABLE          0x1UL
>> +
>> +/* LoongArch timer */
>> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu)
>> +{
>> +    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
>> +}
>> +
>> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu)
>> +{
>> +    uint64_t now, expire;
>> +
>> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +    expire = timer_expire_time_ns(&cpu->timer);
>> +
>> +    return (expire - now) / TIMER_PERIOD;
>> +}
>> +
>> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
>> +                                             uint64_t value)
>> +{
>> +    CPULoongArchState *env = &cpu->env;
>> +    uint64_t now, next;
>> +
>> +    env->CSR_TCFG = value;
>> +    if (value & STABLETIMER_ENABLE) {
>> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +        next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
>> +        timer_mod(&cpu->timer, next);
>> +    }
>> +}
>> +
>> +void loongarch_stable_timer_cb(void *opaque)
>> +{
>> +    LoongArchCPU *cpu  = opaque;
>> +    CPULoongArchState *env = &cpu->env;
>> +    uint64_t now, next;
>> +
>> +    if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
>> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +        next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
>> +        timer_mod(&cpu->timer, next);
>> +    } else {
>> +        env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
>> +    }
>> +
>> +    env->CSR_ESTAT |= 1 << IRQ_TIMER;
>> +    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
>> +}
>> --
>> 2.27.0
>>
>>
> 
>
diff mbox series

Patch

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 343632c644..f34e9763af 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -234,12 +234,21 @@  static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
     LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
     Error *local_err = NULL;
 
+#ifndef CONFIG_USER_ONLY
+    LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+#endif
+
     cpu_exec_realizefn(cs, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
         return;
     }
 
+#ifndef CONFIG_USER_ONLY
+    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
+                  &loongarch_stable_timer_cb, cpu);
+#endif
+
     cpu_reset(cs);
     qemu_init_vcpu(cs);
 
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index a4acd3b285..aeb8a5d397 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -12,6 +12,7 @@ 
 #include "fpu/softfloat-types.h"
 #include "hw/registerfields.h"
 #include "cpu-csr.h"
+#include "qemu/timer.h"
 
 #define TCG_GUEST_DEFAULT_MO (0)
 
@@ -148,6 +149,9 @@  FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
 extern const char * const regnames[];
 extern const char * const fregnames[];
 
+#define N_IRQS      14
+#define IRQ_TIMER   11
+
 typedef struct CPULoongArchState CPULoongArchState;
 struct CPULoongArchState {
     uint64_t gpr[32];
@@ -242,6 +246,7 @@  struct LoongArchCPU {
 
     CPUNegativeOffsetState neg;
     CPULoongArchState env;
+    QEMUTimer timer; /* Internal timer */
 };
 
 #define TYPE_LOONGARCH_CPU "loongarch-cpu"
@@ -306,4 +311,9 @@  enum {
 #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
 
+void loongarch_stable_timer_cb(void *opaque);
+uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu);
+uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu);
+void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
+                                             uint64_t value);
 #endif /* LOONGARCH_CPU_H */
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 103f36ee15..bda9f47ae4 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -17,6 +17,7 @@  loongarch_tcg_ss.add(zlib)
 loongarch_softmmu_ss = ss.source_set()
 loongarch_softmmu_ss.add(files(
   'machine.c',
+  'stabletimer.c',
 ))
 
 loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
diff --git a/target/loongarch/stabletimer.c b/target/loongarch/stabletimer.c
new file mode 100644
index 0000000000..151f5073f5
--- /dev/null
+++ b/target/loongarch/stabletimer.c
@@ -0,0 +1,63 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch timer support
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/loongarch/loongarch.h"
+#include "qemu/timer.h"
+#include "cpu.h"
+
+#define TIMER_PERIOD                10 /* 10 ns period for 100 Mhz frequency */
+#define STABLETIMER_TICK_MASK       0xfffffffffffcUL
+#define STABLETIMER_ENABLE          0x1UL
+
+/* LoongArch timer */
+uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu)
+{
+    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
+}
+
+uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu)
+{
+    uint64_t now, expire;
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    expire = timer_expire_time_ns(&cpu->timer);
+
+    return (expire - now) / TIMER_PERIOD;
+}
+
+void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
+                                             uint64_t value)
+{
+    CPULoongArchState *env = &cpu->env;
+    uint64_t now, next;
+
+    env->CSR_TCFG = value;
+    if (value & STABLETIMER_ENABLE) {
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
+        timer_mod(&cpu->timer, next);
+    }
+}
+
+void loongarch_stable_timer_cb(void *opaque)
+{
+    LoongArchCPU *cpu  = opaque;
+    CPULoongArchState *env = &cpu->env;
+    uint64_t now, next;
+
+    if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
+        timer_mod(&cpu->timer, next);
+    } else {
+        env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
+    }
+
+    env->CSR_ESTAT |= 1 << IRQ_TIMER;
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
+}