Period mode timer is added. Timer only need program once with period mode, its compared tick value will reload when timer is fired.
Signed-off-by: Bibo Mao maobibo@loongson.cn --- .../kvm/include/loongarch/arch_timer.h | 5 ++++ .../selftests/kvm/loongarch/arch_timer.c | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+)
diff --git a/tools/testing/selftests/kvm/include/loongarch/arch_timer.h b/tools/testing/selftests/kvm/include/loongarch/arch_timer.h index 94b1cba2744d..b6399e748f72 100644 --- a/tools/testing/selftests/kvm/include/loongarch/arch_timer.h +++ b/tools/testing/selftests/kvm/include/loongarch/arch_timer.h @@ -36,6 +36,11 @@ static inline void timer_set_next_cmp_ms(unsigned int msec, bool period) csr_write(val, LOONGARCH_CSR_TCFG); }
+static inline void disable_timer(void) +{ + csr_write(0, LOONGARCH_CSR_TCFG); +} + static inline unsigned long timer_get_val(void) { return csr_read(LOONGARCH_CSR_TVAL); diff --git a/tools/testing/selftests/kvm/loongarch/arch_timer.c b/tools/testing/selftests/kvm/loongarch/arch_timer.c index 2a2cebcf3885..a4a39f24bb7e 100644 --- a/tools/testing/selftests/kvm/loongarch/arch_timer.c +++ b/tools/testing/selftests/kvm/loongarch/arch_timer.c @@ -23,6 +23,13 @@ static void guest_irq_handler(struct ex_regs *regs) GUEST_ASSERT_EQ(intid, 1);
cfg = timer_get_cfg(); + if (cfg & CSR_TCFG_PERIOD) { + WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter - 1); + if (shared_data->nr_iter == 0) + disable_timer(); + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); + return; + }
/* * On physical machine, value of LOONGARCH_CSR_TVAL is BIT_ULL(48) - 1 @@ -67,6 +74,26 @@ static void guest_test_oneshot_timer(uint32_t cpu) } }
+static void guest_test_period_timer(uint32_t cpu) +{ + uint32_t irq_iter; + uint64_t us; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + shared_data->nr_iter = test_args.nr_iter; + shared_data->xcnt = timer_get_cycles(); + us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us; + timer_set_next_cmp_ms(test_args.timer_period_ms, true); + /* Setup a timeout for the interrupt to arrive */ + udelay(us * test_args.nr_iter); + irq_iter = READ_ONCE(shared_data->nr_iter); + __GUEST_ASSERT(irq_iter == 0, + "irq_iter = 0x%x.\n" + " Guest period timer interrupt was not triggered within the specified\n" + " interval, try to increase the error margin by [-e] option.\n", + irq_iter); +} + static void guest_code(void) { uint32_t cpu = guest_get_vcpuid(); @@ -74,6 +101,7 @@ static void guest_code(void) timer_irq_enable(); local_irq_enable(); guest_test_oneshot_timer(cpu); + guest_test_period_timer(cpu);
GUEST_DONE(); }