===================================================================
RCS file: /var/cvs/linux/arch/i386/kernel/time.c,v
retrieving revision 1.1.2.8
@@ -76,6 +76,7 @@
static unsigned long fast_gettimeoffset_quotient=0;
extern rwlock_t xtime_lock;
+extern volatile unsigned long lost_ticks;
static inline unsigned long do_fast_gettimeoffset(void)
{
@@ -217,7 +218,7 @@
count_p = count;
count = ((LATCH-1) - count) * TICK_SIZE;
- count = (count + LATCH/2) / LATCH;
+ count = count / LATCH;
return count;
}
@@ -236,7 +237,6 @@
*/
void do_gettimeofday(struct timeval *tv)
{
- extern volatile unsigned long lost_ticks;
unsigned long flags;
unsigned long usec, sec;
@@ -412,14 +412,48 @@
static int use_tsc = 0;
/*
+ * Using a bit better the TSC information now we are also able to recover
+ * from lost timer interrupts. -arca
+ */
+static inline void recover_lost_timer(unsigned long delta_cycles,
+ int delay_usec)
+{
+ /*
+ * The algorithm I invented to know if we losed an irq in the meantime
+ * works this way:
+ *
+ * - convert delta from cycles to usec
+ * - remove from the delta_usec the latency of the irqs
+ * - convert from usec to timer ticks
+ *
+ * -arca
+ */
+
+ register unsigned long delta_usec;
+
+ __asm__("mull %2"
+ :"=a" (delta_cycles), "=d" (delta_usec)
+ :"g" (fast_gettimeoffset_quotient), "0" (delta_cycles));
+ delta_usec -= delay_usec;
+ delta_usec /= 1000000/HZ;
+
+ if ((long) delta_usec > 1)
+ {
+ printk(KERN_DEBUG "lost ticks %lu\n", delta_usec - 1);
+
+ delta_usec -= 1;
+ lost_ticks += delta_usec;
+ jiffies += delta_usec;
+ }
+}
+
+/*
* This is the same as the above, except we _also_ save the current
* Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly.
*/
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int count;
-
/*
* Here we are in the timer irq handler. We just have irqs locally
* disabled but we don't know if the timer_bh is running on the other
@@ -443,16 +477,24 @@
* has the SA_INTERRUPT flag set. -arca
*/
+ unsigned long old_cycles;
+ int old_delay, count;
+
/* read Pentium cycle counter */
- __asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
+ __asm__("rdtsc" : "=a" (old_cycles) : : "edx");
outb_p(0x00, 0x43); /* latch the count ASAP */
count = inb_p(0x40); /* read the latched count */
+ old_cycles = xchg(&last_tsc_low, old_cycles);
count |= inb(0x40) << 8;
count = ((LATCH-1) - count) * TICK_SIZE;
- delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+ old_delay = delay_at_last_interrupt;
+ delay_at_last_interrupt = count / LATCH;
+
+ recover_lost_timer(last_tsc_low - old_cycles,
+ delay_at_last_interrupt - old_delay);
}
do_timer_interrupt(irq, NULL, regs);
@@ -543,30 +585,40 @@
* device.
*/
+/*
+ * To get a more safe quotient value (that it will be used forever) we
+ * try many times and we'll stop if we'll get the same value for two times
+ * consecutively. -arca
+ */
+
#define CALIBRATE_LATCH (5 * LATCH)
#define CALIBRATE_TIME (5 * 1000020/HZ)
__initfunc(static unsigned long calibrate_tsc(void))
{
- /* Set the Gate high, disable speaker */
- outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
- /*
- * Now let's take care of CTC channel 2
- *
- * Set the Gate high, program CTC channel 2 for mode 0,
- * (interrupt on terminal count mode), binary count,
- * load 5 * LATCH count, (LSB and MSB) to begin countdown.
- */
- outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
- outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
- outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+ int i;
+ unsigned long last_quotient = -999992 /* be quiet compiler */;
+ for (i=0; i<300; i++)
{
unsigned long startlow, starthigh;
unsigned long endlow, endhigh;
unsigned long count;
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ /*
+ * Now let's take care of CTC channel 2
+ *
+ * Set the Gate high, program CTC channel 2 for mode 0,
+ * (interrupt on terminal count mode), binary count,
+ * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+ */
+ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
+ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+
__asm__ __volatile__("rdtsc":"=a" (startlow),"=d" (starthigh));
count = 0;
do {
@@ -599,8 +651,16 @@
:"=a" (endlow), "=d" (endhigh)
:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
- return endlow;
+ if (i && last_quotient == endlow)
+ {
+ printk("calibrate_tsc: consistent quotient %lu "
+ "found after %d tries\n", endlow, i);
+ return endlow;
+ }
+ last_quotient = endlow;
}
+
+ printk("calibrate_tsc: inconsistent quotient!\n");
/*
* The CTC wasn't reliable: we got a hit on the very first read,
===================================================================
RCS file: /var/cvs/linux/kernel/sched.c,v
retrieving revision 1.1.2.18
@@ -47,7 +47,7 @@
unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
-long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */
+long tick = 1000000 / HZ; /* timer interrupt period */
/* The current time */
volatile struct timeval xtime __attribute__ ((aligned (16)));
@@ -72,7 +72,7 @@
long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
long time_phase = 0; /* phase offset (scaled us) */
-long time_freq = ((1000000 + HZ/2) % HZ - HZ/2) << SHIFT_USEC; /* frequency offset (scaled ppm) */
+long time_freq = (1000000 % HZ) << SHIFT_USEC; /* frequency offset (scaled ppm) */
long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
long time_reftime = 0; /* time at last adjustment (s) */
@@ -1299,15 +1299,13 @@
static void update_wall_time(unsigned long ticks)
{
do {
- ticks--;
update_wall_time_one_tick();
- } while (ticks);
-
- if (xtime.tv_usec >= 1000000) {
- xtime.tv_usec -= 1000000;
- xtime.tv_sec++;
- second_overflow();
- }
+ while (xtime.tv_usec >= 1000000) {
+ xtime.tv_usec -= 1000000;
+ xtime.tv_sec++;
+ second_overflow();
+ }
+ } while (--ticks);
}
static inline void do_process_times(struct task_struct *p,