blob: 75914c661e077a174d4edb3e3d922fc64b8e6cd6 [file] [log] [blame]
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 */