aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/arch_timer.h31
-rw-r--r--drivers/clocksource/arm_arch_timer.c42
2 files changed, 50 insertions, 23 deletions
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index 01917b4c65ca..6bd1a9a1573a 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -25,6 +25,7 @@
25#include <linux/bug.h> 25#include <linux/bug.h>
26#include <linux/init.h> 26#include <linux/init.h>
27#include <linux/jump_label.h> 27#include <linux/jump_label.h>
28#include <linux/smp.h>
28#include <linux/types.h> 29#include <linux/types.h>
29 30
30#include <clocksource/arm_arch_timer.h> 31#include <clocksource/arm_arch_timer.h>
@@ -55,17 +56,25 @@ struct arch_timer_erratum_workaround {
55 int (*set_next_event_virt)(unsigned long, struct clock_event_device *); 56 int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
56}; 57};
57 58
58extern const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround; 59DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
59 60 timer_unstable_counter_workaround);
60#define arch_timer_reg_read_stable(reg) \ 61
61({ \ 62#define arch_timer_reg_read_stable(reg) \
62 u64 _val; \ 63({ \
63 if (needs_unstable_timer_counter_workaround() && \ 64 u64 _val; \
64 timer_unstable_counter_workaround->read_##reg) \ 65 if (needs_unstable_timer_counter_workaround()) { \
65 _val = timer_unstable_counter_workaround->read_##reg(); \ 66 const struct arch_timer_erratum_workaround *wa; \
66 else \ 67 preempt_disable(); \
67 _val = read_sysreg(reg); \ 68 wa = __this_cpu_read(timer_unstable_counter_workaround); \
68 _val; \ 69 if (wa && wa->read_##reg) \
70 _val = wa->read_##reg(); \
71 else \
72 _val = read_sysreg(reg); \
73 preempt_enable(); \
74 } else { \
75 _val = read_sysreg(reg); \
76 } \
77 _val; \
69}) 78})
70 79
71/* 80/*
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
238const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; 238DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *,
239 timer_unstable_counter_workaround);
239EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); 240EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
240 241
241DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); 242DEFINE_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
340static 341static
341void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa) 342void 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 } \