Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clocksource/drivers/sh_tmu: Always leave device running after probe

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

authored by

Niklas Söderlund and committed by
Daniel Lezcano
b1278972 f8f9c1f4

-18
-18
drivers/clocksource/sh_tmu.c
··· 143 143 144 144 static int __sh_tmu_enable(struct sh_tmu_channel *ch) 145 145 { 146 - int ret; 147 - 148 - /* enable clock */ 149 - ret = clk_enable(ch->tmu->clk); 150 - if (ret) { 151 - dev_err(&ch->tmu->pdev->dev, "ch%u: cannot enable clock\n", 152 - ch->index); 153 - return ret; 154 - } 155 - 156 146 /* make sure channel is disabled */ 157 147 sh_tmu_start_stop_ch(ch, 0); 158 148 ··· 164 174 if (ch->enable_count++ > 0) 165 175 return 0; 166 176 167 - pm_runtime_get_sync(&ch->tmu->pdev->dev); 168 177 dev_pm_syscore_device(&ch->tmu->pdev->dev, true); 169 178 170 179 return __sh_tmu_enable(ch); ··· 176 187 177 188 /* disable interrupts in TMU block */ 178 189 sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); 179 - 180 - /* stop clock */ 181 - clk_disable(ch->tmu->clk); 182 190 } 183 191 184 192 static void sh_tmu_disable(struct sh_tmu_channel *ch) ··· 189 203 __sh_tmu_disable(ch); 190 204 191 205 dev_pm_syscore_device(&ch->tmu->pdev->dev, false); 192 - pm_runtime_put(&ch->tmu->pdev->dev); 193 206 } 194 207 195 208 static void sh_tmu_set_next(struct sh_tmu_channel *ch, unsigned long delta, ··· 537 552 goto err_clk_unprepare; 538 553 539 554 tmu->rate = clk_get_rate(tmu->clk) / 4; 540 - clk_disable(tmu->clk); 541 555 542 556 /* Map the memory resource. */ 543 557 ret = sh_tmu_map_memory(tmu); ··· 610 626 out: 611 627 if (tmu->has_clockevent || tmu->has_clocksource) 612 628 pm_runtime_irq_safe(&pdev->dev); 613 - else 614 - pm_runtime_idle(&pdev->dev); 615 629 616 630 return 0; 617 631 }