diff options
| -rw-r--r-- | include/linux/clocksource.h | 3 | ||||
| -rw-r--r-- | include/linux/time.h | 2 | ||||
| -rw-r--r-- | kernel/posix-timers.c | 15 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 44 | 
4 files changed, 64 insertions, 0 deletions
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index f0a7fb98441..f88d32f8ff7 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -79,6 +79,7 @@ struct clocksource {  	/* timekeeping specific data, ignore */  	cycle_t cycle_interval;  	u64	xtime_interval; +	u32	raw_interval;  	/*  	 * Second part is written at each timer interrupt  	 * Keep it in a different cache line to dirty no @@ -87,6 +88,7 @@ struct clocksource {  	cycle_t cycle_last ____cacheline_aligned_in_smp;  	u64 xtime_nsec;  	s64 error; +	struct timespec raw_time;  #ifdef CONFIG_CLOCKSOURCE_WATCHDOG  	/* Watchdog related data, used by the framework */ @@ -215,6 +217,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c,  	/* Go back from cycles -> shifted ns, this time use ntp adjused mult */  	c->xtime_interval = (u64)c->cycle_interval * c->mult; +	c->raw_interval = ((u64)c->cycle_interval * c->mult_orig) >> c->shift;  } diff --git a/include/linux/time.h b/include/linux/time.h index e15206a7e82..205f974b9eb 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -117,6 +117,7 @@ extern int do_setitimer(int which, struct itimerval *value,  extern unsigned int alarm_setitimer(unsigned int seconds);  extern int do_getitimer(int which, struct itimerval *value);  extern void getnstimeofday(struct timespec *tv); +extern void getrawmonotonic(struct timespec *ts);  extern void getboottime(struct timespec *ts);  extern void monotonic_to_bootbased(struct timespec *ts); @@ -214,6 +215,7 @@ struct itimerval {  #define CLOCK_MONOTONIC			1  #define CLOCK_PROCESS_CPUTIME_ID	2  #define CLOCK_THREAD_CPUTIME_ID		3 +#define CLOCK_MONOTONIC_RAW		4  /*   * The IDs of various hardware clocks: diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index e36d5798cbf..d3c66b53dff 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)  }  /* + * Get monotonic time for posix timers + */ +static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp) +{ +	getrawmonotonic(tp); +	return 0; +} + +/*   * Initialize everything, well, just everything in Posix clocks/timers ;)   */  static __init int init_posix_timers(void) @@ -235,9 +244,15 @@ static __init int init_posix_timers(void)  		.clock_get = posix_ktime_get_ts,  		.clock_set = do_posix_clock_nosettime,  	}; +	struct k_clock clock_monotonic_raw = { +		.clock_getres = hrtimer_get_res, +		.clock_get = posix_get_monotonic_raw, +		.clock_set = do_posix_clock_nosettime, +	};  	register_posix_clock(CLOCK_REALTIME, &clock_realtime);  	register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); +	register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);  	posix_timers_cache = kmem_cache_create("posix_timers_cache",  					sizeof (struct k_itimer), 0, SLAB_PANIC, diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 83d3555a699..5099c95b8aa 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -75,6 +75,9 @@ static void clocksource_forward_now(void)  	nsec = cyc2ns(clock, cycle_delta);  	timespec_add_ns(&xtime, nsec); + +	nsec = ((s64)cycle_delta * clock->mult_orig) >> clock->shift; +	clock->raw_time.tv_nsec += nsec;  }  /** @@ -183,6 +186,8 @@ static void change_clocksource(void)  	clocksource_forward_now(); +	new->raw_time = clock->raw_time; +  	clock = new;  	clock->cycle_last = 0;  	clock->cycle_last = clocksource_read(new); @@ -205,6 +210,39 @@ static inline void change_clocksource(void) { }  #endif  /** + * getrawmonotonic - Returns the raw monotonic time in a timespec + * @ts:		pointer to the timespec to be set + * + * Returns the raw monotonic time (completely un-modified by ntp) + */ +void getrawmonotonic(struct timespec *ts) +{ +	unsigned long seq; +	s64 nsecs; +	cycle_t cycle_now, cycle_delta; + +	do { +		seq = read_seqbegin(&xtime_lock); + +		/* read clocksource: */ +		cycle_now = clocksource_read(clock); + +		/* calculate the delta since the last update_wall_time: */ +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; + +		/* convert to nanoseconds: */ +		nsecs = ((s64)cycle_delta * clock->mult_orig) >> clock->shift; + +		*ts = clock->raw_time; + +	} while (read_seqretry(&xtime_lock, seq)); + +	timespec_add_ns(ts, nsecs); +} +EXPORT_SYMBOL(getrawmonotonic); + + +/**   * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres   */  int timekeeping_valid_for_hres(void) @@ -466,6 +504,12 @@ void update_wall_time(void)  			second_overflow();  		} +		clock->raw_time.tv_nsec += clock->raw_interval; +		if (clock->raw_time.tv_nsec >= NSEC_PER_SEC) { +			clock->raw_time.tv_nsec -= NSEC_PER_SEC; +			clock->raw_time.tv_sec++; +		} +  		/* accumulate error between NTP and clock interval */  		clock->error += tick_length;  		clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);  |