]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/clocksource/arm_arch_timer.c
HID: rmi: fallback to generic/multitouch if hid-rmi is not built
[mirror_ubuntu-artful-kernel.git] / drivers / clocksource / arm_arch_timer.c
index 4c8c3fb2e8b248b3335d1c4f582f7faab1121d37..93aa1364376ac8d94145b7dca83240413d080517 100644 (file)
@@ -96,41 +96,107 @@ 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;
-
-static int __init early_fsl_a008585_cfg(char *buf)
+/*
+ * 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)
 {
-       int ret;
-       bool val;
+       return __fsl_a008585_read_reg(cntp_tval_el0);
+}
 
-       ret = strtobool(buf, &val);
-       if (ret)
-               return ret;
+static u32 notrace fsl_a008585_read_cntv_tval_el0(void)
+{
+       return __fsl_a008585_read_reg(cntv_tval_el0);
+}
 
-       fsl_a008585_enable = val;
-       return 0;
+static u64 notrace fsl_a008585_read_cntvct_el0(void)
+{
+       return __fsl_a008585_read_reg(cntvct_el0);
 }
-early_param("clocksource.arm_arch_timer.fsl-a008585", early_fsl_a008585_cfg);
+#endif
 
-u32 __fsl_a008585_read_cntp_tval_el0(void)
+#ifdef CONFIG_HISILICON_ERRATUM_161010101
+/*
+ * Verify whether the value of the second read is larger than the first by
+ * less than 32 is the only way to confirm the value is correct, so clear the
+ * lower 5 bits to check whether the difference is greater than 32 or not.
+ * Theoretically the erratum should not occur more than twice in succession
+ * when reading the system counter, but it is possible that some interrupts
+ * may lead to more than twice read errors, triggering the warning, so setting
+ * the number of retries far beyond the number of iterations the loop has been
+ * observed to take.
+ */
+#define __hisi_161010101_read_reg(reg) ({                              \
+       u64 _old, _new;                                         \
+       int _retries = 50;                                      \
+                                                               \
+       do {                                                    \
+               _old = read_sysreg(reg);                        \
+               _new = read_sysreg(reg);                        \
+               _retries--;                                     \
+       } while (unlikely((_new - _old) >> 5) && _retries);     \
+                                                               \
+       WARN_ON_ONCE(!_retries);                                \
+       _new;                                                   \
+})
+
+static u32 notrace hisi_161010101_read_cntp_tval_el0(void)
 {
-       return __fsl_a008585_read_reg(cntp_tval_el0);
+       return __hisi_161010101_read_reg(cntp_tval_el0);
 }
 
-u32 __fsl_a008585_read_cntv_tval_el0(void)
+static u32 notrace hisi_161010101_read_cntv_tval_el0(void)
 {
-       return __fsl_a008585_read_reg(cntv_tval_el0);
+       return __hisi_161010101_read_reg(cntv_tval_el0);
 }
 
-u64 __fsl_a008585_read_cntvct_el0(void)
+static u64 notrace hisi_161010101_read_cntvct_el0(void)
 {
-       return __fsl_a008585_read_reg(cntvct_el0);
+       return __hisi_161010101_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
+#ifdef CONFIG_HISILICON_ERRATUM_161010101
+       {
+               .id = "hisilicon,erratum-161010101",
+               .read_cntp_tval_el0 = hisi_161010101_read_cntp_tval_el0,
+               .read_cntv_tval_el0 = hisi_161010101_read_cntv_tval_el0,
+               .read_cntvct_el0 = hisi_161010101_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,
@@ -281,8 +347,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;
@@ -300,20 +366,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)
@@ -343,16 +409,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
 }
 
@@ -385,7 +451,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";
@@ -580,7 +646,7 @@ static struct clocksource clocksource_counter = {
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static struct cyclecounter cyclecounter = {
+static struct cyclecounter cyclecounter __ro_after_init = {
        .read   = arch_counter_read_cc,
        .mask   = CLOCKSOURCE_MASK(56),
 };
@@ -605,7 +671,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.
@@ -893,12 +959,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