diff options
author | Scott Wood <scottwood@freescale.com> | 2014-05-14 18:19:12 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-05-14 18:37:18 (GMT) |
commit | 86ba38e6f5f2fbfe9b49e153ea89593b26482019 (patch) | |
tree | f99d2906b0eafca507f37289e68052fc105cc2dc /kernel/hrtimer.c | |
parent | 07c8b57b111585a617b2b456497fc9b33c00743c (diff) | |
download | linux-fsl-qoriq-86ba38e6f5f2fbfe9b49e153ea89593b26482019.tar.xz |
Reset to 3.12.19
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r-- | kernel/hrtimer.c | 370 |
1 files changed, 52 insertions, 318 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index c19183d..383319b 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -47,13 +47,11 @@ #include <linux/sched/sysctl.h> #include <linux/sched/rt.h> #include <linux/timer.h> -#include <linux/kthread.h> #include <linux/freezer.h> #include <asm/uaccess.h> #include <trace/events/timer.h> -#include <trace/events/hist.h> /* * The timer bases: @@ -609,7 +607,8 @@ static int hrtimer_reprogram(struct hrtimer *timer, * When the callback is running, we do not reprogram the clock event * device. The timer callback is either running on a different CPU or * the callback is executed in the hrtimer_interrupt context. The - * reprogramming is handled at the end of the hrtimer_interrupt. + * reprogramming is handled either by the softirq, which called the + * callback or at the end of the hrtimer_interrupt. */ if (hrtimer_callback_running(timer)) return 0; @@ -644,9 +643,6 @@ static int hrtimer_reprogram(struct hrtimer *timer, return res; } -static void __run_hrtimer(struct hrtimer *timer, ktime_t *now); -static int hrtimer_rt_defer(struct hrtimer *timer); - /* * Initialize the high resolution related parts of cpu_base */ @@ -663,18 +659,9 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) * and expiry check is done in the hrtimer_interrupt or in the softirq. */ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base, - int wakeup) + struct hrtimer_clock_base *base) { - if (!(base->cpu_base->hres_active && hrtimer_reprogram(timer, base))) - return 0; - if (!wakeup) - return -ETIME; -#ifdef CONFIG_PREEMPT_RT_BASE - if (!hrtimer_rt_defer(timer)) - return -ETIME; -#endif - return 1; + return base->cpu_base->hres_active && hrtimer_reprogram(timer, base); } static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) @@ -742,44 +729,6 @@ static void clock_was_set_work(struct work_struct *work) static DECLARE_WORK(hrtimer_work, clock_was_set_work); -#ifdef CONFIG_PREEMPT_RT_FULL -/* - * RT can not call schedule_work from real interrupt context. - * Need to make a thread to do the real work. - */ -static struct task_struct *clock_set_delay_thread; -static bool do_clock_set_delay; - -static int run_clock_set_delay(void *ignore) -{ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - if (do_clock_set_delay) { - do_clock_set_delay = false; - schedule_work(&hrtimer_work); - } - schedule(); - } - __set_current_state(TASK_RUNNING); - return 0; -} - -void clock_was_set_delayed(void) -{ - do_clock_set_delay = true; - /* Make visible before waking up process */ - smp_wmb(); - wake_up_process(clock_set_delay_thread); -} - -static __init int create_clock_set_delay_thread(void) -{ - clock_set_delay_thread = kthread_run(run_clock_set_delay, NULL, "kclksetdelayd"); - BUG_ON(!clock_set_delay_thread); - return 0; -} -early_initcall(create_clock_set_delay_thread); -#else /* PREEMPT_RT_FULL */ /* * Called from timekeeping and resume code to reprogramm the hrtimer * interrupt device on all cpus. @@ -788,7 +737,6 @@ void clock_was_set_delayed(void) { schedule_work(&hrtimer_work); } -#endif #else @@ -798,18 +746,12 @@ static inline int hrtimer_switch_to_hres(void) { return 0; } static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base, - int wakeup) + struct hrtimer_clock_base *base) { return 0; } static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { } static inline void retrigger_next_event(void *arg) { } -static inline int hrtimer_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - return 0; -} #endif /* CONFIG_HIGH_RES_TIMERS */ @@ -928,32 +870,6 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) } EXPORT_SYMBOL_GPL(hrtimer_forward); -#ifdef CONFIG_PREEMPT_RT_BASE -# define wake_up_timer_waiters(b) wake_up(&(b)->wait) - -/** - * hrtimer_wait_for_timer - Wait for a running timer - * - * @timer: timer to wait for - * - * The function waits in case the timers callback function is - * currently executed on the waitqueue of the timer base. The - * waitqueue is woken up after the timer callback function has - * finished execution. - */ -void hrtimer_wait_for_timer(const struct hrtimer *timer) -{ - struct hrtimer_clock_base *base = timer->base; - - if (base && base->cpu_base && !timer->irqsafe) - wait_event(base->cpu_base->wait, - !(timer->state & HRTIMER_STATE_CALLBACK)); -} - -#else -# define wake_up_timer_waiters(b) do { } while (0) -#endif - /* * enqueue_hrtimer - internal function to (re)start a timer * @@ -997,11 +913,6 @@ static void __remove_hrtimer(struct hrtimer *timer, if (!(timer->state & HRTIMER_STATE_ENQUEUED)) goto out; - if (unlikely(!list_empty(&timer->cb_entry))) { - list_del_init(&timer->cb_entry); - goto out; - } - next_timer = timerqueue_getnext(&base->active); timerqueue_del(&base->active, &timer->node); if (&timer->node == next_timer) { @@ -1086,17 +997,6 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, #endif } -#ifdef CONFIG_MISSED_TIMER_OFFSETS_HIST - { - ktime_t now = new_base->get_time(); - - if (ktime_to_ns(tim) < ktime_to_ns(now)) - timer->praecox = now; - else - timer->praecox = ktime_set(0, 0); - } -#endif - hrtimer_set_expires_range_ns(timer, tim, delta_ns); timer_stats_hrtimer_set_start_info(timer); @@ -1109,19 +1009,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, * * XXX send_remote_softirq() ? */ - if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) { - ret = hrtimer_enqueue_reprogram(timer, new_base, wakeup); - if (ret < 0) { - /* - * In case we failed to reprogram the timer (mostly - * because out current timer is already elapsed), - * remove it again and report a failure. This avoids - * stale base->first entries. - */ - debug_deactivate(timer); - __remove_hrtimer(timer, new_base, - timer->state & HRTIMER_STATE_CALLBACK, 0); - } else if (ret > 0) { + if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases) + && hrtimer_enqueue_reprogram(timer, new_base)) { + if (wakeup) { /* * We need to drop cpu_base->lock to avoid a * lock ordering issue vs. rq->lock. @@ -1129,7 +1019,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, raw_spin_unlock(&new_base->cpu_base->lock); raise_softirq_irqoff(HRTIMER_SOFTIRQ); local_irq_restore(flags); - return 0; + return ret; + } else { + __raise_softirq_irqoff(HRTIMER_SOFTIRQ); } } @@ -1219,7 +1111,7 @@ int hrtimer_cancel(struct hrtimer *timer) if (ret >= 0) return ret; - hrtimer_wait_for_timer(timer); + cpu_relax(); } } EXPORT_SYMBOL_GPL(hrtimer_cancel); @@ -1298,7 +1190,6 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, base = hrtimer_clockid_to_base(clock_id); timer->base = &cpu_base->clock_base[base]; - INIT_LIST_HEAD(&timer->cb_entry); timerqueue_init(&timer->node); #ifdef CONFIG_TIMER_STATS @@ -1382,126 +1273,6 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now) timer->state &= ~HRTIMER_STATE_CALLBACK; } -static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer); - -#ifdef CONFIG_PREEMPT_RT_BASE -static void hrtimer_rt_reprogram(int restart, struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - /* - * Note, we clear the callback flag before we requeue the - * timer otherwise we trigger the callback_running() check - * in hrtimer_reprogram(). - */ - timer->state &= ~HRTIMER_STATE_CALLBACK; - - if (restart != HRTIMER_NORESTART) { - BUG_ON(hrtimer_active(timer)); - /* - * Enqueue the timer, if it's the leftmost timer then - * we need to reprogram it. - */ - if (!enqueue_hrtimer(timer, base)) - return; - -#ifndef CONFIG_HIGH_RES_TIMERS - } -#else - if (base->cpu_base->hres_active && - hrtimer_reprogram(timer, base)) - goto requeue; - - } else if (hrtimer_active(timer)) { - /* - * If the timer was rearmed on another CPU, reprogram - * the event device. - */ - if (&timer->node == base->active.next && - base->cpu_base->hres_active && - hrtimer_reprogram(timer, base)) - goto requeue; - } - return; - -requeue: - /* - * Timer is expired. Thus move it from tree to pending list - * again. - */ - __remove_hrtimer(timer, base, timer->state, 0); - list_add_tail(&timer->cb_entry, &base->expired); -#endif -} - -/* - * The changes in mainline which removed the callback modes from - * hrtimer are not yet working with -rt. The non wakeup_process() - * based callbacks which involve sleeping locks need to be treated - * seperately. - */ -static void hrtimer_rt_run_pending(void) -{ - enum hrtimer_restart (*fn)(struct hrtimer *); - struct hrtimer_cpu_base *cpu_base; - struct hrtimer_clock_base *base; - struct hrtimer *timer; - int index, restart; - - local_irq_disable(); - cpu_base = &per_cpu(hrtimer_bases, smp_processor_id()); - - raw_spin_lock(&cpu_base->lock); - - for (index = 0; index < HRTIMER_MAX_CLOCK_BASES; index++) { - base = &cpu_base->clock_base[index]; - - while (!list_empty(&base->expired)) { - timer = list_first_entry(&base->expired, - struct hrtimer, cb_entry); - - /* - * Same as the above __run_hrtimer function - * just we run with interrupts enabled. - */ - debug_hrtimer_deactivate(timer); - __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); - timer_stats_account_hrtimer(timer); - fn = timer->function; - - raw_spin_unlock_irq(&cpu_base->lock); - restart = fn(timer); - raw_spin_lock_irq(&cpu_base->lock); - - hrtimer_rt_reprogram(restart, timer, base); - } - } - - raw_spin_unlock_irq(&cpu_base->lock); - - wake_up_timer_waiters(cpu_base); -} - -static int hrtimer_rt_defer(struct hrtimer *timer) -{ - if (timer->irqsafe) - return 0; - - __remove_hrtimer(timer, timer->base, timer->state, 0); - list_add_tail(&timer->cb_entry, &timer->base->expired); - return 1; -} - -#else - -static inline void hrtimer_rt_run_pending(void) -{ - hrtimer_peek_ahead_timers(); -} - -static inline int hrtimer_rt_defer(struct hrtimer *timer) { return 0; } - -#endif - #ifdef CONFIG_HIGH_RES_TIMERS /* @@ -1512,7 +1283,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) { struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); ktime_t expires_next, now, entry_time, delta; - int i, retries = 0, raise = 0; + int i, retries = 0; BUG_ON(!cpu_base->hres_active); cpu_base->nr_events++; @@ -1547,15 +1318,6 @@ retry: timer = container_of(node, struct hrtimer, node); - trace_hrtimer_interrupt(raw_smp_processor_id(), - ktime_to_ns(ktime_sub(ktime_to_ns(timer->praecox) ? - timer->praecox : hrtimer_get_expires(timer), - basenow)), - current, - timer->function == hrtimer_wakeup ? - container_of(timer, struct hrtimer_sleeper, - timer)->task : NULL); - /* * The immediate goal for using the softexpires is * minimizing wakeups, not running timers at the @@ -1581,10 +1343,7 @@ retry: break; } - if (!hrtimer_rt_defer(timer)) - __run_hrtimer(timer, &basenow); - else - raise = 1; + __run_hrtimer(timer, &basenow); } } @@ -1599,7 +1358,7 @@ retry: if (expires_next.tv64 == KTIME_MAX || !tick_program_event(expires_next, 0)) { cpu_base->hang_detected = 0; - goto out; + return; } /* @@ -1643,9 +1402,6 @@ retry: tick_program_event(expires_next, 1); printk_once(KERN_WARNING "hrtimer: interrupt took %llu ns\n", ktime_to_ns(delta)); -out: - if (raise) - raise_softirq_irqoff(HRTIMER_SOFTIRQ); } /* @@ -1681,16 +1437,40 @@ void hrtimer_peek_ahead_timers(void) __hrtimer_peek_ahead_timers(); local_irq_restore(flags); } + +static void run_hrtimer_softirq(struct softirq_action *h) +{ + hrtimer_peek_ahead_timers(); +} + #else /* CONFIG_HIGH_RES_TIMERS */ static inline void __hrtimer_peek_ahead_timers(void) { } #endif /* !CONFIG_HIGH_RES_TIMERS */ - -static void run_hrtimer_softirq(struct softirq_action *h) +/* + * Called from timer softirq every jiffy, expire hrtimers: + * + * For HRT its the fall back code to run the softirq in the timer + * softirq context in case the hrtimer initialization failed or has + * not been done yet. + */ +void hrtimer_run_pending(void) { - hrtimer_rt_run_pending(); + if (hrtimer_hres_active()) + return; + + /* + * This _is_ ugly: We have to check in the softirq context, + * whether we can switch to highres and / or nohz mode. The + * clocksource switch happens in the timer interrupt with + * xtime_lock held. Notification from there only sets the + * check bit in the tick_oneshot code, otherwise we might + * deadlock vs. xtime_lock. + */ + if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) + hrtimer_switch_to_hres(); } /* @@ -1701,18 +1481,11 @@ void hrtimer_run_queues(void) struct timerqueue_node *node; struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); struct hrtimer_clock_base *base; - int index, gettime = 1, raise = 0; + int index, gettime = 1; if (hrtimer_hres_active()) return; - /* - * Check whether we can switch to highres mode. - */ - if (tick_check_oneshot_change(!hrtimer_is_hres_enabled()) - && hrtimer_switch_to_hres()) - return; - for (index = 0; index < HRTIMER_MAX_CLOCK_BASES; index++) { base = &cpu_base->clock_base[index]; if (!timerqueue_getnext(&base->active)) @@ -1733,16 +1506,10 @@ void hrtimer_run_queues(void) hrtimer_get_expires_tv64(timer)) break; - if (!hrtimer_rt_defer(timer)) - __run_hrtimer(timer, &base->softirq_time); - else - raise = 1; + __run_hrtimer(timer, &base->softirq_time); } raw_spin_unlock(&cpu_base->lock); } - - if (raise) - raise_softirq_irqoff(HRTIMER_SOFTIRQ); } /* @@ -1764,18 +1531,16 @@ static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer) void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) { sl->timer.function = hrtimer_wakeup; - sl->timer.irqsafe = 1; sl->task = task; } EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); -static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode, - unsigned long state) +static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) { hrtimer_init_sleeper(t, current); do { - set_current_state(state); + set_current_state(TASK_INTERRUPTIBLE); hrtimer_start_expires(&t->timer, mode); if (!hrtimer_active(&t->timer)) t->task = NULL; @@ -1819,8 +1584,7 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) HRTIMER_MODE_ABS); hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); - /* cpu_chill() does not care about restart state. */ - if (do_nanosleep(&t, HRTIMER_MODE_ABS, TASK_INTERRUPTIBLE)) + if (do_nanosleep(&t, HRTIMER_MODE_ABS)) goto out; rmtp = restart->nanosleep.rmtp; @@ -1837,10 +1601,8 @@ out: return ret; } -static long -__hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, - const enum hrtimer_mode mode, const clockid_t clockid, - unsigned long state) +long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, + const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; struct hrtimer_sleeper t; @@ -1853,7 +1615,7 @@ __hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, hrtimer_init_on_stack(&t.timer, clockid, mode); hrtimer_set_expires_range_ns(&t.timer, timespec_to_ktime(*rqtp), slack); - if (do_nanosleep(&t, mode, state)) + if (do_nanosleep(&t, mode)) goto out; /* Absolute timers do not update the rmtp value and restart: */ @@ -1880,12 +1642,6 @@ out: return ret; } -long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, - const enum hrtimer_mode mode, const clockid_t clockid) -{ - return __hrtimer_nanosleep(rqtp, rmtp, mode, clockid, TASK_INTERRUPTIBLE); -} - SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, struct timespec __user *, rmtp) { @@ -1900,26 +1656,6 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); } -#ifdef CONFIG_PREEMPT_RT_FULL -/* - * Sleep for 1 ms in hope whoever holds what we want will let it go. - */ -void cpu_chill(void) -{ - struct timespec tu = { - .tv_nsec = NSEC_PER_MSEC, - }; - unsigned int freeze_flag = current->flags & PF_NOFREEZE; - - current->flags |= PF_NOFREEZE; - __hrtimer_nanosleep(&tu, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC, - TASK_UNINTERRUPTIBLE); - if (!freeze_flag) - current->flags &= ~PF_NOFREEZE; -} -EXPORT_SYMBOL(cpu_chill); -#endif - /* * Functions related to boot-time initialization: */ @@ -1931,13 +1667,9 @@ static void init_hrtimers_cpu(int cpu) for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { cpu_base->clock_base[i].cpu_base = cpu_base; timerqueue_init_head(&cpu_base->clock_base[i].active); - INIT_LIST_HEAD(&cpu_base->clock_base[i].expired); } hrtimer_init_hres(cpu_base); -#ifdef CONFIG_PREEMPT_RT_BASE - init_waitqueue_head(&cpu_base->wait); -#endif } #ifdef CONFIG_HOTPLUG_CPU @@ -2050,7 +1782,9 @@ void __init hrtimers_init(void) hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); register_cpu_notifier(&hrtimers_nb); +#ifdef CONFIG_HIGH_RES_TIMERS open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq); +#endif } /** |