summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorScott Wood <oss@buserror.net>2016-09-22 04:35:17 -0400
committerWill Deacon <will.deacon@arm.com>2016-09-23 12:19:25 -0400
commitf6dc1576cd517440313c9551b6ffa3d7e389c7c7 (patch)
treeb8b7e96634c2df9b8de85b5bb80923c2b6aeae97 /drivers
parent22e43390456152f6e72ad2632e2b3fb363e94146 (diff)
arm64: arch_timer: Work around QorIQ Erratum A-008585
Erratum A-008585 says that the ARM generic timer counter "has the potential to contain an erroneous value for a small number of core clock cycles every time the timer value changes". Accesses to TVAL (both read and write) are also affected due to the implicit counter read. Accesses to CVAL are not affected. The workaround is to reread TVAL and count registers until successive reads return the same value. Writes to TVAL are replaced with an equivalent write to CVAL. The workaround is to reread TVAL and count registers until successive reads return the same value, and when writing TVAL to retry until counter reads before and after the write return the same value. The workaround is enabled if the fsl,erratum-a008585 property is found in the timer node in the device tree. This can be overridden with the clocksource.arm_arch_timer.fsl-a008585 boot parameter, which allows KVM users to enable the workaround until a mechanism is implemented to automatically communicate this information. This erratum can be found on LS1043A and LS2080A. Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Scott Wood <oss@buserror.net> [will: renamed read macro to reflect that it's not usually unstable] Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clocksource/Kconfig10
-rw-r--r--drivers/clocksource/arm_arch_timer.c104
2 files changed, 114 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 567788664723..8a753fd5b79d 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -305,6 +305,16 @@ config ARM_ARCH_TIMER_EVTSTREAM
305 This must be disabled for hardware validation purposes to detect any 305 This must be disabled for hardware validation purposes to detect any
306 hardware anomalies of missing events. 306 hardware anomalies of missing events.
307 307
308config FSL_ERRATUM_A008585
309 bool "Workaround for Freescale/NXP Erratum A-008585"
310 default y
311 depends on ARM_ARCH_TIMER && ARM64
312 help
313 This option enables a workaround for Freescale/NXP Erratum
314 A-008585 ("ARM generic timer may contain an erroneous
315 value"). The workaround will only be active if the
316 fsl,erratum-a008585 property is found in the timer node.
317
308config ARM_GLOBAL_TIMER 318config ARM_GLOBAL_TIMER
309 bool "Support for the ARM global timer" if COMPILE_TEST 319 bool "Support for the ARM global timer" if COMPILE_TEST
310 select CLKSRC_OF if OF 320 select CLKSRC_OF if OF
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 57700541f951..eb5fb4121ac8 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -94,6 +94,43 @@ early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
94 * Architected system timer support. 94 * Architected system timer support.
95 */ 95 */
96 96
97#ifdef CONFIG_FSL_ERRATUM_A008585
98DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
99EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
100
101static int fsl_a008585_enable = -1;
102
103static int __init early_fsl_a008585_cfg(char *buf)
104{
105 int ret;
106 bool val;
107
108 ret = strtobool(buf, &val);
109 if (ret)
110 return ret;
111
112 fsl_a008585_enable = val;
113 return 0;
114}
115early_param("clocksource.arm_arch_timer.fsl-a008585", early_fsl_a008585_cfg);
116
117u32 __fsl_a008585_read_cntp_tval_el0(void)
118{
119 return __fsl_a008585_read_reg(cntp_tval_el0);
120}
121
122u32 __fsl_a008585_read_cntv_tval_el0(void)
123{
124 return __fsl_a008585_read_reg(cntv_tval_el0);
125}
126
127u64 __fsl_a008585_read_cntvct_el0(void)
128{
129 return __fsl_a008585_read_reg(cntvct_el0);
130}
131EXPORT_SYMBOL(__fsl_a008585_read_cntvct_el0);
132#endif /* CONFIG_FSL_ERRATUM_A008585 */
133
97static __always_inline 134static __always_inline
98void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, 135void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val,
99 struct clock_event_device *clk) 136 struct clock_event_device *clk)
@@ -243,6 +280,40 @@ static __always_inline void set_next_event(const int access, unsigned long evt,
243 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); 280 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
244} 281}
245 282
283#ifdef CONFIG_FSL_ERRATUM_A008585
284static __always_inline void fsl_a008585_set_next_event(const int access,
285 unsigned long evt, struct clock_event_device *clk)
286{
287 unsigned long ctrl;
288 u64 cval = evt + arch_counter_get_cntvct();
289
290 ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk);
291 ctrl |= ARCH_TIMER_CTRL_ENABLE;
292 ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
293
294 if (access == ARCH_TIMER_PHYS_ACCESS)
295 write_sysreg(cval, cntp_cval_el0);
296 else if (access == ARCH_TIMER_VIRT_ACCESS)
297 write_sysreg(cval, cntv_cval_el0);
298
299 arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
300}
301
302static int fsl_a008585_set_next_event_virt(unsigned long evt,
303 struct clock_event_device *clk)
304{
305 fsl_a008585_set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk);
306 return 0;
307}
308
309static int fsl_a008585_set_next_event_phys(unsigned long evt,
310 struct clock_event_device *clk)
311{
312 fsl_a008585_set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk);
313 return 0;
314}
315#endif /* CONFIG_FSL_ERRATUM_A008585 */
316
246static int arch_timer_set_next_event_virt(unsigned long evt, 317static int arch_timer_set_next_event_virt(unsigned long evt,
247 struct clock_event_device *clk) 318 struct clock_event_device *clk)
248{ 319{
@@ -271,6 +342,19 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt,
271 return 0; 342 return 0;
272} 343}
273 344
345static void fsl_a008585_set_sne(struct clock_event_device *clk)
346{
347#ifdef CONFIG_FSL_ERRATUM_A008585
348 if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
349 return;
350
351 if (arch_timer_uses_ppi == VIRT_PPI)
352 clk->set_next_event = fsl_a008585_set_next_event_virt;
353 else
354 clk->set_next_event = fsl_a008585_set_next_event_phys;
355#endif
356}
357
274static void __arch_timer_setup(unsigned type, 358static void __arch_timer_setup(unsigned type,
275 struct clock_event_device *clk) 359 struct clock_event_device *clk)
276{ 360{
@@ -299,6 +383,8 @@ static void __arch_timer_setup(unsigned type,
299 default: 383 default:
300 BUG(); 384 BUG();
301 } 385 }
386
387 fsl_a008585_set_sne(clk);
302 } else { 388 } else {
303 clk->features |= CLOCK_EVT_FEAT_DYNIRQ; 389 clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
304 clk->name = "arch_mem_timer"; 390 clk->name = "arch_mem_timer";
@@ -515,6 +601,15 @@ static void __init arch_counter_register(unsigned type)
515 arch_timer_read_counter = arch_counter_get_cntvct; 601 arch_timer_read_counter = arch_counter_get_cntvct;
516 else 602 else
517 arch_timer_read_counter = arch_counter_get_cntpct; 603 arch_timer_read_counter = arch_counter_get_cntpct;
604
605#ifdef CONFIG_FSL_ERRATUM_A008585
606 /*
607 * Don't use the vdso fastpath if errata require using
608 * the out-of-line counter accessor.
609 */
610 if (static_branch_unlikely(&arch_timer_read_ool_enabled))
611 clocksource_counter.name = "arch_sys_counter_ool";
612#endif
518 } else { 613 } else {
519 arch_timer_read_counter = arch_counter_get_cntvct_mem; 614 arch_timer_read_counter = arch_counter_get_cntvct_mem;
520 615
@@ -800,6 +895,15 @@ static int __init arch_timer_of_init(struct device_node *np)
800 895
801 arch_timer_c3stop = !of_property_read_bool(np, "always-on"); 896 arch_timer_c3stop = !of_property_read_bool(np, "always-on");
802 897
898#ifdef CONFIG_FSL_ERRATUM_A008585
899 if (fsl_a008585_enable < 0)
900 fsl_a008585_enable = of_property_read_bool(np, "fsl,erratum-a008585");
901 if (fsl_a008585_enable) {
902 static_branch_enable(&arch_timer_read_ool_enabled);
903 pr_info("Enabling workaround for FSL erratum A-008585\n");
904 }
905#endif
906
803 /* 907 /*
804 * If we cannot rely on firmware initializing the timer registers then 908 * If we cannot rely on firmware initializing the timer registers then
805 * we should use the physical timers instead. 909 * we should use the physical timers instead.