sleep.c revision 7a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76
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> 17b40827fa7268fda8a62490728a61c2856f33830bBorislav Petkov 18e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#include "realmode/wakeup.h" 19e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#include "sleep.h" 204fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 214fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machekunsigned long acpi_realmode_flags; 224fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 239744f5a32853642f8ed0749a1c9ed8cf9c9c9dc4Marcin Slusarz#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) 245000cadcf3188e935dae28c4fc7e24639704ea55Matt Mackallstatic char temp_stack[4096]; 25e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#endif 264fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 274fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek/** 28f1a2003e22f6b50ea21f7f4b38b38c5ebc9c8017Rafael J. Wysocki * acpi_suspend_lowlevel - save kernel state 294fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * 304fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * Create an identity mapped page table and copy the wakeup routine to 314fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek * low memory. 324fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek */ 33f1a2003e22f6b50ea21f7f4b38b38c5ebc9c8017Rafael J. Wysockiint acpi_suspend_lowlevel(void) 344fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek{ 35e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek struct wakeup_header *header; 36d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin /* address in low memory of the wakeup routine. */ 37d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin char *acpi_realmode; 38e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 39d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code); 40e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 41d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET); 42d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin if (header->signature != WAKEUP_HEADER_SIGNATURE) { 43e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek printk(KERN_ERR "wakeup header does not match\n"); 44e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek return -EINVAL; 45e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek } 46e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 47e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->video_mode = saved_video_mode; 48e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 494b4f7280d7fd1feeff134c2cf2db32fd583b6c29H. Peter Anvin header->wakeup_jmp_seg = acpi_wakeup_address >> 4; 50065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin 51065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin /* 52065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin * Set up the wakeup GDT. We set these up as Big Real Mode, 53065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin * that is, with limits set to 4 GB. At least the Lenovo 54065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin * Thinkpad X61 is known to need this for the video BIOS 55065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin * initialization quirk to work; this is likely to also 56065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin * be the case for other laptops or integrated video devices. 57065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin */ 58065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin 594b4f7280d7fd1feeff134c2cf2db32fd583b6c29H. Peter Anvin /* GDT[0]: GDT self-pointer */ 604b4f7280d7fd1feeff134c2cf2db32fd583b6c29H. Peter Anvin header->wakeup_gdt[0] = 614b4f7280d7fd1feeff134c2cf2db32fd583b6c29H. Peter Anvin (u64)(sizeof(header->wakeup_gdt) - 1) + 62d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin ((u64)__pa(&header->wakeup_gdt) << 16); 63065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin /* GDT[1]: big real mode-like code segment */ 643bf2e77453a87c22eb57ed4926760ac131c84459H. Peter Anvin header->wakeup_gdt[1] = 653bf2e77453a87c22eb57ed4926760ac131c84459H. Peter Anvin GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff); 66065cb3dfe24978651caedfa54da585388ad15ddeH. Peter Anvin /* GDT[2]: big real mode-like data segment */ 673bf2e77453a87c22eb57ed4926760ac131c84459H. Peter Anvin header->wakeup_gdt[2] = 683bf2e77453a87c22eb57ed4926760ac131c84459H. Peter Anvin GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff); 694b4f7280d7fd1feeff134c2cf2db32fd583b6c29H. Peter Anvin 70e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#ifndef CONFIG_64BIT 71e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek store_gdt((struct desc_ptr *)&header->pmode_gdt); 72e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 73a7c4c0d934c6cbc58de262d090d4a715445453f0H. Peter Anvin if (rdmsr_safe(MSR_EFER, &header->pmode_efer_low, 74a7c4c0d934c6cbc58de262d090d4a715445453f0H. Peter Anvin &header->pmode_efer_high)) 75a7c4c0d934c6cbc58de262d090d4a715445453f0H. Peter Anvin header->pmode_efer_low = header->pmode_efer_high = 0; 76e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#endif /* !CONFIG_64BIT */ 77e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 78e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->pmode_cr0 = read_cr0(); 79e532c06f2a835b5cc4f4166f467437d9b09c1d0eDavid Fries header->pmode_cr4 = read_cr4_safe(); 807a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook header->pmode_behavior = 0; 817a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook if (!rdmsr_safe(MSR_IA32_MISC_ENABLE, 827a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook &header->pmode_misc_en_low, 837a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook &header->pmode_misc_en_high)) 847a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook header->pmode_behavior |= 857a3136666bc0f0419f7aaa7b1fabb4b0e0a7fb76Kees Cook (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE); 86e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->realmode_flags = acpi_realmode_flags; 87e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->real_magic = 0x12345678; 88e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek 89e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#ifndef CONFIG_64BIT 90e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek header->pmode_entry = (u32)&wakeup_pmode_return; 91b40827fa7268fda8a62490728a61c2856f33830bBorislav Petkov header->pmode_cr3 = (u32)__pa(&initial_page_table); 92e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek saved_magic = 0x12345678; 93e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#else /* CONFIG_64BIT */ 94d1ee433539ea5963a8f946f3428b335d1c5fdb20H. Peter Anvin header->trampoline_segment = trampoline_address() >> 4; 951ea598c29748a559a0086a84a016886d786e6272Ingo Molnar#ifdef CONFIG_SMP 9611d4c3f9b671720e80353dd7e433ff2bf65e9500H. Peter Anvin stack_start = (unsigned long)temp_stack + sizeof(temp_stack); 973038edabf48f01421c621cb77a712b446d3a5d67Rafael J. Wysocki early_gdt_descr.address = 983038edabf48f01421c621cb77a712b446d3a5d67Rafael J. Wysocki (unsigned long)get_cpu_gdt_table(smp_processor_id()); 99004aa322f855a765741d9437a98dd8fe2e4f32a6Tejun Heo initial_gs = per_cpu_offset(smp_processor_id()); 1001ea598c29748a559a0086a84a016886d786e6272Ingo Molnar#endif 101e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek initial_code = (unsigned long)wakeup_long64; 102ce4b3c55475e451cb489e857640396c37ca88974Jaswinder Singh Rajput saved_magic = 0x123456789abcdef0L; 103e44b7b7525ad9d43163ab5e60c784325419e0ea6Pavel Machek#endif /* CONFIG_64BIT */ 1044fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 105f1a2003e22f6b50ea21f7f4b38b38c5ebc9c8017Rafael J. Wysocki do_suspend_lowlevel(); 1064fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek return 0; 1074fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek} 1084fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 1094fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machekstatic int __init acpi_sleep_setup(char *str) 1104fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek{ 1114fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek while ((str != NULL) && (*str != '\0')) { 1124fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (strncmp(str, "s3_bios", 7) == 0) 1134fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek acpi_realmode_flags |= 1; 1144fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (strncmp(str, "s3_mode", 7) == 0) 1154fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek acpi_realmode_flags |= 2; 1164fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (strncmp(str, "s3_beep", 7) == 0) 1174fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek acpi_realmode_flags |= 4; 118bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li#ifdef CONFIG_HIBERNATION 119bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li if (strncmp(str, "s4_nohwsig", 10) == 0) 120bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li acpi_no_s4_hw_signature(); 121bdfe6b7c681669148dae4db27eb24ee5408ba371Shaohua Li#endif 12272ad5d77fb981963edae15eee8196c80238f5ed0Rafael J. Wysocki if (strncmp(str, "nonvs", 5) == 0) 12372ad5d77fb981963edae15eee8196c80238f5ed0Rafael J. Wysocki acpi_nvs_nosave(); 124d8f3de0d2412bb91639cfefc5b3c79dbf3812212Rafael J. Wysocki if (strncmp(str, "old_ordering", 12) == 0) 125d8f3de0d2412bb91639cfefc5b3c79dbf3812212Rafael J. Wysocki acpi_old_suspend_ordering(); 1264fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek str = strchr(str, ','); 1274fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek if (str != NULL) 1284fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek str += strspn(str, ", \t"); 1294fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek } 1304fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek return 1; 1314fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek} 1324fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek 1334fc2fba804cae404d2665e23b8cbd46d5f63a07ePavel Machek__setup("acpi_sleep=", acpi_sleep_setup); 134