summaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/suspend.c
diff options
context:
space:
mode:
authorMichael Holzheu2013-04-08 16:09:31 +0200
committerMartin Schwidefsky2013-04-17 14:07:30 +0200
commit91c15a951091a64a5f048ff93292057e3b590b6f (patch)
tree33e7f36ede3deaa958d14736d83b401b0bc03123 /arch/s390/kernel/suspend.c
parents390/bitops: get rid of __BITOPS_BARRIER() (diff)
downloadkernel-qcow2-linux-91c15a951091a64a5f048ff93292057e3b590b6f.tar.gz
kernel-qcow2-linux-91c15a951091a64a5f048ff93292057e3b590b6f.tar.xz
kernel-qcow2-linux-91c15a951091a64a5f048ff93292057e3b590b6f.zip
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>
Diffstat (limited to 'arch/s390/kernel/suspend.c')
-rw-r--r--arch/s390/kernel/suspend.c31
1 files changed, 31 insertions, 0 deletions
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 {
static struct page_key_data *page_key_data;
static struct page_key_data *page_key_rp, *page_key_wp;
static unsigned long page_key_rx, page_key_wx;
+unsigned long suspend_zero_pages;
/*
* For each page in the hibernation image one additional byte is
@@ -149,6 +150,36 @@ int pfn_is_nosave(unsigned long pfn)
return 0;
}
+/*
+ * PM notifier callback for suspend
+ */
+static int suspend_pm_cb(struct notifier_block *nb, unsigned long action,
+ void *ptr)
+{
+ switch (action) {
+ case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER);
+ if (!suspend_zero_pages)
+ return NOTIFY_BAD;
+ break;
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ free_pages(suspend_zero_pages, LC_ORDER);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
+static int __init suspend_pm_init(void)
+{
+ pm_notifier(suspend_pm_cb, 0);
+ return 0;
+}
+arch_initcall(suspend_pm_init);
+
void save_processor_state(void)
{
/* swsusp_arch_suspend() actually saves all cpu register contents.