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 <[email protected]>
---
 .../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();
 }
-- 
2.39.3


Reply via email to