From 6acc71ccac7187fc0ef85f10bd09c2058f21fab5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 20 Feb 2017 18:34:48 +0000 Subject: arm64: arch_timer: Allows a CPU-specific erratum to only affect a subset of CPUs Instead of applying a CPU-specific workaround to all CPUs in the system, allow it to only affect a subset of them (typical big-little case). This is done by turning the erratum pointer into a per-CPU variable. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/clocksource/arm_arch_timer.c | 42 +++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) (limited to 'drivers/clocksource/arm_arch_timer.c') diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index a0c9ee8..4551587 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -235,7 +235,8 @@ static u64 notrace hisi_161010101_read_cntvct_el0(void) #endif #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND -const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; +DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, + timer_unstable_counter_workaround); EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); @@ -338,9 +339,18 @@ arch_timer_iterate_errata(enum arch_timer_erratum_match_type type, } static -void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa) +void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa, + bool local) { - timer_unstable_counter_workaround = wa; + int i; + + if (local) { + __this_cpu_write(timer_unstable_counter_workaround, wa); + } else { + for_each_possible_cpu(i) + per_cpu(timer_unstable_counter_workaround, i) = wa; + } + static_branch_enable(&arch_timer_read_ool_enabled); } @@ -369,14 +379,17 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t return; if (needs_unstable_timer_counter_workaround()) { - if (wa != timer_unstable_counter_workaround) + const struct arch_timer_erratum_workaround *__wa; + __wa = __this_cpu_read(timer_unstable_counter_workaround); + if (__wa && wa != __wa) pr_warn("Can't enable workaround for %s (clashes with %s\n)", - wa->desc, - timer_unstable_counter_workaround->desc); - return; + wa->desc, __wa->desc); + + if (__wa) + return; } - arch_timer_enable_workaround(wa); + arch_timer_enable_workaround(wa, local); pr_info("Enabling %s workaround for %s\n", local ? "local" : "global", wa->desc); } @@ -384,10 +397,15 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t #define erratum_handler(fn, r, ...) \ ({ \ bool __val; \ - if (needs_unstable_timer_counter_workaround() && \ - timer_unstable_counter_workaround->fn) { \ - r = timer_unstable_counter_workaround->fn(__VA_ARGS__); \ - __val = true; \ + if (needs_unstable_timer_counter_workaround()) { \ + const struct arch_timer_erratum_workaround *__wa; \ + __wa = __this_cpu_read(timer_unstable_counter_workaround); \ + if (__wa && __wa->fn) { \ + r = __wa->fn(__VA_ARGS__); \ + __val = true; \ + } else { \ + __val = false; \ + } \ } else { \ __val = false; \ } \ -- cgit v1.1