Fix for 2.0.3* to do_fast_gettimeoffset

Philip Gladstone (philip@raptor.com)
Thu, 14 May 1998 16:02:24 -0400


This is a multi-part message in MIME format.
--------------DFBBCDF04AA36AE3C1AA7CF8
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached patch fixes a problem where the times returned
by do_fast_gettimeoffset were incorrect. This is easy to
demonstrate by using the following chunk of code to get
the current offset (arch/i386/kernel/time.c), and then running
your favourite set of programs.

static unsigned long do_both_gettimeoffset(void)
{
unsigned long slow, fast;
static int fast_after_slow;
static int slow_after_fast = 5;

fast = do_fast_gettimeoffset();
slow = do_slow_gettimeoffset();

if (slow + fast_after_slow < fast) {
fast_after_slow = fast - slow;
printk(KERN_WARNING "do_fast_gettimeoffset()=%ld -
do_slow_gettimeoffset()=%ld = %d\n", fast, slow, fast_after_slow);
}

if (fast + slow_after_fast < slow) {
slow_after_fast = slow - fast;
printk(KERN_WARNING "do_fast_gettimeoffset()=%ld -
do_slow_gettimeoffset()=%ld = %d\n", fast, slow, -slow_after_fast);
}

return fast;
}

Anyway, the attached patch fixes the problem -- (honestly it fixes most
of the problem, the bit left is small).

The cost of this patch is 3 i/o instructions on each timer interrupt and
a little
bit of computation.

philip

-- 
Philip Gladstone                           +1 781 530 2461
Raptor Systems / Axent Technologies 
Waltham, MA         		    http://www.raptor.com/
--------------DFBBCDF04AA36AE3C1AA7CF8
Content-Type: text/plain; charset=us-ascii; name="pentium_time.pf"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="pentium_time.pf"

--- time.c.orig Thu May 14 15:52:24 1998 +++ linux/arch/i386/kernel/time.c Thu May 14 15:53:37 1998 @@ -43,6 +43,9 @@ unsigned long high; } init_timer_cc, last_timer_cc; +/* Number of usecs that the last interrupt was delayed */ +static int delay_at_last_interrupt; + /* * This is more assembly than C, but it's also rather * timing-critical and we have to use assembler to get @@ -129,10 +132,16 @@ * we need to check the result so that we'll get a timer * that is monotonic. */ - if (edx >= 1000020/HZ) - edx = 1000020/HZ-1; + /* + * Monotonic times should be enforced in gettimeofday, + * and it is not the case that the error is limited to + * one tick. + * + * if (edx >= 1000020/HZ) + * edx = 1000020/HZ-1; + */ - eax = edx + missing_time; + eax = edx + missing_time + delay_at_last_interrupt; return eax; } #endif @@ -385,10 +394,24 @@ */ static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + int count; + + /* It is important that these two operations happen at the + * same time. It is unclear which order is better! + */ + + outb_p(0x00, 0x43); /* latch the count ASAP */ /* read Pentium cycle counter */ __asm__(".byte 0x0f,0x31" :"=a" (last_timer_cc.low), "=d" (last_timer_cc.high)); + + count = inb_p(0x40); /* read the latched count */ + count |= inb(0x40) << 8; + + count = ((LATCH-1) - count) * TICK_SIZE; + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + timer_interrupt(irq, NULL, regs); } #endif

--------------DFBBCDF04AA36AE3C1AA7CF8--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu