aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2012-02-13 08:07:27 -0500
committerAvi Kivity <avi@redhat.com>2012-03-20 06:37:45 -0400
commitb74f05d61b73af584d0c39121980171389ecfaaa (patch)
tree1406185fb45430549b37ef3b4f62f9c5772ef139 /arch/x86
parent9587190107d0c0cbaccbf7bf6b0245d29095a9ae (diff)
x86: kvmclock: abstract save/restore sched_clock_state
Upon resume from hibernation, CPU 0's hvclock area contains the old values for system_time and tsc_timestamp. It is necessary for the hypervisor to update these values with uptodate ones before the CPU uses them. Abstract TSC's save/restore sched_clock_state functions and use restore_state to write to KVM_SYSTEM_TIME MSR, forcing an update. Also move restore_sched_clock_state before __restore_processor_state, since the later calls CONFIG_LOCK_STAT's lockstat_clock (also for TSC). Thanks to Igor Mammedov for tracking it down. Fixes suspend-to-disk with kvmclock. Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/tsc.h4
-rw-r--r--arch/x86/include/asm/x86_init.h4
-rw-r--r--arch/x86/kernel/kvmclock.c11
-rw-r--r--arch/x86/kernel/tsc.c4
-rw-r--r--arch/x86/kernel/x86_init.c4
-rw-r--r--arch/x86/power/cpu.c4
6 files changed, 24 insertions, 7 deletions
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 15d99153a96d..c91e8b9d588b 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -61,7 +61,7 @@ extern void check_tsc_sync_source(int cpu);
61extern void check_tsc_sync_target(void); 61extern void check_tsc_sync_target(void);
62 62
63extern int notsc_setup(char *); 63extern int notsc_setup(char *);
64extern void save_sched_clock_state(void); 64extern void tsc_save_sched_clock_state(void);
65extern void restore_sched_clock_state(void); 65extern void tsc_restore_sched_clock_state(void);
66 66
67#endif /* _ASM_X86_TSC_H */ 67#endif /* _ASM_X86_TSC_H */
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 5d0afac2962c..baaca8defec8 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -162,6 +162,8 @@ struct x86_cpuinit_ops {
162 * @is_untracked_pat_range exclude from PAT logic 162 * @is_untracked_pat_range exclude from PAT logic
163 * @nmi_init enable NMI on cpus 163 * @nmi_init enable NMI on cpus
164 * @i8042_detect pre-detect if i8042 controller exists 164 * @i8042_detect pre-detect if i8042 controller exists
165 * @save_sched_clock_state: save state for sched_clock() on suspend
166 * @restore_sched_clock_state: restore state for sched_clock() on resume
165 */ 167 */
166struct x86_platform_ops { 168struct x86_platform_ops {
167 unsigned long (*calibrate_tsc)(void); 169 unsigned long (*calibrate_tsc)(void);
@@ -173,6 +175,8 @@ struct x86_platform_ops {
173 void (*nmi_init)(void); 175 void (*nmi_init)(void);
174 unsigned char (*get_nmi_reason)(void); 176 unsigned char (*get_nmi_reason)(void);
175 int (*i8042_detect)(void); 177 int (*i8042_detect)(void);
178 void (*save_sched_clock_state)(void);
179 void (*restore_sched_clock_state)(void);
176}; 180};
177 181
178struct pci_dev; 182struct pci_dev;
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index ca4e735adc54..f8492da65bfc 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -136,6 +136,15 @@ int kvm_register_clock(char *txt)
136 return ret; 136 return ret;
137} 137}
138 138
139static void kvm_save_sched_clock_state(void)
140{
141}
142
143static void kvm_restore_sched_clock_state(void)
144{
145 kvm_register_clock("primary cpu clock, resume");
146}
147
139#ifdef CONFIG_X86_LOCAL_APIC 148#ifdef CONFIG_X86_LOCAL_APIC
140static void __cpuinit kvm_setup_secondary_clock(void) 149static void __cpuinit kvm_setup_secondary_clock(void)
141{ 150{
@@ -195,6 +204,8 @@ void __init kvmclock_init(void)
195 x86_cpuinit.early_percpu_clock_init = 204 x86_cpuinit.early_percpu_clock_init =
196 kvm_setup_secondary_clock; 205 kvm_setup_secondary_clock;
197#endif 206#endif
207 x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
208 x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
198 machine_ops.shutdown = kvm_shutdown; 209 machine_ops.shutdown = kvm_shutdown;
199#ifdef CONFIG_KEXEC 210#ifdef CONFIG_KEXEC
200 machine_ops.crash_shutdown = kvm_crash_shutdown; 211 machine_ops.crash_shutdown = kvm_crash_shutdown;
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index a62c201c97ec..aed2aa1088f1 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -629,7 +629,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
629 629
630static unsigned long long cyc2ns_suspend; 630static unsigned long long cyc2ns_suspend;
631 631
632void save_sched_clock_state(void) 632void tsc_save_sched_clock_state(void)
633{ 633{
634 if (!sched_clock_stable) 634 if (!sched_clock_stable)
635 return; 635 return;
@@ -645,7 +645,7 @@ void save_sched_clock_state(void)
645 * that sched_clock() continues from the point where it was left off during 645 * that sched_clock() continues from the point where it was left off during
646 * suspend. 646 * suspend.
647 */ 647 */
648void restore_sched_clock_state(void) 648void tsc_restore_sched_clock_state(void)
649{ 649{
650 unsigned long long offset; 650 unsigned long long offset;
651 unsigned long flags; 651 unsigned long flags;
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 6f2ec53deed0..e9f265fd79ae 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -108,7 +108,9 @@ struct x86_platform_ops x86_platform = {
108 .is_untracked_pat_range = is_ISA_range, 108 .is_untracked_pat_range = is_ISA_range,
109 .nmi_init = default_nmi_init, 109 .nmi_init = default_nmi_init,
110 .get_nmi_reason = default_get_nmi_reason, 110 .get_nmi_reason = default_get_nmi_reason,
111 .i8042_detect = default_i8042_detect 111 .i8042_detect = default_i8042_detect,
112 .save_sched_clock_state = tsc_save_sched_clock_state,
113 .restore_sched_clock_state = tsc_restore_sched_clock_state,
112}; 114};
113 115
114EXPORT_SYMBOL_GPL(x86_platform); 116EXPORT_SYMBOL_GPL(x86_platform);
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index f10c0afa1cb4..0e76a2814127 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -114,7 +114,7 @@ static void __save_processor_state(struct saved_context *ctxt)
114void save_processor_state(void) 114void save_processor_state(void)
115{ 115{
116 __save_processor_state(&saved_context); 116 __save_processor_state(&saved_context);
117 save_sched_clock_state(); 117 x86_platform.save_sched_clock_state();
118} 118}
119#ifdef CONFIG_X86_32 119#ifdef CONFIG_X86_32
120EXPORT_SYMBOL(save_processor_state); 120EXPORT_SYMBOL(save_processor_state);
@@ -230,8 +230,8 @@ static void __restore_processor_state(struct saved_context *ctxt)
230/* Needed by apm.c */ 230/* Needed by apm.c */
231void restore_processor_state(void) 231void restore_processor_state(void)
232{ 232{
233 x86_platform.restore_sched_clock_state();
233 __restore_processor_state(&saved_context); 234 __restore_processor_state(&saved_context);
234 restore_sched_clock_state();
235} 235}
236#ifdef CONFIG_X86_32 236#ifdef CONFIG_X86_32
237EXPORT_SYMBOL(restore_processor_state); 237EXPORT_SYMBOL(restore_processor_state);