diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2019-04-08 11:49:04 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2019-04-30 11:10:57 -0400 |
commit | 5ef19a161cfa88a59508979e2f39d3d092c1d5c0 (patch) | |
tree | 2772116c607252e543d024465bba3165caa99435 | |
parent | dea86a80033f8b0fb25a805f46dde9f3b1a7c23a (diff) |
clocksource/arm_arch_timer: Direcly assign set_next_event workaround
When a given timer is affected by an erratum and requires an
alternative implementation of set_next_event, we do a rather
complicated dance to detect and call the workaround on each
set_next_event call.
This is clearly idiotic, as we can perfectly detect whether
this CPU requires a workaround while setting up the clock event
device.
This only requires the CPU-specific detection to be done a bit
earlier, and we can then safely override the set_next_event pointer
if we have a workaround associated to that CPU.
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by; Daniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm/include/asm/arch_timer.h | 4 | ||||
-rw-r--r-- | arch/arm64/include/asm/arch_timer.h | 16 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 46 |
3 files changed, 28 insertions, 38 deletions
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 0a8d7bba2cb0..3f0a0191f763 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h | |||
@@ -11,6 +11,10 @@ | |||
11 | #include <clocksource/arm_arch_timer.h> | 11 | #include <clocksource/arm_arch_timer.h> |
12 | 12 | ||
13 | #ifdef CONFIG_ARM_ARCH_TIMER | 13 | #ifdef CONFIG_ARM_ARCH_TIMER |
14 | /* 32bit ARM doesn't know anything about timer errata... */ | ||
15 | #define has_erratum_handler(h) (false) | ||
16 | #define erratum_handler(h) (arch_timer_##h) | ||
17 | |||
14 | int arch_timer_arch_init(void); | 18 | int arch_timer_arch_init(void); |
15 | 19 | ||
16 | /* | 20 | /* |
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index f2a234d6516c..c3762ffcc933 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h | |||
@@ -31,10 +31,26 @@ | |||
31 | #include <clocksource/arm_arch_timer.h> | 31 | #include <clocksource/arm_arch_timer.h> |
32 | 32 | ||
33 | #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND) | 33 | #if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND) |
34 | #define has_erratum_handler(h) \ | ||
35 | ({ \ | ||
36 | const struct arch_timer_erratum_workaround *__wa; \ | ||
37 | __wa = __this_cpu_read(timer_unstable_counter_workaround); \ | ||
38 | (__wa && __wa->h); \ | ||
39 | }) | ||
40 | |||
41 | #define erratum_handler(h) \ | ||
42 | ({ \ | ||
43 | const struct arch_timer_erratum_workaround *__wa; \ | ||
44 | __wa = __this_cpu_read(timer_unstable_counter_workaround); \ | ||
45 | (__wa && __wa->h) ? __wa->h : arch_timer_##h; \ | ||
46 | }) | ||
47 | |||
34 | extern struct static_key_false arch_timer_read_ool_enabled; | 48 | extern struct static_key_false arch_timer_read_ool_enabled; |
35 | #define needs_unstable_timer_counter_workaround() \ | 49 | #define needs_unstable_timer_counter_workaround() \ |
36 | static_branch_unlikely(&arch_timer_read_ool_enabled) | 50 | static_branch_unlikely(&arch_timer_read_ool_enabled) |
37 | #else | 51 | #else |
52 | #define has_erratum_handler(h) false | ||
53 | #define erratum_handler(h) (arch_timer_##h) | ||
38 | #define needs_unstable_timer_counter_workaround() false | 54 | #define needs_unstable_timer_counter_workaround() false |
39 | #endif | 55 | #endif |
40 | 56 | ||
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index da11a9508b77..b2a88a64aab4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -598,36 +598,12 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t | |||
598 | local ? "local" : "global", wa->desc); | 598 | local ? "local" : "global", wa->desc); |
599 | } | 599 | } |
600 | 600 | ||
601 | #define erratum_handler(fn, r, ...) \ | ||
602 | ({ \ | ||
603 | bool __val; \ | ||
604 | if (needs_unstable_timer_counter_workaround()) { \ | ||
605 | const struct arch_timer_erratum_workaround *__wa; \ | ||
606 | __wa = __this_cpu_read(timer_unstable_counter_workaround); \ | ||
607 | if (__wa && __wa->fn) { \ | ||
608 | r = __wa->fn(__VA_ARGS__); \ | ||
609 | __val = true; \ | ||
610 | } else { \ | ||
611 | __val = false; \ | ||
612 | } \ | ||
613 | } else { \ | ||
614 | __val = false; \ | ||
615 | } \ | ||
616 | __val; \ | ||
617 | }) | ||
618 | |||
619 | static bool arch_timer_this_cpu_has_cntvct_wa(void) | 601 | static bool arch_timer_this_cpu_has_cntvct_wa(void) |
620 | { | 602 | { |
621 | const struct arch_timer_erratum_workaround *wa; | 603 | return has_erratum_handler(read_cntvct_el0); |
622 | |||
623 | wa = __this_cpu_read(timer_unstable_counter_workaround); | ||
624 | return wa && wa->read_cntvct_el0; | ||
625 | } | 604 | } |
626 | #else | 605 | #else |
627 | #define arch_timer_check_ool_workaround(t,a) do { } while(0) | 606 | #define arch_timer_check_ool_workaround(t,a) do { } while(0) |
628 | #define erratum_set_next_event_tval_virt(...) ({BUG(); 0;}) | ||
629 | #define erratum_set_next_event_tval_phys(...) ({BUG(); 0;}) | ||
630 | #define erratum_handler(fn, r, ...) ({false;}) | ||
631 | #define arch_timer_this_cpu_has_cntvct_wa() ({false;}) | 607 | #define arch_timer_this_cpu_has_cntvct_wa() ({false;}) |
632 | #endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ | 608 | #endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ |
633 | 609 | ||
@@ -721,11 +697,6 @@ static __always_inline void set_next_event(const int access, unsigned long evt, | |||
721 | static int arch_timer_set_next_event_virt(unsigned long evt, | 697 | static int arch_timer_set_next_event_virt(unsigned long evt, |
722 | struct clock_event_device *clk) | 698 | struct clock_event_device *clk) |
723 | { | 699 | { |
724 | int ret; | ||
725 | |||
726 | if (erratum_handler(set_next_event_virt, ret, evt, clk)) | ||
727 | return ret; | ||
728 | |||
729 | set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); | 700 | set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); |
730 | return 0; | 701 | return 0; |
731 | } | 702 | } |
@@ -733,11 +704,6 @@ static int arch_timer_set_next_event_virt(unsigned long evt, | |||
733 | static int arch_timer_set_next_event_phys(unsigned long evt, | 704 | static int arch_timer_set_next_event_phys(unsigned long evt, |
734 | struct clock_event_device *clk) | 705 | struct clock_event_device *clk) |
735 | { | 706 | { |
736 | int ret; | ||
737 | |||
738 | if (erratum_handler(set_next_event_phys, ret, evt, clk)) | ||
739 | return ret; | ||
740 | |||
741 | set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); | 707 | set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); |
742 | return 0; | 708 | return 0; |
743 | } | 709 | } |
@@ -762,6 +728,10 @@ static void __arch_timer_setup(unsigned type, | |||
762 | clk->features = CLOCK_EVT_FEAT_ONESHOT; | 728 | clk->features = CLOCK_EVT_FEAT_ONESHOT; |
763 | 729 | ||
764 | if (type == ARCH_TIMER_TYPE_CP15) { | 730 | if (type == ARCH_TIMER_TYPE_CP15) { |
731 | typeof(clk->set_next_event) sne; | ||
732 | |||
733 | arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); | ||
734 | |||
765 | if (arch_timer_c3stop) | 735 | if (arch_timer_c3stop) |
766 | clk->features |= CLOCK_EVT_FEAT_C3STOP; | 736 | clk->features |= CLOCK_EVT_FEAT_C3STOP; |
767 | clk->name = "arch_sys_timer"; | 737 | clk->name = "arch_sys_timer"; |
@@ -772,20 +742,20 @@ static void __arch_timer_setup(unsigned type, | |||
772 | case ARCH_TIMER_VIRT_PPI: | 742 | case ARCH_TIMER_VIRT_PPI: |
773 | clk->set_state_shutdown = arch_timer_shutdown_virt; | 743 | clk->set_state_shutdown = arch_timer_shutdown_virt; |
774 | clk->set_state_oneshot_stopped = arch_timer_shutdown_virt; | 744 | clk->set_state_oneshot_stopped = arch_timer_shutdown_virt; |
775 | clk->set_next_event = arch_timer_set_next_event_virt; | 745 | sne = erratum_handler(set_next_event_virt); |
776 | break; | 746 | break; |
777 | case ARCH_TIMER_PHYS_SECURE_PPI: | 747 | case ARCH_TIMER_PHYS_SECURE_PPI: |
778 | case ARCH_TIMER_PHYS_NONSECURE_PPI: | 748 | case ARCH_TIMER_PHYS_NONSECURE_PPI: |
779 | case ARCH_TIMER_HYP_PPI: | 749 | case ARCH_TIMER_HYP_PPI: |
780 | clk->set_state_shutdown = arch_timer_shutdown_phys; | 750 | clk->set_state_shutdown = arch_timer_shutdown_phys; |
781 | clk->set_state_oneshot_stopped = arch_timer_shutdown_phys; | 751 | clk->set_state_oneshot_stopped = arch_timer_shutdown_phys; |
782 | clk->set_next_event = arch_timer_set_next_event_phys; | 752 | sne = erratum_handler(set_next_event_phys); |
783 | break; | 753 | break; |
784 | default: | 754 | default: |
785 | BUG(); | 755 | BUG(); |
786 | } | 756 | } |
787 | 757 | ||
788 | arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); | 758 | clk->set_next_event = sne; |
789 | } else { | 759 | } else { |
790 | clk->features |= CLOCK_EVT_FEAT_DYNIRQ; | 760 | clk->features |= CLOCK_EVT_FEAT_DYNIRQ; |
791 | clk->name = "arch_mem_timer"; | 761 | clk->name = "arch_mem_timer"; |