]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
clocksource/drivers/arm_arch_timer: Introduce generic errata handling infrastructure
authorDing Tianhong <dingtianhong@huawei.com>
Mon, 6 Feb 2017 16:47:41 +0000 (16:47 +0000)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Tue, 7 Feb 2017 23:14:03 +0000 (00:14 +0100)
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>
arch/arm64/include/asm/arch_timer.h
drivers/clocksource/Kconfig
drivers/clocksource/arm_arch_timer.c

index eaa5bbe3fa8750f78b206b188e46ecee09f70de1..b4b34004a21e2a8ee9514d55f1cd0b90db70bc03 100644 (file)
 
 #include <clocksource/arm_arch_timer.h>
 
-#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585)
+#if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND)
 extern struct static_key_false arch_timer_read_ool_enabled;
-#define needs_fsl_a008585_workaround() \
+#define needs_unstable_timer_counter_workaround() \
        static_branch_unlikely(&arch_timer_read_ool_enabled)
 #else
-#define needs_fsl_a008585_workaround()  false
+#define needs_unstable_timer_counter_workaround()  false
 #endif
 
-u32 __fsl_a008585_read_cntp_tval_el0(void);
-u32 __fsl_a008585_read_cntv_tval_el0(void);
-u64 __fsl_a008585_read_cntvct_el0(void);
 
-/*
- * The number of retries is an arbitrary value well beyond the highest number
- * of iterations the loop has been observed to take.
- */
-#define __fsl_a008585_read_reg(reg) ({                 \
-       u64 _old, _new;                                 \
-       int _retries = 200;                             \
-                                                       \
-       do {                                            \
-               _old = read_sysreg(reg);                \
-               _new = read_sysreg(reg);                \
-               _retries--;                             \
-       } while (unlikely(_old != _new) && _retries);   \
-                                                       \
-       WARN_ON_ONCE(!_retries);                        \
-       _new;                                           \
-})
+struct arch_timer_erratum_workaround {
+       const char *id;         /* Indicate the Erratum ID */
+       u32 (*read_cntp_tval_el0)(void);
+       u32 (*read_cntv_tval_el0)(void);
+       u64 (*read_cntvct_el0)(void);
+};
+
+extern const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround;
 
 #define arch_timer_reg_read_stable(reg)                \
 ({                                                     \
        u64 _val;                                       \
-       if (needs_fsl_a008585_workaround())             \
-               _val = __fsl_a008585_read_##reg();      \
+       if (needs_unstable_timer_counter_workaround())          \
+               _val = timer_unstable_counter_workaround->read_##reg();\
        else                                            \
                _val = read_sysreg(reg);                \
        _val;                                           \
index 4002d6d8d195bec2932edd1f93d80335db715ec5..1945af2d8d3e271a24677578990b7e54756e982e 100644 (file)
@@ -342,10 +342,14 @@ config ARM_ARCH_TIMER_EVTSTREAM
          This must be disabled for hardware validation purposes to detect any
          hardware anomalies of missing events.
 
+config ARM_ARCH_TIMER_OOL_WORKAROUND
+       bool
+
 config FSL_ERRATUM_A008585
        bool "Workaround for Freescale/NXP Erratum A-008585"
        default y
        depends on ARM_ARCH_TIMER && ARM64
+       select ARM_ARCH_TIMER_OOL_WORKAROUND
        help
          This option enables a workaround for Freescale/NXP Erratum
          A-008585 ("ARM generic timer may contain an erroneous
index 6a9d031c3535ede5ba02e4967140ae55796ed2cb..2af0739efd4193cad1562797f7f5376c6116ee67 100644 (file)
@@ -96,27 +96,58 @@ early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
  */
 
 #ifdef CONFIG_FSL_ERRATUM_A008585
-DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
-EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
-
-static int fsl_a008585_enable = -1;
-
-u32 __fsl_a008585_read_cntp_tval_el0(void)
+/*
+ * The number of retries is an arbitrary value well beyond the highest number
+ * of iterations the loop has been observed to take.
+ */
+#define __fsl_a008585_read_reg(reg) ({                 \
+       u64 _old, _new;                                 \
+       int _retries = 200;                             \
+                                                       \
+       do {                                            \
+               _old = read_sysreg(reg);                \
+               _new = read_sysreg(reg);                \
+               _retries--;                             \
+       } while (unlikely(_old != _new) && _retries);   \
+                                                       \
+       WARN_ON_ONCE(!_retries);                        \
+       _new;                                           \
+})
+
+static u32 notrace fsl_a008585_read_cntp_tval_el0(void)
 {
        return __fsl_a008585_read_reg(cntp_tval_el0);
 }
 
-u32 __fsl_a008585_read_cntv_tval_el0(void)
+static u32 notrace fsl_a008585_read_cntv_tval_el0(void)
 {
        return __fsl_a008585_read_reg(cntv_tval_el0);
 }
 
-u64 __fsl_a008585_read_cntvct_el0(void)
+static u64 notrace fsl_a008585_read_cntvct_el0(void)
 {
        return __fsl_a008585_read_reg(cntvct_el0);
 }
-EXPORT_SYMBOL(__fsl_a008585_read_cntvct_el0);
-#endif /* CONFIG_FSL_ERRATUM_A008585 */
+#endif
+
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
+const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL;
+EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
+
+DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
+EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
+
+static const struct arch_timer_erratum_workaround ool_workarounds[] = {
+#ifdef CONFIG_FSL_ERRATUM_A008585
+       {
+               .id = "fsl,erratum-a008585",
+               .read_cntp_tval_el0 = fsl_a008585_read_cntp_tval_el0,
+               .read_cntv_tval_el0 = fsl_a008585_read_cntv_tval_el0,
+               .read_cntvct_el0 = fsl_a008585_read_cntvct_el0,
+       },
+#endif
+};
+#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */
 
 static __always_inline
 void 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,
        arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
 }
 
