14fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek/* 24fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * sleep.c - x86-specific ACPI sleep support. 34fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * 44fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * Copyright (C) 2001-2003 Patrick Mochel 5a2531293dbb7608fa672ff28efe3ab4027917a2fPavel Machek * Copyright (C) 2001-2003 Pavel Machek <pavel@ucw.cz> 64fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek */ 74fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 84fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek#include <linux/acpi.h> 94fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek#include <linux/bootmem.h> 10a9ce6bc15100023b411f8117e53a016d61889800Yinghai Lu#include <linux/memblock.h> 114fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek#include <linux/dmi.h> 124fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek#include <linux/cpumask.h> 134fdf08b5bf8d449cc9897395895157c6ff8ddc41H. Peter Anvin#include <asm/segment.h> 143038edabf48f01421c621cb77a712b446d3a5d67Rafael J. Wysocki#include <asm/desc.h> 15b40827fa7268fda8a62490728a61c2856f33830bBorislav Petkov#include <asm/pgtable.h> 16d344e38b2c151ca5e5e39f562017127e93912528H. Peter Anvin#include <asm/cacheflush.h> 17c9b77ccb52a5c77233b0e557b7d4417b00ef4012Jarkko Sakkinen#include <asm/realmode.h> 18b40827fa7268fda8a62490728a61c2856f33830bBorislav Petkov 19c4845474a01f699966272536e8416222e3f2d2cbJarkko Sakkinen#include "../../realmode/rm/wakeup.h" 20e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#include "sleep.h" 214fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 224fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machekunsigned long acpi_realmode_flags; 234fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 249744f5a32853642f8ed0749a1c9ed8cf9c9c9dc4Marcin Slusarz#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) 255000cadcf3188e935dae28c4fc7e24639704ea55Matt Mackallstatic char temp_stack[4096]; 26e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#endif 274fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 284fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek/** 2940bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng * x86_acpi_enter_sleep_state - enter sleep state 3040bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng * @state: Sleep state to enter. 3140bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng * 3240bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng * Wrapper around acpi_enter_sleep_state() to be called by assmebly. 3340bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng */ 342605fc216fa492f9e7c488bdc7f687cd6dcc703bAndi Kleenacpi_status asmlinkage __visible x86_acpi_enter_sleep_state(u8 state) 3540bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng{ 3640bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng return acpi_enter_sleep_state(state); 3740bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng} 3840bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng 3940bce100cafb945f1fb5475a70628b4379c74f38Lv Zheng/** 40d6a77ead21b69c395ca6d09a066ededfac601bccKonrad Rzeszutek Wilk * x86_acpi_suspend_lowlevel - save kernel state 414fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * 424fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * Create an identity mapped page table and copy the wakeup routine to 434fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * low memory. 444fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek */ 45d6a77ead21b69c395ca6d09a066ededfac601bccKonrad Rzeszutek Wilkint x86_acpi_suspend_lowlevel(void) 464fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek{ 47c9b77ccb52a5c77233b0e557b7d4417b00ef4012Jarkko Sakkinen struct wakeup_header *header = 48b429dbf6e866bd6dadb56fae66f61f611cde57ffJarkko Sakkinen (struct wakeup_header *) __va(real_mode_header->wakeup_header); 49e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 50d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin if (header->signature != WAKEUP_HEADER_SIGNATURE) { 51e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek printk(KERN_ERR "wakeup header does not match\n"); 52e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek return -EINVAL; 53e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek } 54e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 55e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->video_mode = saved_video_mode; 56e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 5773201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin header->pmode_behavior = 0; 5873201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin 59e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#ifndef CONFIG_64BIT 60357d122670937c35b33d99c46356ef2b63182a1fKonrad Rzeszutek Wilk native_store_gdt((struct desc_ptr *)&header->pmode_gdt); 61e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 625ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin /* 635ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin * We have to check that we can write back the value, and not 645ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin * just read it. At least on 90 nm Pentium M (Family 6, Model 655ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin * 13), reading an invalid MSR is not guaranteed to trap, see 665ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin * Erratum X4 in "Intel Pentium M Processor on 90 nm Process 675ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin * with 2-MB L2 Cache and Intel® Processor A100 and A110 on 90 685ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin * nm process with 512-KB L2 Cache Specification Update". 695ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin */ 7073201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin if (!rdmsr_safe(MSR_EFER, 7173201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin &header->pmode_efer_low, 725ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin &header->pmode_efer_high) && 735ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin !wrmsr_safe(MSR_EFER, 745ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin header->pmode_efer_low, 755ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin header->pmode_efer_high)) 7673201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER); 77e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#endif /* !CONFIG_64BIT */ 78e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 79e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->pmode_cr0 = read_cr0(); 8073201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin if (__this_cpu_read(cpu_info.cpuid_level) >= 0) { 8173201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin header->pmode_cr4 = read_cr4(); 8273201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4); 8373201dbec64aebf6b0dca855b523f437972dc7bbH. Peter Anvin } 847a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook if (!rdmsr_safe(MSR_IA32_MISC_ENABLE, 857a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook &header->pmode_misc_en_low, 865ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin &header->pmode_misc_en_high) && 875ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin !wrmsr_safe(MSR_IA32_MISC_ENABLE, 885ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin header->pmode_misc_en_low, 895ff560fd48d5b3d82fa0c3aff625c9da1a301911H. Peter Anvin header->pmode_misc_en_high)) 907a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook header->pmode_behavior |= 917a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE); 92e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->realmode_flags = acpi_realmode_flags; 93e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->real_magic = 0x12345678; 94e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 95e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#ifndef CONFIG_64BIT 96e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->pmode_entry = (u32)&wakeup_pmode_return; 97afd51a0e32cd79261f0e823400886ed322a355acAlexander Duyck header->pmode_cr3 = (u32)__pa_symbol(initial_page_table); 98e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek saved_magic = 0x12345678; 99e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#else /* CONFIG_64BIT */ 1001ea598c29748a559a0086a84a016886d786e6272Ingo Molnar#ifdef CONFIG_SMP 10111d4c3f9b671720e80353dd7e433ff2bf65e9500H. Peter Anvin stack_start = (unsigned long)temp_stack + sizeof(temp_stack); 1023038edabf48f01421c621cb77a712b446d3a5d67Rafael J. Wysocki early_gdt_descr.address = 1033038edabf48f01421c621cb77a712b446d3a5d67Rafael J. Wysocki (unsigned long)get_cpu_gdt_table(smp_processor_id()); 104004aa322f855a765741d9437a98dd8fe2e4f32a6Tejun Heo initial_gs = per_cpu_offset(smp_processor_id()); 1051ea598c29748a559a0086a84a016886d786e6272Ingo Molnar#endif 106e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek initial_code = (unsigned long)wakeup_long64; 107ce4b3c55475e451cb489e857640396c37ca88974Jaswinder Singh Rajput saved_magic = 0x123456789abcdef0L; 108e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#endif /* CONFIG_64BIT */ 1094fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 110f1a2003e22f6b50ea21f7f4b38b38c5ebc9c8017Rafael J. Wysocki do_suspend_lowlevel(); 1114fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek return 0; 1124fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek} 1134fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 1144fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machekstatic int __init acpi_sleep_setup(char *str) 1154fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek{ 1164fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek while ((str != NULL) && (*str != '\0')) { 1174fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (strncmp(str, "s3_bios", 7) == 0) 1184fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek acpi_realmode_flags |= 1; 1194fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (strncmp(str, "s3_mode", 7) == 0) 1204fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek acpi_realmode_flags |= 2; 1214fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (strncmp(str, "s3_beep", 7) == 0) 1224fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek acpi_realmode_flags |= 4; 123bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li#ifdef CONFIG_HIBERNATION 124bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li if (strncmp(str, "s4_nohwsig", 10) == 0) 125bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li acpi_no_s4_hw_signature(); 126bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li#endif 12772ad5d77fb981963edae15eee8196c80238f5ed0Rafael J. Wysocki if (strncmp(str, "nonvs", 5) == 0) 12872ad5d77fb981963edae15eee8196c80238f5ed0Rafael J. Wysocki acpi_nvs_nosave(); 1291bad2f19f7f79d1ec9e6c48168fd7ce8dc1c305fKristen Carlson Accardi if (strncmp(str, "nonvs_s3", 8) == 0) 1301bad2f19f7f79d1ec9e6c48168fd7ce8dc1c305fKristen Carlson Accardi acpi_nvs_nosave_s3(); 131d8f3de0d2412bb91639cfefc5b3c79dbf3812212Rafael J. Wysocki if (strncmp(str, "old_ordering", 12) == 0) 132d8f3de0d2412bb91639cfefc5b3c79dbf3812212Rafael J. Wysocki acpi_old_suspend_ordering(); 1334fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek str = strchr(str, ','); 1344fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (str != NULL) 1354fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek str += strspn(str, ", \t"); 1364fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek } 1374fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek return 1; 1384fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek} 1394fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 1404fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek__setup("acpi_sleep=", acpi_sleep_setup); 141