From 62c8148268e597ae1e1ffce254399fbbb236972e Mon Sep 17 00:00:00 2001 From: JorgeMVP Date: Thu, 18 May 2023 20:19:48 +0200 Subject: [PATCH] generic_timer: force timer to de-assert irq Generic Timer IRQs are level-sensitive, when the CNT_TVAL is updated the trigger condition is de-asserted and the change is propagated to the GIC in a finite time to clear the pending state. However, we have to make sure the timer deasserts before EOIR/DIR, otherwise the interrupt happens again. Therefore, we need an isb() to cause the timer to de-assert before EOIR/DIR. There is also a chance of spurious IRQ. A spurious IRQ can be generated, in the case we have a level-sensitive IRQ, and its pending state is cleared at device-level but not yet propagated to the GIC. In between the IRQ deactivation and IRQ ack of the new interrupt if the requested change from the timer gets propagated then it causes a spurious IRQ. Signed-off-by: JorgeMVP --- include/drivers/timer/arm_generic.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/drivers/timer/arm_generic.h b/include/drivers/timer/arm_generic.h index fb055f21b..6168c41b0 100644 --- a/include/drivers/timer/arm_generic.h +++ b/include/drivers/timer/arm_generic.h @@ -32,6 +32,11 @@ static inline void ackDeadlineIRQ(void) { ticks_t deadline = UINT64_MAX; setDeadline(deadline); + /* Ensure that the timer deasserts the IRQ before GIC EOIR/DIR. + * This is sufficient to remove the pending state from the GICR + * and avoid the interrupt happening twice because of the level + * sensitive configuration. */ + isb(); } #else /* CONFIG_KERNEL_MCS */ #include @@ -39,6 +44,11 @@ static inline void resetTimer(void) { SYSTEM_WRITE_WORD(CNT_TVAL, TIMER_RELOAD); SYSTEM_WRITE_WORD(CNT_CTL, BIT(0)); + /* Ensure that the timer deasserts the IRQ before GIC EOIR/DIR. + * This is sufficient to remove the pending state from the GICR + * and avoid the interrupt happening twice because of the level + * sensitive configuration. */ + isb(); } #endif /* !CONFIG_KERNEL_MCS */