Skip to content

Commit

Permalink
NTP: move the cmos update code into ntp.c
Browse files Browse the repository at this point in the history
i386 and sparc64 have the identical code to update the cmos clock.  Move it
into kernel/time/ntp.c as there are other architectures coming along with the
same requirements.

[akpm@linux-foundation.org: build fixes]
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: David Miller <davem@davemloft.net>
Cc: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Thomas Gleixner authored and Linus Torvalds committed Jul 22, 2007
1 parent 99bc2fc commit 8264445
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 103 deletions.
4 changes: 4 additions & 0 deletions arch/i386/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ config GENERIC_TIME
bool
default y

config GENERIC_CMOS_UPDATE
bool
default y

config CLOCKSOURCE_WATCHDOG
bool
default y
Expand Down
50 changes: 2 additions & 48 deletions arch/i386/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,55 +207,9 @@ unsigned long read_persistent_clock(void)
return retval;
}

static void sync_cmos_clock(unsigned long dummy);

static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
int no_sync_cmos_clock;

static void sync_cmos_clock(unsigned long dummy)
{
struct timeval now, next;
int fail = 1;

/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
* This code is run on a timer. If the clock is set, that timer
* may not expire at the correct time. Thus, we adjust...
*/
if (!ntp_synced())
/*
* Not synced, exit, do not restart a timer (if one is
* running, let it run out).
*/
return;

do_gettimeofday(&now);
if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
fail = set_rtc_mmss(now.tv_sec);

next.tv_usec = USEC_AFTER - now.tv_usec;
if (next.tv_usec <= 0)
next.tv_usec += USEC_PER_SEC;

if (!fail)
next.tv_sec = 659;
else
next.tv_sec = 0;

if (next.tv_usec >= USEC_PER_SEC) {
next.tv_sec++;
next.tv_usec -= USEC_PER_SEC;
}
mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
}

void notify_arch_cmos_timer(void)
int update_persistent_clock(struct timespec now)
{
if (!no_sync_cmos_clock)
mod_timer(&sync_cmos_timer, jiffies + 1);
return set_rtc_mmss(now.tv_sec);
}

extern void (*late_time_init)(void);
Expand Down
4 changes: 4 additions & 0 deletions arch/sparc64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ config GENERIC_TIME
bool
default y

config GENERIC_CMOS_UPDATE
bool
default y

config GENERIC_CLOCKEVENTS
bool
default y
Expand Down
53 changes: 2 additions & 51 deletions arch/sparc64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,58 +403,9 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {

static unsigned long timer_ticks_per_nsec_quotient __read_mostly;

#define TICK_SIZE (tick_nsec / 1000)

#define USEC_AFTER 500000
#define USEC_BEFORE 500000

static void sync_cmos_clock(unsigned long dummy);

static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);

static void sync_cmos_clock(unsigned long dummy)
{
struct timeval now, next;
int fail = 1;

/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
* This code is run on a timer. If the clock is set, that timer
* may not expire at the correct time. Thus, we adjust...
*/
if (!ntp_synced())
/*
* Not synced, exit, do not restart a timer (if one is
* running, let it run out).
*/
return;

do_gettimeofday(&now);
if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
fail = set_rtc_mmss(now.tv_sec);

next.tv_usec = USEC_AFTER - now.tv_usec;
if (next.tv_usec <= 0)
next.tv_usec += USEC_PER_SEC;

if (!fail)
next.tv_sec = 659;
else
next.tv_sec = 0;

if (next.tv_usec >= USEC_PER_SEC) {
next.tv_sec++;
next.tv_usec -= USEC_PER_SEC;
}
mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
}

void notify_arch_cmos_timer(void)
int update_persistent_clock(struct timespec now)
{
mod_timer(&sync_cmos_timer, jiffies + 1);
return set_rtc_mmss(now.tv_sec);
}

/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
Expand Down
1 change: 0 additions & 1 deletion include/asm-i386/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ unsigned long native_calculate_cpu_khz(void);

extern int timer_ack;
extern int no_timer_check;
extern int no_sync_cmos_clock;
extern int recalibrate_cpu_khz(void);

#ifndef CONFIG_PARAVIRT
Expand Down
3 changes: 3 additions & 0 deletions include/linux/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/types.h>

#ifdef __KERNEL__
# include <linux/cache.h>
# include <linux/seqlock.h>
#endif

Expand Down Expand Up @@ -94,6 +95,8 @@ extern struct timespec wall_to_monotonic;
extern seqlock_t xtime_lock __attribute__((weak));

extern unsigned long read_persistent_clock(void);
extern int update_persistent_clock(struct timespec now);
extern int no_sync_cmos_clock __read_mostly;
void timekeeping_init(void);

static inline unsigned long get_seconds(void)
Expand Down
59 changes: 56 additions & 3 deletions kernel/time/ntp.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <linux/mm.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/timex.h>
#include <linux/jiffies.h>
#include <linux/hrtimer.h>
Expand Down Expand Up @@ -175,12 +176,64 @@ u64 current_tick_length(void)
return tick_length;
}

#ifdef CONFIG_GENERIC_CMOS_UPDATE

void __attribute__ ((weak)) notify_arch_cmos_timer(void)
/* Disable the cmos update - used by virtualization and embedded */
int no_sync_cmos_clock __read_mostly;

static void sync_cmos_clock(unsigned long dummy);

static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);

static void sync_cmos_clock(unsigned long dummy)
{
struct timespec now, next;
int fail = 1;

/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
* This code is run on a timer. If the clock is set, that timer
* may not expire at the correct time. Thus, we adjust...
*/
if (!ntp_synced())
/*
* Not synced, exit, do not restart a timer (if one is
* running, let it run out).
*/
return;

getnstimeofday(&now);
if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
fail = update_persistent_clock(now);

next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;
if (next.tv_nsec <= 0)
next.tv_nsec += NSEC_PER_SEC;

if (!fail)
next.tv_sec = 659;
else
next.tv_sec = 0;

if (next.tv_nsec >= NSEC_PER_SEC) {
next.tv_sec++;
next.tv_nsec -= NSEC_PER_SEC;
}
mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next));
}

static void notify_cmos_timer(void)
{
return;
if (no_sync_cmos_clock)
mod_timer(&sync_cmos_timer, jiffies + 1);
}

#else
static inline void notify_cmos_timer(void) { }
#endif

/* adjtimex mainly allows reading (and writing, if superuser) of
* kernel time-keeping variables. used by xntpd.
*/
Expand Down Expand Up @@ -345,6 +398,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
txc->stbcnt = 0;
write_sequnlock_irq(&xtime_lock);
do_gettimeofday(&txc->time);
notify_arch_cmos_timer();
notify_cmos_timer();
return(result);
}

0 comments on commit 8264445

Please sign in to comment.