diff options
author | Ursula Braun <ursula.braun@de.ibm.com> | 2009-06-16 04:30:43 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-16 04:31:18 -0400 |
commit | 1175b257c8a2cb384823621cad0c1e0945f74300 (patch) | |
tree | 21574b661ec1ab06413cf62b58a6a57d1fd66715 | |
parent | 672e405b603af0bed99a4c173cdfce9bbf81c963 (diff) |
[S390] pm: netiucv power management callbacks.
Patch establishes a dummy netiucv device to make sure iucv is notified
about suspend/resume even if netiucv is the only loaded iucv-exploting
module without any real net_device defined.
The PM freeze callback closes all open netiucv connections. Thus the
corresponding iucv path is removed.
The PM thaw/restore callback re-opens previously closed netiucv
connections.
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | drivers/s390/net/netiucv.c | 115 |
1 files changed, 109 insertions, 6 deletions
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index aec9e5d3cf4b..fdb02d043d3e 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -1,11 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV network driver | 2 | * IUCV network driver |
3 | * | 3 | * |
4 | * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
6 | * | 5 | * |
7 | * Sysfs integration and all bugs therein by Cornelia Huck | 6 | * Author(s): |
8 | * (cornelia.huck@de.ibm.com) | 7 | * Original netiucv driver: |
8 | * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
9 | * Sysfs integration and all bugs therein: | ||
10 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
11 | * PM functions: | ||
12 | * Ursula Braun (ursula.braun@de.ibm.com) | ||
9 | * | 13 | * |
10 | * Documentation used: | 14 | * Documentation used: |
11 | * the source of the original IUCV driver by: | 15 | * the source of the original IUCV driver by: |
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | |||
149 | 153 | ||
150 | #define PRINTK_HEADER " iucv: " /* for debugging */ | 154 | #define PRINTK_HEADER " iucv: " /* for debugging */ |
151 | 155 | ||
156 | /* dummy device to make sure netiucv_pm functions are called */ | ||
157 | static struct device *netiucv_dev; | ||
158 | |||
159 | static int netiucv_pm_prepare(struct device *); | ||
160 | static void netiucv_pm_complete(struct device *); | ||
161 | static int netiucv_pm_freeze(struct device *); | ||
162 | static int netiucv_pm_restore_thaw(struct device *); | ||
163 | |||
164 | static struct dev_pm_ops netiucv_pm_ops = { | ||
165 | .prepare = netiucv_pm_prepare, | ||
166 | .complete = netiucv_pm_complete, | ||
167 | .freeze = netiucv_pm_freeze, | ||
168 | .thaw = netiucv_pm_restore_thaw, | ||
169 | .restore = netiucv_pm_restore_thaw, | ||
170 | }; | ||
171 | |||
152 | static struct device_driver netiucv_driver = { | 172 | static struct device_driver netiucv_driver = { |
153 | .owner = THIS_MODULE, | 173 | .owner = THIS_MODULE, |
154 | .name = "netiucv", | 174 | .name = "netiucv", |
155 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
176 | .pm = &netiucv_pm_ops, | ||
156 | }; | 177 | }; |
157 | 178 | ||
158 | static int netiucv_callback_connreq(struct iucv_path *, | 179 | static int netiucv_callback_connreq(struct iucv_path *, |
@@ -233,6 +254,7 @@ struct netiucv_priv { | |||
233 | fsm_instance *fsm; | 254 | fsm_instance *fsm; |
234 | struct iucv_connection *conn; | 255 | struct iucv_connection *conn; |
235 | struct device *dev; | 256 | struct device *dev; |
257 | int pm_state; | ||
236 | }; | 258 | }; |
237 | 259 | ||
238 | /** | 260 | /** |
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev) | |||
1265 | return 0; | 1287 | return 0; |
1266 | } | 1288 | } |
1267 | 1289 | ||
1290 | static int netiucv_pm_prepare(struct device *dev) | ||
1291 | { | ||
1292 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | static void netiucv_pm_complete(struct device *dev) | ||
1297 | { | ||
1298 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1299 | return; | ||
1300 | } | ||
1301 | |||
1302 | /** | ||
1303 | * netiucv_pm_freeze() - Freeze PM callback | ||
1304 | * @dev: netiucv device | ||
1305 | * | ||
1306 | * close open netiucv interfaces | ||
1307 | */ | ||
1308 | static int netiucv_pm_freeze(struct device *dev) | ||
1309 | { | ||
1310 | struct netiucv_priv *priv = dev->driver_data; | ||
1311 | struct net_device *ndev = NULL; | ||
1312 | int rc = 0; | ||
1313 | |||
1314 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1315 | if (priv && priv->conn) | ||
1316 | ndev = priv->conn->netdev; | ||
1317 | if (!ndev) | ||
1318 | goto out; | ||
1319 | netif_device_detach(ndev); | ||
1320 | priv->pm_state = fsm_getstate(priv->fsm); | ||
1321 | rc = netiucv_close(ndev); | ||
1322 | out: | ||
1323 | return rc; | ||
1324 | } | ||
1325 | |||
1326 | /** | ||
1327 | * netiucv_pm_restore_thaw() - Thaw and restore PM callback | ||
1328 | * @dev: netiucv device | ||
1329 | * | ||
1330 | * re-open netiucv interfaces closed during freeze | ||
1331 | */ | ||
1332 | static int netiucv_pm_restore_thaw(struct device *dev) | ||
1333 | { | ||
1334 | struct netiucv_priv *priv = dev->driver_data; | ||
1335 | struct net_device *ndev = NULL; | ||
1336 | int rc = 0; | ||
1337 | |||
1338 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1339 | if (priv && priv->conn) | ||
1340 | ndev = priv->conn->netdev; | ||
1341 | if (!ndev) | ||
1342 | goto out; | ||
1343 | switch (priv->pm_state) { | ||
1344 | case DEV_STATE_RUNNING: | ||
1345 | case DEV_STATE_STARTWAIT: | ||
1346 | rc = netiucv_open(ndev); | ||
1347 | break; | ||
1348 | default: | ||
1349 | break; | ||
1350 | } | ||
1351 | netif_device_attach(ndev); | ||
1352 | out: | ||
1353 | return rc; | ||
1354 | } | ||
1355 | |||
1268 | /** | 1356 | /** |
1269 | * Start transmission of a packet. | 1357 | * Start transmission of a packet. |
1270 | * Called from generic network device layer. | 1358 | * Called from generic network device layer. |
@@ -1731,7 +1819,6 @@ static int netiucv_register_device(struct net_device *ndev) | |||
1731 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 1819 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1732 | int ret; | 1820 | int ret; |
1733 | 1821 | ||
1734 | |||
1735 | IUCV_DBF_TEXT(trace, 3, __func__); | 1822 | IUCV_DBF_TEXT(trace, 3, __func__); |
1736 | 1823 | ||
1737 | if (dev) { | 1824 | if (dev) { |
@@ -2100,6 +2187,7 @@ static void __exit netiucv_exit(void) | |||
2100 | netiucv_unregister_device(dev); | 2187 | netiucv_unregister_device(dev); |
2101 | } | 2188 | } |
2102 | 2189 | ||
2190 | device_unregister(netiucv_dev); | ||
2103 | driver_unregister(&netiucv_driver); | 2191 | driver_unregister(&netiucv_driver); |
2104 | iucv_unregister(&netiucv_handler, 1); | 2192 | iucv_unregister(&netiucv_handler, 1); |
2105 | iucv_unregister_dbf_views(); | 2193 | iucv_unregister_dbf_views(); |
@@ -2125,10 +2213,25 @@ static int __init netiucv_init(void) | |||
2125 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); | 2213 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); |
2126 | goto out_iucv; | 2214 | goto out_iucv; |
2127 | } | 2215 | } |
2128 | 2216 | /* establish dummy device */ | |
2217 | netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
2218 | if (!netiucv_dev) { | ||
2219 | rc = -ENOMEM; | ||
2220 | goto out_driver; | ||
2221 | } | ||
2222 | dev_set_name(netiucv_dev, "netiucv"); | ||
2223 | netiucv_dev->bus = &iucv_bus; | ||
2224 | netiucv_dev->parent = iucv_root; | ||
2225 | netiucv_dev->release = (void (*)(struct device *))kfree; | ||
2226 | netiucv_dev->driver = &netiucv_driver; | ||
2227 | rc = device_register(netiucv_dev); | ||
2228 | if (rc) | ||
2229 | goto out_driver; | ||
2129 | netiucv_banner(); | 2230 | netiucv_banner(); |
2130 | return rc; | 2231 | return rc; |
2131 | 2232 | ||
2233 | out_driver: | ||
2234 | driver_unregister(&netiucv_driver); | ||
2132 | out_iucv: | 2235 | out_iucv: |
2133 | iucv_unregister(&netiucv_handler, 1); | 2236 | iucv_unregister(&netiucv_handler, 1); |
2134 | out_dbf: | 2237 | out_dbf: |