aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/arm_arch_timer.c
diff options
context:
space:
mode:
authorDing Tianhong <dingtianhong@huawei.com>2017-02-06 11:47:41 -0500
committerDaniel Lezcano <daniel.lezcano@linaro.org>2017-02-07 18:14:03 -0500
commit16d10ef29f25aba923779234bb93a451b14d20e6 (patch)
tree3bec3cde9fcf0bd8e0d9a8940ef29ee9b49aeb18 /drivers/clocksource/arm_arch_timer.c
parent5444ea6a7f46276876e94ecf8d44615af1ef22f7 (diff)
clocksource/drivers/arm_arch_timer: Introduce generic errata handling infrastructure
Currently we have code inline in the arch timer probe path to cater for Freescale erratum A-008585, complete with ifdeffery. This is a little ugly, and will get worse as we try to add more errata handling. This patch refactors the handling of Freescale erratum A-008585. Now the erratum is described in a generic arch_timer_erratum_workaround structure, and the probe path can iterate over these to detect errata and enable workarounds. This will simplify the addition and maintenance of code handling Hisilicon erratum 161010101. Signed-off-by: Ding Tianhong <dingtianhong@huawei.com> [Mark: split patch, correct Kconfig, reword commit message] Signed-off-by: Mark Rutland <mark.rutland@arm.com> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r--drivers/clocksource/arm_arch_timer.c92
1 files changed, 63 insertions, 29 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 6a9d031c3535..2af0739efd41 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -96,27 +96,58 @@ early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
96 */ 96 */
97 97
98#ifdef CONFIG_FSL_ERRATUM_A008585 98#ifdef CONFIG_FSL_ERRATUM_A008585
99DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); 99/*
100EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled); 100 * The number of retries is an arbitrary value well beyond the highest number
101 101 * of iterations the loop has been observed to take.
102static int fsl_a008585_enable = -1; 102 */
103 103#define __fsl_a008585_read_reg(reg) ({ \
104u32 __fsl_a008585_read_cntp_tval_el0(void) 104 u64 _old, _new; \
105 int _retries = 200; \
106 \
107 do { \
108 _old = read_sysreg(reg); \
109 _new = read_sysreg(reg); \
110 _retries--; \
111 } while (unlikely(_old != _new) && _retries); \
112 \
113 WARN_ON_ONCE(!_retries); \
114 _new; \
115})
116
117static u32 notrace fsl_a008585_read_cntp_tval_el0(void)
105{ 118{
106 return __fsl_a008585_read_reg(cntp_tval_el0); 119 return __fsl_a008585_read_reg(cntp_tval_el0);
107} 120}
108 121
109u32 __fsl_a008585_read_cntv_tval_el0(void) 122static u32 notrace fsl_a008585_read_cntv_tval_el0(void)
110{ 123{
111 return __fsl_a008585_read_reg(cntv_tval_el0); 124 return __fsl_a008585_read_reg(cntv_tval_el0);
112} 125}
113 126
114u64 __fsl_a008585_read_cntvct_el0(void) 127static u64 notrace fsl_a008585_read_cntvct_el0(void)
115{ 128{
116 return __fsl_a008585_read_reg(cntvct_el0); 129 return __fsl_a008585_read_reg(cntvct_el0);
117} 130}
118EXPORT_SYMBOL(__fsl_a008585_read_cntvct_el0); 131#endif
119#endif /* CONFIG_FSL_ERRATUM_A008585 */ 132
133#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
134const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL;
135EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
136
137DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
138EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
139
140static const struct arch_timer_erratum_workaround ool_workarounds[] = {
141#ifdef CONFIG_FSL_ERRATUM_A008585
142 {
143 .id = "fsl,erratum-a008585",
144 .read_cntp_tval_el0 = fsl_a008585_read_cntp_tval_el0,
145 .read_cntv_tval_el0 = fsl_a008585_read_cntv_tval_el0,
146 .read_cntvct_el0 = fsl_a008585_read_cntvct_el0,
147 },
148#endif
149};
150#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */
120 151
121static __always_inline 152static __always_inline
122void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, 153void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val,
@@ -267,8 +298,8 @@ static __always_inline void set_next_event(const int access, unsigned long evt,
267 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 298 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
268} 299}
269 300
270#ifdef CONFIG_FSL_ERRATUM_A008585 301#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
271static __always_inline void fsl_a008585_set_next_event(const int access, 302static __always_inline void erratum_set_next_event_generic(const int access,
272 unsigned long evt, struct clock_event_device *clk) 303 unsigned long evt, struct clock_event_device *clk)
273{ 304{
274 unsigned long ctrl; 305 unsigned long ctrl;
@@ -286,20 +317,20 @@ static __always_inline void fsl_a008585_set_next_event(const int access,
286 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 317 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
287} 318}
288 319
289static int fsl_a008585_set_next_event_virt(unsigned long evt, 320static int erratum_set_next_event_virt(unsigned long evt,
290 struct clock_event_device *clk) 321 struct clock_event_device *clk)
291{ 322{
292 fsl_a008585_set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); 323 erratum_set_next_event_generic(ARCH_TIMER_VIRT_ACCESS, evt, clk);
293 return 0; 324 return 0;
294} 325}
295 326
296static int fsl_a008585_set_next_event_phys(unsigned long evt, 327static int erratum_set_next_event_phys(unsigned long evt,
297 struct clock_event_device *clk) 328 struct clock_event_device *clk)
298{ 329{
299 fsl_a008585_set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); 330 erratum_set_next_event_generic(ARCH_TIMER_PHYS_ACCESS, evt, clk);
300 return 0; 331 return 0;
301} 332}
302#endif /* CONFIG_FSL_ERRATUM_A008585 */ 333#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */
303 334
304static int arch_timer_set_next_event_virt(unsigned long evt, 335static int arch_timer_set_next_event_virt(unsigned long evt,
305 struct clock_event_device *clk) 336 struct clock_event_device *clk)
@@ -329,16 +360,16 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt,
329 return 0; 360 return 0;
330} 361}
331 362
332static void fsl_a008585_set_sne(struct clock_event_device *clk) 363static void erratum_workaround_set_sne(struct clock_event_device *clk)
333{ 364{
334#ifdef CONFIG_FSL_ERRATUM_A008585 365#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
335 if (!static_branch_unlikely(&arch_timer_read_ool_enabled)) 366 if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
336 return; 367 return;
337 368
338 if (arch_timer_uses_ppi == VIRT_PPI) 369 if (arch_timer_uses_ppi == VIRT_PPI)
339 clk->set_next_event = fsl_a008585_set_next_event_virt; 370 clk->set_next_event = erratum_set_next_event_virt;
340 else 371 else
341 clk->set_next_event = fsl_a008585_set_next_event_phys; 372 clk->set_next_event = erratum_set_next_event_phys;
342#endif 373#endif
343} 374}
344 375
@@ -371,7 +402,7 @@ static void __arch_timer_setup(unsigned type,
371 BUG(); 402 BUG();
372 } 403 }
373 404
374 fsl_a008585_set_sne(clk); 405 erratum_workaround_set_sne(clk);
375 } else { 406 } else {
376 clk->features |= CLOCK_EVT_FEAT_DYNIRQ; 407 clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
377 clk->name = "arch_mem_timer"; 408 clk->name = "arch_mem_timer";
@@ -591,7 +622,7 @@ static void __init arch_counter_register(unsigned type)
591 622
592 clocksource_counter.archdata.vdso_direct = true; 623 clocksource_counter.archdata.vdso_direct = true;
593 624
594#ifdef CONFIG_FSL_ERRATUM_A008585 625#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
595 /* 626 /*
596 * Don't use the vdso fastpath if errata require using 627 * Don't use the vdso fastpath if errata require using
597 * the out-of-line counter accessor. 628 * the out-of-line counter accessor.
@@ -879,12 +910,15 @@ static int __init arch_timer_of_init(struct device_node *np)
879 910
880 arch_timer_c3stop = !of_property_read_bool(np, "always-on"); 911 arch_timer_c3stop = !of_property_read_bool(np, "always-on");
881 912
882#ifdef CONFIG_FSL_ERRATUM_A008585 913#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
883 if (fsl_a008585_enable < 0) 914 for (i = 0; i < ARRAY_SIZE(ool_workarounds); i++) {
884 fsl_a008585_enable = of_property_read_bool(np, "fsl,erratum-a008585"); 915 if (of_property_read_bool(np, ool_workarounds[i].id)) {
885 if (fsl_a008585_enable) { 916 timer_unstable_counter_workaround = &ool_workarounds[i];
886 static_branch_enable(&arch_timer_read_ool_enabled); 917 static_branch_enable(&arch_timer_read_ool_enabled);
887 pr_info("Enabling workaround for FSL erratum A-008585\n"); 918 pr_info("arch_timer: Enabling workaround for %s\n",
919 timer_unstable_counter_workaround->id);
920 break;
921 }
888 } 922 }
889#endif 923#endif
890 924