alarmtimer: Do not signal SIGEV_NONE timers
[pandora-kernel.git] / kernel / time / timekeeping.c
index 2b021b0..068c092 100644 (file)
@@ -161,23 +161,43 @@ static struct timespec xtime __attribute__ ((aligned (16)));
 static struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
 static struct timespec total_sleep_time;
 
+/* Offset clock monotonic -> clock realtime */
+static ktime_t offs_real;
+
+/* Offset clock monotonic -> clock boottime */
+static ktime_t offs_boot;
+
 /*
  * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock.
  */
 static struct timespec raw_time;
 
-/* flag for if timekeeping is suspended */
-int __read_mostly timekeeping_suspended;
+/* must hold write on xtime_lock */
+static void update_rt_offset(void)
+{
+       struct timespec tmp, *wtm = &wall_to_monotonic;
 
-/* must hold xtime_lock */
-void timekeeping_leap_insert(int leapsecond)
+       set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec);
+       offs_real = timespec_to_ktime(tmp);
+}
+
+/* must hold write on xtime_lock */
+static void timekeeping_update(bool clearntp)
 {
-       xtime.tv_sec += leapsecond;
-       wall_to_monotonic.tv_sec -= leapsecond;
-       update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-                       timekeeper.mult);
+       if (clearntp) {
+               timekeeper.ntp_error = 0;
+               ntp_clear();
+       }
+       update_rt_offset();
+       update_vsyscall(&xtime, &wall_to_monotonic,
+                        timekeeper.clock, timekeeper.mult);
 }
 
+
+
+/* flag for if timekeeping is suspended */
+int __read_mostly timekeeping_suspended;
+
 /**
  * timekeeping_forward_now - update clock to the current time
  *
@@ -249,6 +269,8 @@ ktime_t ktime_get(void)
                secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
                nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
                nsecs += timekeeping_get_ns();
+               /* If arch requires, add in gettimeoffset() */
+               nsecs += arch_gettimeoffset();
 
        } while (read_seqretry(&xtime_lock, seq));
        /*
@@ -280,6 +302,8 @@ void ktime_get_ts(struct timespec *ts)
                *ts = xtime;
                tomono = wall_to_monotonic;
                nsecs = timekeeping_get_ns();
+               /* If arch requires, add in gettimeoffset() */
+               nsecs += arch_gettimeoffset();
 
        } while (read_seqretry(&xtime_lock, seq));
 
@@ -358,7 +382,7 @@ int do_settimeofday(const struct timespec *tv)
        struct timespec ts_delta;
        unsigned long flags;
 
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+       if (!timespec_valid_strict(tv))
                return -EINVAL;
 
        write_seqlock_irqsave(&xtime_lock, flags);
@@ -371,11 +395,7 @@ int do_settimeofday(const struct timespec *tv)
 
        xtime = *tv;
 
-       timekeeper.ntp_error = 0;
-       ntp_clear();
-
-       update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-                               timekeeper.mult);
+       timekeeping_update(true);
 
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
@@ -397,6 +417,8 @@ EXPORT_SYMBOL(do_settimeofday);
 int timekeeping_inject_offset(struct timespec *ts)
 {
        unsigned long flags;
+       struct timespec tmp;
+       int ret = 0;
 
        if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
@@ -405,21 +427,24 @@ int timekeeping_inject_offset(struct timespec *ts)
 
        timekeeping_forward_now();
 
+       tmp = timespec_add(xtime,  *ts);
+       if (!timespec_valid_strict(&tmp)) {
+               ret = -EINVAL;
+               goto error;
+       }
+
        xtime = timespec_add(xtime, *ts);
        wall_to_monotonic = timespec_sub(wall_to_monotonic, *ts);
 
-       timekeeper.ntp_error = 0;
-       ntp_clear();
-
-       update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-                               timekeeper.mult);
+error: /* even if we error out, we forwarded the time, so call update */
+       timekeeping_update(true);
 
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(timekeeping_inject_offset);
 
@@ -566,7 +591,20 @@ void __init timekeeping_init(void)
        struct timespec now, boot;
 
        read_persistent_clock(&now);
+       if (!timespec_valid_strict(&now)) {
+               pr_warn("WARNING: Persistent clock returned invalid value!\n"
+                       "         Check your CMOS/BIOS settings.\n");
+               now.tv_sec = 0;
+               now.tv_nsec = 0;
+       }
+
        read_boot_clock(&boot);
+       if (!timespec_valid_strict(&boot)) {
+               pr_warn("WARNING: Boot clock returned invalid value!\n"
+                       "         Check your CMOS/BIOS settings.\n");
+               boot.tv_sec = 0;
+               boot.tv_nsec = 0;
+       }
 
        write_seqlock_irqsave(&xtime_lock, flags);
 
