Skip to content

Commit 315ad1d

Browse files
ibirnbaumcarlescufi
authored andcommitted
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 <[email protected]>
1 parent a69cd66 commit 315ad1d

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

drivers/timer/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ DT_COMPAT_ARM_V7M_SYSTICK := arm,armv7m-systick
120120
DT_COMPAT_ARM_V8M_SYSTICK := arm,armv8m-systick
121121
DT_COMPAT_ARM_V8_1M_SYSTICK := arm,armv8.1m-systick
122122

123+
config ARM_ARCH_TIMER_ERRATUM_740657
124+
bool "ARM architected timer is affected by ARM erratum 740657"
125+
depends on ARM_ARCH_TIMER
126+
help
127+
This option indicates that the ARM architected timer as implemented
128+
in the target hardware is affected by the ARM erratum 740657 (comp.
129+
ARM Cortex-A9 processors Software Developers Errata Notice, ARM
130+
document ID032315) which leads to an additional, spurious interrupt
131+
indication upon every actual timer interrupt. This option activates
132+
the workaround for the erratum within the timer driver.
133+
123134
config CORTEX_M_SYSTICK
124135
bool "Cortex-M SYSTICK timer"
125136
depends on CPU_CORTEX_M_HAS_SYSTICK

drivers/timer/arm_arch_timer.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ static void arm_arch_timer_compare_isr(const void *arg)
2424

2525
k_spinlock_key_t key = k_spin_lock(&lock);
2626

27+
#ifdef CONFIG_ARM_ARCH_TIMER_ERRATUM_740657
28+
/*
29+
* Workaround required for Cortex-A9 MPCore erratum 740657
30+
* comp. ARM Cortex-A9 processors Software Developers Errata Notice,
31+
* ARM document ID032315.
32+
*/
33+
34+
if (!arm_arch_timer_get_int_status()) {
35+
/*
36+
* If the event flag is not set, this is a spurious interrupt.
37+
* DO NOT modify the compare register's value, DO NOT announce
38+
* elapsed ticks!
39+
*/
40+
k_spin_unlock(&lock, key);
41+
return;
42+
}
43+
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
44+
2745
uint64_t curr_cycle = arm_arch_timer_count();
2846
uint32_t delta_ticks = (uint32_t)((curr_cycle - last_cycle) / CYC_PER_TICK);
2947

@@ -39,7 +57,28 @@ static void arm_arch_timer_compare_isr(const void *arg)
3957
arm_arch_timer_set_irq_mask(false);
4058
} else {
4159
arm_arch_timer_set_irq_mask(true);
60+
#ifdef CONFIG_ARM_ARCH_TIMER_ERRATUM_740657
61+
/*
62+
* In tickless mode, the compare register is normally not
63+
* updated from within the ISR. Yet, to work around the timer's
64+
* erratum, a new value *must* be written while the interrupt
65+
* is being processed before the interrupt is acknowledged
66+
* by the handling interrupt controller.
67+
*/
68+
arm_arch_timer_set_compare(~0ULL);
69+
}
70+
71+
/*
72+
* Clear the event flag so that in case the erratum strikes (the timer's
73+
* vector will still be indicated as pending by the GIC's pending register
74+
* after this ISR has been executed) the error will be detected by the
75+
* check performed upon entry of the ISR -> the event flag is not set,
76+
* therefore, no actual hardware interrupt has occurred.
77+
*/
78+
arm_arch_timer_clear_int_status();
79+
#else
4280
}
81+
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
4382

4483
k_spin_unlock(&lock, key);
4584

include/arch/arm/aarch32/cortex_a_r/timer.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ extern "C" {
3535
#define TIMER_COMP_ENABLE BIT(1)
3636
#define TIMER_ENABLE BIT(0)
3737

38+
#define TIMER_ISR_EVENT_FLAG BIT(0)
39+
3840
DEVICE_MMIO_TOPLEVEL_STATIC(timer_regs, ARM_TIMER_NODE);
3941

4042
#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)
6365
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
6466
}
6567

68+
#if defined(CONFIG_ARM_ARCH_TIMER_ERRATUM_740657)
69+
70+
/*
71+
* R/W access to the event flag register is required for the timer errata
72+
* 740657 workaround -> comp. ISR implementation in arm_arch_timer.c.
73+
* This functionality is not present in the aarch64 implementation of the
74+
* ARM global timer access functions.
75+
*
76+
* comp. ARM Cortex-A9 processors Software Developers Errata Notice,
77+
* ARM document ID032315.
78+
*/
79+
80+
static ALWAYS_INLINE uint8_t arm_arch_timer_get_int_status(void)
81+
{
82+
return (uint8_t)(sys_read32(TIMER_REG_GET(TIMER_ISR)) & TIMER_ISR_EVENT_FLAG);
83+
}
84+
85+
static ALWAYS_INLINE void arm_arch_timer_clear_int_status(void)
86+
{
87+
sys_write32(TIMER_ISR_EVENT_FLAG, TIMER_REG_GET(TIMER_ISR));
88+
}
89+
90+
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
91+
6692
static ALWAYS_INLINE void arm_arch_timer_enable(bool enable)
6793
{
6894
uint32_t ctrl;

0 commit comments

Comments
 (0)