| From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Date: Fri, 3 Jul 2009 08:44:31 -0500 |
| Subject: hrtimer: by timers by default into the softirq context |
| |
| We can't have hrtimers callbacks running in hardirq context on RT. Therefore |
| the timers are deferred to the softirq context by default. |
| There are few timers which expect to be run in hardirq context even on RT. |
| Those are: |
| - very short running where low latency is critical (kvm lapic) |
| - timers which take raw locks and need run in hard-irq context (perf, sched) |
| - wake up related timer (kernel side of clock_nanosleep() and so on) |
| |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| arch/x86/kvm/lapic.c | 2 +- |
| include/linux/hrtimer.h | 6 ++++++ |
| kernel/events/core.c | 4 ++-- |
| kernel/sched/core.c | 2 +- |
| kernel/sched/deadline.c | 2 +- |
| kernel/sched/rt.c | 4 ++-- |
| kernel/time/hrtimer.c | 21 +++++++++++++++++++-- |
| kernel/time/tick-broadcast-hrtimer.c | 2 +- |
| kernel/time/tick-sched.c | 2 +- |
| kernel/watchdog.c | 2 +- |
| 10 files changed, 35 insertions(+), 12 deletions(-) |
| |
| --- a/arch/x86/kvm/lapic.c |
| +++ b/arch/x86/kvm/lapic.c |
| @@ -2158,7 +2158,7 @@ int kvm_create_lapic(struct kvm_vcpu *vc |
| apic->vcpu = vcpu; |
| |
| hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, |
| - HRTIMER_MODE_ABS_PINNED); |
| + HRTIMER_MODE_ABS_PINNED_HARD); |
| apic->lapic_timer.timer.function = apic_timer_fn; |
| |
| /* |
| --- a/include/linux/hrtimer.h |
| +++ b/include/linux/hrtimer.h |
| @@ -42,6 +42,7 @@ enum hrtimer_mode { |
| HRTIMER_MODE_REL = 0x01, |
| HRTIMER_MODE_PINNED = 0x02, |
| HRTIMER_MODE_SOFT = 0x04, |
| + HRTIMER_MODE_HARD = 0x08, |
| |
| HRTIMER_MODE_ABS_PINNED = HRTIMER_MODE_ABS | HRTIMER_MODE_PINNED, |
| HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL | HRTIMER_MODE_PINNED, |
| @@ -52,6 +53,11 @@ enum hrtimer_mode { |
| HRTIMER_MODE_ABS_PINNED_SOFT = HRTIMER_MODE_ABS_PINNED | HRTIMER_MODE_SOFT, |
| HRTIMER_MODE_REL_PINNED_SOFT = HRTIMER_MODE_REL_PINNED | HRTIMER_MODE_SOFT, |
| |
| + HRTIMER_MODE_ABS_HARD = HRTIMER_MODE_ABS | HRTIMER_MODE_HARD, |
| + HRTIMER_MODE_REL_HARD = HRTIMER_MODE_REL | HRTIMER_MODE_HARD, |
| + |
| + HRTIMER_MODE_ABS_PINNED_HARD = HRTIMER_MODE_ABS_PINNED | HRTIMER_MODE_HARD, |
| + HRTIMER_MODE_REL_PINNED_HARD = HRTIMER_MODE_REL_PINNED | HRTIMER_MODE_HARD, |
| }; |
| |
| /* |
| --- a/kernel/events/core.c |
| +++ b/kernel/events/core.c |
| @@ -1090,7 +1090,7 @@ static void __perf_mux_hrtimer_init(stru |
| cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * interval); |
| |
| raw_spin_lock_init(&cpuctx->hrtimer_lock); |
| - hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); |
| + hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD); |
| timer->function = perf_mux_hrtimer_handler; |
| } |
| |
| @@ -8683,7 +8683,7 @@ static void perf_swevent_init_hrtimer(st |
| if (!is_sampling_event(event)) |
| return; |
| |
| - hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); |
| hwc->hrtimer.function = perf_swevent_hrtimer; |
| |
| /* |
| --- a/kernel/sched/core.c |
| +++ b/kernel/sched/core.c |
| @@ -344,7 +344,7 @@ static void init_rq_hrtick(struct rq *rq |
| rq->hrtick_csd.info = rq; |
| #endif |
| |
| - hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); |
| rq->hrtick_timer.function = hrtick; |
| } |
| #else /* CONFIG_SCHED_HRTICK */ |
| --- a/kernel/sched/deadline.c |
| +++ b/kernel/sched/deadline.c |
| @@ -1057,7 +1057,7 @@ void init_dl_task_timer(struct sched_dl_ |
| { |
| struct hrtimer *timer = &dl_se->dl_timer; |
| |
| - hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); |
| timer->function = dl_task_timer; |
| } |
| |
| --- a/kernel/sched/rt.c |
| +++ b/kernel/sched/rt.c |
| @@ -47,8 +47,8 @@ void init_rt_bandwidth(struct rt_bandwid |
| |
| raw_spin_lock_init(&rt_b->rt_runtime_lock); |
| |
| - hrtimer_init(&rt_b->rt_period_timer, |
| - CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + hrtimer_init(&rt_b->rt_period_timer, CLOCK_MONOTONIC, |
| + HRTIMER_MODE_REL_HARD); |
| rt_b->rt_period_timer.function = sched_rt_period_timer; |
| } |
| |
| --- a/kernel/time/hrtimer.c |
| +++ b/kernel/time/hrtimer.c |
| @@ -1119,7 +1119,9 @@ void hrtimer_start_range_ns(struct hrtim |
| * Check whether the HRTIMER_MODE_SOFT bit and hrtimer.is_soft |
| * match. |
| */ |
| +#ifndef CONFIG_PREEMPT_RT_BASE |
| WARN_ON_ONCE(!(mode & HRTIMER_MODE_SOFT) ^ !timer->is_soft); |
| +#endif |
| |
| base = lock_hrtimer_base(timer, &flags); |
| |
| @@ -1246,10 +1248,17 @@ static inline int hrtimer_clockid_to_bas |
| static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, |
| enum hrtimer_mode mode) |
| { |
| - bool softtimer = !!(mode & HRTIMER_MODE_SOFT); |
| - int base = softtimer ? HRTIMER_MAX_CLOCK_BASES / 2 : 0; |
| + bool softtimer; |
| + int base; |
| struct hrtimer_cpu_base *cpu_base; |
| |
| + softtimer = !!(mode & HRTIMER_MODE_SOFT); |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + if (!softtimer && !(mode & HRTIMER_MODE_HARD)) |
| + softtimer = true; |
| +#endif |
| + base = softtimer ? HRTIMER_MAX_CLOCK_BASES / 2 : 0; |
| + |
| memset(timer, 0, sizeof(struct hrtimer)); |
| |
| cpu_base = raw_cpu_ptr(&hrtimer_bases); |
| @@ -1633,6 +1642,14 @@ static void __hrtimer_init_sleeper(struc |
| enum hrtimer_mode mode, |
| struct task_struct *task) |
| { |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + if (!(mode & (HRTIMER_MODE_SOFT | HRTIMER_MODE_HARD))) { |
| + if (task_is_realtime(current) || system_state != SYSTEM_RUNNING) |
| + mode |= HRTIMER_MODE_HARD; |
| + else |
| + mode |= HRTIMER_MODE_SOFT; |
| + } |
| +#endif |
| __hrtimer_init(&sl->timer, clock_id, mode); |
| sl->timer.function = hrtimer_wakeup; |
| sl->task = task; |
| --- a/kernel/time/tick-broadcast-hrtimer.c |
| +++ b/kernel/time/tick-broadcast-hrtimer.c |
| @@ -106,7 +106,7 @@ static enum hrtimer_restart bc_handler(s |
| |
| void tick_setup_hrtimer_broadcast(void) |
| { |
| - hrtimer_init(&bctimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
| + hrtimer_init(&bctimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); |
| bctimer.function = bc_handler; |
| clockevents_register_device(&ce_broadcast_hrtimer); |
| } |
| --- a/kernel/time/tick-sched.c |
| +++ b/kernel/time/tick-sched.c |
| @@ -1231,7 +1231,7 @@ void tick_setup_sched_timer(void) |
| /* |
| * Emulate tick processing via per-CPU hrtimers: |
| */ |
| - hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
| + hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); |
| ts->sched_timer.function = tick_sched_timer; |
| |
| /* Get the next period (per-CPU) */ |
| --- a/kernel/watchdog.c |
| +++ b/kernel/watchdog.c |
| @@ -463,7 +463,7 @@ static void watchdog_enable(unsigned int |
| * Start the timer first to prevent the NMI watchdog triggering |
| * before the timer has a chance to fire. |
| */ |
| - hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); |
| hrtimer->function = watchdog_timer_fn; |
| hrtimer_start(hrtimer, ns_to_ktime(sample_period), |
| HRTIMER_MODE_REL_PINNED); |