arch_timer: add workaround for arm erratum 858921

If CNTVCT or CNTPCT are read while they are updated with the lower
32bits rolled-over, it is possible to read a wrong value(both AArch32 or
AArch64). So if the low 32 bits are set, we need to reread the counter.

Change-Id: Ifd9720c8ff6d0622610b8f53d029635b3130280a
Signed-off-by: Cong Zhang <congzhan@codeaurora.org>
This commit is contained in:
Cong Zhang committed 2020-03-18 19:08:12 +08:00
1 parent d23aff3968
commit dccb453157
3 files changed
+60 -2

No files matched your search

+29 -2
View File
@@ -11,6 +11,20 @@
#include <clocksource/arm_arch_timer.h>
#ifdef CONFIG_ARM_ARCH_TIMER
#ifdef CONFIG_ARM_ERRATUM_858921
DECLARE_PER_CPU(bool, timer_erratum_858921_workaround_enabled);
static __always_inline bool erratum_858921_workaround_enabled(void)
{
return this_cpu_read(timer_erratum_858921_workaround_enabled);
}
#else
static __always_inline bool erratum_858921_workaround_enabled(void)
{
return false;
}
#endif
int arch_timer_arch_init(void);
/*
@@ -79,12 +93,19 @@ static inline u32 arch_timer_get_cntfrq(void)
return val;
}
#define L32_BITS 0x00000000FFFFFFFF
static inline u64 arch_counter_get_cntpct(void)
{
u64 cval;
isb();
asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
if (erratum_858921_workaround_enabled()) {
do {
asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r"(cval));
} while ((cval & L32_BITS) == L32_BITS);
} else {
asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
}
return cval;
}
@@ -93,7 +114,13 @@ static inline u64 arch_counter_get_cntvct(void)
u64 cval;
isb();
asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
if (erratum_858921_workaround_enabled()) {
do {
asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r"(cval));
} while ((cval & L32_BITS) == L32_BITS);
} else {
asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
}
return cval;
}
+10
View File
@@ -366,6 +366,16 @@ config ARM64_ERRATUM_858921
The workaround will be dynamically enabled when an affected
core is detected.
config ARM_ERRATUM_858921
bool "Workaround for Cortex-A73(AArch32) erratum 858921"
default y
depends on ARM_ARCH_TIMER && ARM
help
This option enables a workaround applicable to AArch32 Cortex-A73
(all versions), whose counter may return incorrect values.
The workaround will be dynamically enabled when an affected
core is detected.
config SUN50I_ERRATUM_UNKNOWN1
bool "Workaround for Allwinner A64 erratum UNKNOWN1"
default y
+21
View File
@@ -31,6 +31,7 @@
#include <asm/arch_timer.h>
#include <asm/traps.h>
#include <asm/virt.h>
#include <asm/cputype.h>
#include <clocksource/arm_arch_timer.h>
@@ -193,6 +194,25 @@ struct ate_acpi_oem_info {
u32 oem_revision;
};
#ifdef CONFIG_ARM_ERRATUM_858921
DEFINE_PER_CPU(bool, timer_erratum_858921_workaround_enabled);
EXPORT_PER_CPU_SYMBOL(timer_erratum_858921_workaround_enabled);
static void arch_timer_check_858921_workaround(void)
{
unsigned int cpuid_part;
cpuid_part = read_cpuid_part();
if (cpuid_part == ARM_CPU_PART_CORTEX_A73 ||
cpuid_part == QCOM_CPU_PART_KRYO2XX_GOLD) {
this_cpu_write(timer_erratum_858921_workaround_enabled, true);
} else {
this_cpu_write(timer_erratum_858921_workaround_enabled, false);
}
}
#else
#define arch_timer_check_858921_workaround() do { } while (0)
#endif
#ifdef CONFIG_FSL_ERRATUM_A008585
/*
* The number of retries is an arbitrary value well beyond the highest number
@@ -803,6 +823,7 @@ static void __arch_timer_setup(unsigned type,
}
arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL);
arch_timer_check_858921_workaround();
} else {
clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
clk->name = "arch_mem_timer";