-#ifdef CONFIG_FSL_ERRATUM_A008585
-static __always_inline void fsl_a008585_set_next_event(const int access,
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
+static __always_inline void erratum_set_next_event_generic(const int access,
                unsigned long evt, struct clock_event_device *clk)
 {
        unsigned long ctrl;
@@ -286,20 +317,20 @@ static __always_inline void fsl_a008585_set_next_event(const int access,
        arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
 }
 
-static int fsl_a008585_set_next_event_virt(unsigned long evt,
+static int erratum_set_next_event_virt(unsigned long evt,
                                           struct clock_event_device *clk)
 {
-       fsl_a008585_set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk);
+       erratum_set_next_event_generic(ARCH_TIMER_VIRT_ACCESS, evt, clk);
        return 0;
 }
 
-static int fsl_a008585_set_next_event_phys(unsigned long evt,
+static int erratum_set_next_event_phys(unsigned long evt,
                                           struct clock_event_device *clk)
 {
-       fsl_a008585_set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk);
+       erratum_set_next_event_generic(ARCH_TIMER_PHYS_ACCESS, evt, clk);
        return 0;
 }
-#endif /* CONFIG_FSL_ERRATUM_A008585 */
+#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */
 
 static int arch_timer_set_next_event_virt(unsigned long evt,
                                          struct clock_event_device *clk)
@@ -329,16 +360,16 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt,
        return 0;
 }
 
-static void fsl_a008585_set_sne(struct clock_event_device *clk)
+static void erratum_workaround_set_sne(struct clock_event_device *clk)
 {
-#ifdef CONFIG_FSL_ERRATUM_A008585
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
        if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
                return;
 
        if (arch_timer_uses_ppi == VIRT_PPI)
-               clk->set_next_event = fsl_a008585_set_next_event_virt;
+               clk->set_next_event = erratum_set_next_event_virt;
        else
-               clk->set_next_event = fsl_a008585_set_next_event_phys;
+               clk->set_next_event = erratum_set_next_event_phys;
 #endif
 }
 
@@ -371,7 +402,7 @@ static void __arch_timer_setup(unsigned type,
                        BUG();
                }
 
-               fsl_a008585_set_sne(clk);
+               erratum_workaround_set_sne(clk);
        } else {
                clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
                clk->name = "arch_mem_timer";
@@ -591,7 +622,7 @@ static void __init arch_counter_register(unsigned type)
 
                clocksource_counter.archdata.vdso_direct = true;
 
-#ifdef CONFIG_FSL_ERRATUM_A008585
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
                /*
                 * Don't use the vdso fastpath if errata require using
                 * the out-of-line counter accessor.
@@ -879,12 +910,15 @@ static int __init arch_timer_of_init(struct device_node *np)
 
        arch_timer_c3stop = !of_property_read_bool(np, "always-on");
 
-#ifdef CONFIG_FSL_ERRATUM_A008585
-       if (fsl_a008585_enable < 0)
-               fsl_a008585_enable = of_property_read_bool(np, "fsl,erratum-a008585");
-       if (fsl_a008585_enable) {
-               static_branch_enable(&arch_timer_read_ool_enabled);
-               pr_info("Enabling workaround for FSL erratum A-008585\n");
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
+       for (i = 0; i < ARRAY_SIZE(ool_workarounds); i++) {
+               if (of_property_read_bool(np, ool_workarounds[i].id)) {
+                       timer_unstable_counter_workaround = &ool_workarounds[i];
+                       static_branch_enable(&arch_timer_read_ool_enabled);
+                       pr_info("arch_timer: Enabling workaround for %s\n",
+                               timer_unstable_counter_workaround->id);
+                       break;
+               }
        }
 #endif