|
@@ -59,6 +59,15 @@
|
|
|
|
|
|
#include "tick-internal.h"
|
|
|
|
|
|
+/*
|
|
|
+ * Masks for selecting the soft and hard context timers from
|
|
|
+ * cpu_base->active
|
|
|
+ */
|
|
|
+#define MASK_SHIFT (HRTIMER_BASE_MONOTONIC_SOFT)
|
|
|
+#define HRTIMER_ACTIVE_HARD ((1U << MASK_SHIFT) - 1)
|
|
|
+#define HRTIMER_ACTIVE_SOFT (HRTIMER_ACTIVE_HARD << MASK_SHIFT)
|
|
|
+#define HRTIMER_ACTIVE_ALL (HRTIMER_ACTIVE_SOFT | HRTIMER_ACTIVE_HARD)
|
|
|
+
|
|
|
/*
|
|
|
* The timer bases:
|
|
|
*
|
|
@@ -70,7 +79,6 @@
|
|
|
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
|
|
|
{
|
|
|
.lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
|
|
|
- .seq = SEQCNT_ZERO(hrtimer_bases.seq),
|
|
|
.clock_base =
|
|
|
{
|
|
|
{
|
|
@@ -93,6 +101,26 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
|
|
|
.clockid = CLOCK_TAI,
|
|
|
.get_time = &ktime_get_clocktai,
|
|
|
},
|
|
|
+ {
|
|
|
+ .index = HRTIMER_BASE_MONOTONIC_SOFT,
|
|
|
+ .clockid = CLOCK_MONOTONIC,
|
|
|
+ .get_time = &ktime_get,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .index = HRTIMER_BASE_REALTIME_SOFT,
|
|
|
+ .clockid = CLOCK_REALTIME,
|
|
|
+ .get_time = &ktime_get_real,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .index = HRTIMER_BASE_BOOTTIME_SOFT,
|
|
|
+ .clockid = CLOCK_BOOTTIME,
|
|
|
+ .get_time = &ktime_get_boottime,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .index = HRTIMER_BASE_TAI_SOFT,
|
|
|
+ .clockid = CLOCK_TAI,
|
|
|
+ .get_time = &ktime_get_clocktai,
|
|
|
+ },
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -118,7 +146,6 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
|
|
|
* timer->base->cpu_base
|
|
|
*/
|
|
|
static struct hrtimer_cpu_base migration_cpu_base = {
|
|
|
- .seq = SEQCNT_ZERO(migration_cpu_base),
|
|
|
.clock_base = { { .cpu_base = &migration_cpu_base, }, },
|
|
|
};
|
|
|
|
|
@@ -156,45 +183,33 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * With HIGHRES=y we do not migrate the timer when it is expiring
|
|
|
- * before the next event on the target cpu because we cannot reprogram
|
|
|
- * the target cpu hardware and we would cause it to fire late.
|
|
|
+ * We do not migrate the timer when it is expiring before the next
|
|
|
+ * event on the target cpu. When high resolution is enabled, we cannot
|
|
|
+ * reprogram the target cpu hardware and we would cause it to fire
|
|
|
+ * late. To keep it simple, we handle the high resolution enabled and
|
|
|
+ * disabled case similar.
|
|
|
*
|
|
|
* Called with cpu_base->lock of target cpu held.
|
|
|
*/
|
|
|
static int
|
|
|
hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base)
|
|
|
{
|
|
|
-#ifdef CONFIG_HIGH_RES_TIMERS
|
|
|
ktime_t expires;
|
|
|
|
|
|
- if (!new_base->cpu_base->hres_active)
|
|
|
- return 0;
|
|
|
-
|
|
|
expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset);
|
|
|
- return expires <= new_base->cpu_base->expires_next;
|
|
|
-#else
|
|
|
- return 0;
|
|
|
-#endif
|
|
|
+ return expires < new_base->cpu_base->expires_next;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_NO_HZ_COMMON
|
|
|
-static inline
|
|
|
-struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base,
|
|
|
- int pinned)
|
|
|
-{
|
|
|
- if (pinned || !base->migration_enabled)
|
|
|
- return base;
|
|
|
- return &per_cpu(hrtimer_bases, get_nohz_timer_target());
|
|
|
-}
|
|
|
-#else
|
|
|
static inline
|
|
|
struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base,
|
|
|
int pinned)
|
|
|
{
|
|
|
+#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
|
|
|
+ if (static_branch_likely(&timers_migration_enabled) && !pinned)
|
|
|
+ return &per_cpu(hrtimer_bases, get_nohz_timer_target());
|
|
|
+#endif
|
|
|
return base;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
/*
|
|
|
* We switch the timer base to a power-optimized selected CPU target,
|
|
@@ -396,7 +411,8 @@ static inline void debug_hrtimer_init(struct hrtimer *timer)
|
|
|
debug_object_init(timer, &hrtimer_debug_descr);
|
|
|
}
|
|
|
|
|
|
-static inline void debug_hrtimer_activate(struct hrtimer *timer)
|
|
|
+static inline void debug_hrtimer_activate(struct hrtimer *timer,
|
|
|
+ enum hrtimer_mode mode)
|
|
|
{
|
|
|
debug_object_activate(timer, &hrtimer_debug_descr);
|
|
|
}
|
|
@@ -429,8 +445,10 @@ void destroy_hrtimer_on_stack(struct hrtimer *timer)
|
|
|
EXPORT_SYMBOL_GPL(destroy_hrtimer_on_stack);
|
|
|
|
|
|
#else
|
|
|
+
|
|
|
static inline void debug_hrtimer_init(struct hrtimer *timer) { }
|
|
|
-static inline void debug_hrtimer_activate(struct hrtimer *timer) { }
|
|
|
+static inline void debug_hrtimer_activate(struct hrtimer *timer,
|
|
|
+ enum hrtimer_mode mode) { }
|
|
|
static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { }
|
|
|
#endif
|
|
|
|
|
@@ -442,10 +460,11 @@ debug_init(struct hrtimer *timer, clockid_t clockid,
|
|
|
trace_hrtimer_init(timer, clockid, mode);
|
|
|
}
|
|
|
|
|
|
-static inline void debug_activate(struct hrtimer *timer)
|
|
|
+static inline void debug_activate(struct hrtimer *timer,
|
|
|
+ enum hrtimer_mode mode)
|
|
|
{
|
|
|
- debug_hrtimer_activate(timer);
|
|
|
- trace_hrtimer_start(timer);
|
|
|
+ debug_hrtimer_activate(timer, mode);
|
|
|
+ trace_hrtimer_start(timer, mode);
|
|
|
}
|
|
|
|
|
|
static inline void debug_deactivate(struct hrtimer *timer)
|
|
@@ -454,35 +473,43 @@ static inline void debug_deactivate(struct hrtimer *timer)
|
|
|
trace_hrtimer_cancel(timer);
|
|
|
}
|
|
|
|
|
|
-#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
|
|
|
-static inline void hrtimer_update_next_timer(struct hrtimer_cpu_base *cpu_base,
|
|
|
- struct hrtimer *timer)
|
|
|
+static struct hrtimer_clock_base *
|
|
|
+__next_base(struct hrtimer_cpu_base *cpu_base, unsigned int *active)
|
|
|
{
|
|
|
-#ifdef CONFIG_HIGH_RES_TIMERS
|
|
|
- cpu_base->next_timer = timer;
|
|
|
-#endif
|
|
|
+ unsigned int idx;
|
|
|
+
|
|
|
+ if (!*active)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ idx = __ffs(*active);
|
|
|
+ *active &= ~(1U << idx);
|
|
|
+
|
|
|
+ return &cpu_base->clock_base[idx];
|
|
|
}
|
|
|
|
|
|
-static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base)
|
|
|
+#define for_each_active_base(base, cpu_base, active) \
|
|
|
+ while ((base = __next_base((cpu_base), &(active))))
|
|
|
+
|
|
|
+static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base,
|
|
|
+ unsigned int active,
|
|
|
+ ktime_t expires_next)
|
|
|
{
|
|
|
- struct hrtimer_clock_base *base = cpu_base->clock_base;
|
|
|
- unsigned int active = cpu_base->active_bases;
|
|
|
- ktime_t expires, expires_next = KTIME_MAX;
|
|
|
+ struct hrtimer_clock_base *base;
|
|
|
+ ktime_t expires;
|
|
|
|
|
|
- hrtimer_update_next_timer(cpu_base, NULL);
|
|
|
- for (; active; base++, active >>= 1) {
|
|
|
+ for_each_active_base(base, cpu_base, active) {
|
|
|
struct timerqueue_node *next;
|
|
|
struct hrtimer *timer;
|
|
|
|
|
|
- if (!(active & 0x01))
|
|
|
- continue;
|
|
|
-
|
|
|
next = timerqueue_getnext(&base->active);
|
|
|
timer = container_of(next, struct hrtimer, node);
|
|
|
expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
|
|
|
if (expires < expires_next) {
|
|
|
expires_next = expires;
|
|
|
- hrtimer_update_next_timer(cpu_base, timer);
|
|
|
+ if (timer->is_soft)
|
|
|
+ cpu_base->softirq_next_timer = timer;
|
|
|
+ else
|
|
|
+ cpu_base->next_timer = timer;
|
|
|
}
|
|
|
}
|
|
|
/*
|
|
@@ -494,7 +521,47 @@ static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base)
|
|
|
expires_next = 0;
|
|
|
return expires_next;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
+/*
|
|
|
+ * Recomputes cpu_base::*next_timer and returns the earliest expires_next but
|
|
|
+ * does not set cpu_base::*expires_next, that is done by hrtimer_reprogram.
|
|
|
+ *
|
|
|
+ * When a softirq is pending, we can ignore the HRTIMER_ACTIVE_SOFT bases,
|
|
|
+ * those timers will get run whenever the softirq gets handled, at the end of
|
|
|
+ * hrtimer_run_softirq(), hrtimer_update_softirq_timer() will re-add these bases.
|
|
|
+ *
|
|
|
+ * Therefore softirq values are those from the HRTIMER_ACTIVE_SOFT clock bases.
|
|
|
+ * The !softirq values are the minima across HRTIMER_ACTIVE_ALL, unless an actual
|
|
|
+ * softirq is pending, in which case they're the minima of HRTIMER_ACTIVE_HARD.
|
|
|
+ *
|
|
|
+ * @active_mask must be one of:
|
|
|
+ * - HRTIMER_ACTIVE_ALL,
|
|
|
+ * - HRTIMER_ACTIVE_SOFT, or
|
|
|
+ * - HRTIMER_ACTIVE_HARD.
|
|
|
+ */
|
|
|
+static ktime_t
|
|
|
+__hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_mask)
|
|
|
+{
|
|
|
+ unsigned int active;
|
|
|
+ struct hrtimer *next_timer = NULL;
|
|
|
+ ktime_t expires_next = KTIME_MAX;
|
|
|
+
|
|
|
+ if (!cpu_base->softirq_activated && (active_mask & HRTIMER_ACTIVE_SOFT)) {
|
|
|
+ active = cpu_base->active_bases & HRTIMER_ACTIVE_SOFT;
|
|
|
+ cpu_base->softirq_next_timer = NULL;
|
|
|
+ expires_next = __hrtimer_next_event_base(cpu_base, active, KTIME_MAX);
|
|
|
+
|
|
|
+ next_timer = cpu_base->softirq_next_timer;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (active_mask & HRTIMER_ACTIVE_HARD) {
|
|
|
+ active = cpu_base->active_bases & HRTIMER_ACTIVE_HARD;
|
|
|
+ cpu_base->next_timer = next_timer;
|
|
|
+ expires_next = __hrtimer_next_event_base(cpu_base, active, expires_next);
|
|
|
+ }
|
|
|
+
|
|
|
+ return expires_next;
|
|
|
+}
|
|
|
|
|
|
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
|
|
|
{
|
|
@@ -502,36 +569,14 @@ static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
|
|
|
ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
|
|
|
ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
|
|
|
|
|
|
- return ktime_get_update_offsets_now(&base->clock_was_set_seq,
|
|
|
+ ktime_t now = ktime_get_update_offsets_now(&base->clock_was_set_seq,
|
|
|
offs_real, offs_boot, offs_tai);
|
|
|
-}
|
|
|
-
|
|
|
-/* High resolution timer related functions */
|
|
|
-#ifdef CONFIG_HIGH_RES_TIMERS
|
|
|
|
|
|
-/*
|
|
|
- * High resolution timer enabled ?
|
|
|
- */
|
|
|
-static bool hrtimer_hres_enabled __read_mostly = true;
|
|
|
-unsigned int hrtimer_resolution __read_mostly = LOW_RES_NSEC;
|
|
|
-EXPORT_SYMBOL_GPL(hrtimer_resolution);
|
|
|
+ base->clock_base[HRTIMER_BASE_REALTIME_SOFT].offset = *offs_real;
|
|
|
+ base->clock_base[HRTIMER_BASE_BOOTTIME_SOFT].offset = *offs_boot;
|
|
|
+ base->clock_base[HRTIMER_BASE_TAI_SOFT].offset = *offs_tai;
|
|
|
|
|
|
-/*
|
|
|
- * Enable / Disable high resolution mode
|
|
|
- */
|
|
|
-static int __init setup_hrtimer_hres(char *str)
|
|
|
-{
|
|
|
- return (kstrtobool(str, &hrtimer_hres_enabled) == 0);
|
|
|
-}
|
|
|
-
|
|
|
-__setup("highres=", setup_hrtimer_hres);
|
|
|
-
|
|
|
-/*
|
|
|
- * hrtimer_high_res_enabled - query, if the highres mode is enabled
|
|
|
- */
|
|
|
-static inline int hrtimer_is_hres_enabled(void)
|
|
|
-{
|
|
|
- return hrtimer_hres_enabled;
|
|
|
+ return now;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -539,7 +584,8 @@ static inline int hrtimer_is_hres_enabled(void)
|
|
|
*/
|
|
|
static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *cpu_base)
|
|
|
{
|
|
|
- return cpu_base->hres_active;
|
|
|
+ return IS_ENABLED(CONFIG_HIGH_RES_TIMERS) ?
|
|
|
+ cpu_base->hres_active : 0;
|
|
|
}
|
|
|
|
|
|
static inline int hrtimer_hres_active(void)
|
|
@@ -557,10 +603,23 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
|
|
{
|
|
|
ktime_t expires_next;
|
|
|
|
|
|
- if (!cpu_base->hres_active)
|
|
|
- return;
|
|
|
+ /*
|
|
|
+ * Find the current next expiration time.
|
|
|
+ */
|
|
|
+ expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
|
|
|
|
|
|
- expires_next = __hrtimer_get_next_event(cpu_base);
|
|
|
+ if (cpu_base->next_timer && cpu_base->next_timer->is_soft) {
|
|
|
+ /*
|
|
|
+ * When the softirq is activated, hrtimer has to be
|
|
|
+ * programmed with the first hard hrtimer because soft
|
|
|
+ * timer interrupt could occur too late.
|
|
|
+ */
|
|
|
+ if (cpu_base->softirq_activated)
|
|
|
+ expires_next = __hrtimer_get_next_event(cpu_base,
|
|
|
+ HRTIMER_ACTIVE_HARD);
|
|
|
+ else
|
|
|
+ cpu_base->softirq_expires_next = expires_next;
|
|
|
+ }
|
|
|
|
|
|
if (skip_equal && expires_next == cpu_base->expires_next)
|
|
|
return;
|
|
@@ -568,6 +627,9 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
|
|
cpu_base->expires_next = expires_next;
|
|
|
|
|
|
/*
|
|
|
+ * If hres is not active, hardware does not have to be
|
|
|
+ * reprogrammed yet.
|
|
|
+ *
|
|
|
* If a hang was detected in the last timer interrupt then we
|
|
|
* leave the hang delay active in the hardware. We want the
|
|
|
* system to make progress. That also prevents the following
|
|
@@ -581,83 +643,38 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
|
|
* set. So we'd effectivly block all timers until the T2 event
|
|
|
* fires.
|
|
|
*/
|
|
|
- if (cpu_base->hang_detected)
|
|
|
+ if (!__hrtimer_hres_active(cpu_base) || cpu_base->hang_detected)
|
|
|
return;
|
|
|
|
|
|
tick_program_event(cpu_base->expires_next, 1);
|
|
|
}
|
|
|
|
|
|
+/* High resolution timer related functions */
|
|
|
+#ifdef CONFIG_HIGH_RES_TIMERS
|
|
|
+
|
|
|
/*
|
|
|
- * When a timer is enqueued and expires earlier than the already enqueued
|
|
|
- * timers, we have to check, whether it expires earlier than the timer for
|
|
|
- * which the clock event device was armed.
|
|
|
- *
|
|
|
- * Called with interrupts disabled and base->cpu_base.lock held
|
|
|
+ * High resolution timer enabled ?
|
|
|
*/
|
|
|
-static void hrtimer_reprogram(struct hrtimer *timer,
|
|
|
- struct hrtimer_clock_base *base)
|
|
|
-{
|
|
|
- struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
|
|
|
- ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
|
|
|
-
|
|
|
- WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0);
|
|
|
-
|
|
|
- /*
|
|
|
- * If the timer is not on the current cpu, we cannot reprogram
|
|
|
- * the other cpus clock event device.
|
|
|
- */
|
|
|
- if (base->cpu_base != cpu_base)
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * If the hrtimer interrupt is running, then it will
|
|
|
- * reevaluate the clock bases and reprogram the clock event
|
|
|
- * device. The callbacks are always executed in hard interrupt
|
|
|
- * context so we don't need an extra check for a running
|
|
|
- * callback.
|
|
|
- */
|
|
|
- if (cpu_base->in_hrtirq)
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * CLOCK_REALTIME timer might be requested with an absolute
|
|
|
- * expiry time which is less than base->offset. Set it to 0.
|
|
|
- */
|
|
|
- if (expires < 0)
|
|
|
- expires = 0;
|
|
|
-
|
|
|
- if (expires >= cpu_base->expires_next)
|
|
|
- return;
|
|
|
-
|
|
|
- /* Update the pointer to the next expiring timer */
|
|
|
- cpu_base->next_timer = timer;
|
|
|
-
|
|
|
- /*
|
|
|
- * If a hang was detected in the last timer interrupt then we
|
|
|
- * do not schedule a timer which is earlier than the expiry
|
|
|
- * which we enforced in the hang detection. We want the system
|
|
|
- * to make progress.
|
|
|
- */
|
|
|
- if (cpu_base->hang_detected)
|
|
|
- return;
|
|
|
+static bool hrtimer_hres_enabled __read_mostly = true;
|
|
|
+unsigned int hrtimer_resolution __read_mostly = LOW_RES_NSEC;
|
|
|
+EXPORT_SYMBOL_GPL(hrtimer_resolution);
|
|
|
|
|
|
- /*
|
|
|
- * Program the timer hardware. We enforce the expiry for
|
|
|
- * events which are already in the past.
|
|
|
- */
|
|
|
- cpu_base->expires_next = expires;
|
|
|
- tick_program_event(expires, 1);
|
|
|
+/*
|
|
|
+ * Enable / Disable high resolution mode
|
|
|
+ */
|
|
|
+static int __init setup_hrtimer_hres(char *str)
|
|
|
+{
|
|
|
+ return (kstrtobool(str, &hrtimer_hres_enabled) == 0);
|
|
|
}
|
|
|
|
|
|
+__setup("highres=", setup_hrtimer_hres);
|
|
|
+
|
|
|
/*
|
|
|
- * Initialize the high resolution related parts of cpu_base
|
|
|
+ * hrtimer_high_res_enabled - query, if the highres mode is enabled
|
|
|
*/
|
|
|
-static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
|
|
|
+static inline int hrtimer_is_hres_enabled(void)
|
|
|
{
|
|
|
- base->expires_next = KTIME_MAX;
|
|
|
- base->hang_detected = 0;
|
|
|
- base->hres_active = 0;
|
|
|
- base->next_timer = NULL;
|
|
|
+ return hrtimer_hres_enabled;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -669,7 +686,7 @@ static void retrigger_next_event(void *arg)
|
|
|
{
|
|
|
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
|
|
|
|
|
|
- if (!base->hres_active)
|
|
|
+ if (!__hrtimer_hres_active(base))
|
|
|
return;
|
|
|
|
|
|
raw_spin_lock(&base->lock);
|
|
@@ -716,22 +733,101 @@ void clock_was_set_delayed(void)
|
|
|
|
|
|
#else
|
|
|
|
|
|
-static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *b) { return 0; }
|
|
|
-static inline int hrtimer_hres_active(void) { return 0; }
|
|
|
static inline int hrtimer_is_hres_enabled(void) { return 0; }
|
|
|
static inline void hrtimer_switch_to_hres(void) { }
|
|
|
-static inline void
|
|
|
-hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
|
|
|
-static inline int hrtimer_reprogram(struct hrtimer *timer,
|
|
|
- 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) { }
|
|
|
|
|
|
#endif /* CONFIG_HIGH_RES_TIMERS */
|
|
|
|
|
|
+/*
|
|
|
+ * When a timer is enqueued and expires earlier than the already enqueued
|
|
|
+ * timers, we have to check, whether it expires earlier than the timer for
|
|
|
+ * which the clock event device was armed.
|
|
|
+ *
|
|
|
+ * Called with interrupts disabled and base->cpu_base.lock held
|
|
|
+ */
|
|
|
+static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
|
|
|
+{
|
|
|
+ struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
|
|
|
+ struct hrtimer_clock_base *base = timer->base;
|
|
|
+ ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
|
|
|
+
|
|
|
+ WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * CLOCK_REALTIME timer might be requested with an absolute
|
|
|
+ * expiry time which is less than base->offset. Set it to 0.
|
|
|
+ */
|
|
|
+ if (expires < 0)
|
|
|
+ expires = 0;
|
|
|
+
|
|
|
+ if (timer->is_soft) {
|
|
|
+ /*
|
|
|
+ * soft hrtimer could be started on a remote CPU. In this
|
|
|
+ * case softirq_expires_next needs to be updated on the
|
|
|
+ * remote CPU. The soft hrtimer will not expire before the
|
|
|
+ * first hard hrtimer on the remote CPU -
|
|
|
+ * hrtimer_check_target() prevents this case.
|
|
|
+ */
|
|
|
+ struct hrtimer_cpu_base *timer_cpu_base = base->cpu_base;
|
|
|
+
|
|
|
+ if (timer_cpu_base->softirq_activated)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!ktime_before(expires, timer_cpu_base->softirq_expires_next))
|
|
|
+ return;
|
|
|
+
|
|
|
+ timer_cpu_base->softirq_next_timer = timer;
|
|
|
+ timer_cpu_base->softirq_expires_next = expires;
|
|
|
+
|
|
|
+ if (!ktime_before(expires, timer_cpu_base->expires_next) ||
|
|
|
+ !reprogram)
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the timer is not on the current cpu, we cannot reprogram
|
|
|
+ * the other cpus clock event device.
|
|
|
+ */
|
|
|
+ if (base->cpu_base != cpu_base)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the hrtimer interrupt is running, then it will
|
|
|
+ * reevaluate the clock bases and reprogram the clock event
|
|
|
+ * device. The callbacks are always executed in hard interrupt
|
|
|
+ * context so we don't need an extra check for a running
|
|
|
+ * callback.
|
|
|
+ */
|
|
|
+ if (cpu_base->in_hrtirq)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (expires >= cpu_base->expires_next)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Update the pointer to the next expiring timer */
|
|
|
+ cpu_base->next_timer = timer;
|
|
|
+ cpu_base->expires_next = expires;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If hres is not active, hardware does not have to be
|
|
|
+ * programmed yet.
|
|
|
+ *
|
|
|
+ * If a hang was detected in the last timer interrupt then we
|
|
|
+ * do not schedule a timer which is earlier than the expiry
|
|
|
+ * which we enforced in the hang detection. We want the system
|
|
|
+ * to make progress.
|
|
|
+ */
|
|
|
+ if (!__hrtimer_hres_active(cpu_base) || cpu_base->hang_detected)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Program the timer hardware. We enforce the expiry for
|
|
|
+ * events which are already in the past.
|
|
|
+ */
|
|
|
+ tick_program_event(expires, 1);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Clock realtime was set
|
|
|
*
|
|
@@ -837,9 +933,10 @@ EXPORT_SYMBOL_GPL(hrtimer_forward);
|
|
|
* Returns 1 when the new timer is the leftmost timer in the tree.
|
|
|
*/
|
|
|
static int enqueue_hrtimer(struct hrtimer *timer,
|
|
|
- struct hrtimer_clock_base *base)
|
|
|
+ struct hrtimer_clock_base *base,
|
|
|
+ enum hrtimer_mode mode)
|
|
|
{
|
|
|
- debug_activate(timer);
|
|
|
+ debug_activate(timer, mode);
|
|
|
|
|
|
base->cpu_base->active_bases |= 1 << base->index;
|
|
|
|
|
@@ -872,7 +969,6 @@ static void __remove_hrtimer(struct hrtimer *timer,
|
|
|
if (!timerqueue_del(&base->active, &timer->node))
|
|
|
cpu_base->active_bases &= ~(1 << base->index);
|
|
|
|
|
|
-#ifdef CONFIG_HIGH_RES_TIMERS
|
|
|
/*
|
|
|
* Note: If reprogram is false we do not update
|
|
|
* cpu_base->next_timer. This happens when we remove the first
|
|
@@ -883,7 +979,6 @@ static void __remove_hrtimer(struct hrtimer *timer,
|
|
|
*/
|
|
|
if (reprogram && timer == cpu_base->next_timer)
|
|
|
hrtimer_force_reprogram(cpu_base, 1);
|
|
|
-#endif
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -932,22 +1027,36 @@ static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim,
|
|
|
return tim;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
|
|
|
- * @timer: the timer to be added
|
|
|
- * @tim: expiry time
|
|
|
- * @delta_ns: "slack" range for the timer
|
|
|
- * @mode: expiry mode: absolute (HRTIMER_MODE_ABS) or
|
|
|
- * relative (HRTIMER_MODE_REL)
|
|
|
- */
|
|
|
-void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
|
|
- u64 delta_ns, const enum hrtimer_mode mode)
|
|
|
+static void
|
|
|
+hrtimer_update_softirq_timer(struct hrtimer_cpu_base *cpu_base, bool reprogram)
|
|
|
{
|
|
|
- struct hrtimer_clock_base *base, *new_base;
|
|
|
- unsigned long flags;
|
|
|
- int leftmost;
|
|
|
+ ktime_t expires;
|
|
|
|
|
|
- base = lock_hrtimer_base(timer, &flags);
|
|
|
+ /*
|
|
|
+ * Find the next SOFT expiration.
|
|
|
+ */
|
|
|
+ expires = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_SOFT);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * reprogramming needs to be triggered, even if the next soft
|
|
|
+ * hrtimer expires at the same time than the next hard
|
|
|
+ * hrtimer. cpu_base->softirq_expires_next needs to be updated!
|
|
|
+ */
|
|
|
+ if (expires == KTIME_MAX)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * cpu_base->*next_timer is recomputed by __hrtimer_get_next_event()
|
|
|
+ * cpu_base->*expires_next is only set by hrtimer_reprogram()
|
|
|
+ */
|
|
|
+ hrtimer_reprogram(cpu_base->softirq_next_timer, reprogram);
|
|
|
+}
|
|
|
+
|
|
|
+static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
|
|
+ u64 delta_ns, const enum hrtimer_mode mode,
|
|
|
+ struct hrtimer_clock_base *base)
|
|
|
+{
|
|
|
+ struct hrtimer_clock_base *new_base;
|
|
|
|
|
|
/* Remove an active timer from the queue: */
|
|
|
remove_hrtimer(timer, base, true);
|
|
@@ -962,21 +1071,35 @@ void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
|
|
/* Switch the timer base, if necessary: */
|
|
|
new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
|
|
|
|
|
|
- leftmost = enqueue_hrtimer(timer, new_base);
|
|
|
- if (!leftmost)
|
|
|
- goto unlock;
|
|
|
+ return enqueue_hrtimer(timer, new_base, mode);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hrtimer_start_range_ns - (re)start an hrtimer
|
|
|
+ * @timer: the timer to be added
|
|
|
+ * @tim: expiry time
|
|
|
+ * @delta_ns: "slack" range for the timer
|
|
|
+ * @mode: timer mode: absolute (HRTIMER_MODE_ABS) or
|
|
|
+ * relative (HRTIMER_MODE_REL), and pinned (HRTIMER_MODE_PINNED);
|
|
|
+ * softirq based mode is considered for debug purpose only!
|
|
|
+ */
|
|
|
+void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
|
|
|
+ u64 delta_ns, const enum hrtimer_mode mode)
|
|
|
+{
|
|
|
+ struct hrtimer_clock_base *base;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Check whether the HRTIMER_MODE_SOFT bit and hrtimer.is_soft
|
|
|
+ * match.
|
|
|
+ */
|
|
|
+ WARN_ON_ONCE(!(mode & HRTIMER_MODE_SOFT) ^ !timer->is_soft);
|
|
|
+
|
|
|
+ base = lock_hrtimer_base(timer, &flags);
|
|
|
+
|
|
|
+ if (__hrtimer_start_range_ns(timer, tim, delta_ns, mode, base))
|
|
|
+ hrtimer_reprogram(timer, true);
|
|
|
|
|
|
- if (!hrtimer_is_hres_active(timer)) {
|
|
|
- /*
|
|
|
- * Kick to reschedule the next tick to handle the new timer
|
|
|
- * on dynticks target.
|
|
|
- */
|
|
|
- if (new_base->cpu_base->nohz_active)
|
|
|
- wake_up_nohz_cpu(new_base->cpu_base->cpu);
|
|
|
- } else {
|
|
|
- hrtimer_reprogram(timer, new_base);
|
|
|
- }
|
|
|
-unlock:
|
|
|
unlock_hrtimer_base(timer, &flags);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
|
|
@@ -1074,7 +1197,7 @@ u64 hrtimer_get_next_event(void)
|
|
|
raw_spin_lock_irqsave(&cpu_base->lock, flags);
|
|
|
|
|
|
if (!__hrtimer_hres_active(cpu_base))
|
|
|
- expires = __hrtimer_get_next_event(cpu_base);
|
|
|
+ expires = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
|
|
|
|
|
|
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
|
|
|
|
|
@@ -1097,17 +1220,24 @@ static inline int hrtimer_clockid_to_base(clockid_t clock_id)
|
|
|
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;
|
|
|
struct hrtimer_cpu_base *cpu_base;
|
|
|
- int base;
|
|
|
|
|
|
memset(timer, 0, sizeof(struct hrtimer));
|
|
|
|
|
|
cpu_base = raw_cpu_ptr(&hrtimer_bases);
|
|
|
|
|
|
- if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
|
|
|
+ /*
|
|
|
+ * POSIX magic: Relative CLOCK_REALTIME timers are not affected by
|
|
|
+ * clock modifications, so they needs to become CLOCK_MONOTONIC to
|
|
|
+ * ensure POSIX compliance.
|
|
|
+ */
|
|
|
+ if (clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL)
|
|
|
clock_id = CLOCK_MONOTONIC;
|
|
|
|
|
|
- base = hrtimer_clockid_to_base(clock_id);
|
|
|
+ base += hrtimer_clockid_to_base(clock_id);
|
|
|
+ timer->is_soft = softtimer;
|
|
|
timer->base = &cpu_base->clock_base[base];
|
|
|
timerqueue_init(&timer->node);
|
|
|
}
|
|
@@ -1116,7 +1246,13 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
* hrtimer_init - initialize a timer to the given clock
|
|
|
* @timer: the timer to be initialized
|
|
|
* @clock_id: the clock to be used
|
|
|
- * @mode: timer mode abs/rel
|
|
|
+ * @mode: The modes which are relevant for intitialization:
|
|
|
+ * HRTIMER_MODE_ABS, HRTIMER_MODE_REL, HRTIMER_MODE_ABS_SOFT,
|
|
|
+ * HRTIMER_MODE_REL_SOFT
|
|
|
+ *
|
|
|
+ * The PINNED variants of the above can be handed in,
|
|
|
+ * but the PINNED bit is ignored as pinning happens
|
|
|
+ * when the hrtimer is started
|
|
|
*/
|
|
|
void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
enum hrtimer_mode mode)
|
|
@@ -1135,19 +1271,19 @@ EXPORT_SYMBOL_GPL(hrtimer_init);
|
|
|
*/
|
|
|
bool hrtimer_active(const struct hrtimer *timer)
|
|
|
{
|
|
|
- struct hrtimer_cpu_base *cpu_base;
|
|
|
+ struct hrtimer_clock_base *base;
|
|
|
unsigned int seq;
|
|
|
|
|
|
do {
|
|
|
- cpu_base = READ_ONCE(timer->base->cpu_base);
|
|
|
- seq = raw_read_seqcount_begin(&cpu_base->seq);
|
|
|
+ base = READ_ONCE(timer->base);
|
|
|
+ seq = raw_read_seqcount_begin(&base->seq);
|
|
|
|
|
|
if (timer->state != HRTIMER_STATE_INACTIVE ||
|
|
|
- cpu_base->running == timer)
|
|
|
+ base->running == timer)
|
|
|
return true;
|
|
|
|
|
|
- } while (read_seqcount_retry(&cpu_base->seq, seq) ||
|
|
|
- cpu_base != READ_ONCE(timer->base->cpu_base));
|
|
|
+ } while (read_seqcount_retry(&base->seq, seq) ||
|
|
|
+ base != READ_ONCE(timer->base));
|
|
|
|
|
|
return false;
|
|
|
}
|
|
@@ -1173,7 +1309,8 @@ EXPORT_SYMBOL_GPL(hrtimer_active);
|
|
|
|
|
|
static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
|
|
|
struct hrtimer_clock_base *base,
|
|
|
- struct hrtimer *timer, ktime_t *now)
|
|
|
+ struct hrtimer *timer, ktime_t *now,
|
|
|
+ unsigned long flags)
|
|
|
{
|
|
|
enum hrtimer_restart (*fn)(struct hrtimer *);
|
|
|
int restart;
|
|
@@ -1181,16 +1318,16 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
|
|
|
lockdep_assert_held(&cpu_base->lock);
|
|
|
|
|
|
debug_deactivate(timer);
|
|
|
- cpu_base->running = timer;
|
|
|
+ base->running = timer;
|
|
|
|
|
|
/*
|
|
|
* Separate the ->running assignment from the ->state assignment.
|
|
|
*
|
|
|
* As with a regular write barrier, this ensures the read side in
|
|
|
- * hrtimer_active() cannot observe cpu_base->running == NULL &&
|
|
|
+ * hrtimer_active() cannot observe base->running == NULL &&
|
|
|
* timer->state == INACTIVE.
|
|
|
*/
|
|
|
- raw_write_seqcount_barrier(&cpu_base->seq);
|
|
|
+ raw_write_seqcount_barrier(&base->seq);
|
|
|
|
|
|
__remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0);
|
|
|
fn = timer->function;
|
|
@@ -1204,15 +1341,15 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
|
|
|
timer->is_rel = false;
|
|
|
|
|
|
/*
|
|
|
- * Because we run timers from hardirq context, there is no chance
|
|
|
- * they get migrated to another cpu, therefore its safe to unlock
|
|
|
- * the timer base.
|
|
|
+ * The timer is marked as running in the CPU base, so it is
|
|
|
+ * protected against migration to a different CPU even if the lock
|
|
|
+ * is dropped.
|
|
|
*/
|
|
|
- raw_spin_unlock(&cpu_base->lock);
|
|
|
+ raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
|
|
|
trace_hrtimer_expire_entry(timer, now);
|
|
|
restart = fn(timer);
|
|
|
trace_hrtimer_expire_exit(timer);
|
|
|
- raw_spin_lock(&cpu_base->lock);
|
|
|
+ raw_spin_lock_irq(&cpu_base->lock);
|
|
|
|
|
|
/*
|
|
|
* Note: We clear the running state after enqueue_hrtimer and
|
|
@@ -1225,33 +1362,31 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
|
|
|
*/
|
|
|
if (restart != HRTIMER_NORESTART &&
|
|
|
!(timer->state & HRTIMER_STATE_ENQUEUED))
|
|
|
- enqueue_hrtimer(timer, base);
|
|
|
+ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS);
|
|
|
|
|
|
/*
|
|
|
* Separate the ->running assignment from the ->state assignment.
|
|
|
*
|
|
|
* As with a regular write barrier, this ensures the read side in
|
|
|
- * hrtimer_active() cannot observe cpu_base->running == NULL &&
|
|
|
+ * hrtimer_active() cannot observe base->running.timer == NULL &&
|
|
|
* timer->state == INACTIVE.
|
|
|
*/
|
|
|
- raw_write_seqcount_barrier(&cpu_base->seq);
|
|
|
+ raw_write_seqcount_barrier(&base->seq);
|
|
|
|
|
|
- WARN_ON_ONCE(cpu_base->running != timer);
|
|
|
- cpu_base->running = NULL;
|
|
|
+ WARN_ON_ONCE(base->running != timer);
|
|
|
+ base->running = NULL;
|
|
|
}
|
|
|
|
|
|
-static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now)
|
|
|
+static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now,
|
|
|
+ unsigned long flags, unsigned int active_mask)
|
|
|
{
|
|
|
- struct hrtimer_clock_base *base = cpu_base->clock_base;
|
|
|
- unsigned int active = cpu_base->active_bases;
|
|
|
+ struct hrtimer_clock_base *base;
|
|
|
+ unsigned int active = cpu_base->active_bases & active_mask;
|
|
|
|
|
|
- for (; active; base++, active >>= 1) {
|
|
|
+ for_each_active_base(base, cpu_base, active) {
|
|
|
struct timerqueue_node *node;
|
|
|
ktime_t basenow;
|
|
|
|
|
|
- if (!(active & 0x01))
|
|
|
- continue;
|
|
|
-
|
|
|
basenow = ktime_add(now, base->offset);
|
|
|
|
|
|
while ((node = timerqueue_getnext(&base->active))) {
|
|
@@ -1274,11 +1409,28 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now)
|
|
|
if (basenow < hrtimer_get_softexpires_tv64(timer))
|
|
|
break;
|
|
|
|
|
|
- __run_hrtimer(cpu_base, base, timer, &basenow);
|
|
|
+ __run_hrtimer(cpu_base, base, timer, &basenow, flags);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static __latent_entropy void hrtimer_run_softirq(struct softirq_action *h)
|
|
|
+{
|
|
|
+ struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
|
|
|
+ unsigned long flags;
|
|
|
+ ktime_t now;
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&cpu_base->lock, flags);
|
|
|
+
|
|
|
+ now = hrtimer_update_base(cpu_base);
|
|
|
+ __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_SOFT);
|
|
|
+
|
|
|
+ cpu_base->softirq_activated = 0;
|
|
|
+ hrtimer_update_softirq_timer(cpu_base, true);
|
|
|
+
|
|
|
+ raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_HIGH_RES_TIMERS
|
|
|
|
|
|
/*
|
|
@@ -1289,13 +1441,14 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
|
|
{
|
|
|
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
|
|
|
ktime_t expires_next, now, entry_time, delta;
|
|
|
+ unsigned long flags;
|
|
|
int retries = 0;
|
|
|
|
|
|
BUG_ON(!cpu_base->hres_active);
|
|
|
cpu_base->nr_events++;
|
|
|
dev->next_event = KTIME_MAX;
|
|
|
|
|
|
- raw_spin_lock(&cpu_base->lock);
|
|
|
+ raw_spin_lock_irqsave(&cpu_base->lock, flags);
|
|
|
entry_time = now = hrtimer_update_base(cpu_base);
|
|
|
retry:
|
|
|
cpu_base->in_hrtirq = 1;
|
|
@@ -1308,17 +1461,23 @@ retry:
|
|
|
*/
|
|
|
cpu_base->expires_next = KTIME_MAX;
|
|
|
|
|
|
- __hrtimer_run_queues(cpu_base, now);
|
|
|
+ if (!ktime_before(now, cpu_base->softirq_expires_next)) {
|
|
|
+ cpu_base->softirq_expires_next = KTIME_MAX;
|
|
|
+ cpu_base->softirq_activated = 1;
|
|
|
+ raise_softirq_irqoff(HRTIMER_SOFTIRQ);
|
|
|
+ }
|
|
|
+
|
|
|
+ __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
|
|
|
|
|
|
/* Reevaluate the clock bases for the next expiry */
|
|
|
- expires_next = __hrtimer_get_next_event(cpu_base);
|
|
|
+ expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
|
|
|
/*
|
|
|
* Store the new expiry value so the migration code can verify
|
|
|
* against it.
|
|
|
*/
|
|
|
cpu_base->expires_next = expires_next;
|
|
|
cpu_base->in_hrtirq = 0;
|
|
|
- raw_spin_unlock(&cpu_base->lock);
|
|
|
+ raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
|
|
|
|
|
|
/* Reprogramming necessary ? */
|
|
|
if (!tick_program_event(expires_next, 0)) {
|
|
@@ -1339,7 +1498,7 @@ retry:
|
|
|
* Acquire base lock for updating the offsets and retrieving
|
|
|
* the current time.
|
|
|
*/
|
|
|
- raw_spin_lock(&cpu_base->lock);
|
|
|
+ raw_spin_lock_irqsave(&cpu_base->lock, flags);
|
|
|
now = hrtimer_update_base(cpu_base);
|
|
|
cpu_base->nr_retries++;
|
|
|
if (++retries < 3)
|
|
@@ -1352,7 +1511,8 @@ retry:
|
|
|
*/
|
|
|
cpu_base->nr_hangs++;
|
|
|
cpu_base->hang_detected = 1;
|
|
|
- raw_spin_unlock(&cpu_base->lock);
|
|
|
+ raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
|
|
|
+
|
|
|
delta = ktime_sub(now, entry_time);
|
|
|
if ((unsigned int)delta > cpu_base->max_hang_time)
|
|
|
cpu_base->max_hang_time = (unsigned int) delta;
|
|
@@ -1394,6 +1554,7 @@ static inline void __hrtimer_peek_ahead_timers(void) { }
|
|
|
void hrtimer_run_queues(void)
|
|
|
{
|
|
|
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
|
|
|
+ unsigned long flags;
|
|
|
ktime_t now;
|
|
|
|
|
|
if (__hrtimer_hres_active(cpu_base))
|
|
@@ -1411,10 +1572,17 @@ void hrtimer_run_queues(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- raw_spin_lock(&cpu_base->lock);
|
|
|
+ raw_spin_lock_irqsave(&cpu_base->lock, flags);
|
|
|
now = hrtimer_update_base(cpu_base);
|
|
|
- __hrtimer_run_queues(cpu_base, now);
|
|
|
- raw_spin_unlock(&cpu_base->lock);
|
|
|
+
|
|
|
+ if (!ktime_before(now, cpu_base->softirq_expires_next)) {
|
|
|
+ cpu_base->softirq_expires_next = KTIME_MAX;
|
|
|
+ cpu_base->softirq_activated = 1;
|
|
|
+ raise_softirq_irqoff(HRTIMER_SOFTIRQ);
|
|
|
+ }
|
|
|
+
|
|
|
+ __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
|
|
|
+ raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1591,9 +1759,14 @@ int hrtimers_prepare_cpu(unsigned int cpu)
|
|
|
timerqueue_init_head(&cpu_base->clock_base[i].active);
|
|
|
}
|
|
|
|
|
|
- cpu_base->active_bases = 0;
|
|
|
cpu_base->cpu = cpu;
|
|
|
- hrtimer_init_hres(cpu_base);
|
|
|
+ cpu_base->active_bases = 0;
|
|
|
+ cpu_base->hres_active = 0;
|
|
|
+ cpu_base->hang_detected = 0;
|
|
|
+ cpu_base->next_timer = NULL;
|
|
|
+ cpu_base->softirq_next_timer = NULL;
|
|
|
+ cpu_base->expires_next = KTIME_MAX;
|
|
|
+ cpu_base->softirq_expires_next = KTIME_MAX;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1625,7 +1798,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
|
|
|
* sort out already expired timers and reprogram the
|
|
|
* event device.
|
|
|
*/
|
|
|
- enqueue_hrtimer(timer, new_base);
|
|
|
+ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1637,6 +1810,12 @@ int hrtimers_dead_cpu(unsigned int scpu)
|
|
|
BUG_ON(cpu_online(scpu));
|
|
|
tick_cancel_sched_timer(scpu);
|
|
|
|
|
|
+ /*
|
|
|
+ * this BH disable ensures that raise_softirq_irqoff() does
|
|
|
+ * not wakeup ksoftirqd (and acquire the pi-lock) while
|
|
|
+ * holding the cpu_base lock
|
|
|
+ */
|
|
|
+ local_bh_disable();
|
|
|
local_irq_disable();
|
|
|
old_base = &per_cpu(hrtimer_bases, scpu);
|
|
|
new_base = this_cpu_ptr(&hrtimer_bases);
|
|
@@ -1652,12 +1831,19 @@ int hrtimers_dead_cpu(unsigned int scpu)
|
|
|
&new_base->clock_base[i]);
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * The migration might have changed the first expiring softirq
|
|
|
+ * timer on this CPU. Update it.
|
|
|
+ */
|
|
|
+ hrtimer_update_softirq_timer(new_base, false);
|
|
|
+
|
|
|
raw_spin_unlock(&old_base->lock);
|
|
|
raw_spin_unlock(&new_base->lock);
|
|
|
|
|
|
/* Check, if we got expired work to do */
|
|
|
__hrtimer_peek_ahead_timers();
|
|
|
local_irq_enable();
|
|
|
+ local_bh_enable();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1666,18 +1852,19 @@ int hrtimers_dead_cpu(unsigned int scpu)
|
|
|
void __init hrtimers_init(void)
|
|
|
{
|
|
|
hrtimers_prepare_cpu(smp_processor_id());
|
|
|
+ open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* schedule_hrtimeout_range_clock - sleep until timeout
|
|
|
* @expires: timeout value (ktime_t)
|
|
|
* @delta: slack in expires timeout (ktime_t)
|
|
|
- * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
|
|
|
- * @clock: timer clock, CLOCK_MONOTONIC or CLOCK_REALTIME
|
|
|
+ * @mode: timer mode
|
|
|
+ * @clock_id: timer clock to be used
|
|
|
*/
|
|
|
int __sched
|
|
|
schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta,
|
|
|
- const enum hrtimer_mode mode, int clock)
|
|
|
+ const enum hrtimer_mode mode, clockid_t clock_id)
|
|
|
{
|
|
|
struct hrtimer_sleeper t;
|
|
|
|
|
@@ -1698,7 +1885,7 @@ schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta,
|
|
|
return -EINTR;
|
|
|
}
|
|
|
|
|
|
- hrtimer_init_on_stack(&t.timer, clock, mode);
|
|
|
+ hrtimer_init_on_stack(&t.timer, clock_id, mode);
|
|
|
hrtimer_set_expires_range_ns(&t.timer, *expires, delta);
|
|
|
|
|
|
hrtimer_init_sleeper(&t, current);
|
|
@@ -1720,7 +1907,7 @@ schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta,
|
|
|
* schedule_hrtimeout_range - sleep until timeout
|
|
|
* @expires: timeout value (ktime_t)
|
|
|
* @delta: slack in expires timeout (ktime_t)
|
|
|
- * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
|
|
|
+ * @mode: timer mode
|
|
|
*
|
|
|
* Make the current task sleep until the given expiry time has
|
|
|
* elapsed. The routine will return immediately unless
|
|
@@ -1759,7 +1946,7 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout_range);
|
|
|
/**
|
|
|
* schedule_hrtimeout - sleep until timeout
|
|
|
* @expires: timeout value (ktime_t)
|
|
|
- * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
|
|
|
+ * @mode: timer mode
|
|
|
*
|
|
|
* Make the current task sleep until the given expiry time has
|
|
|
* elapsed. The routine will return immediately unless
|