drivers: timer: arm_arch_timer: Workaround for Cortex-A9 erratum 740657

Modification of the ARM architected timer driver and its configuration
data in order to address an erratum which exists at least in the Cor-
tex-A9 CPU, and which can also be observed in the QEMU implementation
of the Cortex-A9.

Comp.: ARM Cortex-A9 processors Software Developer Errata Notice
ARM document ID032315
Erratum 740657

This erratum causes a spurious interrupt pending indication with the
interrupt controller if no new compare value is written within the
timer ISR before the interrupt is cleared. This is usually the case
in tickless mode. If the spurious interrupt is not prevented, the
timer ISR will be called twice, but on second execution, the pending
flag is not set within the timer's register space. Not handling this
issue will lead to erratic tick announcements to the kernel.

Signed-off-by: Immo Birnbaum <Immo.Birnbaum@weidmueller.com>
This commit is contained in:
Immo Birnbaum 2021-07-15 11:41:34 +02:00 committed by Carles Cufí
commit 315ad1d6e6
3 changed files with 76 additions and 0 deletions

View file

@ -120,6 +120,17 @@ DT_COMPAT_ARM_V7M_SYSTICK := arm,armv7m-systick
DT_COMPAT_ARM_V8M_SYSTICK := arm,armv8m-systick
DT_COMPAT_ARM_V8_1M_SYSTICK := arm,armv8.1m-systick
config ARM_ARCH_TIMER_ERRATUM_740657
bool "ARM architected timer is affected by ARM erratum 740657"
depends on ARM_ARCH_TIMER
help
This option indicates that the ARM architected timer as implemented
in the target hardware is affected by the ARM erratum 740657 (comp.
ARM Cortex-A9 processors Software Developers Errata Notice, ARM
document ID032315) which leads to an additional, spurious interrupt
indication upon every actual timer interrupt. This option activates
the workaround for the erratum within the timer driver.
config CORTEX_M_SYSTICK
bool "Cortex-M SYSTICK timer"
depends on CPU_CORTEX_M_HAS_SYSTICK

View file

@ -24,6 +24,24 @@ static void arm_arch_timer_compare_isr(const void *arg)
k_spinlock_key_t key = k_spin_lock(&lock);
#ifdef CONFIG_ARM_ARCH_TIMER_ERRATUM_740657
/*
* Workaround required for Cortex-A9 MPCore erratum 740657
* comp. ARM Cortex-A9 processors Software Developers Errata Notice,
* ARM document ID032315.
*/
if (!arm_arch_timer_get_int_status()) {
/*
* If the event flag is not set, this is a spurious interrupt.
* DO NOT modify the compare register's value, DO NOT announce
* elapsed ticks!
*/
k_spin_unlock(&lock, key);
return;
}
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
uint64_t curr_cycle = arm_arch_timer_count();
uint32_t delta_ticks = (uint32_t)((curr_cycle - last_cycle) / CYC_PER_TICK);
@ -39,8 +57,29 @@ static void arm_arch_timer_compare_isr(const void *arg)
arm_arch_timer_set_irq_mask(false);
} else {
arm_arch_timer_set_irq_mask(true);
#ifdef CONFIG_ARM_ARCH_TIMER_ERRATUM_740657
/*
* In tickless mode, the compare register is normally not
* updated from within the ISR. Yet, to work around the timer's
* erratum, a new value *must* be written while the interrupt
* is being processed before the interrupt is acknowledged
* by the handling interrupt controller.
*/
arm_arch_timer_set_compare(~0ULL);
}
/*
* Clear the event flag so that in case the erratum strikes (the timer's
* vector will still be indicated as pending by the GIC's pending register
* after this ISR has been executed) the error will be detected by the
* check performed upon entry of the ISR -> the event flag is not set,
* therefore, no actual hardware interrupt has occurred.
*/
arm_arch_timer_clear_int_status();
#else
}
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
k_spin_unlock(&lock, key);
sys_clock_announce(delta_ticks);

View file

@ -35,6 +35,8 @@ extern "C" {
#define TIMER_COMP_ENABLE BIT(1)
#define TIMER_ENABLE BIT(0)
#define TIMER_ISR_EVENT_FLAG BIT(0)
DEVICE_MMIO_TOPLEVEL_STATIC(timer_regs, ARM_TIMER_NODE);
#define TIMER_REG_GET(offs) (DEVICE_MMIO_TOPLEVEL_GET(timer_regs) + offs)
@ -63,6 +65,30 @@ static ALWAYS_INLINE void arm_arch_timer_set_compare(uint64_t val)
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
}
#if defined(CONFIG_ARM_ARCH_TIMER_ERRATUM_740657)
/*
* R/W access to the event flag register is required for the timer errata
* 740657 workaround -> comp. ISR implementation in arm_arch_timer.c.
* This functionality is not present in the aarch64 implementation of the
* ARM global timer access functions.
*
* comp. ARM Cortex-A9 processors Software Developers Errata Notice,
* ARM document ID032315.
*/
static ALWAYS_INLINE uint8_t arm_arch_timer_get_int_status(void)
{
return (uint8_t)(sys_read32(TIMER_REG_GET(TIMER_ISR)) & TIMER_ISR_EVENT_FLAG);
}
static ALWAYS_INLINE void arm_arch_timer_clear_int_status(void)
{
sys_write32(TIMER_ISR_EVENT_FLAG, TIMER_REG_GET(TIMER_ISR));
}
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
static ALWAYS_INLINE void arm_arch_timer_enable(bool enable)
{
uint32_t ctrl;