]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/hrtimer.c
Merge branch 'for-2.6.39' into for-2.6.40
[linux-2.6.git] / kernel / hrtimer.c
index 57c4d33c9a9d6197e65fb1148a7186794e78d231..9017478c5d4c3f224cde995518976ed8d88d79d5 100644 (file)
 /*
  * The timer bases:
  *
- * Note: If we want to add new timer bases, we have to skip the two
- * clock ids captured by the cpu-timers. We do this by holding empty
- * entries rather than doing math adjustment of the clock ids.
- * This ensures that we capture erroneous accesses to these clock ids
- * rather than moving them into the range of valid clock id's.
+ * There are more clockids then hrtimer bases. Thus, we index
+ * into the timer bases by the hrtimer_base_type enum. When trying
+ * to reach a base using a clockid, hrtimer_clockid_to_base()
+ * is used to convert from clockid to the proper hrtimer_base_type.
  */
 DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
 {
@@ -74,25 +73,39 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
                        .get_time = &ktime_get,
                        .resolution = KTIME_LOW_RES,
                },
+               {
+                       .index = CLOCK_BOOTTIME,
+                       .get_time = &ktime_get_boottime,
+                       .resolution = KTIME_LOW_RES,
+               },
        }
 };
 
+static int hrtimer_clock_to_base_table[MAX_CLOCKS];
+
+static inline int hrtimer_clockid_to_base(clockid_t clock_id)
+{
+       return hrtimer_clock_to_base_table[clock_id];
+}
+
+
 /*
  * Get the coarse grained time at the softirq based on xtime and
  * wall_to_monotonic.
  */
 static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
 {
-       ktime_t xtim, tomono;
-       struct timespec xts, tom;
+       ktime_t xtim, mono, boot;
+       struct timespec xts, tom, slp;
 
-       get_xtime_and_monotonic_offset(&xts, &tom);
+       get_xtime_and_monotonic_and_sleep_offset(&xts, &tom, &slp);
 
        xtim = timespec_to_ktime(xts);
-       tomono = timespec_to_ktime(tom);
-       base->clock_base[CLOCK_REALTIME].softirq_time = xtim;
-       base->clock_base[CLOCK_MONOTONIC].softirq_time =
-               ktime_add(xtim, tomono);
+       mono = ktime_add(xtim, timespec_to_ktime(tom));
+       boot = ktime_add(mono, timespec_to_ktime(slp));
+       base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim;
+       base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono;
+       base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot;
 }
 
 /*
@@ -179,10 +192,11 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
        struct hrtimer_cpu_base *new_cpu_base;
        int this_cpu = smp_processor_id();
        int cpu = hrtimer_get_target(this_cpu, pinned);
+       int basenum = hrtimer_clockid_to_base(base->index);
 
 again:
        new_cpu_base = &per_cpu(hrtimer_bases, cpu);
-       new_base = &new_cpu_base->clock_base[base->index];
+       new_base = &new_cpu_base->clock_base[basenum];
 
        if (base != new_base) {
                /*
@@ -329,6 +343,11 @@ EXPORT_SYMBOL_GPL(ktime_add_safe);
 
 static struct debug_obj_descr hrtimer_debug_descr;
 
+static void *hrtimer_debug_hint(void *addr)
+{
+       return ((struct hrtimer *) addr)->function;
+}
+
 /*
  * fixup_init is called when:
  * - an active object is initialized
@@ -388,6 +407,7 @@ static int hrtimer_fixup_free(void *addr, enum debug_obj_state state)
 
 static struct debug_obj_descr hrtimer_debug_descr = {
        .name           = "hrtimer",
+       .debug_hint     = hrtimer_debug_hint,
        .fixup_init     = hrtimer_fixup_init,
        .fixup_activate = hrtimer_fixup_activate,
        .fixup_free     = hrtimer_fixup_free,
@@ -606,20 +626,23 @@ static int hrtimer_reprogram(struct hrtimer *timer,
 static void retrigger_next_event(void *arg)
 {
        struct hrtimer_cpu_base *base;
-       struct timespec realtime_offset, wtm;
+       struct timespec realtime_offset, wtm, sleep;
 
        if (!hrtimer_hres_active())
                return;
 
-       get_xtime_and_monotonic_offset(&realtime_offset, &wtm);
+       get_xtime_and_monotonic_and_sleep_offset(&realtime_offset, &wtm,
+                                                       &sleep);
        set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec);
 
        base = &__get_cpu_var(hrtimer_bases);
 
        /* Adjust CLOCK_REALTIME offset */
        raw_spin_lock(&base->lock);
-       base->clock_base[CLOCK_REALTIME].offset =
+       base->clock_base[HRTIMER_BASE_REALTIME].offset =
                timespec_to_ktime(realtime_offset);
+       base->clock_base[HRTIMER_BASE_BOOTTIME].offset =
+               timespec_to_ktime(sleep);
 
        hrtimer_force_reprogram(base, 0);
        raw_spin_unlock(&base->lock);
@@ -663,14 +686,6 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
        base->hres_active = 0;
 }
 
-/*
- * Initialize the high resolution related parts of a hrtimer
- */
-static inline void hrtimer_init_timer_hres(struct hrtimer *timer)
-{
-}
-
-
 /*
  * When High resolution timers are active, try to reprogram. Note, that in case
  * the state has HRTIMER_STATE_CALLBACK set, no reprogramming and no expiry
@@ -716,8 +731,9 @@ static int hrtimer_switch_to_hres(void)
                return 0;
        }
        base->hres_active = 1;
-       base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES;
-       base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES;
+       base->clock_base[HRTIMER_BASE_REALTIME].resolution = KTIME_HIGH_RES;
+       base->clock_base[HRTIMER_BASE_MONOTONIC].resolution = KTIME_HIGH_RES;
+       base->clock_base[HRTIMER_BASE_BOOTTIME].resolution = KTIME_HIGH_RES;
 
        tick_setup_sched_timer();
 
@@ -741,7 +757,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
        return 0;
 }
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { }
-static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { }
 
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
@@ -1112,6 +1127,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
                           enum hrtimer_mode mode)
 {
        struct hrtimer_cpu_base *cpu_base;
+       int base;
 
        memset(timer, 0, sizeof(struct hrtimer));
 
@@ -1120,8 +1136,8 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
        if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
                clock_id = CLOCK_MONOTONIC;
 
-       timer->base = &cpu_base->clock_base[clock_id];
-       hrtimer_init_timer_hres(timer);
+       base = hrtimer_clockid_to_base(clock_id);
+       timer->base = &cpu_base->clock_base[base];
        timerqueue_init(&timer->node);
 
 #ifdef CONFIG_TIMER_STATS
@@ -1156,9 +1172,10 @@ EXPORT_SYMBOL_GPL(hrtimer_init);
 int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
 {
        struct hrtimer_cpu_base *cpu_base;
+       int base = hrtimer_clockid_to_base(which_clock);
 
        cpu_base = &__raw_get_cpu_var(hrtimer_bases);
-       *tp = ktime_to_timespec(cpu_base->clock_base[which_clock].resolution);
+       *tp = ktime_to_timespec(cpu_base->clock_base[base].resolution);
 
        return 0;
 }
@@ -1705,6 +1722,10 @@ static struct notifier_block __cpuinitdata hrtimers_nb = {
 
 void __init hrtimers_init(void)
 {
+       hrtimer_clock_to_base_table[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME;
+       hrtimer_clock_to_base_table[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC;
+       hrtimer_clock_to_base_table[CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME;
+
        hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE,
                          (void *)(long)smp_processor_id());
        register_cpu_notifier(&hrtimers_nb);