summaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-01-19 12:20:59 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2017-04-07 06:22:08 -0400
commit651bb2e9dca6e6dbad3fba5f6e6086a23575b8b5 (patch)
treef7325f49f59ac0b20f78bd66917414005943e86b /drivers/clocksource
parenteeb1efbcb83c0cfe6d567abbacd675bbddf3d658 (diff)
arm64: arch_timer: Add infrastructure for multiple erratum detection methods
We're currently stuck with DT when it comes to handling errata, which is pretty restrictive. In order to make things more flexible, let's introduce an infrastructure that could support alternative discovery methods. No change in functionality. Acked-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/arm_arch_timer.c83
1 files changed, 72 insertions, 11 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 7a8a4117f123..5c5c2af74ad9 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -182,7 +182,9 @@ EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
182static const struct arch_timer_erratum_workaround ool_workarounds[] = { 182static const struct arch_timer_erratum_workaround ool_workarounds[] = {
183#ifdef CONFIG_FSL_ERRATUM_A008585 183#ifdef CONFIG_FSL_ERRATUM_A008585
184 { 184 {
185 .match_type = ate_match_dt,
185 .id = "fsl,erratum-a008585", 186 .id = "fsl,erratum-a008585",
187 .desc = "Freescale erratum a005858",
186 .read_cntp_tval_el0 = fsl_a008585_read_cntp_tval_el0, 188 .read_cntp_tval_el0 = fsl_a008585_read_cntp_tval_el0,
187 .read_cntv_tval_el0 = fsl_a008585_read_cntv_tval_el0, 189 .read_cntv_tval_el0 = fsl_a008585_read_cntv_tval_el0,
188 .read_cntvct_el0 = fsl_a008585_read_cntvct_el0, 190 .read_cntvct_el0 = fsl_a008585_read_cntvct_el0,
@@ -190,13 +192,81 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = {
190#endif 192#endif
191#ifdef CONFIG_HISILICON_ERRATUM_161010101 193#ifdef CONFIG_HISILICON_ERRATUM_161010101
192 { 194 {
195 .match_type = ate_match_dt,
193 .id = "hisilicon,erratum-161010101", 196 .id = "hisilicon,erratum-161010101",
197 .desc = "HiSilicon erratum 161010101",
194 .read_cntp_tval_el0 = hisi_161010101_read_cntp_tval_el0, 198 .read_cntp_tval_el0 = hisi_161010101_read_cntp_tval_el0,
195 .read_cntv_tval_el0 = hisi_161010101_read_cntv_tval_el0, 199 .read_cntv_tval_el0 = hisi_161010101_read_cntv_tval_el0,
196 .read_cntvct_el0 = hisi_161010101_read_cntvct_el0, 200 .read_cntvct_el0 = hisi_161010101_read_cntvct_el0,
197 }, 201 },
198#endif 202#endif
199}; 203};
204
205typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *,
206 const void *);
207
208static
209bool arch_timer_check_dt_erratum(const struct arch_timer_erratum_workaround *wa,
210 const void *arg)
211{
212 const struct device_node *np = arg;
213
214 return of_property_read_bool(np, wa->id);
215}
216
217static const struct arch_timer_erratum_workaround *
218arch_timer_iterate_errata(enum arch_timer_erratum_match_type type,
219 ate_match_fn_t match_fn,
220 void *arg)
221{
222 int i;
223
224 for (i = 0; i < ARRAY_SIZE(ool_workarounds); i++) {
225 if (ool_workarounds[i].match_type != type)
226 continue;
227
228 if (match_fn(&ool_workarounds[i], arg))
229 return &ool_workarounds[i];
230 }
231
232 return NULL;
233}
234
235static
236void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa)
237{
238 timer_unstable_counter_workaround = wa;
239 static_branch_enable(&arch_timer_read_ool_enabled);
240}
241
242static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type type,
243 void *arg)
244{
245 const struct arch_timer_erratum_workaround *wa;
246 ate_match_fn_t match_fn = NULL;
247
248 if (static_branch_unlikely(&arch_timer_read_ool_enabled))
249 return;
250
251 switch (type) {
252 case ate_match_dt:
253 match_fn = arch_timer_check_dt_erratum;
254 break;
255 default:
256 WARN_ON(1);
257 return;
258 }
259
260 wa = arch_timer_iterate_errata(type, match_fn, arg);
261 if (!wa)
262 return;
263
264 arch_timer_enable_workaround(wa);
265 pr_info("Enabling global workaround for %s\n", wa->desc);
266}
267
268#else
269#define arch_timer_check_ool_workaround(t,a) do { } while(0)
200#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ 270#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */
201 271
202static __always_inline 272static __always_inline
@@ -960,17 +1030,8 @@ static int __init arch_timer_of_init(struct device_node *np)
960 1030
961 arch_timer_c3stop = !of_property_read_bool(np, "always-on"); 1031 arch_timer_c3stop = !of_property_read_bool(np, "always-on");
962 1032
963#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND 1033 /* Check for globally applicable workarounds */
964 for (i = 0; i < ARRAY_SIZE(ool_workarounds); i++) { 1034 arch_timer_check_ool_workaround(ate_match_dt, np);
965 if (of_property_read_bool(np, ool_workarounds[i].id)) {
966 timer_unstable_counter_workaround = &ool_workarounds[i];
967 static_branch_enable(&arch_timer_read_ool_enabled);
968 pr_info("arch_timer: Enabling workaround for %s\n",
969 timer_unstable_counter_workaround->id);
970 break;
971 }
972 }
973#endif
974 1035
975 /* 1036 /*
976 * If we cannot rely on firmware initializing the timer registers then 1037 * If we cannot rely on firmware initializing the timer registers then