Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dccb4531 authored by Cong Zhang's avatar Cong Zhang
Browse files

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: default avatarCong Zhang <congzhan@codeaurora.org>
parent d23aff39
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -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();
	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();
	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 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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";