From: Dmitry Torokhov It needs at least the patch below to handle timer wrap-arounds. arch/i386/kernel/timers/timer_pm.c | 16 +++++++--------- 1 files changed, 7 insertions(+), 9 deletions(-) diff -puN arch/i386/kernel/timers/timer_pm.c~timer_pm-wraparound-fixes arch/i386/kernel/timers/timer_pm.c --- 25/arch/i386/kernel/timers/timer_pm.c~timer_pm-wraparound-fixes 2003-12-29 12:27:35.000000000 -0800 +++ 25-akpm/arch/i386/kernel/timers/timer_pm.c 2003-12-29 12:27:35.000000000 -0800 @@ -92,28 +92,28 @@ static void mark_offset_pmtmr(void) { u32 lost, delta, last_offset; static int first_run = 1; - last_offset = offset_tick; write_seqlock(&monotonic_lock); + last_offset = offset_tick; offset_tick = inl(pmtmr_ioport); offset_tick &= ACPI_PM_MASK; /* limit it to 24 bits */ /* calculate tick interval */ - delta = (offset_tick - last_offset) & ACPI_PM_MASK; + delta = likely(last_offset < offset_tick) ? + offset_tick - last_offset : ACPI_PM_MASK - last_offset + offset_tick; /* convert to usecs */ delta = cyc2us(delta); /* update the monotonic base value */ - monotonic_base += delta*NSEC_PER_USEC; + monotonic_base += delta * NSEC_PER_USEC; write_sequnlock(&monotonic_lock); /* convert to ticks */ delta += offset_delay; - lost = delta/(USEC_PER_SEC/HZ); - offset_delay = delta%(USEC_PER_SEC/HZ); - + lost = delta / (USEC_PER_SEC / HZ); + offset_delay = delta % (USEC_PER_SEC / HZ); /* compensate for lost ticks */ if (lost >= 2) @@ -125,8 +125,6 @@ static void mark_offset_pmtmr(void) first_run = 0; offset_delay = 0; } - - return; } @@ -181,7 +179,7 @@ static unsigned long get_offset_pmtmr(vo offset = offset_tick; now = inl(pmtmr_ioport); now &= ACPI_PM_MASK; - delta = (now - offset)&ACPI_PM_MASK; + delta = likely(offset < now) ? now - offset : ACPI_PM_MASK - offset + now; return (unsigned long) offset_delay + cyc2us(delta); } _