aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm')
-rw-r--r--arch/s390/mm/cmm.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index b201135cc18c..5e5f3849660f 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -18,6 +18,7 @@
18#include <linux/swap.h> 18#include <linux/swap.h>
19#include <linux/kthread.h> 19#include <linux/kthread.h>
20#include <linux/oom.h> 20#include <linux/oom.h>
21#include <linux/suspend.h>
21 22
22#include <asm/pgalloc.h> 23#include <asm/pgalloc.h>
23#include <asm/uaccess.h> 24#include <asm/uaccess.h>
@@ -44,6 +45,7 @@ static volatile long cmm_pages_target;
44static volatile long cmm_timed_pages_target; 45static volatile long cmm_timed_pages_target;
45static long cmm_timeout_pages; 46static long cmm_timeout_pages;
46static long cmm_timeout_seconds; 47static long cmm_timeout_seconds;
48static int cmm_suspended;
47 49
48static struct cmm_page_array *cmm_page_list; 50static struct cmm_page_array *cmm_page_list;
49static struct cmm_page_array *cmm_timed_page_list; 51static struct cmm_page_array *cmm_timed_page_list;
@@ -147,9 +149,9 @@ cmm_thread(void *dummy)
147 149
148 while (1) { 150 while (1) {
149 rc = wait_event_interruptible(cmm_thread_wait, 151 rc = wait_event_interruptible(cmm_thread_wait,
150 (cmm_pages != cmm_pages_target || 152 (!cmm_suspended && (cmm_pages != cmm_pages_target ||
151 cmm_timed_pages != cmm_timed_pages_target || 153 cmm_timed_pages != cmm_timed_pages_target)) ||
152 kthread_should_stop())); 154 kthread_should_stop());
153 if (kthread_should_stop() || rc == -ERESTARTSYS) { 155 if (kthread_should_stop() || rc == -ERESTARTSYS) {
154 cmm_pages_target = cmm_pages; 156 cmm_pages_target = cmm_pages;
155 cmm_timed_pages_target = cmm_timed_pages; 157 cmm_timed_pages_target = cmm_timed_pages;
@@ -411,6 +413,38 @@ cmm_smsg_target(char *from, char *msg)
411 413
412static struct ctl_table_header *cmm_sysctl_header; 414static struct ctl_table_header *cmm_sysctl_header;
413 415
416static int cmm_suspend(void)
417{
418 cmm_suspended = 1;
419 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
420 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
421 return 0;
422}
423
424static int cmm_resume(void)
425{
426 cmm_suspended = 0;
427 cmm_kick_thread();
428 return 0;
429}
430
431static int cmm_power_event(struct notifier_block *this,
432 unsigned long event, void *ptr)
433{
434 switch (event) {
435 case PM_POST_HIBERNATION:
436 return cmm_resume();
437 case PM_HIBERNATION_PREPARE:
438 return cmm_suspend();
439 default:
440 return NOTIFY_DONE;
441 }
442}
443
444static struct notifier_block cmm_power_notifier = {
445 .notifier_call = cmm_power_event,
446};
447
414static int 448static int
415cmm_init (void) 449cmm_init (void)
416{ 450{
@@ -419,7 +453,7 @@ cmm_init (void)
419#ifdef CONFIG_CMM_PROC 453#ifdef CONFIG_CMM_PROC
420 cmm_sysctl_header = register_sysctl_table(cmm_dir_table); 454 cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
421 if (!cmm_sysctl_header) 455 if (!cmm_sysctl_header)
422 goto out; 456 goto out_sysctl;
423#endif 457#endif
424#ifdef CONFIG_CMM_IUCV 458#ifdef CONFIG_CMM_IUCV
425 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); 459 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -429,17 +463,21 @@ cmm_init (void)
429 rc = register_oom_notifier(&cmm_oom_nb); 463 rc = register_oom_notifier(&cmm_oom_nb);
430 if (rc < 0) 464 if (rc < 0)
431 goto out_oom_notify; 465 goto out_oom_notify;
466 rc = register_pm_notifier(&cmm_power_notifier);
467 if (rc)
468 goto out_pm;
432 init_waitqueue_head(&cmm_thread_wait); 469 init_waitqueue_head(&cmm_thread_wait);
433 init_timer(&cmm_timer); 470 init_timer(&cmm_timer);
434 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); 471 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
435 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; 472 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
436 if (!rc) 473 if (rc)
437 goto out; 474 goto out_kthread;
438 /* 475 return 0;
439 * kthread_create failed. undo all the stuff from above again.
440 */
441 unregister_oom_notifier(&cmm_oom_nb);
442 476
477out_kthread:
478 unregister_pm_notifier(&cmm_power_notifier);
479out_pm:
480 unregister_oom_notifier(&cmm_oom_nb);
443out_oom_notify: 481out_oom_notify:
444#ifdef CONFIG_CMM_IUCV 482#ifdef CONFIG_CMM_IUCV
445 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 483 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -447,8 +485,8 @@ out_smsg:
447#endif 485#endif
448#ifdef CONFIG_CMM_PROC 486#ifdef CONFIG_CMM_PROC
449 unregister_sysctl_table(cmm_sysctl_header); 487 unregister_sysctl_table(cmm_sysctl_header);
488out_sysctl:
450#endif 489#endif
451out:
452 return rc; 490 return rc;
453} 491}
454 492
@@ -456,6 +494,7 @@ static void
456cmm_exit(void) 494cmm_exit(void)
457{ 495{
458 kthread_stop(cmm_thread_ptr); 496 kthread_stop(cmm_thread_ptr);
497 unregister_pm_notifier(&cmm_power_notifier);
459 unregister_oom_notifier(&cmm_oom_nb); 498 unregister_oom_notifier(&cmm_oom_nb);
460 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); 499 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
461 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); 500 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);