@@ -587,6 +625,7 @@ void __init timekeeping_init(void)
        }
        set_normalized_timespec(&wall_to_monotonic,
                                -boot.tv_sec, -boot.tv_nsec);
+       update_rt_offset();
        total_sleep_time.tv_sec = 0;
        total_sleep_time.tv_nsec = 0;
        write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -595,6 +634,12 @@ void __init timekeeping_init(void)
 /* time in seconds when suspend began */
 static struct timespec timekeeping_suspend_time;
 
+static void update_sleep_time(struct timespec t)
+{
+       total_sleep_time = t;
+       offs_boot = timespec_to_ktime(t);
+}
+
 /**
  * __timekeeping_inject_sleeptime - Internal function to add sleep interval
  * @delta: pointer to a timespec delta value
@@ -604,7 +649,7 @@ static struct timespec timekeeping_suspend_time;
  */
 static void __timekeeping_inject_sleeptime(struct timespec *delta)
 {
-       if (!timespec_valid(delta)) {
+       if (!timespec_valid_strict(delta)) {
                printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid "
                                        "sleep delta value!\n");
                return;
@@ -612,7 +657,7 @@ static void __timekeeping_inject_sleeptime(struct timespec *delta)
 
        xtime = timespec_add(xtime, *delta);
        wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta);
-       total_sleep_time = timespec_add(total_sleep_time, *delta);
+       update_sleep_time(timespec_add(total_sleep_time, *delta));
 }
 
 
@@ -641,10 +686,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
 
        __timekeeping_inject_sleeptime(delta);
 
-       timekeeper.ntp_error = 0;
-       ntp_clear();
-       update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-                               timekeeper.mult);
+       timekeeping_update(true);
 
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
@@ -679,6 +721,7 @@ static void timekeeping_resume(void)
        timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
        timekeeper.ntp_error = 0;
        timekeeping_suspended = 0;
+       timekeeping_update(false);
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        touch_softlockup_watchdog();
@@ -802,14 +845,44 @@ static void timekeeping_adjust(s64 offset)
        s64 error, interval = timekeeper.cycle_interval;
        int adj;
 
+       /*
+        * The point of this is to check if the error is greater then half
+        * an interval.
+        *
+        * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
+        *
+        * Note we subtract one in the shift, so that error is really error*2.
+        * This "saves" dividing(shifting) intererval twice, but keeps the
+        * (error > interval) comparision as still measuring if error is
+        * larger then half an interval.
+        *
+        * Note: It does not "save" on aggrivation when reading the code.
+        */
        error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1);
        if (error > interval) {
+               /*
+                * We now divide error by 4(via shift), which checks if
+                * the error is greater then twice the interval.
+                * If it is greater, we need a bigadjust, if its smaller,
+                * we can adjust by 1.
+                */
                error >>= 2;
+               /*
+                * XXX - In update_wall_time, we round up to the next
+                * nanosecond, and store the amount rounded up into
+                * the error. This causes the likely below to be unlikely.
+                *
+                * The properfix is to avoid rounding up by using
+                * the high precision timekeeper.xtime_nsec instead of
+                * xtime.tv_nsec everywhere. Fixing this will take some
+                * time.
+                */
                if (likely(error <= interval))
                        adj = 1;
                else
                        adj = timekeeping_bigadjust(error, &interval, &offset);
        } else if (error < -interval) {
+               /* See comment above, this is just switched for the negative */
                error >>= 2;
                if (likely(error >= -interval)) {
                        adj = -1;
@@ -817,9 +890,65 @@ static void timekeeping_adjust(s64 offset)
                        offset = -offset;
                } else
                        adj = timekeeping_bigadjust(error, &interval, &offset);
-       } else
+       } else /* No adjustment needed */
                return;
 
