diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2017-03-20 12:47:59 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2017-04-07 06:22:08 -0400 |
commit | 0064030c6fd4ca6cfab42de037b2a89445beeead (patch) | |
tree | 154c9a14ca011eb838fc34adcf6492ad9a322466 /drivers/clocksource | |
parent | 651bb2e9dca6e6dbad3fba5f6e6086a23575b8b5 (diff) |
arm64: arch_timer: Add erratum handler for CPU-specific capability
Should we ever have a workaround for an erratum that is detected using
a capability and affecting a particular CPU, it'd be nice to have
a way to probe them directly.
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5c5c2af74ad9..532e47fa43b3 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -214,6 +214,13 @@ bool arch_timer_check_dt_erratum(const struct arch_timer_erratum_workaround *wa, | |||
214 | return of_property_read_bool(np, wa->id); | 214 | return of_property_read_bool(np, wa->id); |
215 | } | 215 | } |
216 | 216 | ||
217 | static | ||
218 | bool arch_timer_check_local_cap_erratum(const struct arch_timer_erratum_workaround *wa, | ||
219 | const void *arg) | ||
220 | { | ||
221 | return this_cpu_has_cap((uintptr_t)wa->id); | ||
222 | } | ||
223 | |||
217 | static const struct arch_timer_erratum_workaround * | 224 | static const struct arch_timer_erratum_workaround * |
218 | arch_timer_iterate_errata(enum arch_timer_erratum_match_type type, | 225 | arch_timer_iterate_errata(enum arch_timer_erratum_match_type type, |
219 | ate_match_fn_t match_fn, | 226 | ate_match_fn_t match_fn, |
@@ -244,14 +251,16 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t | |||
244 | { | 251 | { |
245 | const struct arch_timer_erratum_workaround *wa; | 252 | const struct arch_timer_erratum_workaround *wa; |
246 | ate_match_fn_t match_fn = NULL; | 253 | ate_match_fn_t match_fn = NULL; |
247 | 254 | bool local = false; | |
248 | if (static_branch_unlikely(&arch_timer_read_ool_enabled)) | ||
249 | return; | ||
250 | 255 | ||
251 | switch (type) { | 256 | switch (type) { |
252 | case ate_match_dt: | 257 | case ate_match_dt: |
253 | match_fn = arch_timer_check_dt_erratum; | 258 | match_fn = arch_timer_check_dt_erratum; |
254 | break; | 259 | break; |
260 | case ate_match_local_cap_id: | ||
261 | match_fn = arch_timer_check_local_cap_erratum; | ||
262 | local = true; | ||
263 | break; | ||
255 | default: | 264 | default: |
256 | WARN_ON(1); | 265 | WARN_ON(1); |
257 | return; | 266 | return; |
@@ -261,8 +270,17 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t | |||
261 | if (!wa) | 270 | if (!wa) |
262 | return; | 271 | return; |
263 | 272 | ||
273 | if (needs_unstable_timer_counter_workaround()) { | ||
274 | if (wa != timer_unstable_counter_workaround) | ||
275 | pr_warn("Can't enable workaround for %s (clashes with %s\n)", | ||
276 | wa->desc, | ||
277 | timer_unstable_counter_workaround->desc); | ||
278 | return; | ||
279 | } | ||
280 | |||
264 | arch_timer_enable_workaround(wa); | 281 | arch_timer_enable_workaround(wa); |
265 | pr_info("Enabling global workaround for %s\n", wa->desc); | 282 | pr_info("Enabling %s workaround for %s\n", |
283 | local ? "local" : "global", wa->desc); | ||
266 | } | 284 | } |
267 | 285 | ||
268 | #else | 286 | #else |
@@ -522,6 +540,8 @@ static void __arch_timer_setup(unsigned type, | |||
522 | BUG(); | 540 | BUG(); |
523 | } | 541 | } |
524 | 542 | ||
543 | arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); | ||
544 | |||
525 | erratum_workaround_set_sne(clk); | 545 | erratum_workaround_set_sne(clk); |
526 | } else { | 546 | } else { |
527 | clk->features |= CLOCK_EVT_FEAT_DYNIRQ; | 547 | clk->features |= CLOCK_EVT_FEAT_DYNIRQ; |