| 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 haradirq context on RT. Therefore |
| CLOCK_MONOTONIC (and so on) are mapped by default to CLOCK_MONOTONIC_SOFT |
| behaviour (and are invoked in softirq context). |
| 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 | 22 +++++++++++++++++++++- |
| kernel/time/tick-broadcast-hrtimer.c | 2 +- |
| kernel/time/tick-sched.c | 2 +- |
| kernel/watchdog.c | 2 +- |
| 10 files changed, 37 insertions(+), 11 deletions(-) |
| |
| --- a/arch/x86/kvm/lapic.c |
| +++ b/arch/x86/kvm/lapic.c |
| @@ -2059,7 +2059,7 @@ int kvm_create_lapic(struct kvm_vcpu *vc |
| } |
| apic->vcpu = vcpu; |
| |
| - hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, |
| + hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC_HARD, |
| HRTIMER_MODE_ABS_PINNED); |
| apic->lapic_timer.timer.function = apic_timer_fn; |
| |
| --- a/include/linux/hrtimer.h |
| +++ b/include/linux/hrtimer.h |
| @@ -29,12 +29,18 @@ |
| * are kernel internal and never exported to user space. |
| */ |
| #define HRTIMER_BASE_SOFT_MASK MAX_CLOCKS |
| +#define HRTIMER_BASE_HARD_MASK (MAX_CLOCKS << 1) |
| |
| #define CLOCK_REALTIME_SOFT (CLOCK_REALTIME | HRTIMER_BASE_SOFT_MASK) |
| #define CLOCK_MONOTONIC_SOFT (CLOCK_MONOTONIC | HRTIMER_BASE_SOFT_MASK) |
| #define CLOCK_BOOTTIME_SOFT (CLOCK_BOOTTIME | HRTIMER_BASE_SOFT_MASK) |
| #define CLOCK_TAI_SOFT (CLOCK_TAI | HRTIMER_BASE_SOFT_MASK) |
| |
| +#define CLOCK_REALTIME_HARD (CLOCK_REALTIME | HRTIMER_BASE_HARD_MASK) |
| +#define CLOCK_MONOTONIC_HARD (CLOCK_MONOTONIC | HRTIMER_BASE_HARD_MASK) |
| +#define CLOCK_BOOTTIME_HARD (CLOCK_BOOTTIME | HRTIMER_BASE_HARD_MASK) |
| +#define CLOCK_TAI_HARD (CLOCK_TAI | HRTIMER_BASE_HARD_MASK) |
| + |
| struct hrtimer_clock_base; |
| struct hrtimer_cpu_base; |
| |
| --- a/kernel/events/core.c |
| +++ b/kernel/events/core.c |
| @@ -1042,7 +1042,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_HARD, HRTIMER_MODE_ABS_PINNED); |
| timer->function = perf_mux_hrtimer_handler; |
| } |
| |
| @@ -8485,7 +8485,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_HARD, HRTIMER_MODE_REL); |
| hwc->hrtimer.function = perf_swevent_hrtimer; |
| |
| /* |
| --- a/kernel/sched/core.c |
| +++ b/kernel/sched/core.c |
| @@ -350,7 +350,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_HARD, HRTIMER_MODE_REL); |
| rq->hrtick_timer.function = hrtick; |
| } |
| #else /* CONFIG_SCHED_HRTICK */ |
| --- a/kernel/sched/deadline.c |
| +++ b/kernel/sched/deadline.c |
| @@ -691,7 +691,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_HARD, HRTIMER_MODE_REL); |
| timer->function = dl_task_timer; |
| } |
| |
| --- a/kernel/sched/rt.c |
| +++ b/kernel/sched/rt.c |
| @@ -46,8 +46,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_HARD, |
| + HRTIMER_MODE_REL); |
| rt_b->rt_period_timer.function = sched_rt_period_timer; |
| } |
| |
| --- a/kernel/time/hrtimer.c |
| +++ b/kernel/time/hrtimer.c |
| @@ -122,20 +122,32 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, |
| } |
| }; |
| |
| -#define MAX_CLOCKS_HRT (MAX_CLOCKS * 2) |
| +#define MAX_CLOCKS_HRT (MAX_CLOCKS * 3) |
| |
| static const int hrtimer_clock_to_base_table[MAX_CLOCKS_HRT] = { |
| /* Make sure we catch unsupported clockids */ |
| [0 ... MAX_CLOCKS_HRT - 1] = HRTIMER_MAX_CLOCK_BASES, |
| |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME_SOFT, |
| + [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC_SOFT, |
| + [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME_SOFT, |
| + [CLOCK_TAI] = HRTIMER_BASE_TAI_SOFT, |
| +#else |
| [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME, |
| [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC, |
| [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME, |
| [CLOCK_TAI] = HRTIMER_BASE_TAI, |
| +#endif |
| [CLOCK_REALTIME_SOFT] = HRTIMER_BASE_REALTIME_SOFT, |
| [CLOCK_MONOTONIC_SOFT] = HRTIMER_BASE_MONOTONIC_SOFT, |
| [CLOCK_BOOTTIME_SOFT] = HRTIMER_BASE_BOOTTIME_SOFT, |
| [CLOCK_TAI_SOFT] = HRTIMER_BASE_TAI_SOFT, |
| + |
| + [CLOCK_REALTIME_HARD] = HRTIMER_BASE_REALTIME, |
| + [CLOCK_MONOTONIC_HARD] = HRTIMER_BASE_MONOTONIC, |
| + [CLOCK_BOOTTIME_HARD] = HRTIMER_BASE_BOOTTIME, |
| + [CLOCK_TAI_HARD] = HRTIMER_BASE_TAI, |
| }; |
| |
| /* |
| @@ -1194,7 +1206,11 @@ static inline int hrtimer_clockid_to_bas |
| return base; |
| } |
| WARN(1, "Invalid clockid %d. Using MONOTONIC\n", clock_id); |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + return HRTIMER_BASE_MONOTONIC_SOFT; |
| +#else |
| return HRTIMER_BASE_MONOTONIC; |
| +#endif |
| } |
| |
| static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, |
| @@ -1587,6 +1603,10 @@ static void __hrtimer_init_sleeper(struc |
| enum hrtimer_mode mode, |
| struct task_struct *task) |
| { |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| + if (!(clock_id & HRTIMER_BASE_SOFT_MASK)) |
| + clock_id |= HRTIMER_BASE_HARD_MASK; |
| +#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 |
| @@ -105,7 +105,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_HARD, HRTIMER_MODE_ABS); |
| bctimer.function = bc_handler; |
| clockevents_register_device(&ce_broadcast_hrtimer); |
| } |
| --- a/kernel/time/tick-sched.c |
| +++ b/kernel/time/tick-sched.c |
| @@ -1196,7 +1196,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_HARD, HRTIMER_MODE_ABS); |
| ts->sched_timer.function = tick_sched_timer; |
| |
| /* Get the next period (per-CPU) */ |
| --- a/kernel/watchdog.c |
| +++ b/kernel/watchdog.c |
| @@ -382,7 +382,7 @@ static void watchdog_enable(unsigned int |
| struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); |
| |
| /* kick off the timer for the hardlockup detector */ |
| - hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| + hrtimer_init(hrtimer, CLOCK_MONOTONIC_HARD, HRTIMER_MODE_REL); |
| hrtimer->function = watchdog_timer_fn; |
| |
| /* Enable the perf event */ |