Skip to content

Commit

Permalink
s390/hibernate: Save and restore absolute zero pages
Browse files Browse the repository at this point in the history
Since commit 5f954c3 ([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>
  • Loading branch information
Michael Holzheu authored and Martin Schwidefsky committed Apr 17, 2013
1 parent 5294ee0 commit 91c15a9
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
1 change: 1 addition & 0 deletions arch/s390/kernel/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <asm/cputime.h>

extern void *restart_stack;
extern unsigned long suspend_zero_pages;

void system_call(void);
void pgm_check_handler(void);
Expand Down
31 changes: 31 additions & 0 deletions arch/s390/kernel/suspend.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
29 changes: 26 additions & 3 deletions arch/s390/kernel/swsusp_asm64.S
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ ENTRY(swsusp_arch_suspend)
/* Store prefix register on stack */
stpx __SF_EMPTY(%r15)

/* Save prefix register contents for lowcore */
llgf %r4,__SF_EMPTY(%r15)
/* Save prefix register contents for lowcore copy */
llgf %r10,__SF_EMPTY(%r15)

/* Get pointer to save area */
lghi %r1,0x1000
Expand Down Expand Up @@ -91,7 +91,18 @@ ENTRY(swsusp_arch_suspend)
xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
spx __SF_EMPTY(%r15)

/* Save absolute zero pages */
larl %r2,suspend_zero_pages
lg %r2,0(%r2)
lghi %r4,0
lghi %r3,2*PAGE_SIZE
lghi %r5,2*PAGE_SIZE
1: mvcle %r2,%r4,0
jo 1b

/* Copy lowcore to absolute zero lowcore */
lghi %r2,0
lgr %r4,%r10
lghi %r3,2*PAGE_SIZE
lghi %r5,2*PAGE_SIZE
1: mvcle %r2,%r4,0
Expand Down Expand Up @@ -248,8 +259,20 @@ restore_registers:
/* Load old stack */
lg %r15,0x2f8(%r13)

/* Save prefix register */
mvc __SF_EMPTY(4,%r15),0x318(%r13)

/* Restore absolute zero pages */
lghi %r2,0
larl %r4,suspend_zero_pages
lg %r4,0(%r4)
lghi %r3,2*PAGE_SIZE
lghi %r5,2*PAGE_SIZE
1: mvcle %r2,%r4,0
jo 1b

/* Restore prefix register */
spx 0x318(%r13)
spx __SF_EMPTY(%r15)

/* Activate DAT */
stosm __SF_EMPTY(%r15),0x04
Expand Down

0 comments on commit 91c15a9

Please sign in to comment.