diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2009-06-16 04:30:22 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-16 04:31:09 -0400 |
commit | dcbd16d5111258df7c821ec1e4124fe6ffbf3c16 (patch) | |
tree | ee095cc2a4fc2a81bde256f8125b0199fe02a9ff /drivers/s390/cio/css.c | |
parent | 7e597a21a1470b12428cb0edd03c40986026451f (diff) |
[S390] pm: css bus power management callbacks
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 157 |
1 files changed, 152 insertions, 5 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0085d8901792..85d43c6bcb66 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/css.c | 2 | * driver for channel subsystem |
3 | * driver for channel subsystem | ||
4 | * | 3 | * |
5 | * Copyright IBM Corp. 2002,2008 | 4 | * Copyright IBM Corp. 2002, 2009 |
6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) | 5 | * |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #define KMSG_COMPONENT "cio" | 10 | #define KMSG_COMPONENT "cio" |
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <linux/reboot.h> | 19 | #include <linux/reboot.h> |
20 | #include <linux/suspend.h> | ||
20 | #include <asm/isc.h> | 21 | #include <asm/isc.h> |
21 | #include <asm/crw.h> | 22 | #include <asm/crw.h> |
22 | 23 | ||
@@ -780,6 +781,79 @@ static struct notifier_block css_reboot_notifier = { | |||
780 | }; | 781 | }; |
781 | 782 | ||
782 | /* | 783 | /* |
784 | * Since the css devices are neither on a bus nor have a class | ||
785 | * nor have a special device type, we cannot stop/restart channel | ||
786 | * path measurements via the normal suspend/resume callbacks, but have | ||
787 | * to use notifiers. | ||
788 | */ | ||
789 | static int css_power_event(struct notifier_block *this, unsigned long event, | ||
790 | void *ptr) | ||
791 | { | ||
792 | void *secm_area; | ||
793 | int ret, i; | ||
794 | |||
795 | switch (event) { | ||
796 | case PM_HIBERNATION_PREPARE: | ||
797 | case PM_SUSPEND_PREPARE: | ||
798 | ret = NOTIFY_DONE; | ||
799 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
800 | struct channel_subsystem *css; | ||
801 | |||
802 | css = channel_subsystems[i]; | ||
803 | mutex_lock(&css->mutex); | ||
804 | if (!css->cm_enabled) { | ||
805 | mutex_unlock(&css->mutex); | ||
806 | continue; | ||
807 | } | ||
808 | secm_area = (void *)get_zeroed_page(GFP_KERNEL | | ||
809 | GFP_DMA); | ||
810 | if (secm_area) { | ||
811 | if (__chsc_do_secm(css, 0, secm_area)) | ||
812 | ret = NOTIFY_BAD; | ||
813 | free_page((unsigned long)secm_area); | ||
814 | } else | ||
815 | ret = NOTIFY_BAD; | ||
816 | |||
817 | mutex_unlock(&css->mutex); | ||
818 | } | ||
819 | break; | ||
820 | case PM_POST_HIBERNATION: | ||
821 | case PM_POST_SUSPEND: | ||
822 | ret = NOTIFY_DONE; | ||
823 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
824 | struct channel_subsystem *css; | ||
825 | |||
826 | css = channel_subsystems[i]; | ||
827 | mutex_lock(&css->mutex); | ||
828 | if (!css->cm_enabled) { | ||
829 | mutex_unlock(&css->mutex); | ||
830 | continue; | ||
831 | } | ||
832 | secm_area = (void *)get_zeroed_page(GFP_KERNEL | | ||
833 | GFP_DMA); | ||
834 | if (secm_area) { | ||
835 | if (__chsc_do_secm(css, 1, secm_area)) | ||
836 | ret = NOTIFY_BAD; | ||
837 | free_page((unsigned long)secm_area); | ||
838 | } else | ||
839 | ret = NOTIFY_BAD; | ||
840 | |||
841 | mutex_unlock(&css->mutex); | ||
842 | } | ||
843 | /* search for subchannels, which appeared during hibernation */ | ||
844 | css_schedule_reprobe(); | ||
845 | break; | ||
846 | default: | ||
847 | ret = NOTIFY_DONE; | ||
848 | } | ||
849 | return ret; | ||
850 | |||
851 | } | ||
852 | static struct notifier_block css_power_notifier = { | ||
853 | .notifier_call = css_power_event, | ||
854 | }; | ||
855 | |||
856 | /* | ||
783 | * Now that the driver core is running, we can setup our channel subsystem. | 857 | * Now that the driver core is running, we can setup our channel subsystem. |
784 | * The struct subchannel's are created during probing (except for the | 858 | * The struct subchannel's are created during probing (except for the |
785 | * static console subchannel). | 859 | * static console subchannel). |
@@ -852,6 +926,11 @@ init_channel_subsystem (void) | |||
852 | ret = register_reboot_notifier(&css_reboot_notifier); | 926 | ret = register_reboot_notifier(&css_reboot_notifier); |
853 | if (ret) | 927 | if (ret) |
854 | goto out_unregister; | 928 | goto out_unregister; |
929 | ret = register_pm_notifier(&css_power_notifier); | ||
930 | if (ret) { | ||
931 | unregister_reboot_notifier(&css_reboot_notifier); | ||
932 | goto out_unregister; | ||
933 | } | ||
855 | css_init_done = 1; | 934 | css_init_done = 1; |
856 | 935 | ||
857 | /* Enable default isc for I/O subchannels. */ | 936 | /* Enable default isc for I/O subchannels. */ |
@@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
953 | return ret; | 1032 | return ret; |
954 | } | 1033 | } |
955 | 1034 | ||
1035 | static int css_pm_prepare(struct device *dev) | ||
1036 | { | ||
1037 | struct subchannel *sch = to_subchannel(dev); | ||
1038 | struct css_driver *drv; | ||
1039 | |||
1040 | if (mutex_is_locked(&sch->reg_mutex)) | ||
1041 | return -EAGAIN; | ||
1042 | if (!sch->dev.driver) | ||
1043 | return 0; | ||
1044 | drv = to_cssdriver(sch->dev.driver); | ||
1045 | /* Notify drivers that they may not register children. */ | ||
1046 | return drv->prepare ? drv->prepare(sch) : 0; | ||
1047 | } | ||
1048 | |||
1049 | static void css_pm_complete(struct device *dev) | ||
1050 | { | ||
1051 | struct subchannel *sch = to_subchannel(dev); | ||
1052 | struct css_driver *drv; | ||
1053 | |||
1054 | if (!sch->dev.driver) | ||
1055 | return; | ||
1056 | drv = to_cssdriver(sch->dev.driver); | ||
1057 | if (drv->complete) | ||
1058 | drv->complete(sch); | ||
1059 | } | ||
1060 | |||
1061 | static int css_pm_freeze(struct device *dev) | ||
1062 | { | ||
1063 | struct subchannel *sch = to_subchannel(dev); | ||
1064 | struct css_driver *drv; | ||
1065 | |||
1066 | if (!sch->dev.driver) | ||
1067 | return 0; | ||
1068 | drv = to_cssdriver(sch->dev.driver); | ||
1069 | return drv->freeze ? drv->freeze(sch) : 0; | ||
1070 | } | ||
1071 | |||
1072 | static int css_pm_thaw(struct device *dev) | ||
1073 | { | ||
1074 | struct subchannel *sch = to_subchannel(dev); | ||
1075 | struct css_driver *drv; | ||
1076 | |||
1077 | if (!sch->dev.driver) | ||
1078 | return 0; | ||
1079 | drv = to_cssdriver(sch->dev.driver); | ||
1080 | return drv->thaw ? drv->thaw(sch) : 0; | ||
1081 | } | ||
1082 | |||
1083 | static int css_pm_restore(struct device *dev) | ||
1084 | { | ||
1085 | struct subchannel *sch = to_subchannel(dev); | ||
1086 | struct css_driver *drv; | ||
1087 | |||
1088 | if (!sch->dev.driver) | ||
1089 | return 0; | ||
1090 | drv = to_cssdriver(sch->dev.driver); | ||
1091 | return drv->restore ? drv->restore(sch) : 0; | ||
1092 | } | ||
1093 | |||
1094 | static struct dev_pm_ops css_pm_ops = { | ||
1095 | .prepare = css_pm_prepare, | ||
1096 | .complete = css_pm_complete, | ||
1097 | .freeze = css_pm_freeze, | ||
1098 | .thaw = css_pm_thaw, | ||
1099 | .restore = css_pm_restore, | ||
1100 | }; | ||
1101 | |||
956 | struct bus_type css_bus_type = { | 1102 | struct bus_type css_bus_type = { |
957 | .name = "css", | 1103 | .name = "css", |
958 | .match = css_bus_match, | 1104 | .match = css_bus_match, |
@@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { | |||
960 | .remove = css_remove, | 1106 | .remove = css_remove, |
961 | .shutdown = css_shutdown, | 1107 | .shutdown = css_shutdown, |
962 | .uevent = css_uevent, | 1108 | .uevent = css_uevent, |
1109 | .pm = &css_pm_ops, | ||
963 | }; | 1110 | }; |
964 | 1111 | ||
965 | /** | 1112 | /** |