]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.11-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 May 2021 10:33:32 +0000 (12:33 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 May 2021 10:33:32 +0000 (12:33 +0200)
added patches:
clocksource-drivers-timer-ti-dm-handle-dra7-timer-wrap-errata-i940.patch
clocksource-drivers-timer-ti-dm-prepare-to-handle-dra7-timer-wrap-issue.patch

queue-5.11/clocksource-drivers-timer-ti-dm-handle-dra7-timer-wrap-errata-i940.patch [new file with mode: 0644]
queue-5.11/clocksource-drivers-timer-ti-dm-prepare-to-handle-dra7-timer-wrap-issue.patch [new file with mode: 0644]
queue-5.11/series

diff --git a/queue-5.11/clocksource-drivers-timer-ti-dm-handle-dra7-timer-wrap-errata-i940.patch b/queue-5.11/clocksource-drivers-timer-ti-dm-handle-dra7-timer-wrap-errata-i940.patch
new file mode 100644 (file)
index 0000000..54f1ac2
--- /dev/null
@@ -0,0 +1,205 @@
+From 25de4ce5ed02994aea8bc111d133308f6fd62566 Mon Sep 17 00:00:00 2001
+From: Tony Lindgren <tony@atomide.com>
+Date: Tue, 23 Mar 2021 09:43:26 +0200
+Subject: clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
+
+From: Tony Lindgren <tony@atomide.com>
+
+commit 25de4ce5ed02994aea8bc111d133308f6fd62566 upstream.
+
+There is a timer wrap issue on dra7 for the ARM architected timer.
+In a typical clock configuration the timer fails to wrap after 388 days.
+
+To work around the issue, we need to use timer-ti-dm percpu timers instead.
+
+Let's configure dmtimer3 and 4 as percpu timers by default, and warn about
+the issue if the dtb is not configured properly.
+
+Let's do this as a single patch so it can be backported to v5.8 and later
+kernels easily. Note that this patch depends on earlier timer-ti-dm
+systimer posted mode fixes, and a preparatory clockevent patch
+"clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue".
+
+For more information, please see the errata for "AM572x Sitara Processors
+Silicon Revisions 1.1, 2.0":
+
+https://www.ti.com/lit/er/sprz429m/sprz429m.pdf
+
+The concept is based on earlier reference patches done by Tero Kristo and
+Keerthy.
+
+Cc: Keerthy <j-keerthy@ti.com>
+Cc: Tero Kristo <kristo@kernel.org>
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20210323074326.28302-3-tony@atomide.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/boot/dts/dra7-l4.dtsi             |    4 -
+ arch/arm/boot/dts/dra7.dtsi                |   20 +++++++
+ drivers/clocksource/timer-ti-dm-systimer.c |   76 +++++++++++++++++++++++++++++
+ include/linux/cpuhotplug.h                 |    1 
+ 4 files changed, 99 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/dra7-l4.dtsi
++++ b/arch/arm/boot/dts/dra7-l4.dtsi
+@@ -1168,7 +1168,7 @@
+                       };
+               };
+-              target-module@34000 {                   /* 0x48034000, ap 7 46.0 */
++              timer3_target: target-module@34000 {    /* 0x48034000, ap 7 46.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       reg = <0x34000 0x4>,
+                             <0x34010 0x4>;
+@@ -1195,7 +1195,7 @@
+                       };
+               };
+-              target-module@36000 {                   /* 0x48036000, ap 9 4e.0 */
++              timer4_target: target-module@36000 {    /* 0x48036000, ap 9 4e.0 */
+                       compatible = "ti,sysc-omap4-timer", "ti,sysc";
+                       reg = <0x36000 0x4>,
+                             <0x36010 0x4>;
+--- a/arch/arm/boot/dts/dra7.dtsi
++++ b/arch/arm/boot/dts/dra7.dtsi
+@@ -46,6 +46,7 @@
+       timer {
+               compatible = "arm,armv7-timer";
++              status = "disabled";    /* See ARM architected timer wrap erratum i940 */
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+@@ -1241,3 +1242,22 @@
+               assigned-clock-parents = <&sys_32k_ck>;
+       };
+ };
++
++/* Local timers, see ARM architected timer wrap erratum i940 */
++&timer3_target {
++      ti,no-reset-on-init;
++      ti,no-idle;
++      timer@0 {
++              assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>;
++              assigned-clock-parents = <&timer_sys_clk_div>;
++      };
++};
++
++&timer4_target {
++      ti,no-reset-on-init;
++      ti,no-idle;
++      timer@0 {
++              assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>;
++              assigned-clock-parents = <&timer_sys_clk_div>;
++      };
++};
+--- a/drivers/clocksource/timer-ti-dm-systimer.c
++++ b/drivers/clocksource/timer-ti-dm-systimer.c
+@@ -2,6 +2,7 @@
+ #include <linux/clk.h>
+ #include <linux/clocksource.h>
+ #include <linux/clockchips.h>
++#include <linux/cpuhotplug.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+@@ -630,6 +631,78 @@ err_out_free:
+       return error;
+ }
++/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
++static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
++
++static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
++{
++      struct dmtimer_clockevent *clkevt;
++      int error;
++
++      if (!cpu_possible(cpu))
++              return -EINVAL;
++
++      if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
++          !of_property_read_bool(np->parent, "ti,no-idle"))
++              pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
++
++      clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
++
++      error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
++                                         cpumask_of(cpu), "percpu-dmtimer",
++                                         500);
++      if (error)
++              return error;
++
++      return 0;
++}
++
++/* See TRM for timer internal resynch latency */
++static int omap_dmtimer_starting_cpu(unsigned int cpu)
++{
++      struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
++      struct clock_event_device *dev = &clkevt->dev;
++      struct dmtimer_systimer *t = &clkevt->t;
++
++      clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
++      irq_force_affinity(dev->irq, cpumask_of(cpu));
++
++      return 0;
++}
++
++static int __init dmtimer_percpu_timer_startup(void)
++{
++      struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
++      struct dmtimer_systimer *t = &clkevt->t;
++
++      if (t->sysc) {
++              cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
++                                "clockevents/omap/gptimer:starting",
++                                omap_dmtimer_starting_cpu, NULL);
++      }
++
++      return 0;
++}
++subsys_initcall(dmtimer_percpu_timer_startup);
++
++static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
++{
++      struct device_node *arm_timer;
++
++      arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
++      if (of_device_is_available(arm_timer)) {
++              pr_warn_once("ARM architected timer wrap issue i940 detected\n");
++              return 0;
++      }
++
++      if (pa == 0x48034000)           /* dra7 dmtimer3 */
++              return dmtimer_percpu_timer_init(np, 0);
++      else if (pa == 0x48036000)      /* dra7 dmtimer4 */
++              return dmtimer_percpu_timer_init(np, 1);
++
++      return 0;
++}
++
+ /* Clocksource */
+ static struct dmtimer_clocksource *
+ to_dmtimer_clocksource(struct clocksource *cs)
+@@ -763,6 +836,9 @@ static int __init dmtimer_systimer_init(
+       if (clockevent == pa)
+               return dmtimer_clockevent_init(np);
++      if (of_machine_is_compatible("ti,dra7"))
++              return dmtimer_percpu_quirk_init(np, pa);
++
+       return 0;
+ }
+--- a/include/linux/cpuhotplug.h
++++ b/include/linux/cpuhotplug.h
+@@ -135,6 +135,7 @@ enum cpuhp_state {
+       CPUHP_AP_RISCV_TIMER_STARTING,
+       CPUHP_AP_CLINT_TIMER_STARTING,
+       CPUHP_AP_CSKY_TIMER_STARTING,
++      CPUHP_AP_TI_GP_TIMER_STARTING,
+       CPUHP_AP_HYPERV_TIMER_STARTING,
+       CPUHP_AP_KVM_STARTING,
+       CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
diff --git a/queue-5.11/clocksource-drivers-timer-ti-dm-prepare-to-handle-dra7-timer-wrap-issue.patch b/queue-5.11/clocksource-drivers-timer-ti-dm-prepare-to-handle-dra7-timer-wrap-issue.patch
new file mode 100644 (file)
index 0000000..396f540
--- /dev/null
@@ -0,0 +1,149 @@
+From 3efe7a878a11c13b5297057bfc1e5639ce1241ce Mon Sep 17 00:00:00 2001
+From: Tony Lindgren <tony@atomide.com>
+Date: Tue, 23 Mar 2021 09:43:25 +0200
+Subject: clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
+
+From: Tony Lindgren <tony@atomide.com>
+
+commit 3efe7a878a11c13b5297057bfc1e5639ce1241ce upstream.
+
+There is a timer wrap issue on dra7 for the ARM architected timer.
+In a typical clock configuration the timer fails to wrap after 388 days.
+
+To work around the issue, we need to use timer-ti-dm timers instead.
+
+Let's prepare for adding support for percpu timers by adding a common
+dmtimer_clkevt_init_common() and call it from dmtimer_clockevent_init().
+This patch makes no intentional functional changes.
+
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Link: https://lore.kernel.org/r/20210323074326.28302-2-tony@atomide.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/clocksource/timer-ti-dm-systimer.c |   68 ++++++++++++++++++-----------
+ 1 file changed, 44 insertions(+), 24 deletions(-)
+
+--- a/drivers/clocksource/timer-ti-dm-systimer.c
++++ b/drivers/clocksource/timer-ti-dm-systimer.c
+@@ -530,17 +530,17 @@ static void omap_clockevent_unidle(struc
+       writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
+ }
+-static int __init dmtimer_clockevent_init(struct device_node *np)
++static int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt,
++                                           struct device_node *np,
++                                           unsigned int features,
++                                           const struct cpumask *cpumask,
++                                           const char *name,
++                                           int rating)
+ {
+-      struct dmtimer_clockevent *clkevt;
+       struct clock_event_device *dev;
+       struct dmtimer_systimer *t;
+       int error;
+-      clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
+-      if (!clkevt)
+-              return -ENOMEM;
+-
+       t = &clkevt->t;
+       dev = &clkevt->dev;
+@@ -548,25 +548,23 @@ static int __init dmtimer_clockevent_ini
+        * We mostly use cpuidle_coupled with ARM local timers for runtime,
+        * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
+        */
+-      dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+-      dev->rating = 300;
++      dev->features = features;
++      dev->rating = rating;
+       dev->set_next_event = dmtimer_set_next_event;
+       dev->set_state_shutdown = dmtimer_clockevent_shutdown;
+       dev->set_state_periodic = dmtimer_set_periodic;
+       dev->set_state_oneshot = dmtimer_clockevent_shutdown;
+       dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown;
+       dev->tick_resume = dmtimer_clockevent_shutdown;
+-      dev->cpumask = cpu_possible_mask;
++      dev->cpumask = cpumask;
+       dev->irq = irq_of_parse_and_map(np, 0);
+-      if (!dev->irq) {
+-              error = -ENXIO;
+-              goto err_out_free;
+-      }
++      if (!dev->irq)
++              return -ENXIO;
+       error = dmtimer_systimer_setup(np, &clkevt->t);
+       if (error)
+-              goto err_out_free;
++              return error;
+       clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ);
+@@ -578,32 +576,54 @@ static int __init dmtimer_clockevent_ini
+       writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
+       error = request_irq(dev->irq, dmtimer_clockevent_interrupt,
+-                          IRQF_TIMER, "clockevent", clkevt);
++                          IRQF_TIMER, name, clkevt);
+       if (error)
+               goto err_out_unmap;
+       writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
+       writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
+-      pr_info("TI gptimer clockevent: %s%lu Hz at %pOF\n",
+-              of_find_property(np, "ti,timer-alwon", NULL) ?
++      pr_info("TI gptimer %s: %s%lu Hz at %pOF\n",
++              name, of_find_property(np, "ti,timer-alwon", NULL) ?
+               "always-on " : "", t->rate, np->parent);
+-      clockevents_config_and_register(dev, t->rate,
+-                                      3, /* Timer internal resynch latency */
++      return 0;
++
++err_out_unmap:
++      iounmap(t->base);
++
++      return error;
++}
++
++static int __init dmtimer_clockevent_init(struct device_node *np)
++{
++      struct dmtimer_clockevent *clkevt;
++      int error;
++
++      clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
++      if (!clkevt)
++              return -ENOMEM;
++
++      error = dmtimer_clkevt_init_common(clkevt, np,
++                                         CLOCK_EVT_FEAT_PERIODIC |
++                                         CLOCK_EVT_FEAT_ONESHOT,
++                                         cpu_possible_mask, "clockevent",
++                                         300);
++      if (error)
++              goto err_out_free;
++
++      clockevents_config_and_register(&clkevt->dev, clkevt->t.rate,
++                                      3, /* Timer internal resync latency */
+                                       0xffffffff);
+       if (of_machine_is_compatible("ti,am33xx") ||
+           of_machine_is_compatible("ti,am43")) {
+-              dev->suspend = omap_clockevent_idle;
+-              dev->resume = omap_clockevent_unidle;
++              clkevt->dev.suspend = omap_clockevent_idle;
++              clkevt->dev.resume = omap_clockevent_unidle;
+       }
+       return 0;
+-err_out_unmap:
+-      iounmap(t->base);
+-
+ err_out_free:
+       kfree(clkevt);
index 55ad2b0d2114fb667eceb67bf64caf3ad9cb47f8..2b7f00ce2005e0df15088c45136e9e6d9cb723b9 100644 (file)
@@ -304,3 +304,5 @@ mm-fix-struct-page-layout-on-32-bit-systems.patch
 mips-reinstate-platform-__div64_32-handler.patch
 mips-avoid-divu-in-__div64_32-is-result-would-be-zero.patch
 mips-avoid-handcoded-divu-in-__div64_32-altogether.patch
+clocksource-drivers-timer-ti-dm-prepare-to-handle-dra7-timer-wrap-issue.patch
+clocksource-drivers-timer-ti-dm-handle-dra7-timer-wrap-errata-i940.patch