aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2019-04-08 11:49:04 -0400
committerWill Deacon <will.deacon@arm.com>2019-04-30 11:10:57 -0400
commit5ef19a161cfa88a59508979e2f39d3d092c1d5c0 (patch)
tree2772116c607252e543d024465bba3165caa99435
parentdea86a80033f8b0fb25a805f46dde9f3b1a7c23a (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.h4
-rw-r--r--arch/arm64/include/asm/arch_timer.h16
-rw-r--r--drivers/clocksource/arm_arch_timer.c46
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
14int arch_timer_arch_init(void); 18int 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
34extern struct static_key_false arch_timer_read_ool_enabled; 48extern 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
619static bool arch_timer_this_cpu_has_cntvct_wa(void) 601static 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,
721static int arch_timer_set_next_event_virt(unsigned long evt, 697static 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,
733static int arch_timer_set_next_event_phys(unsigned long evt, 704static 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";