Browse Source

[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<shaohua.li@intel.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Shaohua Li 19 years ago
parent
commit
0dd2ea9af8
3 changed files with 18 additions and 0 deletions
  1. 5 0
      arch/x86_64/kernel/pmtimer.c
  2. 12 0
      arch/x86_64/kernel/time.c
  3. 1 0
      include/asm-x86_64/proto.h

+ 5 - 0
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;

+ 12 - 0
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;
 }

+ 1 - 0
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;