summaryrefslogtreecommitdiffstats
path: root/arch/x86/power/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/power/cpu.c')
-rw-r--r--arch/x86/power/cpu.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 120cee1c3f8..1cf5b300305 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -11,6 +11,7 @@
#include <linux/suspend.h>
#include <linux/export.h>
#include <linux/smp.h>
+#include <linux/perf_event.h>
#include <asm/pgtable.h>
#include <asm/proto.h>
@@ -24,16 +25,12 @@
#include <asm/cpu.h>
#ifdef CONFIG_X86_32
-static struct saved_context saved_context;
-
unsigned long saved_context_ebx;
unsigned long saved_context_esp, saved_context_ebp;
unsigned long saved_context_esi, saved_context_edi;
unsigned long saved_context_eflags;
-#else
-/* CONFIG_X86_64 */
-struct saved_context saved_context;
#endif
+struct saved_context saved_context;
/**
* __save_processor_state - save CPU registers before creating a
@@ -61,13 +58,20 @@ static void __save_processor_state(struct saved_context *ctxt)
* descriptor tables
*/
#ifdef CONFIG_X86_32
- store_gdt(&ctxt->gdt);
store_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
- store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
store_idt((struct desc_ptr *)&ctxt->idt_limit);
#endif
+ /*
+ * We save it here, but restore it only in the hibernate case.
+ * For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit
+ * mode in "secondary_startup_64". In 32-bit mode it is done via
+ * 'pmode_gdt' in wakeup_start.
+ */
+ ctxt->gdt_desc.size = GDT_SIZE - 1;
+ ctxt->gdt_desc.address = (unsigned long)get_cpu_gdt_table(smp_processor_id());
+
store_tr(ctxt->tr);
/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
@@ -134,7 +138,10 @@ static void fix_processor_context(void)
{
int cpu = smp_processor_id();
struct tss_struct *t = &per_cpu(init_tss, cpu);
-
+#ifdef CONFIG_X86_64
+ struct desc_struct *desc = get_cpu_gdt_table(cpu);
+ tss_desc tss;
+#endif
set_tss_desc(cpu, t); /*
* This just modifies memory; should not be
* necessary. But... This is necessary, because
@@ -143,7 +150,9 @@ static void fix_processor_context(void)
*/
#ifdef CONFIG_X86_64
- get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
+ memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));
+ tss.type = 0x9; /* The available 64-bit TSS (see AMD vol 2, pg 91 */
+ write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
syscall_init(); /* This sets MSR_*STAR and related */
#endif
@@ -182,11 +191,9 @@ static void __restore_processor_state(struct saved_context *ctxt)
* ltr is done i fix_processor_context().
*/
#ifdef CONFIG_X86_32
- load_gdt(&ctxt->gdt);
load_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
- load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
load_idt((const struct desc_ptr *)&ctxt->idt_limit);
#endif
@@ -228,6 +235,7 @@ static void __restore_processor_state(struct saved_context *ctxt)
do_fpu_end();
x86_platform.restore_sched_clock_state();
mtrr_bp_restore();
+ perf_restore_debug_store();
}
/* Needed by apm.c */