aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/clocksource.h3
-rw-r--r--include/linux/time.h2
-rw-r--r--kernel/posix-timers.c15
-rw-r--r--kernel/time/timekeeping.c44
4 files changed, 64 insertions, 0 deletions
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index f0a7fb984413..f88d32f8ff7c 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -79,6 +79,7 @@ struct clocksource {
79 /* timekeeping specific data, ignore */ 79 /* timekeeping specific data, ignore */
80 cycle_t cycle_interval; 80 cycle_t cycle_interval;
81 u64 xtime_interval; 81 u64 xtime_interval;
82 u32 raw_interval;
82 /* 83 /*
83 * Second part is written at each timer interrupt 84 * Second part is written at each timer interrupt
84 * Keep it in a different cache line to dirty no 85 * Keep it in a different cache line to dirty no
@@ -87,6 +88,7 @@ struct clocksource {
87 cycle_t cycle_last ____cacheline_aligned_in_smp; 88 cycle_t cycle_last ____cacheline_aligned_in_smp;
88 u64 xtime_nsec; 89 u64 xtime_nsec;
89 s64 error; 90 s64 error;
91 struct timespec raw_time;
90 92
91#ifdef CONFIG_CLOCKSOURCE_WATCHDOG 93#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
92 /* Watchdog related data, used by the framework */ 94 /* Watchdog related data, used by the framework */
@@ -215,6 +217,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
215 217
216 /* Go back from cycles -> shifted ns, this time use ntp adjused mult */ 218 /* Go back from cycles -> shifted ns, this time use ntp adjused mult */
217 c->xtime_interval = (u64)c->cycle_interval * c->mult; 219 c->xtime_interval = (u64)c->cycle_interval * c->mult;
220 c->raw_interval = ((u64)c->cycle_interval * c->mult_orig) >> c->shift;
218} 221}
219 222
220 223
diff --git a/include/linux/time.h b/include/linux/time.h
index e15206a7e82e..205f974b9ebf 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -117,6 +117,7 @@ extern int do_setitimer(int which, struct itimerval *value,
117extern unsigned int alarm_setitimer(unsigned int seconds); 117extern unsigned int alarm_setitimer(unsigned int seconds);
118extern int do_getitimer(int which, struct itimerval *value); 118extern int do_getitimer(int which, struct itimerval *value);
119extern void getnstimeofday(struct timespec *tv); 119extern void getnstimeofday(struct timespec *tv);
120extern void getrawmonotonic(struct timespec *ts);
120extern void getboottime(struct timespec *ts); 121extern void getboottime(struct timespec *ts);
121extern void monotonic_to_bootbased(struct timespec *ts); 122extern void monotonic_to_bootbased(struct timespec *ts);
122 123
@@ -214,6 +215,7 @@ struct itimerval {
214#define CLOCK_MONOTONIC 1 215#define CLOCK_MONOTONIC 1
215#define CLOCK_PROCESS_CPUTIME_ID 2 216#define CLOCK_PROCESS_CPUTIME_ID 2
216#define CLOCK_THREAD_CPUTIME_ID 3 217#define CLOCK_THREAD_CPUTIME_ID 3
218#define CLOCK_MONOTONIC_RAW 4
217 219
218/* 220/*
219 * The IDs of various hardware clocks: 221 * The IDs of various hardware clocks:
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index e36d5798cbff..d3c66b53dff6 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -223,6 +223,15 @@ static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp)
223} 223}
224 224
225/* 225/*
226 * Get monotonic time for posix timers
227 */
228static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)
229{
230 getrawmonotonic(tp);
231 return 0;
232}
233
234/*
226 * Initialize everything, well, just everything in Posix clocks/timers ;) 235 * Initialize everything, well, just everything in Posix clocks/timers ;)
227 */ 236 */
228static __init int init_posix_timers(void) 237static __init int init_posix_timers(void)
@@ -235,9 +244,15 @@ static __init int init_posix_timers(void)
235 .clock_get = posix_ktime_get_ts, 244 .clock_get = posix_ktime_get_ts,
236 .clock_set = do_posix_clock_nosettime, 245 .clock_set = do_posix_clock_nosettime,
237 }; 246 };
247 struct k_clock clock_monotonic_raw = {
248 .clock_getres = hrtimer_get_res,
249 .clock_get = posix_get_monotonic_raw,
250 .clock_set = do_posix_clock_nosettime,
251 };
238 252
239 register_posix_clock(CLOCK_REALTIME, &clock_realtime); 253 register_posix_clock(CLOCK_REALTIME, &clock_realtime);
240 register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); 254 register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
255 register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
241 256
242 posix_timers_cache = kmem_cache_create("posix_timers_cache", 257 posix_timers_cache = kmem_cache_create("posix_timers_cache",
243 sizeof (struct k_itimer), 0, SLAB_PANIC, 258 sizeof (struct k_itimer), 0, SLAB_PANIC,
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 83d3555a6998..5099c95b8aa2 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -75,6 +75,9 @@ static void clocksource_forward_now(void)
75 75
76 nsec = cyc2ns(clock, cycle_delta); 76 nsec = cyc2ns(clock, cycle_delta);
77 timespec_add_ns(&xtime, nsec); 77 timespec_add_ns(&xtime, nsec);
78
79 nsec = ((s64)cycle_delta * clock->mult_orig) >> clock->shift;
80 clock->raw_time.tv_nsec += nsec;
78} 81}
79 82
80/** 83/**
@@ -183,6 +186,8 @@ static void change_clocksource(void)
183 186
184 clocksource_forward_now(); 187 clocksource_forward_now();
185 188
189 new->raw_time = clock->raw_time;
190
186 clock = new; 191 clock = new;
187 clock->cycle_last = 0; 192 clock->cycle_last = 0;
188 clock->cycle_last = clocksource_read(new); 193 clock->cycle_last = clocksource_read(new);
@@ -205,6 +210,39 @@ static inline void change_clocksource(void) { }
205#endif 210#endif
206 211
207/** 212/**
213 * getrawmonotonic - Returns the raw monotonic time in a timespec
214 * @ts: pointer to the timespec to be set
215 *
216 * Returns the raw monotonic time (completely un-modified by ntp)
217 */
218void getrawmonotonic(struct timespec *ts)
219{
220 unsigned long seq;
221 s64 nsecs;
222 cycle_t cycle_now, cycle_delta;
223
224 do {
225 seq = read_seqbegin(&xtime_lock);
226
227 /* read clocksource: */
228 cycle_now = clocksource_read(clock);
229
230 /* calculate the delta since the last update_wall_time: */
231 cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
232
233 /* convert to nanoseconds: */
234 nsecs = ((s64)cycle_delta * clock->mult_orig) >> clock->shift;
235
236 *ts = clock->raw_time;
237
238 } while (read_seqretry(&xtime_lock, seq));
239
240 timespec_add_ns(ts, nsecs);
241}
242EXPORT_SYMBOL(getrawmonotonic);
243
244
245/**
208 * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres 246 * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
209 */ 247 */
210int timekeeping_valid_for_hres(void) 248int timekeeping_valid_for_hres(void)
@@ -466,6 +504,12 @@ void update_wall_time(void)
466 second_overflow(); 504 second_overflow();
467 } 505 }
468 506
507 clock->raw_time.tv_nsec += clock->raw_interval;
508 if (clock->raw_time.tv_nsec >= NSEC_PER_SEC) {
509 clock->raw_time.tv_nsec -= NSEC_PER_SEC;
510 clock->raw_time.tv_sec++;
511 }
512
469 /* accumulate error between NTP and clock interval */ 513 /* accumulate error between NTP and clock interval */
470 clock->error += tick_length; 514 clock->error += tick_length;
471 clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift); 515 clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);