diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-16 04:30:46 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-16 04:31:20 -0400 |
commit | 6a1d96dced593bc17d7a17fdb93c99b275e71eba (patch) | |
tree | 69ac1bb8a52d8b537281118b24617076ff08ac3f /drivers/s390/net | |
parent | 0259162ecd083f1ce0f6022e669f393330b06f4d (diff) |
[S390] pm: smsgiucv power management callbacks.
Create dummy iucv-device to get control when the system is suspended
and resumed. Server the smsg iucv path on suspend, reestablish the
path on resume.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/smsgiucv.c | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090c262..e76a320d373 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV special message driver | 2 | * IUCV special message driver |
3 | * | 3 | * |
4 | * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2003, 2009 |
5 | * | ||
5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -40,6 +41,8 @@ MODULE_AUTHOR | |||
40 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); | 41 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); |
41 | 42 | ||
42 | static struct iucv_path *smsg_path; | 43 | static struct iucv_path *smsg_path; |
44 | /* dummy device used as trigger for PM functions */ | ||
45 | static struct device *smsg_dev; | ||
43 | 46 | ||
44 | static DEFINE_SPINLOCK(smsg_list_lock); | 47 | static DEFINE_SPINLOCK(smsg_list_lock); |
45 | static LIST_HEAD(smsg_list); | 48 | static LIST_HEAD(smsg_list); |
@@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix, | |||
132 | kfree(cb); | 135 | kfree(cb); |
133 | } | 136 | } |
134 | 137 | ||
138 | static int smsg_pm_freeze(struct device *dev) | ||
139 | { | ||
140 | #ifdef CONFIG_PM_DEBUG | ||
141 | printk(KERN_WARNING "smsg_pm_freeze\n"); | ||
142 | #endif | ||
143 | if (smsg_path) | ||
144 | iucv_path_sever(smsg_path, NULL); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int smsg_pm_restore_thaw(struct device *dev) | ||
149 | { | ||
150 | int rc; | ||
151 | |||
152 | #ifdef CONFIG_PM_DEBUG | ||
153 | printk(KERN_WARNING "smsg_pm_restore_thaw\n"); | ||
154 | #endif | ||
155 | if (smsg_path) { | ||
156 | memset(smsg_path, 0, sizeof(*smsg_path)); | ||
157 | smsg_path->msglim = 255; | ||
158 | smsg_path->flags = 0; | ||
159 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | ||
160 | NULL, NULL, NULL); | ||
161 | printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc); | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static struct dev_pm_ops smsg_pm_ops = { | ||
167 | .freeze = smsg_pm_freeze, | ||
168 | .thaw = smsg_pm_restore_thaw, | ||
169 | .restore = smsg_pm_restore_thaw, | ||
170 | }; | ||
171 | |||
135 | static struct device_driver smsg_driver = { | 172 | static struct device_driver smsg_driver = { |
173 | .owner = THIS_MODULE, | ||
136 | .name = "SMSGIUCV", | 174 | .name = "SMSGIUCV", |
137 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
176 | .pm = &smsg_pm_ops, | ||
138 | }; | 177 | }; |
139 | 178 | ||
140 | static void __exit smsg_exit(void) | 179 | static void __exit smsg_exit(void) |
141 | { | 180 | { |
142 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 181 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
182 | device_unregister(smsg_dev); | ||
143 | iucv_unregister(&smsg_handler, 1); | 183 | iucv_unregister(&smsg_handler, 1); |
144 | driver_unregister(&smsg_driver); | 184 | driver_unregister(&smsg_driver); |
145 | } | 185 | } |
@@ -166,12 +206,29 @@ static int __init smsg_init(void) | |||
166 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | 206 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", |
167 | NULL, NULL, NULL); | 207 | NULL, NULL, NULL); |
168 | if (rc) | 208 | if (rc) |
169 | goto out_free; | 209 | goto out_free_path; |
210 | smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
211 | if (!smsg_dev) { | ||
212 | rc = -ENOMEM; | ||
213 | goto out_free_path; | ||
214 | } | ||
215 | dev_set_name(smsg_dev, "smsg_iucv"); | ||
216 | smsg_dev->bus = &iucv_bus; | ||
217 | smsg_dev->parent = iucv_root; | ||
218 | smsg_dev->release = (void (*)(struct device *))kfree; | ||
219 | smsg_dev->driver = &smsg_driver; | ||
220 | rc = device_register(smsg_dev); | ||
221 | if (rc) | ||
222 | goto out_free_dev; | ||
223 | |||
170 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 224 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
171 | return 0; | 225 | return 0; |
172 | 226 | ||
173 | out_free: | 227 | out_free_dev: |
228 | kfree(smsg_dev); | ||
229 | out_free_path: | ||
174 | iucv_path_free(smsg_path); | 230 | iucv_path_free(smsg_path); |
231 | smsg_path = NULL; | ||
175 | out_register: | 232 | out_register: |
176 | iucv_unregister(&smsg_handler, 1); | 233 | iucv_unregister(&smsg_handler, 1); |
177 | out_driver: | 234 | out_driver: |