The patch titled hrt/dynticks hotplug fix has been added to the -mm tree. Its filename is hrt-dynticks-hotplug-fix.patch *** Remember to use Documentation/SubmitChecklist when testing your code *** See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this ------------------------------------------------------ Subject: hrt/dynticks hotplug fix From: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Ingo found some inconsistencies in the suspend/resume behaviour and we tracked them down. The fix below works on most systems. but my jinxed VAIO still plays silly buggers with me. At least it resumes now as reliable as with mainline (one of three attempts). Ingo is not longer around to verify, but I'm quite sure that this is the correct fix (+/- my current distraction). This is a leftover of the original clockevents design, which worked by chance so we never noticed that it is buggy. I just kept it as is when I distangled the old clockevents code. Cc: Ingo Molnar <mingo@xxxxxxx> Cc: john stultz <johnstul@xxxxxxxxxx> Cc: Roman Zippel <zippel@xxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- include/linux/clockchips.h | 2 - kernel/hrtimer.c | 1 kernel/time/clockevents.c | 35 ++++++++++++----------- kernel/time/tick-broadcast.c | 49 ++++++++++++++++++++++----------- kernel/time/tick-common.c | 28 ++++++++++++++++-- kernel/time/tick-internal.h | 20 +++---------- kernel/time/tick-sched.c | 2 + kernel/timer.c | 2 - 8 files changed, 86 insertions(+), 53 deletions(-) diff -puN include/linux/clockchips.h~hrt-dynticks-hotplug-fix include/linux/clockchips.h --- a/include/linux/clockchips.h~hrt-dynticks-hotplug-fix +++ a/include/linux/clockchips.h @@ -34,6 +34,7 @@ enum clock_event_nofitiers { CLOCK_EVT_NOTIFY_BROADCAST_EXIT, CLOCK_EVT_NOTIFY_SUSPEND, CLOCK_EVT_NOTIFY_RESUME, + CLOCK_EVT_NOTIFY_CPU_DEAD, }; /* @@ -129,7 +130,6 @@ extern void clockevents_unregister_notif extern int clockevents_program_event(struct clock_event_device *dev, ktime_t expires); -extern void clockevents_resume_events(void); extern void clockevents_notify(unsigned long reason, void *arg); #else diff -puN kernel/hrtimer.c~hrt-dynticks-hotplug-fix kernel/hrtimer.c --- a/kernel/hrtimer.c~hrt-dynticks-hotplug-fix +++ a/kernel/hrtimer.c @@ -1384,6 +1384,7 @@ static int __cpuinit hrtimer_cpu_notify( #ifdef CONFIG_HOTPLUG_CPU case CPU_DEAD: + clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu); migrate_hrtimers(cpu); break; #endif diff -puN kernel/time/clockevents.c~hrt-dynticks-hotplug-fix kernel/time/clockevents.c --- a/kernel/time/clockevents.c~hrt-dynticks-hotplug-fix +++ a/kernel/time/clockevents.c @@ -248,26 +248,27 @@ void clockevents_notify(unsigned long re { spin_lock(&clockevents_lock); clockevents_do_notify(reason, arg); - spin_unlock(&clockevents_lock); -} -EXPORT_SYMBOL_GPL(clockevents_notify); -void clockevents_do_resume_events(void *arg) -{ - spin_lock(&clockevents_lock); - clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL); + switch (reason) { + case CLOCK_EVT_NOTIFY_CPU_DEAD: + /* + * Unregister the clock event devices which were + * released from the users in the notify chain. + */ + while (!list_empty(&clockevents_released)) { + struct clock_event_device *dev; + + dev = list_entry(clockevents_released.next, + struct clock_event_device, list); + list_del(&dev->list); + } + break; + default: + break; + } spin_unlock(&clockevents_lock); } - -/** - * clockevents_resume_events - resume the active clock devices - * - * Called after timekeeping is functional again - */ -void clockevents_resume_events(void) -{ - on_each_cpu(clockevents_do_resume_events, NULL, 0, 1); -} +EXPORT_SYMBOL_GPL(clockevents_notify); #ifdef CONFIG_SYSFS diff -puN kernel/timer.c~hrt-dynticks-hotplug-fix kernel/timer.c --- a/kernel/timer.c~hrt-dynticks-hotplug-fix +++ a/kernel/timer.c @@ -995,7 +995,7 @@ static int timekeeping_resume(struct sys timekeeping_suspended = 0; write_sequnlock_irqrestore(&xtime_lock, flags); - clockevents_resume_events(); + clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL); /* Resume hrtimers */ clock_was_set(); diff -puN kernel/time/tick-broadcast.c~hrt-dynticks-hotplug-fix kernel/time/tick-broadcast.c --- a/kernel/time/tick-broadcast.c~hrt-dynticks-hotplug-fix +++ a/kernel/time/tick-broadcast.c @@ -261,17 +261,25 @@ void tick_set_periodic_handler(struct cl } /* - * Called with irqs disabled + * Remove a CPU from broadcasting */ -void tick_do_resume(int cpu) +void tick_shutdown_broadcast(unsigned int *cpup) { - unsigned long reason; + struct clock_event_device *bc; + unsigned long flags; + unsigned int cpu = *cpup; + + spin_lock_irqsave(&tick_broadcast_lock, flags); - reason = cpu_isset(cpu, tick_broadcast_mask) ? - CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; - tick_do_broadcast_on_off(&reason); + bc = tick_broadcast_device.evtdev; + cpu_clear(cpu, tick_broadcast_mask); - tick_oneshot_resume(cpu); + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { + if (bc && cpus_empty(tick_broadcast_mask)) + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); + } + + spin_unlock_irqrestore(&tick_broadcast_lock, flags); } #ifdef CONFIG_TICK_ONESHOT @@ -434,16 +442,27 @@ void tick_broadcast_switch_to_oneshot(vo spin_unlock_irqrestore(&tick_broadcast_lock, flags); } -/** - * Called with irqs disabled + +/* + * Remove a dead CPU from broadcasting */ -void tick_oneshot_resume(int cpu) +void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { - unsigned long reason; + struct clock_event_device *bc; + unsigned long flags; + unsigned int cpu = *cpup; + + spin_lock_irqsave(&tick_broadcast_lock, flags); + + bc = tick_broadcast_device.evtdev; + cpu_clear(cpu, tick_broadcast_oneshot_mask); + + if (tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT) { + if (bc && cpus_empty(tick_broadcast_oneshot_mask)) + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); + } - reason = cpu_isset(cpu, tick_broadcast_oneshot_mask) ? - CLOCK_EVT_NOTIFY_BROADCAST_ENTER : - CLOCK_EVT_NOTIFY_BROADCAST_EXIT; - tick_broadcast_oneshot_control(reason); + spin_unlock_irqrestore(&tick_broadcast_lock, flags); } + #endif diff -puN kernel/time/tick-common.c~hrt-dynticks-hotplug-fix kernel/time/tick-common.c --- a/kernel/time/tick-common.c~hrt-dynticks-hotplug-fix +++ a/kernel/time/tick-common.c @@ -271,14 +271,29 @@ out: } /* - * Resume tick devices + * Shutdown an event device on a given cpu: + * + * This is called on a life CPU, when a CPU is dead. So we cannot + * access the hardware device itself. + * We just set the mode and remove it from the lists. */ -static void tick_resume(void) +static void tick_shutdown(unsigned int *cpup) { + struct tick_device *td = &per_cpu(tick_cpu_device, *cpup); + struct clock_event_device *dev = td->evtdev; unsigned long flags; spin_lock_irqsave(&tick_device_lock, flags); - tick_do_resume(smp_processor_id()); + td->mode = TICKDEV_MODE_PERIODIC; + if (dev) { + /* + * Prevent that the clock events layer tries to call + * the set mode function! + */ + dev->mode = CLOCK_EVT_MODE_UNUSED; + clockevents_exchange_device(dev, NULL); + td->evtdev = NULL; + } spin_unlock_irqrestore(&tick_device_lock, flags); } @@ -305,7 +320,12 @@ static int tick_notify(struct notifier_b case CLOCK_EVT_NOTIFY_RESUME: tick_resume_jiffy_update(); - tick_resume(); + break; + + case CLOCK_EVT_NOTIFY_CPU_DEAD: + tick_shutdown_broadcast_oneshot(dev); + tick_shutdown_broadcast(dev); + tick_shutdown(dev); break; default: diff -puN kernel/time/tick-internal.h~hrt-dynticks-hotplug-fix kernel/time/tick-internal.h --- a/kernel/time/tick-internal.h~hrt-dynticks-hotplug-fix +++ a/kernel/time/tick-internal.h @@ -20,12 +20,12 @@ extern void tick_resume_jiffy_update(voi extern int tick_program_event(ktime_t expires, int force); extern void tick_oneshot_notify(void); extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); -extern void tick_oneshot_resume(int cpu); # ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc); extern void tick_broadcast_oneshot_control(unsigned long reason); extern void tick_broadcast_switch_to_oneshot(void); +extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); # else /* BROADCAST */ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { @@ -33,6 +33,7 @@ static inline void tick_broadcast_setup_ } static inline void tick_broadcast_oneshot_control(unsigned long reason) { } static inline void tick_broadcast_switch_to_oneshot(void) { } +static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } # endif /* !BROADCAST */ #else /* !ONESHOT */ @@ -48,13 +49,13 @@ static inline int tick_program_event(kti return 0; } static inline void tick_resume_jiffy_update(void) { } -static inline void tick_oneshot_resume(int cpu) { } static inline void tick_oneshot_notify(void) { } static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); } static inline void tick_broadcast_oneshot_control(unsigned long reason) { } +static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } #endif /* !TICK_ONESHOT */ /* @@ -67,10 +68,10 @@ extern int tick_device_uses_broadcast(st extern int tick_check_broadcast_device(struct clock_event_device *dev); extern int tick_is_broadcast_device(struct clock_event_device *dev); extern void tick_broadcast_on_off(unsigned long reason, int *oncpu); +extern void tick_shutdown_broadcast(unsigned int *cpup); extern void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast); -extern void tick_do_resume(int cpu); #else /* !BROADCAST */ @@ -90,6 +91,7 @@ static inline int tick_device_uses_broad } static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { } +static inline void tick_shutdown_broadcast(unsigned int *cpup) { } /* * Set the periodic handler in non broadcast mode @@ -99,18 +101,6 @@ static inline void tick_set_periodic_han { dev->event_handler = tick_handle_periodic; } -/* - * Called with irqs disabled - */ -static inline void tick_do_resume(int cpu) -{ - struct tick_device *td = &per_cpu(tick_cpu_device, cpu); - - if (td->mode == TICKDEV_MODE_PERIODIC) - tick_setup_periodic(td->evtdev, 0); - else - tick_oneshot_resume(cpu); -} #endif /* !BROADCAST */ /* diff -puN kernel/time/tick-sched.c~hrt-dynticks-hotplug-fix kernel/time/tick-sched.c --- a/kernel/time/tick-sched.c~hrt-dynticks-hotplug-fix +++ a/kernel/time/tick-sched.c @@ -502,6 +502,8 @@ void tick_cancel_sched_timer(int cpu) if (ts->sched_timer.base) hrtimer_cancel(&ts->sched_timer); + ts->tick_stopped = 0; + ts->nohz_mode = NOHZ_MODE_INACTIVE; } #endif /* HIGH_RES_TIMERS */ _ Patches currently in -mm which might be from tglx@xxxxxxxxxxxxx are origin.patch git-block.patch use-cycle_t-instead-of-u64-in-struct-time_interpolator.patch proc-remove-useless-and-buggy-nlink-settings.patch add-irq-flag-to-disable-balancing-for-an-interrupt.patch add-a-functions-to-handle-interrupt-affinity-setting.patch hz-free-ntp.patch uninline-jiffiesh-functions.patch fix-multiple-conversion-bugs-in-msecs_to_jiffies.patch fix-timeout-overflow-with-jiffies.patch gtod-persistent-clock-support.patch i386-use-gtod-persistent-clock-support.patch i386-remove-useless-code-in-tscc.patch simplify-the-registration-of-clocksources.patch x86-rewrite-smp-tsc-sync-code.patch clocksource-replace-is_continuous-by-a-flag-field.patch clocksource-replace-is_continuous-by-a-flag-field-fix.patch clocksource-fixup-is_continous-changes-on-arm.patch clocksource-fixup-is_continous-changes-on-avr32.patch clocksource-fixup-is_continous-changes-on-s390.patch clocksource-fixup-is_continous-changes-on-mips.patch clocksource-remove-the-update-callback.patch clocksource-add-verification-watchdog-helper.patch clocksource-add-verification-watchdog-helper-fix.patch mark-tsc-on-geodelx-reliable.patch uninline-irq_enter.patch fix-cascade-lookup-of-next_timer_interrupt.patch extend-next_timer_interrupt-to-use-a-reference-jiffie.patch hrtimers-namespace-and-enum-cleanup.patch hrtimers-namespace-and-enum-cleanup-vs-git-input.patch hrtimers-cleanup-locking.patch hrtimers-add-state-tracking.patch hrtimers-clean-up-callback-tracking.patch hrtimers-move-and-add-documentation.patch acpi-fix-missing-include-for-up.patch acpi-keep-track-of-timer-broadcasting.patch allow-early-access-to-the-power-management-timer.patch i386-apic-clean-up-the-apic-code.patch clockevents-add-core-functionality.patch tick-management-core-functionality.patch tick-management-broadcast-functionality.patch tick-management-dyntick--highres-functionality.patch clockevents-i383-drivers.patch i386-rework-local-apic-timer-calibration.patch i386-prepare-for-dyntick.patch i386-prepare-nmi-watchdog-for-dynticks.patch hrtimers-add-high-resolution-timer-support.patch hrtimers-prevent-possible-itimer-dos.patch add-debugging-feature-proc-timer_stat.patch add-debugging-feature-proc-timer_list.patch add-sysrq-q-to-print-timer_list-debug-info.patch hrt-dynticks-hotplug-fix.patch generic-vsyscall-gtod-support-for-generic_time.patch generic-vsyscall-gtod-support-for-generic_time-tidy.patch time-x86_64-hpet_address-cleanup.patch revert-x86_64-mm-ignore-long-smi-interrupts-in-clock-calibration.patch time-x86_64-split-x86_64-kernel-timec-up.patch time-x86_64-split-x86_64-kernel-timec-up-tidy.patch time-x86_64-split-x86_64-kernel-timec-up-fix.patch reapply-x86_64-mm-ignore-long-smi-interrupts-in-clock-calibration.patch time-x86_64-convert-x86_64-to-use-generic_time.patch time-x86_64-convert-x86_64-to-use-generic_time-fix.patch time-x86_64-convert-x86_64-to-use-generic_time-tidy.patch time-x86_64-hpet-fixup-clocksource-changes.patch time-x86_64-tsc-fixup-clocksource-changes.patch time-x86_64-re-enable-vsyscall-support-for-x86_64.patch time-x86_64-re-enable-vsyscall-support-for-x86_64-tidy.patch make-good_sigevent-non-static.patch aio-completion-signal-notification.patch scheduled-removal-of-sa_xxx-interrupt-flags-fixups.patch scheduled-removal-of-sa_xxx-interrupt-flags-fixups-2.patch scheduled-removal-of-sa_xxx-interrupt-flags.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html