The following commit has been merged into the timers/core branch of tip:

Commit-ID:     3efe7a878a11c13b5297057bfc1e5639ce1241ce
Gitweb:        
https://git.kernel.org/tip/3efe7a878a11c13b5297057bfc1e5639ce1241ce
Author:        Tony Lindgren <t...@atomide.com>
AuthorDate:    Tue, 23 Mar 2021 09:43:25 +02:00
Committer:     Daniel Lezcano <daniel.lezc...@linaro.org>
CommitterDate: Thu, 08 Apr 2021 16:15:54 +02:00

clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue

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 <t...@atomide.com>
Signed-off-by: Daniel Lezcano <daniel.lezc...@linaro.org>
Link: https://lore.kernel.org/r/20210323074326.28302-2-t...@atomide.com
---
 drivers/clocksource/timer-ti-dm-systimer.c | 66 +++++++++++++--------
 1 file changed, 43 insertions(+), 23 deletions(-)

diff --git a/drivers/clocksource/timer-ti-dm-systimer.c 
b/drivers/clocksource/timer-ti-dm-systimer.c
index 186a599..3308031 100644
--- 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(struct 
clock_event_device *evt)
        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_init(struct 
device_node *np)
         * 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_init(struct 
device_node *np)
        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,
+       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);
 

Reply via email to