From 0dd2ea9af8f0eca43cf6200baa182b3aba307049 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 3 Feb 2006 21:50:56 +0100 Subject: [PATCH] [PATCH] x86_64: [PATCH] timer resume At resume time, TSC's value or something similar might be changed a lot against suspend time. This could make system gets a very big lost ticks. See http://bugzilla.kernel.org/show_bug.cgi?id=5825 Signed-off-by: Shaohua Li Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/pmtimer.c | 5 +++++ arch/x86_64/kernel/time.c | 12 ++++++++++++ include/asm-x86_64/proto.h | 1 + 3 files changed, 18 insertions(+) diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c index feb5f108dd26..8b2655ae4e61 100644 --- a/arch/x86_64/kernel/pmtimer.c +++ b/arch/x86_64/kernel/pmtimer.c @@ -80,6 +80,11 @@ int pmtimer_mark_offset(void) return lost - 1; } +void pmtimer_resume(void) +{ + last_pmtmr_tick = inl(pmtmr_ioport); +} + unsigned int do_gettimeoffset_pm(void) { u32 now, offset, delta = 0; diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 91a448a86ebd..c1f76055b578 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -1047,9 +1047,21 @@ static int timer_resume(struct sys_device *dev) write_seqlock_irqsave(&xtime_lock,flags); xtime.tv_sec = sec; xtime.tv_nsec = 0; + if (vxtime.mode == VXTIME_HPET) { + if (hpet_use_timer) + vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; + else + vxtime.last = hpet_readl(HPET_COUNTER); +#ifdef CONFIG_X86_PM_TIMER + } else if (vxtime.mode == VXTIME_PMTMR) { + pmtimer_resume(); +#endif + } else + vxtime.last_tsc = get_cycles_sync(); write_sequnlock_irqrestore(&xtime_lock,flags); jiffies += sleep_length; wall_jiffies += sleep_length; + monotonic_base += sleep_length * (NSEC_PER_SEC/HZ); touch_softlockup_watchdog(); return 0; } diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index c1e2307445d4..a6748b9568fe 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -41,6 +41,7 @@ extern void iommu_hole_init(void); extern void time_init_gtod(void); extern int pmtimer_mark_offset(void); +extern void pmtimer_resume(void); extern unsigned int do_gettimeoffset_pm(void); #ifdef CONFIG_X86_PM_TIMER extern u32 pmtmr_ioport;