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