| From 2c8c50bb16804151a1d1baf8d9eece02084fc29f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 2 Dec 2025 23:13:41 +0100 |
| Subject: clocksource/drivers/sh_tmu: Always leave device running after probe |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> |
| |
| [ Upstream commit b1278972b08e480990e2789bdc6a7c918bc349be ] |
| |
| The TMU device can be used as both a clocksource and a clockevent |
| provider. The driver tries to be smart and power itself on and off, as |
| well as enabling and disabling its clock when it's not in operation. |
| This behavior is slightly altered if the TMU is used as an early |
| platform device in which case the device is left powered on after probe, |
| but the clock is still enabled and disabled at runtime. |
| |
| This has worked for a long time, but recent improvements in PREEMPT_RT |
| and PROVE_LOCKING have highlighted an issue. As the TMU registers itself |
| as a clockevent provider, clockevents_register_device(), it needs to use |
| raw spinlocks internally as this is the context of which the clockevent |
| framework interacts with the TMU driver. However in the context of |
| holding a raw spinlock the TMU driver can't really manage its power |
| state or clock with calls to pm_runtime_*() and clk_*() as these calls |
| end up in other platform drivers using regular spinlocks to control |
| power and clocks. |
| |
| This mix of spinlock contexts trips a lockdep warning. |
| |
| ============================= |
| [ BUG: Invalid wait context ] |
| 6.18.0-arm64-renesas-09926-gee959e7c5e34 #1 Not tainted |
| ----------------------------- |
| swapper/0/0 is trying to lock: |
| ffff000008c9e180 (&dev->power.lock){-...}-{3:3}, at: __pm_runtime_resume+0x38/0x88 |
| other info that might help us debug this: |
| context-{5:5} |
| 1 lock held by swapper/0/0: |
| ccree e6601000.crypto: ARM CryptoCell 630P Driver: HW version 0xAF400001/0xDCC63000, Driver version 5.0 |
| #0: ffff8000817ec298 |
| ccree e6601000.crypto: ARM ccree device initialized |
| (tick_broadcast_lock){-...}-{2:2}, at: __tick_broadcast_oneshot_control+0xa4/0x3a8 |
| stack backtrace: |
| CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.18.0-arm64-renesas-09926-gee959e7c5e34 #1 PREEMPT |
| Hardware name: Renesas Salvator-X 2nd version board based on r8a77965 (DT) |
| Call trace: |
| show_stack+0x14/0x1c (C) |
| dump_stack_lvl+0x6c/0x90 |
| dump_stack+0x14/0x1c |
| __lock_acquire+0x904/0x1584 |
| lock_acquire+0x220/0x34c |
| _raw_spin_lock_irqsave+0x58/0x80 |
| __pm_runtime_resume+0x38/0x88 |
| sh_tmu_clock_event_set_oneshot+0x84/0xd4 |
| clockevents_switch_state+0xfc/0x13c |
| tick_broadcast_set_event+0x30/0xa4 |
| __tick_broadcast_oneshot_control+0x1e0/0x3a8 |
| tick_broadcast_oneshot_control+0x30/0x40 |
| cpuidle_enter_state+0x40c/0x680 |
| cpuidle_enter+0x30/0x40 |
| do_idle+0x1f4/0x280 |
| cpu_startup_entry+0x34/0x40 |
| kernel_init+0x0/0x130 |
| do_one_initcall+0x0/0x230 |
| __primary_switched+0x88/0x90 |
| |
| For non-PREEMPT_RT builds this is not really an issue, but for |
| PREEMPT_RT builds where normal spinlocks can sleep this might be an |
| issue. Be cautious and always leave the power and clock running after |
| probe. |
| |
| Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> |
| Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> |
| Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| Link: https://patch.msgid.link/20251202221341.1856773-1-niklas.soderlund+renesas@ragnatech.se |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/clocksource/sh_tmu.c | 18 ------------------ |
| 1 file changed, 18 deletions(-) |
| |
| diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c |
| index beffff81c00f3..3fc6ed9b56300 100644 |
| --- a/drivers/clocksource/sh_tmu.c |
| +++ b/drivers/clocksource/sh_tmu.c |
| @@ -143,16 +143,6 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) |
| |
| static int __sh_tmu_enable(struct sh_tmu_channel *ch) |
| { |
| - int ret; |
| - |
| - /* enable clock */ |
| - ret = clk_enable(ch->tmu->clk); |
| - if (ret) { |
| - dev_err(&ch->tmu->pdev->dev, "ch%u: cannot enable clock\n", |
| - ch->index); |
| - return ret; |
| - } |
| - |
| /* make sure channel is disabled */ |
| sh_tmu_start_stop_ch(ch, 0); |
| |
| @@ -174,7 +164,6 @@ static int sh_tmu_enable(struct sh_tmu_channel *ch) |
| if (ch->enable_count++ > 0) |
| return 0; |
| |
| - pm_runtime_get_sync(&ch->tmu->pdev->dev); |
| dev_pm_syscore_device(&ch->tmu->pdev->dev, true); |
| |
| return __sh_tmu_enable(ch); |
| @@ -187,9 +176,6 @@ static void __sh_tmu_disable(struct sh_tmu_channel *ch) |
| |
| /* disable interrupts in TMU block */ |
| sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); |
| - |
| - /* stop clock */ |
| - clk_disable(ch->tmu->clk); |
| } |
| |
| static void sh_tmu_disable(struct sh_tmu_channel *ch) |
| @@ -203,7 +189,6 @@ static void sh_tmu_disable(struct sh_tmu_channel *ch) |
| __sh_tmu_disable(ch); |
| |
| dev_pm_syscore_device(&ch->tmu->pdev->dev, false); |
| - pm_runtime_put(&ch->tmu->pdev->dev); |
| } |
| |
| static void sh_tmu_set_next(struct sh_tmu_channel *ch, unsigned long delta, |
| @@ -552,7 +537,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) |
| goto err_clk_unprepare; |
| |
| tmu->rate = clk_get_rate(tmu->clk) / 4; |
| - clk_disable(tmu->clk); |
| |
| /* Map the memory resource. */ |
| ret = sh_tmu_map_memory(tmu); |
| @@ -626,8 +610,6 @@ static int sh_tmu_probe(struct platform_device *pdev) |
| out: |
| if (tmu->has_clockevent || tmu->has_clocksource) |
| pm_runtime_irq_safe(&pdev->dev); |
| - else |
| - pm_runtime_idle(&pdev->dev); |
| |
| return 0; |
| } |
| -- |
| 2.51.0 |
| |