patch-2.2.10 linux/arch/alpha/kernel/time.c
Next file: linux/arch/alpha/kernel/traps.c
Previous file: linux/arch/alpha/kernel/sys_takara.c
Back to the patch index
Back to the overall index
- Lines: 174
- Date:
Sat Jun 12 11:52:52 1999
- Orig file:
v2.2.9/linux/arch/alpha/kernel/time.c
- Orig date:
Wed Apr 28 11:37:29 1999
diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
@@ -1,7 +1,7 @@
/*
* linux/arch/alpha/kernel/time.c
*
- * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ * Copyright (C) 1991, 1992, 1995, 1999 Linus Torvalds
*
* This file contains the PC-specific time handling details:
* reading the RTC at bootup, etc..
@@ -42,6 +42,9 @@
#include "proto.h"
#include "irq.h"
+extern rwlock_t xtime_lock;
+extern volatile unsigned long lost_ticks; /* kernel/sched.c */
+
static int set_rtc_mmss(unsigned long);
@@ -86,15 +89,15 @@
long nticks;
#ifdef __SMP__
- extern void smp_percpu_timer_interrupt(struct pt_regs *);
- extern unsigned int boot_cpu_id;
- /* when SMP, do this for *all* CPUs,
- but only do the rest for the boot CPU */
+ /* When SMP, do this for *all* CPUs, but only do the rest for
+ the boot CPU. */
smp_percpu_timer_interrupt(regs);
- if (smp_processor_id() != boot_cpu_id)
- return;
+ if (smp_processor_id() != smp_boot_cpuid)
+ return;
#endif
+ write_lock(&xtime_lock);
+
/*
* Calculate how many ticks have passed since the last update,
* including any previous partial leftover. Save any resulting
@@ -124,6 +127,8 @@
int tmp = set_rtc_mmss(xtime.tv_sec);
state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
}
+
+ write_unlock(&xtime_lock);
}
/*
@@ -226,7 +231,8 @@
{
void (*irq_handler)(int, void *, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec, cc1, cc2;
- unsigned long cycle_freq, diff, one_percent;
+ unsigned long cycle_freq, one_percent;
+ long diff;
/*
* The Linux interpretation of the CMOS clock register contents:
@@ -242,7 +248,7 @@
if (!est_cycle_freq) {
/* Sometimes the hwrpb->cycle_freq value is bogus.
- Go another round to check up on it and see. */
+ Go another round to check up on it and see. */
do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
cc2 = rpcc();
@@ -279,8 +285,7 @@
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- {
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
@@ -328,18 +333,24 @@
void
do_gettimeofday(struct timeval *tv)
{
- unsigned long flags, delta_cycles, delta_usec;
- unsigned long sec, usec;
- __u32 now;
- extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
+ unsigned long sec, usec, lost, flags;
+ unsigned long delta_cycles, delta_usec, partial_tick;
- now = rpcc();
- save_and_cli(flags);
+ read_lock_irqsave(&xtime_lock, flags);
+
+ delta_cycles = rpcc() - state.last_time;
sec = xtime.tv_sec;
usec = xtime.tv_usec;
- delta_cycles = now - state.last_time;
- restore_flags(flags);
+ partial_tick = state.partial_tick;
+ lost = lost_ticks;
+
+ read_unlock_irqrestore(&xtime_lock, flags);
+#ifdef __SMP__
+ /* Until and unless we figure out how to get cpu cycle counters
+ in sync and keep them there, we can't use the rpcc tricks. */
+ delta_usec = lost * (1000000 / HZ);
+#else
/*
* usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
* = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
@@ -354,13 +365,10 @@
*/
delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
- + state.partial_tick
- + (lost_ticks << FIX_SHIFT) ) * 15625;
+ + partial_tick
+ + (lost << FIX_SHIFT)) * 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-
- /* the 'lost_tics' term above implements this:
- * delta_usec += lost_ticks * (1000000 / HZ);
- */
+#endif
usec += delta_usec;
if (usec >= 1000000) {
@@ -375,13 +383,41 @@
void
do_settimeofday(struct timeval *tv)
{
- cli();
- xtime = *tv;
+ unsigned long delta_usec;
+ long sec, usec;
+
+ write_lock_irq(&xtime_lock);
+
+ /* The offset that is added into time in do_gettimeofday above
+ must be subtracted out here to keep a coherent view of the
+ time. Without this, a full-tick error is possible. */
+
+#ifdef __SMP__
+ delta_usec = lost_ticks * (1000000 / HZ);
+#else
+ delta_usec = rpcc() - state.last_time;
+ delta_usec = (delta_usec * state.scaled_ticks_per_cycle
+ + state.partial_tick
+ + (lost_ticks << FIX_SHIFT)) * 15625;
+ delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+#endif
+
+ sec = tv->tv_sec;
+ usec = tv->tv_usec;
+ usec -= delta_usec;
+ if (usec < 0) {
+ usec += 1000000;
+ sec -= 1;
+ }
+
+ xtime.tv_sec = sec;
+ xtime.tv_usec = usec;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+
+ write_unlock_irq(&xtime_lock);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)