diff mbox series

[kvm-unit-tests,4/4] arm: timer: Take into account other wake-up events for the TVAL test

Message ID 20211207154641.87740-5-alexandru.elisei@arm.com (mailing list archive)
State New, archived
Headers show
Series [kvm-unit-tests,1/4] arm: timer: Fix TVAL comparison for timer condition met | expand

Commit Message

Alexandru Elisei Dec. 7, 2021, 3:46 p.m. UTC
The TVAL test programs the timer to fire into the future, waits for an
interrupt using the WFI instruction, and when the instruction completes it
checks that the timer interrupt has fired. According to ARM DDI 0487G.a
there are other wake-up events that can cause the WFI to complete (listed
on page D1-2520), among them interrupts routed to a higher exception level,
where the hypervisor is running (if running under virtualization) or
firmware (if running on baremetal).

In practice, this is unlikely to have caused a false test failure, because
for a GICv3 (which the author assumes is a lot more common than a GICv4+)
the WFI is trapped by KVM and the VCPU thread is resumed only after the
timer asserts the interrupt, as the test expects.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---
 arm/timer.c | 39 +++++++++++++++++++++++++++++++++------
 1 file changed, 33 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/arm/timer.c b/arm/timer.c
index 7b2d82896c74..8a668e8adac8 100644
--- a/arm/timer.c
+++ b/arm/timer.c
@@ -278,17 +278,44 @@  static void test_timer_cval(struct timer_info *info)
 	disable_timer(info);
 }
 
-static void test_timer_tval(struct timer_info *info)
+static void timer_do_wfi(struct timer_info *info)
 {
-	s32 left;
-
-	info->write_tval(read_sysreg(cntfrq_el0) / 100);	/* 10 ms */
 	local_irq_disable();
-	info->write_ctl(ARCH_TIMER_CTL_ENABLE);
+	if (info->irq_received)
+		goto out;
 	report_info("waiting for interrupt...");
 	wfi();
+out:
 	local_irq_enable();
-	left = info->read_tval();
+}
+
+static void test_timer_tval(struct timer_info *info)
+{
+	u64 time_10ms = read_sysreg(cntfrq_el0) / 100;
+	s32 left;
+	int i;
+
+	info->write_tval(time_10ms);
+	info->write_ctl(ARCH_TIMER_CTL_ENABLE);
+
+	for (;;) {
+		timer_do_wfi(info);
+		left = info->read_tval();
+		if (info->irq_received || left <= 0)
+			break;
+	}
+
+	/* Wait one second for the GIC to update the interrupt state. */
+	if (left <= 0 && !info->irq_received) {
+		for (i = 0; i < 10; i++) {
+			timer_do_wfi(info);
+			if (info->irq_received)
+				break;
+			mdelay(100);
+		}
+		left = info->read_tval();
+	}
+
 	report(info->irq_received, "interrupt received after TVAL/WFI");
 	report(left <= 0, "timer has expired");
 	report_info("TVAL is %d ticks", left);