clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
PATCH 1/2 clocksource/drivers/timer-ti-dm: Prepare to handle dra7 timer wrap issue
Upstream commit 3efe7a878a11c13b5297057bfc1e5639ce1241ce. Updated to apply to stable linux-5.10.y without need for upstream typo fix commit 4bf07f6562a01a488877e05267808da7147f44a5. Needed to avoid duplicate code for upstream commit 25de4ce5ed02994aea8bc111d133308f6fd62566.
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.
--- drivers/clocksource/timer-ti-dm-systimer.c | 68 ++++++++++++++-------- 1 file changed, 44 insertions(+), 24 deletions(-)
drivers/clocksource/timer-ti-dm-systimer.c +44 -24
@@ -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, -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);
Signature · 1 line
2.31.1
PATCH 2/2 clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
Upstream commit 25de4ce5ed02994aea8bc111d133308f6fd62566 for stable linux-5.10.y. Depends on backported upstream commit 3efe7a878a11c13b5297057bfc1e5639ce1241ce.
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.
--- 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(-)
arch/arm/boot/dts/dra7-l4.dtsi +2 -2
@@ -1168,7 +1168,7 @@ timer2: timer@0 { }; }; - 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 @@ timer3: timer@0 { }; }; - 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>;
arch/arm/boot/dts/dra7.dtsi +20 -0
@@ -46,6 +46,7 @@ aliases { 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)>,
@@ -1090,3 +1091,22 @@ timer@0 { 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>; + }; +};
drivers/clocksource/timer-ti-dm-systimer.c +76 -0
94 lines not on this page · raw message
include/linux/cpuhotplug.h +1 -0
@@ -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,
Signature · 1 line
2.31.1
Re: [Backport for linux-5.10.y PATCH 2/2] clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
Quoted 6 lines · Tony Lindgren
Upstream commit
25de4ce5ed02994aea8bc111d133308f6fd62566for stable linux-5.10.y. Depends on backported upstream commit3efe7a878a11c13b5297057bfc1e5639ce1241ce.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.
FYI, these patches also apply to linux-5.11.y and linux-5.12.y. This patch applies with fuzz to the related device tree changes though, so please let me know if separate patches are needed.
Regards,
Tony
Re: [Backport for linux-5.10.y PATCH 2/2] clocksource/drivers/timer-ti-dm: Handle dra7 timer wrap errata i940
Quoted 11 lines · Tony Lindgren
Quoted 6 lines · Tony Lindgren
Upstream commit
25de4ce5ed02994aea8bc111d133308f6fd62566for stable linux-5.10.y. Depends on backported upstream commit3efe7a878a11c13b5297057bfc1e5639ce1241ce.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.
FYI, these patches also apply to linux-5.11.y and linux-5.12.y. This patch applies with fuzz to the related device tree changes though, so please let me know if separate patches are needed.
All now queued up, thanks.
greg k-h