hrtimer: Add hrtimer support for CLOCK_TAI
John Stultz [Tue, 22 Jan 2013 01:00:11 +0000 (17:00 -0800)]
Add hrtimer support for CLOCK_TAI, as well as posix timer interfaces.

Signed-off-by: John Stultz <john.stultz@linaro.org>

include/linux/hrtimer.h
include/linux/timekeeper_internal.h
kernel/hrtimer.c
kernel/posix-timers.c
kernel/time/timekeeping.c

index cc07d27..d19a5c2 100644 (file)
@@ -157,6 +157,7 @@ enum  hrtimer_base_type {
        HRTIMER_BASE_MONOTONIC,
        HRTIMER_BASE_REALTIME,
        HRTIMER_BASE_BOOTTIME,
+       HRTIMER_BASE_TAI,
        HRTIMER_MAX_CLOCK_BASES,
 };
 
@@ -327,7 +328,9 @@ extern ktime_t ktime_get(void);
 extern ktime_t ktime_get_real(void);
 extern ktime_t ktime_get_boottime(void);
 extern ktime_t ktime_get_monotonic_offset(void);
-extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot);
+extern ktime_t ktime_get_clocktai(void);
+extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
+                                        ktime_t *offs_tai);
 
 DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
 
index ff94f43..26700d8 100644 (file)
@@ -64,6 +64,8 @@ struct timekeeper {
        struct timespec         raw_time;
        /* The current UTC to TAI offset in seconds */
        s32                     tai_offset;
+       /* Offset clock monotonic -> clock tai */
+       ktime_t                 offs_tai;
 
        /* Seqlock for all timekeeper values */
        seqlock_t               lock;
index cc47812..2587207 100644 (file)
@@ -83,6 +83,12 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
                        .get_time = &ktime_get_boottime,
                        .resolution = KTIME_LOW_RES,
                },
+               {
+                       .index = HRTIMER_BASE_TAI,
+                       .clockid = CLOCK_TAI,
+                       .get_time = &ktime_get_clocktai,
+                       .resolution = KTIME_LOW_RES,
+               },
        }
 };
 
@@ -90,6 +96,7 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
        [CLOCK_REALTIME]        = HRTIMER_BASE_REALTIME,
        [CLOCK_MONOTONIC]       = HRTIMER_BASE_MONOTONIC,
        [CLOCK_BOOTTIME]        = HRTIMER_BASE_BOOTTIME,
+       [CLOCK_TAI]             = HRTIMER_BASE_TAI,
 };
 
 static inline int hrtimer_clockid_to_base(clockid_t clock_id)
@@ -106,8 +113,10 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
 {
        ktime_t xtim, mono, boot;
        struct timespec xts, tom, slp;
+       s32 tai_offset;
 
        get_xtime_and_monotonic_and_sleep_offset(&xts, &tom, &slp);
+       tai_offset = timekeeping_get_tai_offset();
 
        xtim = timespec_to_ktime(xts);
        mono = ktime_add(xtim, timespec_to_ktime(tom));
@@ -115,6 +124,8 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
        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;
+       base->clock_base[HRTIMER_BASE_TAI].softirq_time =
+                               ktime_add(xtim, ktime_set(tai_offset, 0));
 }
 
 /*
@@ -651,8 +662,9 @@ static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
 {
        ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
        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(offs_real, offs_boot);
+       return ktime_get_update_offsets(offs_real, offs_boot, offs_tai);
 }
 
 /*
index fbfc5f1..2a2e173 100644 (file)
@@ -269,6 +269,12 @@ static __init int init_posix_timers(void)
        struct k_clock clock_tai = {
                .clock_getres   = hrtimer_get_res,
                .clock_get      = posix_get_tai,
+               .nsleep         = common_nsleep,
+               .nsleep_restart = hrtimer_nanosleep_restart,
+               .timer_create   = common_timer_create,
+               .timer_set      = common_timer_set,
+               .timer_get      = common_timer_get,
+               .timer_del      = common_timer_del,
        };
        struct k_clock clock_boottime = {
                .clock_getres   = hrtimer_get_res,
index 8a84275..8061ae0 100644 (file)
@@ -67,6 +67,7 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)
        tk->wall_to_monotonic = wtm;
        set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec);
        tk->offs_real = timespec_to_ktime(tmp);
+       tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tk->tai_offset, 0));
 }
 
 static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t)
@@ -409,6 +410,20 @@ void timekeeping_clocktai(struct timespec *ts)
 EXPORT_SYMBOL(timekeeping_clocktai);
 
 
+/**
+ * ktime_get_clocktai - Returns the TAI time of day in a ktime
+ *
+ * Returns the time of day in a ktime.
+ */
+ktime_t ktime_get_clocktai(void)
+{
+       struct timespec ts;
+
+       timekeeping_clocktai(&ts);
+       return timespec_to_ktime(ts);
+}
+EXPORT_SYMBOL(ktime_get_clocktai);
+
 #ifdef CONFIG_NTP_PPS
 
 /**
@@ -569,6 +584,7 @@ s32 timekeeping_get_tai_offset(void)
 void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset)
 {
        tk->tai_offset = tai_offset;
+       tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tai_offset, 0));
 }
 
 /**
@@ -1539,7 +1555,8 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
  * Returns current monotonic time and updates the offsets
  * Called from hrtimer_interupt() or retrigger_next_event()
  */
-ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
+ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
+                                                       ktime_t *offs_tai)
 {
        struct timekeeper *tk = &timekeeper;
        ktime_t now;
@@ -1554,6 +1571,7 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
 
                *offs_real = tk->offs_real;
                *offs_boot = tk->offs_boot;
+               *offs_tai = tk->offs_tai;
        } while (read_seqretry(&tk->lock, seq));
 
        now = ktime_add_ns(ktime_set(secs, 0), nsecs);