diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 09:18:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-25 09:18:39 -0400 |
commit | 7e0bb71e75020348bee523720a0c2f04cc72f540 (patch) | |
tree | 1a22d65bbce34e8cc0f82c543c9486ffb58332f7 /arch/s390 | |
parent | b9e2780d576a010d4aba1e69f247170bf3718d6b (diff) | |
parent | 0ab1e79b825a5cd8aeb3b34d89c9a89dea900056 (diff) |
Merge branch 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
* 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (63 commits)
PM / Clocks: Remove redundant NULL checks before kfree()
PM / Documentation: Update docs about suspend and CPU hotplug
ACPI / PM: Add Sony VGN-FW21E to nonvs blacklist.
ARM: mach-shmobile: sh7372 A4R support (v4)
ARM: mach-shmobile: sh7372 A3SP support (v4)
PM / Sleep: Mark devices involved in wakeup signaling during suspend
PM / Hibernate: Improve performance of LZO/plain hibernation, checksum image
PM / Hibernate: Do not initialize static and extern variables to 0
PM / Freezer: Make fake_signal_wake_up() wake TASK_KILLABLE tasks too
PM / Hibernate: Add resumedelay kernel param in addition to resumewait
MAINTAINERS: Update linux-pm list address
PM / ACPI: Blacklist Vaio VGN-FW520F machine known to require acpi_sleep=nonvs
PM / ACPI: Blacklist Sony Vaio known to require acpi_sleep=nonvs
PM / Hibernate: Add resumewait param to support MMC-like devices as resume file
PM / Hibernate: Fix typo in a kerneldoc comment
PM / Hibernate: Freeze kernel threads after preallocating memory
PM: Update the policy on default wakeup settings
PM / VT: Cleanup #if defined uglyness and fix compile error
PM / Suspend: Off by one in pm_suspend()
PM / Hibernate: Include storage keys in hibernation image on s390
...
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/kernel/suspend.c | 118 | ||||
-rw-r--r-- | arch/s390/kernel/swsusp_asm64.S | 3 |
3 files changed, 122 insertions, 0 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index ed5cb5af5281..6b99fc3f9b63 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -91,6 +91,7 @@ config S390 | |||
91 | select HAVE_ARCH_MUTEX_CPU_RELAX | 91 | select HAVE_ARCH_MUTEX_CPU_RELAX |
92 | select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 | 92 | select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 |
93 | select HAVE_RCU_TABLE_FREE if SMP | 93 | select HAVE_RCU_TABLE_FREE if SMP |
94 | select ARCH_SAVE_PAGE_KEYS if HIBERNATION | ||
94 | select ARCH_INLINE_SPIN_TRYLOCK | 95 | select ARCH_INLINE_SPIN_TRYLOCK |
95 | select ARCH_INLINE_SPIN_TRYLOCK_BH | 96 | select ARCH_INLINE_SPIN_TRYLOCK_BH |
96 | select ARCH_INLINE_SPIN_LOCK | 97 | select ARCH_INLINE_SPIN_LOCK |
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c index cf9e5c6d5527..b6f9afed74ec 100644 --- a/arch/s390/kernel/suspend.c +++ b/arch/s390/kernel/suspend.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/pfn.h> | 9 | #include <linux/pfn.h> |
10 | #include <linux/mm.h> | ||
10 | #include <asm/system.h> | 11 | #include <asm/system.h> |
11 | 12 | ||
12 | /* | 13 | /* |
@@ -14,6 +15,123 @@ | |||
14 | */ | 15 | */ |
15 | extern const void __nosave_begin, __nosave_end; | 16 | extern const void __nosave_begin, __nosave_end; |
16 | 17 | ||
18 | /* | ||
19 | * The restore of the saved pages in an hibernation image will set | ||
20 | * the change and referenced bits in the storage key for each page. | ||
21 | * Overindication of the referenced bits after an hibernation cycle | ||
22 | * does not cause any harm but the overindication of the change bits | ||
23 | * would cause trouble. | ||
24 | * Use the ARCH_SAVE_PAGE_KEYS hooks to save the storage key of each | ||
25 | * page to the most significant byte of the associated page frame | ||
26 | * number in the hibernation image. | ||
27 | */ | ||
28 | |||
29 | /* | ||
30 | * Key storage is allocated as a linked list of pages. | ||
31 | * The size of the keys array is (PAGE_SIZE - sizeof(long)) | ||
32 | */ | ||
33 | struct page_key_data { | ||
34 | struct page_key_data *next; | ||
35 | unsigned char data[]; | ||
36 | }; | ||
37 | |||
38 | #define PAGE_KEY_DATA_SIZE (PAGE_SIZE - sizeof(struct page_key_data *)) | ||
39 | |||
40 | static struct page_key_data *page_key_data; | ||
41 | static struct page_key_data *page_key_rp, *page_key_wp; | ||
42 | static unsigned long page_key_rx, page_key_wx; | ||
43 | |||
44 | /* | ||
45 | * For each page in the hibernation image one additional byte is | ||
46 | * stored in the most significant byte of the page frame number. | ||
47 | * On suspend no additional memory is required but on resume the | ||
48 | * keys need to be memorized until the page data has been restored. | ||
49 | * Only then can the storage keys be set to their old state. | ||
50 | */ | ||
51 | unsigned long page_key_additional_pages(unsigned long pages) | ||
52 | { | ||
53 | return DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Free page_key_data list of arrays. | ||
58 | */ | ||
59 | void page_key_free(void) | ||
60 | { | ||
61 | struct page_key_data *pkd; | ||
62 | |||
63 | while (page_key_data) { | ||
64 | pkd = page_key_data; | ||
65 | page_key_data = pkd->next; | ||
66 | free_page((unsigned long) pkd); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Allocate page_key_data list of arrays with enough room to store | ||
72 | * one byte for each page in the hibernation image. | ||
73 | */ | ||
74 | int page_key_alloc(unsigned long pages) | ||
75 | { | ||
76 | struct page_key_data *pk; | ||
77 | unsigned long size; | ||
78 | |||
79 | size = DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE); | ||
80 | while (size--) { | ||
81 | pk = (struct page_key_data *) get_zeroed_page(GFP_KERNEL); | ||
82 | if (!pk) { | ||
83 | page_key_free(); | ||
84 | return -ENOMEM; | ||
85 | } | ||
86 | pk->next = page_key_data; | ||
87 | page_key_data = pk; | ||
88 | } | ||
89 | page_key_rp = page_key_wp = page_key_data; | ||
90 | page_key_rx = page_key_wx = 0; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Save the storage key into the upper 8 bits of the page frame number. | ||
96 | */ | ||
97 | void page_key_read(unsigned long *pfn) | ||
98 | { | ||
99 | unsigned long addr; | ||
100 | |||
101 | addr = (unsigned long) page_address(pfn_to_page(*pfn)); | ||
102 | *(unsigned char *) pfn = (unsigned char) page_get_storage_key(addr); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Extract the storage key from the upper 8 bits of the page frame number | ||
107 | * and store it in the page_key_data list of arrays. | ||
108 | */ | ||
109 | void page_key_memorize(unsigned long *pfn) | ||
110 | { | ||
111 | page_key_wp->data[page_key_wx] = *(unsigned char *) pfn; | ||
112 | *(unsigned char *) pfn = 0; | ||
113 | if (++page_key_wx < PAGE_KEY_DATA_SIZE) | ||
114 | return; | ||
115 | page_key_wp = page_key_wp->next; | ||
116 | page_key_wx = 0; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Get the next key from the page_key_data list of arrays and set the | ||
121 | * storage key of the page referred by @address. If @address refers to | ||
122 | * a "safe" page the swsusp_arch_resume code will transfer the storage | ||
123 | * key from the buffer page to the original page. | ||
124 | */ | ||
125 | void page_key_write(void *address) | ||
126 | { | ||
127 | page_set_storage_key((unsigned long) address, | ||
128 | page_key_rp->data[page_key_rx], 0); | ||
129 | if (++page_key_rx >= PAGE_KEY_DATA_SIZE) | ||
130 | return; | ||
131 | page_key_rp = page_key_rp->next; | ||
132 | page_key_rx = 0; | ||
133 | } | ||
134 | |||
17 | int pfn_is_nosave(unsigned long pfn) | 135 | int pfn_is_nosave(unsigned long pfn) |
18 | { | 136 | { |
19 | unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); | 137 | unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); |
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 51bcdb50a230..acb78cdee896 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S | |||
@@ -136,11 +136,14 @@ ENTRY(swsusp_arch_resume) | |||
136 | 0: | 136 | 0: |
137 | lg %r2,8(%r1) | 137 | lg %r2,8(%r1) |
138 | lg %r4,0(%r1) | 138 | lg %r4,0(%r1) |
139 | iske %r0,%r4 | ||
139 | lghi %r3,PAGE_SIZE | 140 | lghi %r3,PAGE_SIZE |
140 | lghi %r5,PAGE_SIZE | 141 | lghi %r5,PAGE_SIZE |
141 | 1: | 142 | 1: |
142 | mvcle %r2,%r4,0 | 143 | mvcle %r2,%r4,0 |
143 | jo 1b | 144 | jo 1b |
145 | lg %r2,8(%r1) | ||
146 | sske %r0,%r2 | ||
144 | lg %r1,16(%r1) | 147 | lg %r1,16(%r1) |
145 | ltgr %r1,%r1 | 148 | ltgr %r1,%r1 |
146 | jnz 0b | 149 | jnz 0b |