forked from Minki/linux
7b5c4a65cc
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQEcBAABAgAGBQJRAuO3AAoJEHm+PkMAQRiGbfAH/1C3QQKB11aBpYLAw7qijAze yOui26UCnwRryxsO8zBCQjGoByy5DvY/Q0zyUCWUE6nf/JFSoKGUHzfJ1ATyzGll 3vENP6Fnmq0Hgc4t8/gXtXrZ1k/c43cYA2XEhDnEsJlFNmNj2wCQQj9njTNn2cl1 k6XhZ9U1V2hGYpLL5bmsZiLVI6dIpkCVw8d4GZ8BKxSLUacVKMS7ml2kZqxBTMgt AF6T2SPagBBxxNq8q87x4b7vyHYchZmk+9tAV8UMs1ecimasLK8vrRAJvkXXaH1t xgtR0sfIp5raEjoFYswCK+cf5NEusLZDKOEvoABFfEgL4/RKFZ8w7MMsmG8m0rk= =m68Y -----END PGP SIGNATURE----- Merge tag 'v3.8-rc5' into x86/mm The __pa() fixup series that follows touches KVM code that is not present in the existing branch based on v3.7-rc5, so merge in the current upstream from Linus. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
116 lines
3.0 KiB
C
116 lines
3.0 KiB
C
/*
|
|
* sleep.c - x86-specific ACPI sleep support.
|
|
*
|
|
* Copyright (C) 2001-2003 Patrick Mochel
|
|
* Copyright (C) 2001-2003 Pavel Machek <pavel@ucw.cz>
|
|
*/
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/bootmem.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/cpumask.h>
|
|
#include <asm/segment.h>
|
|
#include <asm/desc.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/realmode.h>
|
|
|
|
#include "../../realmode/rm/wakeup.h"
|
|
#include "sleep.h"
|
|
|
|
unsigned long acpi_realmode_flags;
|
|
|
|
#if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
|
|
static char temp_stack[4096];
|
|
#endif
|
|
|
|
/**
|
|
* acpi_suspend_lowlevel - save kernel state
|
|
*
|
|
* Create an identity mapped page table and copy the wakeup routine to
|
|
* low memory.
|
|
*/
|
|
int acpi_suspend_lowlevel(void)
|
|
{
|
|
struct wakeup_header *header =
|
|
(struct wakeup_header *) __va(real_mode_header->wakeup_header);
|
|
|
|
if (header->signature != WAKEUP_HEADER_SIGNATURE) {
|
|
printk(KERN_ERR "wakeup header does not match\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
header->video_mode = saved_video_mode;
|
|
|
|
header->pmode_behavior = 0;
|
|
|
|
#ifndef CONFIG_64BIT
|
|
store_gdt((struct desc_ptr *)&header->pmode_gdt);
|
|
|
|
if (!rdmsr_safe(MSR_EFER,
|
|
&header->pmode_efer_low,
|
|
&header->pmode_efer_high))
|
|
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
|
|
#endif /* !CONFIG_64BIT */
|
|
|
|
header->pmode_cr0 = read_cr0();
|
|
if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
|
|
header->pmode_cr4 = read_cr4();
|
|
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
|
|
}
|
|
if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
|
|
&header->pmode_misc_en_low,
|
|
&header->pmode_misc_en_high))
|
|
header->pmode_behavior |=
|
|
(1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
|
|
header->realmode_flags = acpi_realmode_flags;
|
|
header->real_magic = 0x12345678;
|
|
|
|
#ifndef CONFIG_64BIT
|
|
header->pmode_entry = (u32)&wakeup_pmode_return;
|
|
header->pmode_cr3 = (u32)__pa_symbol(initial_page_table);
|
|
saved_magic = 0x12345678;
|
|
#else /* CONFIG_64BIT */
|
|
#ifdef CONFIG_SMP
|
|
stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
|
|
early_gdt_descr.address =
|
|
(unsigned long)get_cpu_gdt_table(smp_processor_id());
|
|
initial_gs = per_cpu_offset(smp_processor_id());
|
|
#endif
|
|
initial_code = (unsigned long)wakeup_long64;
|
|
saved_magic = 0x123456789abcdef0L;
|
|
#endif /* CONFIG_64BIT */
|
|
|
|
do_suspend_lowlevel();
|
|
return 0;
|
|
}
|
|
|
|
static int __init acpi_sleep_setup(char *str)
|
|
{
|
|
while ((str != NULL) && (*str != '\0')) {
|
|
if (strncmp(str, "s3_bios", 7) == 0)
|
|
acpi_realmode_flags |= 1;
|
|
if (strncmp(str, "s3_mode", 7) == 0)
|
|
acpi_realmode_flags |= 2;
|
|
if (strncmp(str, "s3_beep", 7) == 0)
|
|
acpi_realmode_flags |= 4;
|
|
#ifdef CONFIG_HIBERNATION
|
|
if (strncmp(str, "s4_nohwsig", 10) == 0)
|
|
acpi_no_s4_hw_signature();
|
|
#endif
|
|
if (strncmp(str, "nonvs", 5) == 0)
|
|
acpi_nvs_nosave();
|
|
if (strncmp(str, "nonvs_s3", 8) == 0)
|
|
acpi_nvs_nosave_s3();
|
|
if (strncmp(str, "old_ordering", 12) == 0)
|
|
acpi_old_suspend_ordering();
|
|
str = strchr(str, ',');
|
|
if (str != NULL)
|
|
str += strspn(str, ", \t");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
__setup("acpi_sleep=", acpi_sleep_setup);
|