Skip to content

Commit

Permalink
[PATCH] Time: Introduce arch generic time accessors
Browse files Browse the repository at this point in the history
Introduces clocksource switching code and the arch generic time accessor
functions that use the clocksource infrastructure.

Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
john stultz authored and Linus Torvalds committed Jun 26, 2006
1 parent 5eb6d20 commit cf3c769
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
15 changes: 15 additions & 0 deletions include/linux/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ extern int do_getitimer(int which, struct itimerval *value);
extern void getnstimeofday(struct timespec *tv);

extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_is_continuous(void);

/**
* timespec_to_ns - Convert timespec to nanoseconds
Expand Down Expand Up @@ -144,6 +145,20 @@ extern struct timespec ns_to_timespec(const s64 nsec);
*/
extern struct timeval ns_to_timeval(const s64 nsec);

/**
* timespec_add_ns - Adds nanoseconds to a timespec
* @a: pointer to timespec to be incremented
* @ns: unsigned nanoseconds value to be added
*/
static inline void timespec_add_ns(struct timespec *a, u64 ns)
{
ns += a->tv_nsec;
while(unlikely(ns >= NSEC_PER_SEC)) {
ns -= NSEC_PER_SEC;
a->tv_sec++;
}
a->tv_nsec = ns;
}
#endif /* __KERNEL__ */

#define NFDBITS __NFDBITS
Expand Down
2 changes: 2 additions & 0 deletions kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ EXPORT_SYMBOL(do_gettimeofday);


#else
#ifndef CONFIG_GENERIC_TIME
/*
* Simulate gettimeofday using do_gettimeofday which only allows a timeval
* and therefore only yields usec accuracy
Expand All @@ -537,6 +538,7 @@ void getnstimeofday(struct timespec *tv)
}
EXPORT_SYMBOL_GPL(getnstimeofday);
#endif
#endif

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
Expand Down
170 changes: 170 additions & 0 deletions kernel/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,169 @@ u64 current_tick_length(long shift)
#include <linux/clocksource.h>
static struct clocksource *clock; /* pointer to current clocksource */
static cycle_t last_clock_cycle; /* cycle value at last update_wall_time */

#ifdef CONFIG_GENERIC_TIME
/**
* __get_nsec_offset - Returns nanoseconds since last call to periodic_hook
*
* private function, must hold xtime_lock lock when being
* called. Returns the number of nanoseconds since the
* last call to update_wall_time() (adjusted by NTP scaling)
*/
static inline s64 __get_nsec_offset(void)
{
cycle_t cycle_now, cycle_delta;
s64 ns_offset;

/* read clocksource: */
cycle_now = read_clocksource(clock);

/* calculate the delta since the last update_wall_time: */
cycle_delta = (cycle_now - last_clock_cycle) & clock->mask;

/* convert to nanoseconds: */
ns_offset = cyc2ns(clock, cycle_delta);

return ns_offset;
}

/**
* __get_realtime_clock_ts - Returns the time of day in a timespec
* @ts: pointer to the timespec to be set
*
* Returns the time of day in a timespec. Used by
* do_gettimeofday() and get_realtime_clock_ts().
*/
static inline void __get_realtime_clock_ts(struct timespec *ts)
{
unsigned long seq;
s64 nsecs;

do {
seq = read_seqbegin(&xtime_lock);

*ts = xtime;
nsecs = __get_nsec_offset();

} while (read_seqretry(&xtime_lock, seq));

timespec_add_ns(ts, nsecs);
}

/**
* get_realtime_clock_ts - Returns the time of day in a timespec
* @ts: pointer to the timespec to be set
*
* Returns the time of day in a timespec.
*/
void getnstimeofday(struct timespec *ts)
{
__get_realtime_clock_ts(ts);
}

EXPORT_SYMBOL(getnstimeofday);

/**
* do_gettimeofday - Returns the time of day in a timeval
* @tv: pointer to the timeval to be set
*
* NOTE: Users should be converted to using get_realtime_clock_ts()
*/
void do_gettimeofday(struct timeval *tv)
{
struct timespec now;

__get_realtime_clock_ts(&now);
tv->tv_sec = now.tv_sec;
tv->tv_usec = now.tv_nsec/1000;
}

EXPORT_SYMBOL(do_gettimeofday);
/**
* do_settimeofday - Sets the time of day
* @tv: pointer to the timespec variable containing the new time
*
* Sets the time of day to the new time and update NTP and notify hrtimers
*/
int do_settimeofday(struct timespec *tv)
{
unsigned long flags;
time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec, nsec = tv->tv_nsec;

if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;

write_seqlock_irqsave(&xtime_lock, flags);

nsec -= __get_nsec_offset();

wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);

ntp_clear();

write_sequnlock_irqrestore(&xtime_lock, flags);

/* signal hrtimers about time change */
clock_was_set();

return 0;
}

EXPORT_SYMBOL(do_settimeofday);

/**
* change_clocksource - Swaps clocksources if a new one is available
*
* Accumulates current time interval and initializes new clocksource
*/
static int change_clocksource(void)
{
struct clocksource *new;
cycle_t now;
u64 nsec;
new = get_next_clocksource();
if (clock != new) {
now = read_clocksource(new);
nsec = __get_nsec_offset();
timespec_add_ns(&xtime, nsec);

clock = new;
last_clock_cycle = now;
printk(KERN_INFO "Time: %s clocksource has been installed.\n",
clock->name);
return 1;
} else if (clock->update_callback) {
return clock->update_callback();
}
return 0;
}
#else
#define change_clocksource() (0)
#endif

/**
* timeofday_is_continuous - check to see if timekeeping is free running
*/
int timekeeping_is_continuous(void)
{
unsigned long seq;
int ret;

do {
seq = read_seqbegin(&xtime_lock);

ret = clock->is_continuous;

} while (read_seqretry(&xtime_lock, seq));

return ret;
}

/*
* timekeeping_init - Initializes the clocksource and common timekeeping values
*/
Expand Down Expand Up @@ -901,6 +1064,13 @@ static void update_wall_time(void)
/* store full nanoseconds into xtime */
xtime.tv_nsec = remainder_snsecs >> clock->shift;
remainder_snsecs -= (s64)xtime.tv_nsec << clock->shift;

/* check to see if there is a new clocksource to use */
if (change_clocksource()) {
error = 0;
remainder_snsecs = 0;
calculate_clocksource_interval(clock, tick_nsec);
}
}

/*
Expand Down

0 comments on commit cf3c769

Please sign in to comment.