Commit 63223091 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ia32 Lost tick compensation

Patch from john stultz <johnstul@us.ibm.com>

Adds some lost-tick compensation code, which handles the case where time
accounting goes wrong due to interrupts being disabled for longer than two
ticks.

This patch solves the problem by checking when an interrupt occurs if
timer->get_offset() is a value greater then 2 ticks.  If so, it increments
jiffies appropriately.

I was concerned that we'd be better off finding and fixing the misbehaving
drivers, but it turns out that the main culprits are system management cards
over which the kernel has no control.

However John has added some debug code which will drop a backtrace on the
first five occurrences which will allow us to find-and-fix bad drivers if
overruns _are_ due to Linux software.  (I disabled this - it was irritating
me.  Dave Hansen has a patch which allows it to be turned on via a kernel
boot parameter, like the x86_64 equiv).
parent 369a0c85
......@@ -265,6 +265,41 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
#endif
}
/*
* Lost tick detection and compensation
*/
static inline void detect_lost_tick(void)
{
/* read time since last interrupt */
unsigned long delta = timer->get_offset();
static unsigned long dbg_print;
/* check if delta is greater then two ticks */
if(delta >= 2*(1000000/HZ)){
/*
* only print debug info first 5 times
*/
/*
* AKPM: disable this for now; it's nice, but irritating.
*/
if (0 && dbg_print < 5) {
printk(KERN_WARNING "\nWarning! Detected %lu "
"micro-second gap between interrupts.\n",
delta);
printk(KERN_WARNING " Compensating for %lu lost "
"ticks.\n",
delta/(1000000/HZ)-1);
dump_stack();
dbg_print++;
}
/* calculate number of missed ticks */
delta = delta/(1000000/HZ)-1;
jiffies += delta;
}
}
/*
* 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
......@@ -281,6 +316,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
write_lock(&xtime_lock);
detect_lost_tick();
timer->mark_offset();
do_timer_interrupt(irq, NULL, regs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment