diff options
-rw-r--r-- | arch/s390/appldata/appldata_base.c | 119 |
1 files changed, 115 insertions, 4 deletions
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 1dfc7100c7ee..264528e4f58d 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Exports appldata_register_ops() and appldata_unregister_ops() for the | 5 | * Exports appldata_register_ops() and appldata_unregister_ops() for the |
6 | * data gathering modules. | 6 | * data gathering modules. |
7 | * | 7 | * |
8 | * Copyright IBM Corp. 2003, 2008 | 8 | * Copyright IBM Corp. 2003, 2009 |
9 | * | 9 | * |
10 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> | 10 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> |
11 | */ | 11 | */ |
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/notifier.h> | 26 | #include <linux/notifier.h> |
27 | #include <linux/cpu.h> | 27 | #include <linux/cpu.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/suspend.h> | ||
30 | #include <linux/platform_device.h> | ||
29 | #include <asm/appldata.h> | 31 | #include <asm/appldata.h> |
30 | #include <asm/timer.h> | 32 | #include <asm/timer.h> |
31 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
@@ -41,6 +43,9 @@ | |||
41 | 43 | ||
42 | #define TOD_MICRO 0x01000 /* nr. of TOD clock units | 44 | #define TOD_MICRO 0x01000 /* nr. of TOD clock units |
43 | for 1 microsecond */ | 45 | for 1 microsecond */ |
46 | |||
47 | static struct platform_device *appldata_pdev; | ||
48 | |||
44 | /* | 49 | /* |
45 | * /proc entries (sysctl) | 50 | * /proc entries (sysctl) |
46 | */ | 51 | */ |
@@ -86,6 +91,7 @@ static atomic_t appldata_expire_count = ATOMIC_INIT(0); | |||
86 | static DEFINE_SPINLOCK(appldata_timer_lock); | 91 | static DEFINE_SPINLOCK(appldata_timer_lock); |
87 | static int appldata_interval = APPLDATA_CPU_INTERVAL; | 92 | static int appldata_interval = APPLDATA_CPU_INTERVAL; |
88 | static int appldata_timer_active; | 93 | static int appldata_timer_active; |
94 | static int appldata_timer_suspended = 0; | ||
89 | 95 | ||
90 | /* | 96 | /* |
91 | * Work queue | 97 | * Work queue |
@@ -475,6 +481,93 @@ void appldata_unregister_ops(struct appldata_ops *ops) | |||
475 | /********************** module-ops management <END> **************************/ | 481 | /********************** module-ops management <END> **************************/ |
476 | 482 | ||
477 | 483 | ||
484 | /**************************** suspend / resume *******************************/ | ||
485 | static int appldata_freeze(struct device *dev) | ||
486 | { | ||
487 | struct appldata_ops *ops; | ||
488 | int rc; | ||
489 | struct list_head *lh; | ||
490 | |||
491 | get_online_cpus(); | ||
492 | spin_lock(&appldata_timer_lock); | ||
493 | if (appldata_timer_active) { | ||
494 | __appldata_vtimer_setup(APPLDATA_DEL_TIMER); | ||
495 | appldata_timer_suspended = 1; | ||
496 | } | ||
497 | spin_unlock(&appldata_timer_lock); | ||
498 | put_online_cpus(); | ||
499 | |||
500 | mutex_lock(&appldata_ops_mutex); | ||
501 | list_for_each(lh, &appldata_ops_list) { | ||
502 | ops = list_entry(lh, struct appldata_ops, list); | ||
503 | if (ops->active == 1) { | ||
504 | rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, | ||
505 | (unsigned long) ops->data, ops->size, | ||
506 | ops->mod_lvl); | ||
507 | if (rc != 0) | ||
508 | pr_err("Stopping the data collection for %s " | ||
509 | "failed with rc=%d\n", ops->name, rc); | ||
510 | } | ||
511 | } | ||
512 | mutex_unlock(&appldata_ops_mutex); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int appldata_restore(struct device *dev) | ||
517 | { | ||
518 | struct appldata_ops *ops; | ||
519 | int rc; | ||
520 | struct list_head *lh; | ||
521 | |||
522 | get_online_cpus(); | ||
523 | spin_lock(&appldata_timer_lock); | ||
524 | if (appldata_timer_suspended) { | ||
525 | __appldata_vtimer_setup(APPLDATA_ADD_TIMER); | ||
526 | appldata_timer_suspended = 0; | ||
527 | } | ||
528 | spin_unlock(&appldata_timer_lock); | ||
529 | put_online_cpus(); | ||
530 | |||
531 | mutex_lock(&appldata_ops_mutex); | ||
532 | list_for_each(lh, &appldata_ops_list) { | ||
533 | ops = list_entry(lh, struct appldata_ops, list); | ||
534 | if (ops->active == 1) { | ||
535 | ops->callback(ops->data); // init record | ||
536 | rc = appldata_diag(ops->record_nr, | ||
537 | APPLDATA_START_INTERVAL_REC, | ||
538 | (unsigned long) ops->data, ops->size, | ||
539 | ops->mod_lvl); | ||
540 | if (rc != 0) { | ||
541 | pr_err("Starting the data collection for %s " | ||
542 | "failed with rc=%d\n", ops->name, rc); | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | mutex_unlock(&appldata_ops_mutex); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int appldata_thaw(struct device *dev) | ||
551 | { | ||
552 | return appldata_restore(dev); | ||
553 | } | ||
554 | |||
555 | static struct dev_pm_ops appldata_pm_ops = { | ||
556 | .freeze = appldata_freeze, | ||
557 | .thaw = appldata_thaw, | ||
558 | .restore = appldata_restore, | ||
559 | }; | ||
560 | |||
561 | static struct platform_driver appldata_pdrv = { | ||
562 | .driver = { | ||
563 | .name = "appldata", | ||
564 | .owner = THIS_MODULE, | ||
565 | .pm = &appldata_pm_ops, | ||
566 | }, | ||
567 | }; | ||
568 | /************************* suspend / resume <END> ****************************/ | ||
569 | |||
570 | |||
478 | /******************************* init / exit *********************************/ | 571 | /******************************* init / exit *********************************/ |
479 | 572 | ||
480 | static void __cpuinit appldata_online_cpu(int cpu) | 573 | static void __cpuinit appldata_online_cpu(int cpu) |
@@ -531,11 +624,23 @@ static struct notifier_block __cpuinitdata appldata_nb = { | |||
531 | */ | 624 | */ |
532 | static int __init appldata_init(void) | 625 | static int __init appldata_init(void) |
533 | { | 626 | { |
534 | int i; | 627 | int i, rc; |
628 | |||
629 | rc = platform_driver_register(&appldata_pdrv); | ||
630 | if (rc) | ||
631 | return rc; | ||
535 | 632 | ||
633 | appldata_pdev = platform_device_register_simple("appldata", -1, NULL, | ||
634 | 0); | ||
635 | if (IS_ERR(appldata_pdev)) { | ||
636 | rc = PTR_ERR(appldata_pdev); | ||
637 | goto out_driver; | ||
638 | } | ||
536 | appldata_wq = create_singlethread_workqueue("appldata"); | 639 | appldata_wq = create_singlethread_workqueue("appldata"); |
537 | if (!appldata_wq) | 640 | if (!appldata_wq) { |
538 | return -ENOMEM; | 641 | rc = -ENOMEM; |
642 | goto out_device; | ||
643 | } | ||
539 | 644 | ||
540 | get_online_cpus(); | 645 | get_online_cpus(); |
541 | for_each_online_cpu(i) | 646 | for_each_online_cpu(i) |
@@ -547,6 +652,12 @@ static int __init appldata_init(void) | |||
547 | 652 | ||
548 | appldata_sysctl_header = register_sysctl_table(appldata_dir_table); | 653 | appldata_sysctl_header = register_sysctl_table(appldata_dir_table); |
549 | return 0; | 654 | return 0; |
655 | |||
656 | out_device: | ||
657 | platform_device_unregister(appldata_pdev); | ||
658 | out_driver: | ||
659 | platform_driver_unregister(&appldata_pdrv); | ||
660 | return rc; | ||
550 | } | 661 | } |
551 | 662 | ||
552 | __initcall(appldata_init); | 663 | __initcall(appldata_init); |