+       WARN_ONCE(timekeeper.clock->maxadj &&
+                       (timekeeper.mult + adj > timekeeper.clock->mult +
+                                               timekeeper.clock->maxadj),
+                       "Adjusting %s more then 11%% (%ld vs %ld)\n",
+                       timekeeper.clock->name, (long)timekeeper.mult + adj,
+                       (long)timekeeper.clock->mult +
+                               timekeeper.clock->maxadj);
+       /*
+        * So the following can be confusing.
+        *
+        * To keep things simple, lets assume adj == 1 for now.
+        *
+        * When adj != 1, remember that the interval and offset values
+        * have been appropriately scaled so the math is the same.
+        *
+        * The basic idea here is that we're increasing the multiplier
+        * by one, this causes the xtime_interval to be incremented by
+        * one cycle_interval. This is because:
+        *      xtime_interval = cycle_interval * mult
+        * So if mult is being incremented by one:
+        *      xtime_interval = cycle_interval * (mult + 1)
+        * Its the same as:
+        *      xtime_interval = (cycle_interval * mult) + cycle_interval
+        * Which can be shortened to:
+        *      xtime_interval += cycle_interval
+        *
+        * So offset stores the non-accumulated cycles. Thus the current
+        * time (in shifted nanoseconds) is:
+        *      now = (offset * adj) + xtime_nsec
+        * Now, even though we're adjusting the clock frequency, we have
+        * to keep time consistent. In other words, we can't jump back
+        * in time, and we also want to avoid jumping forward in time.
+        *
+        * So given the same offset value, we need the time to be the same
+        * both before and after the freq adjustment.
+        *      now = (offset * adj_1) + xtime_nsec_1
+        *      now = (offset * adj_2) + xtime_nsec_2
+        * So:
+        *      (offset * adj_1) + xtime_nsec_1 =
+        *              (offset * adj_2) + xtime_nsec_2
+        * And we know:
+        *      adj_2 = adj_1 + 1
+        * So:
+        *      (offset * adj_1) + xtime_nsec_1 =
+        *              (offset * (adj_1+1)) + xtime_nsec_2
+        *      (offset * adj_1) + xtime_nsec_1 =
+        *              (offset * adj_1) + offset + xtime_nsec_2
+        * Canceling the sides:
+        *      xtime_nsec_1 = offset + xtime_nsec_2
+        * Which gives us:
+        *      xtime_nsec_2 = xtime_nsec_1 - offset
+        * Which simplfies to:
+        *      xtime_nsec -= offset
+        *
+        * XXX - TODO: Doc ntp_error calculation.
+        */
        timekeeper.mult += adj;
        timekeeper.xtime_interval += interval;
        timekeeper.xtime_nsec -= offset;
@@ -852,13 +981,18 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
 
        timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
        while (timekeeper.xtime_nsec >= nsecps) {
+               int leap;
                timekeeper.xtime_nsec -= nsecps;
                xtime.tv_sec++;
-               second_overflow();
+               leap = second_overflow(xtime.tv_sec);
+               xtime.tv_sec += leap;
+               wall_to_monotonic.tv_sec -= leap;
+               if (leap)
+                       clock_was_set_delayed();
        }
 
        /* Accumulate raw time */
-       raw_nsecs = timekeeper.raw_interval << shift;
+       raw_nsecs = (u64)timekeeper.raw_interval << shift;
        raw_nsecs += raw_time.tv_nsec;
        if (raw_nsecs >= NSEC_PER_SEC) {
                u64 raw_secs = raw_nsecs;
@@ -899,6 +1033,10 @@ static void update_wall_time(void)
 #else
        offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
 #endif
+       /* Check if there's really nothing to do */
+       if (offset < timekeeper.cycle_interval)
+               return;
+
        timekeeper.xtime_nsec = (s64)xtime.tv_nsec << timekeeper.shift;
 
        /*
@@ -960,14 +1098,17 @@ static void update_wall_time(void)
         * xtime.tv_nsec isn't larger then NSEC_PER_SEC
         */
        if (unlikely(xtime.tv_nsec >= NSEC_PER_SEC)) {
+               int leap;
                xtime.tv_nsec -= NSEC_PER_SEC;
                xtime.tv_sec++;
-               second_overflow();
+               leap = second_overflow(xtime.tv_sec);
+               xtime.tv_sec += leap;
+               wall_to_monotonic.tv_sec -= leap;
+               if (leap)
+                       clock_was_set_delayed();
        }
 
-       /* check to see if there is a new clocksource to use */
-       update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
-                               timekeeper.mult);
+       timekeeping_update(false);
 }
 
 /**
@@ -1020,7 +1161,7 @@ void get_monotonic_boottime(struct timespec *ts)
        } while (read_seqretry(&xtime_lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
-                       ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);
+               (s64)ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);
 }
 EXPORT_SYMBOL_GPL(get_monotonic_boottime);
 
@@ -1126,6 +1267,40 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
        } while (read_seqretry(&xtime_lock, seq));
 }
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+/**
+ * ktime_get_update_offsets - hrtimer helper
+ * @real:      pointer to storage for monotonic -> realtime offset
+ * @_boot:     pointer to storage for monotonic -> boottime offset
+ *
+ * Returns current monotonic time and updates the offsets
+ * Called from hrtimer_interupt() or retrigger_next_event()
+ */
+ktime_t ktime_get_update_offsets(ktime_t *real, ktime_t *boot)
+{
+       ktime_t now;
+       unsigned int seq;
+       u64 secs, nsecs;
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+
+               secs = xtime.tv_sec;
+               nsecs = xtime.tv_nsec;
+               nsecs += timekeeping_get_ns();
+               /* If arch requires, add in gettimeoffset() */
+               nsecs += arch_gettimeoffset();
+
+               *real = offs_real;
+               *boot = offs_boot;
+       } while (read_seqretry(&xtime_lock, seq));
+
+       now = ktime_add_ns(ktime_set(secs, 0), nsecs);
+       now = ktime_sub(now, *real);
+       return now;
+}
+#endif
+
 /**
  * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format
  */