linux/kernel/time
Niklas Söderlund d4c7c28806 timekeeping: Allow runtime PM from change_clocksource()
The struct clocksource callbacks enable() and disable() are described as a
way to allow clock sources to enter a power save mode. See commit
4614e6adaf ("clocksource: add enable() and disable() callbacks")

But using runtime PM from these callbacks triggers a cyclic lockdep warning when
switching clock source using change_clocksource().

  # echo e60f0000.timer > /sys/devices/system/clocksource/clocksource0/current_clocksource
   ======================================================
   WARNING: possible circular locking dependency detected
   ------------------------------------------------------
   migration/0/11 is trying to acquire lock:
   ffff0000403ed220 (&dev->power.lock){-...}-{2:2}, at: __pm_runtime_resume+0x40/0x74

   but task is already holding lock:
   ffff8000113c8f88 (tk_core.seq.seqcount){----}-{0:0}, at: multi_cpu_stop+0xa4/0x190

   which lock already depends on the new lock.

   the existing dependency chain (in reverse order) is:

   -> #2 (tk_core.seq.seqcount){----}-{0:0}:
          ktime_get+0x28/0xa0
          hrtimer_start_range_ns+0x210/0x2dc
          generic_sched_clock_init+0x70/0x88
          sched_clock_init+0x40/0x64
          start_kernel+0x494/0x524

   -> #1 (hrtimer_bases.lock){-.-.}-{2:2}:
          hrtimer_start_range_ns+0x68/0x2dc
          rpm_suspend+0x308/0x5dc
          rpm_idle+0xc4/0x2a4
          pm_runtime_work+0x98/0xc0
          process_one_work+0x294/0x6f0
          worker_thread+0x70/0x45c
          kthread+0x154/0x160
          ret_from_fork+0x10/0x20

   -> #0 (&dev->power.lock){-...}-{2:2}:
          _raw_spin_lock_irqsave+0x7c/0xc4
          __pm_runtime_resume+0x40/0x74
          sh_cmt_start+0x1c4/0x260
          sh_cmt_clocksource_enable+0x28/0x50
          change_clocksource+0x9c/0x160
          multi_cpu_stop+0xa4/0x190
          cpu_stopper_thread+0x90/0x154
          smpboot_thread_fn+0x244/0x270
          kthread+0x154/0x160
          ret_from_fork+0x10/0x20

   other info that might help us debug this:

   Chain exists of:
     &dev->power.lock --> hrtimer_bases.lock --> tk_core.seq.seqcount

    Possible unsafe locking scenario:

          CPU0                    CPU1
          ----                    ----
     lock(tk_core.seq.seqcount);
                                  lock(hrtimer_bases.lock);
                                  lock(tk_core.seq.seqcount);
     lock(&dev->power.lock);

    *** DEADLOCK ***

   2 locks held by migration/0/11:
    #0: ffff8000113c9278 (timekeeper_lock){-.-.}-{2:2}, at: change_clocksource+0x2c/0x160
    #1: ffff8000113c8f88 (tk_core.seq.seqcount){----}-{0:0}, at: multi_cpu_stop+0xa4/0x190

Rework change_clocksource() so it enables the new clocksource and disables
the old clocksource outside of the timekeeper_lock and seqcount write held
region. There is no requirement that these callbacks are invoked from the
lock held region.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://lore.kernel.org/r/20210211134318.323910-1-niklas.soderlund+renesas@ragnatech.se
2021-03-29 16:41:59 +02:00
..
alarmtimer.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
clockevents.c tick: Remove outgoing CPU from broadcast masks 2019-03-23 18:26:43 +01:00
clocksource.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
hrtimer.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
itimer.c time: Prevent undefined behaviour in timespec64_to_ns() 2020-10-26 11:48:11 +01:00
jiffies.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
Kconfig Update/fix two CPU sanity checks in the hotplug and the boot code, 2020-12-27 09:03:41 -08:00
Makefile timekeeping: add CONFIG_LEGACY_TIMER_TICK 2020-10-30 21:57:04 +01:00
namespace.c timens: Delete no-op time_ns_init() 2021-02-05 19:32:09 +01:00
ntp_internal.h ntp: Make the RTC synchronization more reliable 2020-12-11 10:40:52 +01:00
ntp.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
posix-clock.c posix-clocks: Rename the clock_get() callback to clock_get_timespec() 2020-01-14 12:20:49 +01:00
posix-cpu-timers.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
posix-stubs.c posix-timers: Make clock_nanosleep() time namespace aware 2020-01-14 12:20:55 +01:00
posix-timers.c treewide: Use fallthrough pseudo-keyword 2020-08-23 17:36:59 -05:00
posix-timers.h posix-clocks: Introduce clock_get_ktime() callback 2020-01-14 12:20:51 +01:00
sched_clock.c time/sched_clock: Mark sched_clock_read_begin/retry() as notrace 2020-10-26 11:34:31 +01:00
test_udelay.c time/debug: Remove dentry pointer for debugfs 2021-03-18 11:20:26 +01:00
tick-broadcast-hrtimer.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
tick-broadcast.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
tick-common.c tick: Remove pointless cpu valid check in hotplug code 2020-12-16 11:26:27 +01:00
tick-internal.h tick: Get rid of tick_period 2020-11-19 10:48:29 +01:00
tick-legacy.c timekeeping: remove xtime_update 2020-10-30 21:57:07 +01:00
tick-oneshot.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
tick-sched.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
tick-sched.h timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
time.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
timeconst.bc time: Add SPDX license identifiers 2018-11-23 11:51:20 +01:00
timeconv.c time: Add missing colons for parameter documentation of time64_to_tm() 2020-11-15 23:47:23 +01:00
timecounter.c time: Remove license boilerplate 2018-11-23 11:51:21 +01:00
timekeeping_debug.c timekeeping/debug: No need to check return value of debugfs_create functions 2019-01-29 20:08:41 +01:00
timekeeping_internal.h timekeeping/vsyscall: Provide vdso_update_begin/end() 2020-08-06 10:57:30 +02:00
timekeeping.c timekeeping: Allow runtime PM from change_clocksource() 2021-03-29 16:41:59 +02:00
timekeeping.h asm-generic: cross-architecture timer cleanup 2020-12-16 00:07:17 -08:00
timer_list.c timer_list: Use printk format instead of open-coded symbol lookup 2020-11-15 20:47:14 +01:00
timer.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00
vsyscall.c timekeeping, clocksource: Fix various typos in comments 2021-03-22 23:06:48 +01:00