Skip to content

Commit 62524f2

Browse files
Niklas Söderlunddlezcano
authored andcommitted
clocksource/drivers/sh_cmt: Always leave device running after probe
The CMT 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 CMT 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 CMT 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 CMT driver. However in the context of holding a raw spinlock the CMT 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.17.0-rc3-arm64-renesas-03071-gb3c4f4122b28-dirty torvalds#21 Not tainted ----------------------------- swapper/1/0 is trying to lock: ffff00000898d180 (&dev->power.lock){-...}-{3:3}, at: __pm_runtime_resume+0x38/0x88 ccree e6601000.crypto: ARM CryptoCell 630P Driver: HW version 0xAF400001/0xDCC63000, Driver version 5.0 other info that might help us debug this: ccree e6601000.crypto: ARM ccree device initialized context-{5:5} 2 locks held by swapper/1/0: #0: ffff80008173c298 (tick_broadcast_lock){-...}-{2:2}, at: __tick_broadcast_oneshot_control+0xa4/0x3a8 CachyOS#1: ffff0000089a5858 (&ch->lock){....}-{2:2} usbcore: registered new interface driver usbhid , at: sh_cmt_start+0x30/0x364 stack backtrace: CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted 6.17.0-rc3-arm64-renesas-03071-gb3c4f4122b28-dirty torvalds#21 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_cmt_start+0x54/0x364 sh_cmt_clock_event_set_oneshot+0x64/0xb8 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/0x26c cpu_startup_entry+0x34/0x40 secondary_start_kernel+0x11c/0x13c __secondary_switched+0x74/0x78 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/20251016182022.1837417-1-niklas.soderlund+renesas@ragnatech.se
1 parent 6b38a8b commit 62524f2

File tree

1 file changed

+3
-33
lines changed

1 file changed

+3
-33
lines changed

drivers/clocksource/sh_cmt.c

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,6 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
355355

356356
dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
357357

358-
/* enable clock */
359-
ret = clk_enable(ch->cmt->clk);
360-
if (ret) {
361-
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot enable clock\n",
362-
ch->index);
363-
goto err0;
364-
}
365-
366358
/* make sure channel is disabled */
367359
sh_cmt_start_stop_ch(ch, 0);
368360

@@ -384,19 +376,12 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
384376
if (ret || sh_cmt_read_cmcnt(ch)) {
385377
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
386378
ch->index);
387-
ret = -ETIMEDOUT;
388-
goto err1;
379+
return -ETIMEDOUT;
389380
}
390381

391382
/* enable channel */
392383
sh_cmt_start_stop_ch(ch, 1);
393384
return 0;
394-
err1:
395-
/* stop clock */
396-
clk_disable(ch->cmt->clk);
397-
398-
err0:
399-
return ret;
400385
}
401386

402387
static void sh_cmt_disable(struct sh_cmt_channel *ch)
@@ -407,9 +392,6 @@ static void sh_cmt_disable(struct sh_cmt_channel *ch)
407392
/* disable interrupts in CMT block */
408393
sh_cmt_write_cmcsr(ch, 0);
409394

410-
/* stop clock */
411-
clk_disable(ch->cmt->clk);
412-
413395
dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
414396
}
415397

@@ -583,8 +565,6 @@ static int sh_cmt_start_clocksource(struct sh_cmt_channel *ch)
583565
int ret = 0;
584566
unsigned long flags;
585567

586-
pm_runtime_get_sync(&ch->cmt->pdev->dev);
587-
588568
raw_spin_lock_irqsave(&ch->lock, flags);
589569

590570
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
@@ -619,8 +599,6 @@ static void sh_cmt_stop_clocksource(struct sh_cmt_channel *ch)
619599
sh_cmt_disable(ch);
620600

621601
raw_spin_unlock_irqrestore(&ch->lock, flags);
622-
623-
pm_runtime_put(&ch->cmt->pdev->dev);
624602
}
625603

626604
static int sh_cmt_start_clockevent(struct sh_cmt_channel *ch)
@@ -630,10 +608,8 @@ static int sh_cmt_start_clockevent(struct sh_cmt_channel *ch)
630608

631609
raw_spin_lock_irqsave(&ch->lock, flags);
632610

633-
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
634-
pm_runtime_get_sync(&ch->cmt->pdev->dev);
611+
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
635612
ret = sh_cmt_enable(ch);
636-
}
637613

638614
if (ret)
639615
goto out;
@@ -656,10 +632,8 @@ static void sh_cmt_stop_clockevent(struct sh_cmt_channel *ch)
656632

657633
ch->flags &= ~FLAG_CLOCKEVENT;
658634

659-
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
635+
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
660636
sh_cmt_disable(ch);
661-
pm_runtime_put(&ch->cmt->pdev->dev);
662-
}
663637

664638
/* adjust the timeout to maximum if only clocksource left */
665639
if (ch->flags & FLAG_CLOCKSOURCE)
@@ -1134,8 +1108,6 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
11341108
mask &= ~(1 << hwidx);
11351109
}
11361110

1137-
clk_disable(cmt->clk);
1138-
11391111
platform_set_drvdata(pdev, cmt);
11401112

11411113
return 0;
@@ -1183,8 +1155,6 @@ static int sh_cmt_probe(struct platform_device *pdev)
11831155
out:
11841156
if (cmt->has_clockevent || cmt->has_clocksource)
11851157
pm_runtime_irq_safe(&pdev->dev);
1186-
else
1187-
pm_runtime_idle(&pdev->dev);
11881158

11891159
return 0;
11901160
}

0 commit comments

Comments
 (0)