| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * sleep.c - x86-specific ACPI sleep support. | 
 | 3 |  * | 
 | 4 |  *  Copyright (C) 2001-2003 Patrick Mochel | 
 | 5 |  *  Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz> | 
 | 6 |  */ | 
 | 7 |  | 
 | 8 | #include <linux/acpi.h> | 
 | 9 | #include <linux/bootmem.h> | 
| Andrey Panin | 0f8133a | 2005-06-25 14:54:45 -0700 | [diff] [blame] | 10 | #include <linux/dmi.h> | 
| Shaohua Li | 55b2355 | 2006-06-23 02:04:49 -0700 | [diff] [blame] | 11 | #include <linux/cpumask.h> | 
 | 12 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | #include <asm/smp.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 |  | 
 | 15 | /* address in low memory of the wakeup routine. */ | 
 | 16 | unsigned long acpi_wakeup_address = 0; | 
 | 17 | unsigned long acpi_video_flags; | 
 | 18 | extern char wakeup_start, wakeup_end; | 
 | 19 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); | 
 | 21 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | /** | 
 | 23 |  * acpi_save_state_mem - save kernel state | 
 | 24 |  * | 
 | 25 |  * Create an identity mapped page table and copy the wakeup routine to | 
 | 26 |  * low memory. | 
 | 27 |  */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 28 | int acpi_save_state_mem(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | { | 
 | 30 | 	if (!acpi_wakeup_address) | 
 | 31 | 		return 1; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 32 | 	memcpy((void *)acpi_wakeup_address, &wakeup_start, | 
 | 33 | 	       &wakeup_end - &wakeup_start); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | 	acpi_copy_wakeup_routine(acpi_wakeup_address); | 
 | 35 |  | 
 | 36 | 	return 0; | 
 | 37 | } | 
 | 38 |  | 
 | 39 | /* | 
 | 40 |  * acpi_restore_state - undo effects of acpi_save_state_mem | 
 | 41 |  */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 42 | void acpi_restore_state_mem(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | } | 
 | 45 |  | 
 | 46 | /** | 
 | 47 |  * acpi_reserve_bootmem - do _very_ early ACPI initialisation | 
 | 48 |  * | 
 | 49 |  * We allocate a page from the first 1MB of memory for the wakeup | 
 | 50 |  * routine for when we come back from a sleep state. The | 
 | 51 |  * runtime allocator allows specification of <16MB pages, but not | 
 | 52 |  * <1MB pages. | 
 | 53 |  */ | 
 | 54 | void __init acpi_reserve_bootmem(void) | 
 | 55 | { | 
 | 56 | 	if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 57 | 		printk(KERN_ERR | 
 | 58 | 		       "ACPI: Wakeup code way too big, S3 disabled.\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | 		return; | 
 | 60 | 	} | 
 | 61 |  | 
 | 62 | 	acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); | 
 | 63 | 	if (!acpi_wakeup_address) | 
 | 64 | 		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); | 
 | 65 | } | 
 | 66 |  | 
 | 67 | static int __init acpi_sleep_setup(char *str) | 
 | 68 | { | 
 | 69 | 	while ((str != NULL) && (*str != '\0')) { | 
 | 70 | 		if (strncmp(str, "s3_bios", 7) == 0) | 
 | 71 | 			acpi_video_flags = 1; | 
 | 72 | 		if (strncmp(str, "s3_mode", 7) == 0) | 
 | 73 | 			acpi_video_flags |= 2; | 
 | 74 | 		str = strchr(str, ','); | 
 | 75 | 		if (str != NULL) | 
 | 76 | 			str += strspn(str, ", \t"); | 
 | 77 | 	} | 
 | 78 | 	return 1; | 
 | 79 | } | 
 | 80 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | __setup("acpi_sleep=", acpi_sleep_setup); | 
| Andrey Panin | 0f8133a | 2005-06-25 14:54:45 -0700 | [diff] [blame] | 82 |  | 
| Andrey Panin | 0f8133a | 2005-06-25 14:54:45 -0700 | [diff] [blame] | 83 | static __init int reset_videomode_after_s3(struct dmi_system_id *d) | 
 | 84 | { | 
 | 85 | 	acpi_video_flags |= 2; | 
 | 86 | 	return 0; | 
 | 87 | } | 
 | 88 |  | 
 | 89 | static __initdata struct dmi_system_id acpisleep_dmi_table[] = { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 90 | 	{			/* Reset video mode after returning from ACPI S3 sleep */ | 
 | 91 | 	 .callback = reset_videomode_after_s3, | 
 | 92 | 	 .ident = "Toshiba Satellite 4030cdt", | 
 | 93 | 	 .matches = { | 
 | 94 | 		     DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), | 
 | 95 | 		     }, | 
 | 96 | 	 }, | 
 | 97 | 	{} | 
| Andrey Panin | 0f8133a | 2005-06-25 14:54:45 -0700 | [diff] [blame] | 98 | }; | 
 | 99 |  | 
 | 100 | static int __init acpisleep_dmi_init(void) | 
 | 101 | { | 
 | 102 | 	dmi_check_system(acpisleep_dmi_table); | 
 | 103 | 	return 0; | 
 | 104 | } | 
 | 105 |  | 
 | 106 | core_initcall(acpisleep_dmi_init); |