aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/cmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/cmm.c')
-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 ff58779bf7e9..76a3637b88e0 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;
@@ -410,6 +412,38 @@ cmm_smsg_target(char *from, char *msg)
410 412
411static struct ctl_table_header *cmm_sysctl_header; 413static struct ctl_table_header *cmm_sysctl_header;
412 414
415static int cmm_suspend(void)
416{
417 cmm_suspended = 1;
418 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
419 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
420 return 0;
421}
422
423static int cmm_resume(void)
424{
425 cmm_suspended = 0;
426 cmm_kick_thread();
427 return 0;
428}
429
430static int cmm_power_event(struct notifier_block *this,
431 unsigned long event, void *ptr)
432{
433 switch (event) {
434 case PM_POST_HIBERNATION:
435 return cmm_resume();
436 case PM_HIBERNATION_PREPARE:
437 return cmm_suspend();
438 default:
439 return NOTIFY_DONE;
440 }
441}
442
443static struct notifier_block cmm_power_notifier = {
444 .notifier_call = cmm_power_event,
445};
446
413static int 447static int
414cmm_init (void) 448cmm_init (void)
415{ 449{
@@ -418,7 +452,7 @@ cmm_init (void)
418#ifdef CONFIG_CMM_PROC 452#ifdef CONFIG_CMM_PROC
419 cmm_sysctl_header = register_sysctl_table(cmm_dir_table); 453 cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
420 if (!cmm_sysctl_header) 454 if (!cmm_sysctl_header)
421 goto out; 455 goto out_sysctl;
422#endif 456#endif
423#ifdef CONFIG_CMM_IUCV 457#ifdef CONFIG_CMM_IUCV
424 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); 458 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -428,17 +462,21 @@ cmm_init (void)
428 rc = register_oom_notifier(&cmm_oom_nb); 462 rc = register_oom_notifier(&cmm_oom_nb);
429 if (rc < 0) 463 if (rc < 0)
430 goto out_oom_notify; 464 goto out_oom_notify;
465 rc = register_pm_notifier(&cmm_power_notifier);
466 if (rc)
467 goto out_pm;
431 init_waitqueue_head(&cmm_thread_wait); 468 init_waitqueue_head(&cmm_thread_wait);
432 init_timer(&cmm_timer); 469 init_timer(&cmm_timer);
433 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); 470 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
434 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; 471 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
435 if (!rc) 472 if (rc)
436 goto out; 473 goto out_kthread;
437 /* 474 return 0;
438 * kthread_create failed. undo all the stuff from above again.
439 */
440 unregister_oom_notifier(&cmm_oom_nb);
441 475
476out_kthread:
477 unregister_pm_notifier(&cmm_power_notifier);
478out_pm:
479 unregister_oom_notifier(&cmm_oom_nb);
442out_oom_notify: 480out_oom_notify:
443#ifdef CONFIG_CMM_IUCV 481#ifdef CONFIG_CMM_IUCV
444 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 482 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -446,8 +484,8 @@ out_smsg:
446#endif 484#endif
447#ifdef CONFIG_CMM_PROC 485#ifdef CONFIG_CMM_PROC
448 unregister_sysctl_table(cmm_sysctl_header); 486 unregister_sysctl_table(cmm_sysctl_header);
487out_sysctl:
449#endif 488#endif
450out:
451 return rc; 489 return rc;
452} 490}
453 491
@@ -455,6 +493,7 @@ static void
455cmm_exit(void) 493cmm_exit(void)
456{ 494{
457 kthread_stop(cmm_thread_ptr); 495 kthread_stop(cmm_thread_ptr);
496 unregister_pm_notifier(&cmm_power_notifier);
458 unregister_oom_notifier(&cmm_oom_nb); 497 unregister_oom_notifier(&cmm_oom_nb);
459 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); 498 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
460 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); 499 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);