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 <jorgepereira89@gmail.com>
This commit is contained in:
JorgeMVP 2023-05-18 20:19:48 +02:00 committed by Kent McLeod
parent 8c9cf6c7db
commit 62c8148268

View file

@ -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 <arch/machine/timer.h>
@ -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 */