aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2013-04-08 10:09:31 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-04-17 08:07:30 -0400
commit91c15a951091a64a5f048ff93292057e3b590b6f (patch)
tree33e7f36ede3deaa958d14736d83b401b0bc03123
parent5294ee00a16567355c85b849742e5219aad880d0 (diff)
s390/hibernate: Save and restore absolute zero pages
Since commit 5f954c34 ([S390] hibernation: fix lowcore handling) the absolute zero lowcore is lost during suspend/resume. For example, this leads to the problem that the re-IPL device for kdump is no longer set after resume. With this patch during suspend a buffer is allocated in the new PM notifier "suspend_pm_cb" and then the absolute zero lowcore is saved to that buffer. The resume code then copies back this buffer to absolute zero and afterwards the PM notifier releases the memory. Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/kernel/entry.h1
-rw-r--r--arch/s390/kernel/suspend.c31
-rw-r--r--arch/s390/kernel/swsusp_asm64.S29
3 files changed, 58 insertions, 3 deletions
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index c3a736a3ed44..aa0ab02e9595 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -7,6 +7,7 @@
7#include <asm/cputime.h> 7#include <asm/cputime.h>
8 8
9extern void *restart_stack; 9extern void *restart_stack;
10extern unsigned long suspend_zero_pages;
10 11
11void system_call(void); 12void system_call(void);
12void pgm_check_handler(void); 13void pgm_check_handler(void);
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index aa1494d0e380..c479d2f9605b 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -41,6 +41,7 @@ struct page_key_data {
41static struct page_key_data *page_key_data; 41static struct page_key_data *page_key_data;
42static struct page_key_data *page_key_rp, *page_key_wp; 42static struct page_key_data *page_key_rp, *page_key_wp;
43static unsigned long page_key_rx, page_key_wx; 43static unsigned long page_key_rx, page_key_wx;
44unsigned long suspend_zero_pages;
44 45
45/* 46/*
46 * For each page in the hibernation image one additional byte is 47 * For each page in the hibernation image one additional byte is
@@ -149,6 +150,36 @@ int pfn_is_nosave(unsigned long pfn)
149 return 0; 150 return 0;
150} 151}
151 152
153/*
154 * PM notifier callback for suspend
155 */
156static int suspend_pm_cb(struct notifier_block *nb, unsigned long action,
157 void *ptr)
158{
159 switch (action) {
160 case PM_SUSPEND_PREPARE:
161 case PM_HIBERNATION_PREPARE:
162 suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER);
163 if (!suspend_zero_pages)
164 return NOTIFY_BAD;
165 break;
166 case PM_POST_SUSPEND:
167 case PM_POST_HIBERNATION:
168 free_pages(suspend_zero_pages, LC_ORDER);
169 break;
170 default:
171 return NOTIFY_DONE;
172 }
173 return NOTIFY_OK;
174}
175
176static int __init suspend_pm_init(void)
177{
178 pm_notifier(suspend_pm_cb, 0);
179 return 0;
180}
181arch_initcall(suspend_pm_init);
182
152void save_processor_state(void) 183void save_processor_state(void)
153{ 184{
154 /* swsusp_arch_suspend() actually saves all cpu register contents. 185 /* swsusp_arch_suspend() actually saves all cpu register contents.
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index d4ca4e0617b5..c487be4cfc81 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -36,8 +36,8 @@ ENTRY(swsusp_arch_suspend)
36 /* Store prefix register on stack */ 36 /* Store prefix register on stack */
37 stpx __SF_EMPTY(%r15) 37 stpx __SF_EMPTY(%r15)
38 38
39 /* Save prefix register contents for lowcore */ 39 /* Save prefix register contents for lowcore copy */
40 llgf %r4,__SF_EMPTY(%r15) 40 llgf %r10,__SF_EMPTY(%r15)
41 41
42 /* Get pointer to save area */ 42 /* Get pointer to save area */
43 lghi %r1,0x1000 43 lghi %r1,0x1000
@@ -91,7 +91,18 @@ ENTRY(swsusp_arch_suspend)
91 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 91 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
92 spx __SF_EMPTY(%r15) 92 spx __SF_EMPTY(%r15)
93 93
94 /* Save absolute zero pages */
95 larl %r2,suspend_zero_pages
96 lg %r2,0(%r2)
97 lghi %r4,0
98 lghi %r3,2*PAGE_SIZE
99 lghi %r5,2*PAGE_SIZE
1001: mvcle %r2,%r4,0
101 jo 1b
102
103 /* Copy lowcore to absolute zero lowcore */
94 lghi %r2,0 104 lghi %r2,0
105 lgr %r4,%r10
95 lghi %r3,2*PAGE_SIZE 106 lghi %r3,2*PAGE_SIZE
96 lghi %r5,2*PAGE_SIZE 107 lghi %r5,2*PAGE_SIZE
971: mvcle %r2,%r4,0 1081: mvcle %r2,%r4,0
@@ -248,8 +259,20 @@ restore_registers:
248 /* Load old stack */ 259 /* Load old stack */
249 lg %r15,0x2f8(%r13) 260 lg %r15,0x2f8(%r13)
250 261
262 /* Save prefix register */
263 mvc __SF_EMPTY(4,%r15),0x318(%r13)
264
265 /* Restore absolute zero pages */
266 lghi %r2,0
267 larl %r4,suspend_zero_pages
268 lg %r4,0(%r4)
269 lghi %r3,2*PAGE_SIZE
270 lghi %r5,2*PAGE_SIZE
2711: mvcle %r2,%r4,0
272 jo 1b
273
251 /* Restore prefix register */ 274 /* Restore prefix register */
252 spx 0x318(%r13) 275 spx __SF_EMPTY(%r15)
253 276
254 /* Activate DAT */ 277 /* Activate DAT */
255 stosm __SF_EMPTY(%r15),0x04 278 stosm __SF_EMPTY(%r15),0x04