diff options
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Kconfig | 2 | ||||
-rw-r--r-- | kernel/power/disk.c | 6 | ||||
-rw-r--r-- | kernel/power/power.h | 7 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 29 |
4 files changed, 26 insertions, 18 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 396c7873e804..46a5e5acff97 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
@@ -29,7 +29,7 @@ config PM_DEBUG | |||
29 | 29 | ||
30 | config SOFTWARE_SUSPEND | 30 | config SOFTWARE_SUSPEND |
31 | bool "Software Suspend" | 31 | bool "Software Suspend" |
32 | depends on PM && SWAP && (X86 || ((FVR || PPC32) && !SMP)) | 32 | depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FVR || PPC32) && !SMP) |
33 | ---help--- | 33 | ---help--- |
34 | Enable the possibility of suspending the machine. | 34 | Enable the possibility of suspending the machine. |
35 | It doesn't need APM. | 35 | It doesn't need APM. |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 2d8bf054d036..761956e813f5 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -17,12 +17,12 @@ | |||
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
20 | #include <linux/pm.h> | ||
20 | 21 | ||
21 | #include "power.h" | 22 | #include "power.h" |
22 | 23 | ||
23 | 24 | ||
24 | extern suspend_disk_method_t pm_disk_mode; | 25 | extern suspend_disk_method_t pm_disk_mode; |
25 | extern struct pm_ops * pm_ops; | ||
26 | 26 | ||
27 | extern int swsusp_suspend(void); | 27 | extern int swsusp_suspend(void); |
28 | extern int swsusp_write(void); | 28 | extern int swsusp_write(void); |
@@ -49,13 +49,11 @@ dev_t swsusp_resume_device; | |||
49 | 49 | ||
50 | static void power_down(suspend_disk_method_t mode) | 50 | static void power_down(suspend_disk_method_t mode) |
51 | { | 51 | { |
52 | unsigned long flags; | ||
53 | int error = 0; | 52 | int error = 0; |
54 | 53 | ||
55 | local_irq_save(flags); | ||
56 | switch(mode) { | 54 | switch(mode) { |
57 | case PM_DISK_PLATFORM: | 55 | case PM_DISK_PLATFORM: |
58 | device_shutdown(); | 56 | kernel_power_off_prepare(); |
59 | error = pm_ops->enter(PM_SUSPEND_DISK); | 57 | error = pm_ops->enter(PM_SUSPEND_DISK); |
60 | break; | 58 | break; |
61 | case PM_DISK_SHUTDOWN: | 59 | case PM_DISK_SHUTDOWN: |
diff --git a/kernel/power/power.h b/kernel/power/power.h index cd6a3493cc0d..6748de23e83c 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #include <linux/suspend.h> | 1 | #include <linux/suspend.h> |
2 | #include <linux/utsname.h> | 2 | #include <linux/utsname.h> |
3 | 3 | ||
4 | /* With SUSPEND_CONSOLE defined, it suspend looks *really* cool, but | 4 | /* With SUSPEND_CONSOLE defined suspend looks *really* cool, but |
5 | we probably do not take enough locks for switching consoles, etc, | 5 | we probably do not take enough locks for switching consoles, etc, |
6 | so bad things might happen. | 6 | so bad things might happen. |
7 | */ | 7 | */ |
@@ -9,6 +9,9 @@ | |||
9 | #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) | 9 | #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) |
10 | #endif | 10 | #endif |
11 | 11 | ||
12 | #define MAX_PBES ((PAGE_SIZE - sizeof(struct new_utsname) \ | ||
13 | - 4 - 3*sizeof(unsigned long) - sizeof(int) \ | ||
14 | - sizeof(void *)) / sizeof(swp_entry_t)) | ||
12 | 15 | ||
13 | struct swsusp_info { | 16 | struct swsusp_info { |
14 | struct new_utsname uts; | 17 | struct new_utsname uts; |
@@ -18,7 +21,7 @@ struct swsusp_info { | |||
18 | unsigned long image_pages; | 21 | unsigned long image_pages; |
19 | unsigned long pagedir_pages; | 22 | unsigned long pagedir_pages; |
20 | suspend_pagedir_t * suspend_pagedir; | 23 | suspend_pagedir_t * suspend_pagedir; |
21 | swp_entry_t pagedir[768]; | 24 | swp_entry_t pagedir[MAX_PBES]; |
22 | } __attribute__((aligned(PAGE_SIZE))); | 25 | } __attribute__((aligned(PAGE_SIZE))); |
23 | 26 | ||
24 | 27 | ||
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index d967e875ee82..acf79ac1cb6d 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -363,7 +363,7 @@ static void lock_swapdevices(void) | |||
363 | } | 363 | } |
364 | 364 | ||
365 | /** | 365 | /** |
366 | * write_swap_page - Write one page to a fresh swap location. | 366 | * write_page - Write one page to a fresh swap location. |
367 | * @addr: Address we're writing. | 367 | * @addr: Address we're writing. |
368 | * @loc: Place to store the entry we used. | 368 | * @loc: Place to store the entry we used. |
369 | * | 369 | * |
@@ -402,15 +402,14 @@ static int write_page(unsigned long addr, swp_entry_t * loc) | |||
402 | static void data_free(void) | 402 | static void data_free(void) |
403 | { | 403 | { |
404 | swp_entry_t entry; | 404 | swp_entry_t entry; |
405 | int i; | 405 | struct pbe * p; |
406 | 406 | ||
407 | for (i = 0; i < nr_copy_pages; i++) { | 407 | for_each_pbe(p, pagedir_nosave) { |
408 | entry = (pagedir_nosave + i)->swap_address; | 408 | entry = p->swap_address; |
409 | if (entry.val) | 409 | if (entry.val) |
410 | swap_free(entry); | 410 | swap_free(entry); |
411 | else | 411 | else |
412 | break; | 412 | break; |
413 | (pagedir_nosave + i)->swap_address = (swp_entry_t){0}; | ||
414 | } | 413 | } |
415 | } | 414 | } |
416 | 415 | ||
@@ -863,6 +862,9 @@ static int alloc_image_pages(void) | |||
863 | return 0; | 862 | return 0; |
864 | } | 863 | } |
865 | 864 | ||
865 | /* Free pages we allocated for suspend. Suspend pages are alocated | ||
866 | * before atomic copy, so we need to free them after resume. | ||
867 | */ | ||
866 | void swsusp_free(void) | 868 | void swsusp_free(void) |
867 | { | 869 | { |
868 | BUG_ON(PageNosave(virt_to_page(pagedir_save))); | 870 | BUG_ON(PageNosave(virt_to_page(pagedir_save))); |
@@ -918,6 +920,7 @@ static int swsusp_alloc(void) | |||
918 | 920 | ||
919 | pagedir_nosave = NULL; | 921 | pagedir_nosave = NULL; |
920 | nr_copy_pages = calc_nr(nr_copy_pages); | 922 | nr_copy_pages = calc_nr(nr_copy_pages); |
923 | nr_copy_pages_check = nr_copy_pages; | ||
921 | 924 | ||
922 | pr_debug("suspend: (pages needed: %d + %d free: %d)\n", | 925 | pr_debug("suspend: (pages needed: %d + %d free: %d)\n", |
923 | nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); | 926 | nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); |
@@ -928,6 +931,10 @@ static int swsusp_alloc(void) | |||
928 | if (!enough_swap()) | 931 | if (!enough_swap()) |
929 | return -ENOSPC; | 932 | return -ENOSPC; |
930 | 933 | ||
934 | if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE + | ||
935 | !!(nr_copy_pages % PBES_PER_PAGE)) | ||
936 | return -ENOSPC; | ||
937 | |||
931 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { | 938 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { |
932 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); | 939 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); |
933 | return -ENOMEM; | 940 | return -ENOMEM; |
@@ -940,7 +947,6 @@ static int swsusp_alloc(void) | |||
940 | return error; | 947 | return error; |
941 | } | 948 | } |
942 | 949 | ||
943 | nr_copy_pages_check = nr_copy_pages; | ||
944 | return 0; | 950 | return 0; |
945 | } | 951 | } |
946 | 952 | ||
@@ -1213,8 +1219,9 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) | |||
1213 | free_pagedir(pblist); | 1219 | free_pagedir(pblist); |
1214 | free_eaten_memory(); | 1220 | free_eaten_memory(); |
1215 | pblist = NULL; | 1221 | pblist = NULL; |
1216 | } | 1222 | /* Is this even worth handling? It should never ever happen, and we |
1217 | else | 1223 | have just lost user's state, anyway... */ |
1224 | } else | ||
1218 | printk("swsusp: Relocated %d pages\n", rel); | 1225 | printk("swsusp: Relocated %d pages\n", rel); |
1219 | 1226 | ||
1220 | return pblist; | 1227 | return pblist; |
@@ -1434,9 +1441,9 @@ static int read_pagedir(struct pbe *pblist) | |||
1434 | } | 1441 | } |
1435 | 1442 | ||
1436 | if (error) | 1443 | if (error) |
1437 | free_page((unsigned long)pblist); | 1444 | free_pagedir(pblist); |
1438 | 1445 | else | |
1439 | BUG_ON(i != swsusp_info.pagedir_pages); | 1446 | BUG_ON(i != swsusp_info.pagedir_pages); |
1440 | 1447 | ||
1441 | return error; | 1448 | return error; |
1442 | } | 1449 | } |