Skip to content

Commit 056c156

Browse files
author
Marc Zyngier
committed
KVM: arm64: selftests: Deal with spurious timer interrupts
Make sure the timer test can properly handle a spurious timer interrupt, something that is far from being unlikely. This involves checking for the GIC IAR return value (don't bother handling the interrupt if it was spurious) as well as the timer control register (don't do anything if the interrupt is masked or the timer disabled). Take this opportunity to rewrite the timer handler in a more readable way. This solves a bunch of failures that creep up on systems that are slow to retire the interrupt, something that the GIC architecture makes no guarantee about. Reviewed-by: Colton Lewis <coltonlewis@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20230330174800.2677007-20-maz@kernel.org
1 parent 0630fb8 commit 056c156

1 file changed

Lines changed: 25 additions & 15 deletions

File tree

tools/testing/selftests/kvm/aarch64/arch_timer.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,25 +121,35 @@ static void guest_validate_irq(unsigned int intid,
121121
uint64_t xcnt = 0, xcnt_diff_us, cval = 0;
122122
unsigned long xctl = 0;
123123
unsigned int timer_irq = 0;
124+
unsigned int accessor;
124125

125-
if (stage == GUEST_STAGE_VTIMER_CVAL ||
126-
stage == GUEST_STAGE_VTIMER_TVAL) {
127-
xctl = timer_get_ctl(VIRTUAL);
128-
timer_set_ctl(VIRTUAL, CTL_IMASK);
129-
xcnt = timer_get_cntct(VIRTUAL);
130-
cval = timer_get_cval(VIRTUAL);
126+
if (intid == IAR_SPURIOUS)
127+
return;
128+
129+
switch (stage) {
130+
case GUEST_STAGE_VTIMER_CVAL:
131+
case GUEST_STAGE_VTIMER_TVAL:
132+
accessor = VIRTUAL;
131133
timer_irq = vtimer_irq;
132-
} else if (stage == GUEST_STAGE_PTIMER_CVAL ||
133-
stage == GUEST_STAGE_PTIMER_TVAL) {
134-
xctl = timer_get_ctl(PHYSICAL);
135-
timer_set_ctl(PHYSICAL, CTL_IMASK);
136-
xcnt = timer_get_cntct(PHYSICAL);
137-
cval = timer_get_cval(PHYSICAL);
134+
break;
135+
case GUEST_STAGE_PTIMER_CVAL:
136+
case GUEST_STAGE_PTIMER_TVAL:
137+
accessor = PHYSICAL;
138138
timer_irq = ptimer_irq;
139-
} else {
139+
break;
140+
default:
140141
GUEST_ASSERT(0);
142+
return;
141143
}
142144

145+
xctl = timer_get_ctl(accessor);
146+
if ((xctl & CTL_IMASK) || !(xctl & CTL_ENABLE))
147+
return;
148+
149+
timer_set_ctl(accessor, CTL_IMASK);
150+
xcnt = timer_get_cntct(accessor);
151+
cval = timer_get_cval(accessor);
152+
143153
xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt);
144154

145155
/* Make sure we are dealing with the correct timer IRQ */
@@ -148,6 +158,8 @@ static void guest_validate_irq(unsigned int intid,
148158
/* Basic 'timer condition met' check */
149159
GUEST_ASSERT_3(xcnt >= cval, xcnt, cval, xcnt_diff_us);
150160
GUEST_ASSERT_1(xctl & CTL_ISTATUS, xctl);
161+
162+
WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);
151163
}
152164

153165
static void guest_irq_handler(struct ex_regs *regs)
@@ -158,8 +170,6 @@ static void guest_irq_handler(struct ex_regs *regs)
158170

159171
guest_validate_irq(intid, shared_data);
160172

161-
WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);
162-
163173
gic_set_eoi(intid);
164174
}
165175

0 commit comments

Comments
 (0)