diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -66,13 +66,13 @@ void mark_tsc_unstable(void) /* Code to compensate for C3 stalls */ static u64 tsc_c3_offset; -void tsc_c3_compensate(unsigned long nsecs) +void tsc_c3_compensate(unsigned long nsecs, u64 tsc_offset) { /* this could def be optimized */ u64 cycles = ((u64)nsecs * tsc_khz); do_div(cycles, 1000000); - tsc_c3_offset += cycles; + tsc_c3_offset += cycles - tsc_offset; } EXPORT_SYMBOL_GPL(tsc_c3_compensate); @@ -263,6 +263,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; + unsigned long old_tsc_khz = tsc_khz; if (val != CPUFREQ_RESUMECHANGE) write_seqlock_irq(&xtime_lock); @@ -299,6 +300,9 @@ time_cpufreq_notifier(struct notifier_bl if (val != CPUFREQ_RESUMECHANGE) write_sequnlock_irq(&xtime_lock); + if(old_tsc_khz != tsc_khz) + timeofday_force_update(); + return 0; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -177,7 +177,7 @@ static void acpi_safe_halt(void) } static atomic_t c3_cpu_count; -extern void tsc_c3_compensate(unsigned long nsecs); +extern void tsc_c3_compensate(unsigned long nsecs, u64 tsc_offset); static void acpi_processor_idle(void) { @@ -186,6 +186,7 @@ static void acpi_processor_idle(void) struct acpi_processor_cx *next_state = NULL; int sleep_ticks = 0; u32 t1, t2 = 0; + u64 tsc1, tsc2, tsc3; pr = processors[smp_processor_id()]; if (!pr) @@ -359,12 +360,15 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); + rdtscll(tsc1); /* Invoke C3 */ inb(cx->address); /* Dummy op - must do something useless after P_LVL3 read */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); /* Get end time (ticks) */ + rdtscll(tsc2); t2 = inl(acpi_fadt.xpm_tmr_blk.address); + rdtscll(tsc3); if (pr->flags.bm_check) { /* Enable bus master arbitration */ atomic_dec(&c3_cpu_count); @@ -374,7 +378,7 @@ static void acpi_processor_idle(void) #ifdef CONFIG_GENERIC_TIME /* compensate for TSC pause */ - tsc_c3_compensate((u32)(((u64)((t2-t1)&0xFFFFFF)*286070)>>10)); + tsc_c3_compensate((u32)(((u64)((t2-t1)&0xFFFFFF)*286070)>>10), tsc3-tsc1); #endif /* Re-enable interrupts */ diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h --- a/include/asm-i386/tsc.h +++ b/include/asm-i386/tsc.h @@ -44,7 +44,7 @@ static inline cycles_t get_cycles(void) } extern void tsc_init(void); -extern void tsc_c3_compensate(unsigned long usecs); +extern void tsc_c3_compensate(unsigned long usecs, unsigned long long tsc_offset); extern void mark_tsc_unstable(void); #endif diff --git a/include/linux/timeofday.h b/include/linux/timeofday.h --- a/include/linux/timeofday.h +++ b/include/linux/timeofday.h @@ -30,6 +30,7 @@ extern int do_settimeofday(struct timesp /* Internal functions */ extern int timeofday_is_continuous(void); +extern void timeofday_force_update(void); extern void timeofday_init(void); #ifndef CONFIG_IS_TICK_BASED diff --git a/kernel/time/timeofday.c b/kernel/time/timeofday.c --- a/kernel/time/timeofday.c +++ b/kernel/time/timeofday.c @@ -745,6 +745,12 @@ static void timeofday_periodic_hook(unsi jiffies + 1 + msecs_to_jiffies(PERIODIC_INTERVAL_MS)); } + +void timeofday_force_update(void) +{ + timeofday_periodic_hook(0); +} + /** * timeofday_is_continuous - check to see if timekeeping is free running */