diff options
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 49 |
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 | |||
158 | static u32 notrace hisi_161010101_read_cntp_tval_el0(void) | ||
159 | { | ||
160 | return __hisi_161010101_read_reg(cntp_tval_el0); | ||
161 | } | ||
162 | |||
163 | static u32 notrace hisi_161010101_read_cntv_tval_el0(void) | ||
164 | { | ||
165 | return __hisi_161010101_read_reg(cntv_tval_el0); | ||
166 | } | ||
167 | |||
168 | static 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 |
134 | const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; | 175 | const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; |
135 | EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); | 176 | EXPORT_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 | ||