aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/arm_arch_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r--drivers/clocksource/arm_arch_timer.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 2af0739efd41..7b06aef83836 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -130,6 +130,47 @@ static u64 notrace fsl_a008585_read_cntvct_el0(void)
130} 130}
131#endif 131#endif
132 132
133#ifdef CONFIG_HISILICON_ERRATUM_161010101
134/*
135 * Verify whether the value of the second read is larger than the first by
136 * less than 32 is the only way to confirm the value is correct, so clear the
137 * lower 5 bits to check whether the difference is greater than 32 or not.
138 * Theoretically the erratum should not occur more than twice in succession
139 * when reading the system counter, but it is possible that some interrupts
140 * may lead to more than twice read errors, triggering the warning, so setting
141 * the number of retries far beyond the number of iterations the loop has been
142 * observed to take.
143 */
144#define __hisi_161010101_read_reg(reg) ({ \
145 u64 _old, _new; \
146 int _retries = 50; \
147 \
148 do { \
149 _old = read_sysreg(reg); \
150 _new = read_sysreg(reg); \
151 _retries--; \
152 } while (unlikely((_new - _old) >> 5) && _retries); \
153 \
154 WARN_ON_ONCE(!_retries); \
155 _new; \
156})
157
158static u32 notrace hisi_161010101_read_cntp_tval_el0(void)
159{
160 return __hisi_161010101_read_reg(cntp_tval_el0);
161}
162
163static u32 notrace hisi_161010101_read_cntv_tval_el0(void)
164{
165 return __hisi_161010101_read_reg(cntv_tval_el0);
166}
167
168static u64 notrace hisi_161010101_read_cntvct_el0(void)
169{
170 return __hisi_161010101_read_reg(cntvct_el0);
171}
172#endif
173
133#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND 174#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
134const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; 175const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL;
135EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); 176EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
@@ -146,6 +187,14 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = {
146 .read_cntvct_el0 = fsl_a008585_read_cntvct_el0, 187 .read_cntvct_el0 = fsl_a008585_read_cntvct_el0,
147 }, 188 },
148#endif 189#endif
190#ifdef CONFIG_HISILICON_ERRATUM_161010101
191 {
192 .id = "hisilicon,erratum-161010101",
193 .read_cntp_tval_el0 = hisi_161010101_read_cntp_tval_el0,
194 .read_cntv_tval_el0 = hisi_161010101_read_cntv_tval_el0,
195 .read_cntvct_el0 = hisi_161010101_read_cntvct_el0,
196 },
197#endif
149}; 198};
150#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ 199#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */
151 200