diff options
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/cmm.c | 61 |
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; | |||
44 | static volatile long cmm_timed_pages_target; | 45 | static volatile long cmm_timed_pages_target; |
45 | static long cmm_timeout_pages; | 46 | static long cmm_timeout_pages; |
46 | static long cmm_timeout_seconds; | 47 | static long cmm_timeout_seconds; |
48 | static int cmm_suspended; | ||
47 | 49 | ||
48 | static struct cmm_page_array *cmm_page_list; | 50 | static struct cmm_page_array *cmm_page_list; |
49 | static struct cmm_page_array *cmm_timed_page_list; | 51 | static 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 | ||
412 | static struct ctl_table_header *cmm_sysctl_header; | 414 | static struct ctl_table_header *cmm_sysctl_header; |
413 | 415 | ||
416 | static 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 | |||
424 | static int cmm_resume(void) | ||
425 | { | ||
426 | cmm_suspended = 0; | ||
427 | cmm_kick_thread(); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static 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 | |||
444 | static struct notifier_block cmm_power_notifier = { | ||
445 | .notifier_call = cmm_power_event, | ||
446 | }; | ||
447 | |||
414 | static int | 448 | static int |
415 | cmm_init (void) | 449 | cmm_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 | ||
477 | out_kthread: | ||
478 | unregister_pm_notifier(&cmm_power_notifier); | ||
479 | out_pm: | ||
480 | unregister_oom_notifier(&cmm_oom_nb); | ||
443 | out_oom_notify: | 481 | out_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); |
488 | out_sysctl: | ||
450 | #endif | 489 | #endif |
451 | out: | ||
452 | return rc; | 490 | return rc; |
453 | } | 491 | } |
454 | 492 | ||
@@ -456,6 +494,7 @@ static void | |||
456 | cmm_exit(void) | 494 | cmm_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); |