diff options
| author | Bradley Morgan <include@grrlz.net> | 2026-08-13 07:43:42 +0000 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2026-09-11 15:53:53 +0200 |
| commit | 04cb4f75f314e137f0a0c38f9b4fd5c2b4b5667d (patch) | |
| tree | 3a402b5890ea5280c670a82b898c49a5e2b901b1 /drivers/clocksource | |
| parent | df2908090cda368b01ff43709f51890076c56157 (diff) | |
clocksource/drivers/timer-ti-dm: Unregister CPU PM notifier outside of the timer lock
omap_dm_timer_remove() calls cpu_pm_unregister_notifier() with
dm_timer_lock held and interrupts disabled. Nothing sleeps in there
today, but it pins the helper into a context where it can never be
allowed to sleep, which is in the way of restoring the RCU grace
period on the cpu_pm notifier chain.
Do the list lookup under the lock and move the unregister after the
unlock. Nothing can race it at that point: remove() owns the device,
and once the timer is off the list nobody can reach it anymore.
Signed-off-by: Bradley Morgan <include@grrlz.net>
Link: https://patch.msgid.link/20260813074343.26460-2-include@grrlz.net
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/timer-ti-dm.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 6787acac9a43..922a8f14562c 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -1528,7 +1528,7 @@ err_disable: */ static void omap_dm_timer_remove(struct platform_device *pdev) { - struct dmtimer *timer; + struct dmtimer *timer, *found = NULL; unsigned long flags; int ret = -EINVAL; @@ -1536,14 +1536,17 @@ static void omap_dm_timer_remove(struct platform_device *pdev) list_for_each_entry(timer, &omap_timer_list, node) if (!strcmp(dev_name(&timer->pdev->dev), dev_name(&pdev->dev))) { - if (!(timer->capability & OMAP_TIMER_ALWON)) - cpu_pm_unregister_notifier(&timer->nb); list_del(&timer->node); + found = timer; ret = 0; break; } spin_unlock_irqrestore(&dm_timer_lock, flags); + /* Unregister outside the lock: cpu_pm_unregister_notifier() may sleep. */ + if (found && !(found->capability & OMAP_TIMER_ALWON)) + cpu_pm_unregister_notifier(&found->nb); + pm_runtime_disable(&pdev->dev); if (ret) |
