diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2017-02-20 13:34:48 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2017-04-07 06:22:09 -0400 |
commit | 6acc71ccac7187fc0ef85f10bd09c2058f21fab5 (patch) | |
tree | fa55e6e16bdd8b41537ba1d27abefb2c1b2a96ee /drivers/clocksource/arm_arch_timer.c | |
parent | 8c64621bf9501902a3086a5e38135344b3161128 (diff) |
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 <tglx@linutronix.de>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index a0c9ee80147e..4551587bcb44 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) | |||
235 | #endif | 235 | #endif |
236 | 236 | ||
237 | #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND | 237 | #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND |
238 | const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; | 238 | DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, |
239 | timer_unstable_counter_workaround); | ||
239 | EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); | 240 | EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); |
240 | 241 | ||
241 | DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); | 242 | DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); |
@@ -338,9 +339,18 @@ arch_timer_iterate_errata(enum arch_timer_erratum_match_type type, | |||
338 | } | 339 | } |
339 | 340 | ||
340 | static | 341 | static |
341 | void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa) | 342 | void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa, |
343 | bool local) | ||
342 | { | 344 | { |
343 | timer_unstable_counter_workaround = wa; | 345 | int i; |
346 | |||
347 | if (local) { | ||
348 | __this_cpu_write(timer_unstable_counter_workaround, wa); | ||
349 | } else { | ||
350 | for_each_possible_cpu(i) | ||
351 | per_cpu(timer_unstable_counter_workaround, i) = wa; | ||
352 | } | ||
353 | |||
344 | static_branch_enable(&arch_timer_read_ool_enabled); | 354 | static_branch_enable(&arch_timer_read_ool_enabled); |
345 | } | 355 | } |
346 | 356 | ||
@@ -369,14 +379,17 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t | |||
369 | return; | 379 | return; |
370 | 380 | ||
371 | if (needs_unstable_timer_counter_workaround()) { | 381 | if (needs_unstable_timer_counter_workaround()) { |
372 | if (wa != timer_unstable_counter_workaround) | 382 | const struct arch_timer_erratum_workaround *__wa; |
383 | __wa = __this_cpu_read(timer_unstable_counter_workaround); | ||
384 | if (__wa && wa != __wa) | ||
373 | pr_warn("Can't enable workaround for %s (clashes with %s\n)", | 385 | pr_warn("Can't enable workaround for %s (clashes with %s\n)", |
374 | wa->desc, | 386 | wa->desc, __wa->desc); |
375 | timer_unstable_counter_workaround->desc); | 387 | |
376 | return; | 388 | if (__wa) |
389 | return; | ||
377 | } | 390 | } |
378 | 391 | ||
379 | arch_timer_enable_workaround(wa); | 392 | arch_timer_enable_workaround(wa, local); |
380 | pr_info("Enabling %s workaround for %s\n", | 393 | pr_info("Enabling %s workaround for %s\n", |
381 | local ? "local" : "global", wa->desc); | 394 | local ? "local" : "global", wa->desc); |
382 | } | 395 | } |
@@ -384,10 +397,15 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t | |||
384 | #define erratum_handler(fn, r, ...) \ | 397 | #define erratum_handler(fn, r, ...) \ |
385 | ({ \ | 398 | ({ \ |
386 | bool __val; \ | 399 | bool __val; \ |
387 | if (needs_unstable_timer_counter_workaround() && \ | 400 | if (needs_unstable_timer_counter_workaround()) { \ |
388 | timer_unstable_counter_workaround->fn) { \ | 401 | const struct arch_timer_erratum_workaround *__wa; \ |
389 | r = timer_unstable_counter_workaround->fn(__VA_ARGS__); \ | 402 | __wa = __this_cpu_read(timer_unstable_counter_workaround); \ |
390 | __val = true; \ | 403 | if (__wa && __wa->fn) { \ |
404 | r = __wa->fn(__VA_ARGS__); \ | ||
405 | __val = true; \ | ||
406 | } else { \ | ||
407 | __val = false; \ | ||
408 | } \ | ||
391 | } else { \ | 409 | } else { \ |
392 | __val = false; \ | 410 | __val = false; \ |
393 | } \ | 411 | } \ |