diff options
Diffstat (limited to 'arch/i386/kernel/acpi/sleep.c')
-rw-r--r-- | arch/i386/kernel/acpi/sleep.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c new file mode 100644 index 000000000000..28bb0514bb6e --- /dev/null +++ b/arch/i386/kernel/acpi/sleep.c | |||
@@ -0,0 +1,93 @@ | |||
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> | ||
10 | #include <asm/smp.h> | ||
11 | #include <asm/tlbflush.h> | ||
12 | |||
13 | /* address in low memory of the wakeup routine. */ | ||
14 | unsigned long acpi_wakeup_address = 0; | ||
15 | unsigned long acpi_video_flags; | ||
16 | extern char wakeup_start, wakeup_end; | ||
17 | |||
18 | extern void zap_low_mappings(void); | ||
19 | |||
20 | extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); | ||
21 | |||
22 | static void init_low_mapping(pgd_t *pgd, int pgd_limit) | ||
23 | { | ||
24 | int pgd_ofs = 0; | ||
25 | |||
26 | while ((pgd_ofs < pgd_limit) && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) { | ||
27 | set_pgd(pgd, *(pgd+USER_PTRS_PER_PGD)); | ||
28 | pgd_ofs++, pgd++; | ||
29 | } | ||
30 | flush_tlb_all(); | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * acpi_save_state_mem - save kernel state | ||
35 | * | ||
36 | * Create an identity mapped page table and copy the wakeup routine to | ||
37 | * low memory. | ||
38 | */ | ||
39 | int acpi_save_state_mem (void) | ||
40 | { | ||
41 | if (!acpi_wakeup_address) | ||
42 | return 1; | ||
43 | init_low_mapping(swapper_pg_dir, USER_PTRS_PER_PGD); | ||
44 | memcpy((void *) acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start); | ||
45 | acpi_copy_wakeup_routine(acpi_wakeup_address); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * acpi_restore_state - undo effects of acpi_save_state_mem | ||
52 | */ | ||
53 | void acpi_restore_state_mem (void) | ||
54 | { | ||
55 | zap_low_mappings(); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * acpi_reserve_bootmem - do _very_ early ACPI initialisation | ||
60 | * | ||
61 | * We allocate a page from the first 1MB of memory for the wakeup | ||
62 | * routine for when we come back from a sleep state. The | ||
63 | * runtime allocator allows specification of <16MB pages, but not | ||
64 | * <1MB pages. | ||
65 | */ | ||
66 | void __init acpi_reserve_bootmem(void) | ||
67 | { | ||
68 | if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) { | ||
69 | printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n"); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); | ||
74 | if (!acpi_wakeup_address) | ||
75 | printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); | ||
76 | } | ||
77 | |||
78 | static int __init acpi_sleep_setup(char *str) | ||
79 | { | ||
80 | while ((str != NULL) && (*str != '\0')) { | ||
81 | if (strncmp(str, "s3_bios", 7) == 0) | ||
82 | acpi_video_flags = 1; | ||
83 | if (strncmp(str, "s3_mode", 7) == 0) | ||
84 | acpi_video_flags |= 2; | ||
85 | str = strchr(str, ','); | ||
86 | if (str != NULL) | ||
87 | str += strspn(str, ", \t"); | ||
88 | } | ||
89 | return 1; | ||
90 | } | ||
91 | |||
92 | |||
93 | __setup("acpi_sleep=", acpi_sleep_setup); | ||