This patch uses the lost tick information returned by mark_offset() function in dyntick, to recover time. Original code by Srivatsa Vaddagiri Updated by Con Kolivas Signed-off-by: Con Kolivas arch/i386/kernel/time.c | 13 ++++++++----- arch/i386/kernel/timers/timer_cyclone.c | 4 +++- arch/i386/kernel/timers/timer_hpet.c | 4 +++- arch/i386/kernel/timers/timer_none.c | 3 ++- arch/i386/kernel/timers/timer_pit.c | 3 ++- arch/i386/kernel/timers/timer_pm.c | 3 ++- arch/i386/kernel/timers/timer_tsc.c | 13 +++++++++---- include/asm-i386/timer.h | 2 +- 8 files changed, 30 insertions(+), 15 deletions(-) Index: linux-2.6.16-rc4-dt/arch/i386/kernel/time.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/time.c 2006-02-18 10:36:52.000000000 +1100 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/time.c 2006-02-23 11:24:02.000000000 +1100 @@ -245,7 +245,7 @@ EXPORT_SYMBOL(profile_pc); * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -static inline void do_timer_interrupt(int irq, struct pt_regs *regs) +static inline void do_timer_interrupt(int irq, struct pt_regs *regs, int lost) { #ifdef CONFIG_X86_IO_APIC if (timer_ack) { @@ -263,7 +263,8 @@ static inline void do_timer_interrupt(in } #endif - do_timer_interrupt_hook(regs); + if (!dyntick_enabled() || lost) + do_timer_interrupt_hook(regs); if (MCA_bus) { @@ -288,6 +289,8 @@ static inline void do_timer_interrupt(in */ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + int lost; + /* * 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 @@ -297,9 +300,9 @@ irqreturn_t timer_interrupt(int irq, voi */ write_seqlock(&xtime_lock); - cur_timer->mark_offset(); - - do_timer_interrupt(irq, regs); + lost = cur_timer->mark_offset(); + + do_timer_interrupt(irq, regs, lost); write_sequnlock(&xtime_lock); Index: linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_cyclone.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/timers/timer_cyclone.c 2005-08-29 13:31:19.000000000 +1000 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_cyclone.c 2006-02-23 11:24:02.000000000 +1100 @@ -45,7 +45,7 @@ static seqlock_t monotonic_lock = SEQLOC } while (high != cyclone_timer[1]); -static void mark_offset_cyclone(void) +static int mark_offset_cyclone(void) { unsigned long lost, delay; unsigned long delta = last_cyclone_low; @@ -101,6 +101,8 @@ static void mark_offset_cyclone(void) */ if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ)) jiffies_64++; + + return lost; } static unsigned long get_offset_cyclone(void) Index: linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_hpet.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/timers/timer_hpet.c 2006-01-03 17:36:14.000000000 +1100 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_hpet.c 2006-02-23 11:24:02.000000000 +1100 @@ -101,7 +101,7 @@ static unsigned long get_offset_hpet(voi return edx; } -static void mark_offset_hpet(void) +static int mark_offset_hpet(void) { unsigned long long this_offset, last_offset; unsigned long offset; @@ -124,6 +124,8 @@ static void mark_offset_hpet(void) this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; monotonic_base += cycles_2_ns(this_offset - last_offset); write_sequnlock(&monotonic_lock); + + return 1; } static void delay_hpet(unsigned long loops) Index: linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_none.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/timers/timer_none.c 2004-12-25 10:14:46.000000000 +1100 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_none.c 2006-02-23 11:24:02.000000000 +1100 @@ -1,9 +1,10 @@ #include #include -static void mark_offset_none(void) +static int mark_offset_none(void) { /* nothing needed */ + return 1; } static unsigned long get_offset_none(void) Index: linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_pit.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/timers/timer_pit.c 2006-01-03 17:36:14.000000000 +1100 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_pit.c 2006-02-23 11:24:02.000000000 +1100 @@ -32,9 +32,10 @@ static int __init init_pit(char* overrid return 0; } -static void mark_offset_pit(void) +static int mark_offset_pit(void) { /* nothing needed */ + return 1; } static unsigned long long monotonic_clock_pit(void) Index: linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_pm.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/timers/timer_pm.c 2005-10-28 20:21:34.000000000 +1000 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_pm.c 2006-02-23 11:24:02.000000000 +1100 @@ -148,7 +148,7 @@ static inline u32 cyc2us(u32 cycles) * this gets called during each timer interrupt * - Called while holding the writer xtime_lock */ -static void mark_offset_pmtmr(void) +static int mark_offset_pmtmr(void) { u32 lost, delta, last_offset; static int first_run = 1; @@ -184,6 +184,7 @@ static void mark_offset_pmtmr(void) first_run = 0; offset_delay = 0; } + return lost; } static int pmtmr_resume(void) Index: linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_tsc.c =================================================================== --- linux-2.6.16-rc4-dt.orig/arch/i386/kernel/timers/timer_tsc.c 2006-02-18 10:36:52.000000000 +1100 +++ linux-2.6.16-rc4-dt/arch/i386/kernel/timers/timer_tsc.c 2006-02-23 11:24:02.000000000 +1100 @@ -181,10 +181,11 @@ static void delay_tsc(unsigned long loop } #ifdef CONFIG_HPET_TIMER -static void mark_offset_tsc_hpet(void) +static int mark_offset_tsc_hpet(void) { unsigned long long this_offset, last_offset; - unsigned long offset, temp, hpet_current; + unsigned long offset, temp, hpet_current; + int lost_ticks = 0; write_seqlock(&monotonic_lock); last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; @@ -207,7 +208,7 @@ static void mark_offset_tsc_hpet(void) offset = hpet_readl(HPET_T0_CMP) - hpet_tick; if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0)) && detect_lost_ticks) { - int lost_ticks = (offset - hpet_last) / hpet_tick; + lost_ticks = (offset - hpet_last) / hpet_tick; jiffies_64 += lost_ticks; } hpet_last = hpet_current; @@ -228,6 +229,8 @@ static void mark_offset_tsc_hpet(void) delay_at_last_interrupt = hpet_current - offset; ASM_MUL64_REG(temp, delay_at_last_interrupt, hpet_usec_quotient, delay_at_last_interrupt); + + return lost_ticks; } #endif @@ -361,7 +364,7 @@ int recalibrate_cpu_khz(void) } EXPORT_SYMBOL(recalibrate_cpu_khz); -static void mark_offset_tsc(void) +static int mark_offset_tsc(void) { unsigned long lost,delay; unsigned long delta = last_tsc_low; @@ -471,6 +474,8 @@ static void mark_offset_tsc(void) */ if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ)) jiffies_64++; + + return lost; } static int __init init_tsc(char* override) Index: linux-2.6.16-rc4-dt/include/asm-i386/timer.h =================================================================== --- linux-2.6.16-rc4-dt.orig/include/asm-i386/timer.h 2005-10-28 20:22:01.000000000 +1000 +++ linux-2.6.16-rc4-dt/include/asm-i386/timer.h 2006-02-23 11:24:02.000000000 +1100 @@ -19,7 +19,7 @@ */ struct timer_opts { char* name; - void (*mark_offset)(void); + int (*mark_offset)(void); unsigned long (*get_offset)(void); unsigned long long (*monotonic_clock)(void); void (*delay)(unsigned long);