aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/Kconfig2
-rw-r--r--kernel/power/disk.c6
-rw-r--r--kernel/power/power.h7
-rw-r--r--kernel/power/swsusp.c29
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
30config SOFTWARE_SUSPEND 30config 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
24extern suspend_disk_method_t pm_disk_mode; 25extern suspend_disk_method_t pm_disk_mode;
25extern struct pm_ops * pm_ops;
26 26
27extern int swsusp_suspend(void); 27extern int swsusp_suspend(void);
28extern int swsusp_write(void); 28extern int swsusp_write(void);
@@ -49,13 +49,11 @@ dev_t swsusp_resume_device;
49 49
50static void power_down(suspend_disk_method_t mode) 50static 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
13struct swsusp_info { 16struct 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)
402static void data_free(void) 402static 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 */
866void swsusp_free(void) 868void 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}