diff --git a/include/linux/tick.h b/include/linux/tick.h index 535f528eaa97..9e99133a6000 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -111,6 +111,8 @@ enum tick_dep_bits { #define TICK_DEP_MASK_SCHED (1 << TICK_DEP_BIT_SCHED) #define TICK_DEP_MASK_CLOCK_UNSTABLE (1 << TICK_DEP_BIT_CLOCK_UNSTABLE) +extern void register_tick_sched_wakeup_callback(void (*cb)(void)); + #ifdef CONFIG_NO_HZ_COMMON extern bool tick_nohz_enabled; extern bool tick_nohz_tick_stopped(void); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 95c62850d9a4..f8256bb66bfa 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1258,6 +1259,9 @@ void tick_irq_enter(void) * High resolution timer specific code */ #ifdef CONFIG_HIGH_RES_TIMERS + +static void (*wake_callback)(void); + /* * We rearm the timer until we get disabled by the idle code. * Called with interrupts disabled. @@ -1275,8 +1279,15 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) * Do not call, when we are not in irq context and have * no valid regs pointer */ - if (regs) + if (regs) { tick_sched_handle(ts, regs); + if (wake_callback && tick_do_timer_cpu == smp_processor_id()) { + /* + * wakeup user if needed + */ + wake_callback(); + } + } else ts->next_tick = 0; @@ -1393,6 +1404,15 @@ int tick_check_oneshot_change(int allow_nohz) return 0; } +void register_tick_sched_wakeup_callback(void (*cb)(void)) +{ + if (!wake_callback) + wake_callback = cb; + else + pr_warn("tick-sched wake cb already exists; skipping.\n"); +} +EXPORT_SYMBOL_GPL(register_tick_sched_wakeup_callback); + ktime_t *get_next_event_cpu(unsigned int cpu) { return &(per_cpu(tick_cpu_device, cpu).evtdev->next_event);