| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * sleep.c - x86-specific ACPI sleep support. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2001-2003 Patrick Mochel | 
					
						
							|  |  |  |  *  Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/acpi.h>
 | 
					
						
							|  |  |  | #include <linux/bootmem.h>
 | 
					
						
							| 
									
										
										
										
											2005-06-25 14:54:45 -07:00
										 |  |  | #include <linux/dmi.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <asm/smp.h>
 | 
					
						
							|  |  |  | #include <asm/tlbflush.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* address in low memory of the wakeup routine. */ | 
					
						
							|  |  |  | unsigned long acpi_wakeup_address = 0; | 
					
						
							|  |  |  | unsigned long acpi_video_flags; | 
					
						
							|  |  |  | extern char wakeup_start, wakeup_end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern void zap_low_mappings(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | static void init_low_mapping(pgd_t * pgd, int pgd_limit) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int pgd_ofs = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | 	while ((pgd_ofs < pgd_limit) | 
					
						
							|  |  |  | 	       && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) { | 
					
						
							|  |  |  | 		set_pgd(pgd, *(pgd + USER_PTRS_PER_PGD)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		pgd_ofs++, pgd++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	flush_tlb_all(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * acpi_save_state_mem - save kernel state | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Create an identity mapped page table and copy the wakeup routine to | 
					
						
							|  |  |  |  * low memory. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | int acpi_save_state_mem(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (!acpi_wakeup_address) | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	init_low_mapping(swapper_pg_dir, USER_PTRS_PER_PGD); | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | 	memcpy((void *)acpi_wakeup_address, &wakeup_start, | 
					
						
							|  |  |  | 	       &wakeup_end - &wakeup_start); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	acpi_copy_wakeup_routine(acpi_wakeup_address); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * acpi_restore_state - undo effects of acpi_save_state_mem | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | void acpi_restore_state_mem(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	zap_low_mappings(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * acpi_reserve_bootmem - do _very_ early ACPI initialisation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * We allocate a page from the first 1MB of memory for the wakeup | 
					
						
							|  |  |  |  * routine for when we come back from a sleep state. The | 
					
						
							|  |  |  |  * runtime allocator allows specification of <16MB pages, but not | 
					
						
							|  |  |  |  * <1MB pages. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void __init acpi_reserve_bootmem(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) { | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | 		printk(KERN_ERR | 
					
						
							|  |  |  | 		       "ACPI: Wakeup code way too big, S3 disabled.\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); | 
					
						
							|  |  |  | 	if (!acpi_wakeup_address) | 
					
						
							|  |  |  | 		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init acpi_sleep_setup(char *str) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	while ((str != NULL) && (*str != '\0')) { | 
					
						
							|  |  |  | 		if (strncmp(str, "s3_bios", 7) == 0) | 
					
						
							|  |  |  | 			acpi_video_flags = 1; | 
					
						
							|  |  |  | 		if (strncmp(str, "s3_mode", 7) == 0) | 
					
						
							|  |  |  | 			acpi_video_flags |= 2; | 
					
						
							|  |  |  | 		str = strchr(str, ','); | 
					
						
							|  |  |  | 		if (str != NULL) | 
					
						
							|  |  |  | 			str += strspn(str, ", \t"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __setup("acpi_sleep=", acpi_sleep_setup); | 
					
						
							| 
									
										
										
										
											2005-06-25 14:54:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static __init int reset_videomode_after_s3(struct dmi_system_id *d) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	acpi_video_flags |= 2; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static __initdata struct dmi_system_id acpisleep_dmi_table[] = { | 
					
						
							| 
									
										
										
										
											2005-08-05 00:44:28 -04:00
										 |  |  | 	{			/* Reset video mode after returning from ACPI S3 sleep */ | 
					
						
							|  |  |  | 	 .callback = reset_videomode_after_s3, | 
					
						
							|  |  |  | 	 .ident = "Toshiba Satellite 4030cdt", | 
					
						
							|  |  |  | 	 .matches = { | 
					
						
							|  |  |  | 		     DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), | 
					
						
							|  |  |  | 		     }, | 
					
						
							|  |  |  | 	 }, | 
					
						
							|  |  |  | 	{} | 
					
						
							| 
									
										
										
										
											2005-06-25 14:54:45 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init acpisleep_dmi_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dmi_check_system(acpisleep_dmi_table); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | core_initcall(acpisleep_dmi_init); |