diff options
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/claw.c | 20 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_main.c | 43 | ||||
-rw-r--r-- | drivers/s390/net/lcs.c | 74 | ||||
-rw-r--r-- | drivers/s390/net/netiucv.c | 119 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 58 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_mpc.c | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_mpc.h | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 88 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 85 | ||||
-rw-r--r-- | drivers/s390/net/smsgiucv.c | 63 |
10 files changed, 498 insertions, 56 deletions
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 30a43cc79e76..d40f7a934f94 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -3,12 +3,12 @@ | |||
3 | * ESCON CLAW network driver | 3 | * ESCON CLAW network driver |
4 | * | 4 | * |
5 | * Linux for zSeries version | 5 | * Linux for zSeries version |
6 | * Copyright (C) 2002,2005 IBM Corporation | 6 | * Copyright IBM Corp. 2002, 2009 |
7 | * Author(s) Original code written by: | 7 | * Author(s) Original code written by: |
8 | * Kazuo Iimura (iimura@jp.ibm.com) | 8 | * Kazuo Iimura <iimura@jp.ibm.com> |
9 | * Rewritten by | 9 | * Rewritten by |
10 | * Andy Richter (richtera@us.ibm.com) | 10 | * Andy Richter <richtera@us.ibm.com> |
11 | * Marc Price (mwprice@us.ibm.com) | 11 | * Marc Price <mwprice@us.ibm.com> |
12 | * | 12 | * |
13 | * sysfs parms: | 13 | * sysfs parms: |
14 | * group x.x.rrrr,x.x.wwww | 14 | * group x.x.rrrr,x.x.wwww |
@@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev); | |||
253 | /* Functions for unpack reads */ | 253 | /* Functions for unpack reads */ |
254 | static void unpack_read(struct net_device *dev); | 254 | static void unpack_read(struct net_device *dev); |
255 | 255 | ||
256 | static int claw_pm_prepare(struct ccwgroup_device *gdev) | ||
257 | { | ||
258 | return -EPERM; | ||
259 | } | ||
260 | |||
256 | /* ccwgroup table */ | 261 | /* ccwgroup table */ |
257 | 262 | ||
258 | static struct ccwgroup_driver claw_group_driver = { | 263 | static struct ccwgroup_driver claw_group_driver = { |
@@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = { | |||
264 | .remove = claw_remove_device, | 269 | .remove = claw_remove_device, |
265 | .set_online = claw_new_device, | 270 | .set_online = claw_new_device, |
266 | .set_offline = claw_shutdown_device, | 271 | .set_offline = claw_shutdown_device, |
272 | .prepare = claw_pm_prepare, | ||
267 | }; | 273 | }; |
268 | 274 | ||
269 | /* | 275 | /* |
@@ -338,12 +344,6 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) | |||
338 | 344 | ||
339 | CLAW_DBF_TEXT(4, trace, "claw_tx"); | 345 | CLAW_DBF_TEXT(4, trace, "claw_tx"); |
340 | p_ch=&privptr->channel[WRITE]; | 346 | p_ch=&privptr->channel[WRITE]; |
341 | if (skb == NULL) { | ||
342 | privptr->stats.tx_dropped++; | ||
343 | privptr->stats.tx_errors++; | ||
344 | CLAW_DBF_TEXT_(2, trace, "clawtx%d", -EIO); | ||
345 | return -EIO; | ||
346 | } | ||
347 | spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); | 347 | spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); |
348 | rc=claw_hw_tx( skb, dev, 1 ); | 348 | rc=claw_hw_tx( skb, dev, 1 ); |
349 | spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); | 349 | spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 77f4033a0f4f..222e47394437 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/ctcm_main.c | 2 | * drivers/s390/net/ctcm_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2001, 2007 | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * Author(s): | 5 | * Author(s): |
6 | * Original CTC driver(s): | 6 | * Original CTC driver(s): |
7 | * Fritz Elfert (felfert@millenux.com) | 7 | * Fritz Elfert (felfert@millenux.com) |
@@ -1677,10 +1677,8 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) | |||
1677 | BUG_ON(priv == NULL); | 1677 | BUG_ON(priv == NULL); |
1678 | 1678 | ||
1679 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, | 1679 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, |
1680 | "removing device %s, r/w = %s/%s, proto : %d", | 1680 | "removing device %p, proto : %d", |
1681 | priv->channel[READ]->netdev->name, | 1681 | cgdev, priv->protocol); |
1682 | priv->channel[READ]->id, priv->channel[WRITE]->id, | ||
1683 | priv->protocol); | ||
1684 | 1682 | ||
1685 | if (cgdev->state == CCWGROUP_ONLINE) | 1683 | if (cgdev->state == CCWGROUP_ONLINE) |
1686 | ctcm_shutdown_device(cgdev); | 1684 | ctcm_shutdown_device(cgdev); |
@@ -1690,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) | |||
1690 | put_device(&cgdev->dev); | 1688 | put_device(&cgdev->dev); |
1691 | } | 1689 | } |
1692 | 1690 | ||
1691 | static int ctcm_pm_suspend(struct ccwgroup_device *gdev) | ||
1692 | { | ||
1693 | struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); | ||
1694 | |||
1695 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1696 | return 0; | ||
1697 | netif_device_detach(priv->channel[READ]->netdev); | ||
1698 | ctcm_close(priv->channel[READ]->netdev); | ||
1699 | ccw_device_set_offline(gdev->cdev[1]); | ||
1700 | ccw_device_set_offline(gdev->cdev[0]); | ||
1701 | return 0; | ||
1702 | } | ||
1703 | |||
1704 | static int ctcm_pm_resume(struct ccwgroup_device *gdev) | ||
1705 | { | ||
1706 | struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); | ||
1707 | int rc; | ||
1708 | |||
1709 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1710 | return 0; | ||
1711 | rc = ccw_device_set_online(gdev->cdev[1]); | ||
1712 | if (rc) | ||
1713 | goto err_out; | ||
1714 | rc = ccw_device_set_online(gdev->cdev[0]); | ||
1715 | if (rc) | ||
1716 | goto err_out; | ||
1717 | ctcm_open(priv->channel[READ]->netdev); | ||
1718 | err_out: | ||
1719 | netif_device_attach(priv->channel[READ]->netdev); | ||
1720 | return rc; | ||
1721 | } | ||
1722 | |||
1693 | static struct ccwgroup_driver ctcm_group_driver = { | 1723 | static struct ccwgroup_driver ctcm_group_driver = { |
1694 | .owner = THIS_MODULE, | 1724 | .owner = THIS_MODULE, |
1695 | .name = CTC_DRIVER_NAME, | 1725 | .name = CTC_DRIVER_NAME, |
@@ -1699,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = { | |||
1699 | .remove = ctcm_remove_device, | 1729 | .remove = ctcm_remove_device, |
1700 | .set_online = ctcm_new_device, | 1730 | .set_online = ctcm_new_device, |
1701 | .set_offline = ctcm_shutdown_device, | 1731 | .set_offline = ctcm_shutdown_device, |
1732 | .freeze = ctcm_pm_suspend, | ||
1733 | .thaw = ctcm_pm_resume, | ||
1734 | .restore = ctcm_pm_resume, | ||
1702 | }; | 1735 | }; |
1703 | 1736 | ||
1704 | 1737 | ||
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a45bc24eb5f9..07a25c3f94b6 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -1,15 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/net/lcs.c | ||
3 | * | ||
4 | * Linux for S/390 Lan Channel Station Network Driver | 2 | * Linux for S/390 Lan Channel Station Network Driver |
5 | * | 3 | * |
6 | * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, | 4 | * Copyright IBM Corp. 1999, 2009 |
7 | * IBM Corporation | 5 | * Author(s): Original Code written by |
8 | * Author(s): Original Code written by | 6 | * DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com> |
9 | * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) | 7 | * Rewritten by |
10 | * Rewritten by | 8 | * Frank Pavlic <fpavlic@de.ibm.com> and |
11 | * Frank Pavlic (fpavlic@de.ibm.com) and | 9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
13 | * | 10 | * |
14 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) | |||
2313 | put_device(&ccwgdev->dev); | 2310 | put_device(&ccwgdev->dev); |
2314 | } | 2311 | } |
2315 | 2312 | ||
2313 | static int lcs_pm_suspend(struct lcs_card *card) | ||
2314 | { | ||
2315 | if (card->dev) | ||
2316 | netif_device_detach(card->dev); | ||
2317 | lcs_set_allowed_threads(card, 0); | ||
2318 | lcs_wait_for_threads(card, 0xffffffff); | ||
2319 | if (card->state != DEV_STATE_DOWN) | ||
2320 | __lcs_shutdown_device(card->gdev, 1); | ||
2321 | return 0; | ||
2322 | } | ||
2323 | |||
2324 | static int lcs_pm_resume(struct lcs_card *card) | ||
2325 | { | ||
2326 | int rc = 0; | ||
2327 | |||
2328 | if (card->state == DEV_STATE_RECOVER) | ||
2329 | rc = lcs_new_device(card->gdev); | ||
2330 | if (card->dev) | ||
2331 | netif_device_attach(card->dev); | ||
2332 | if (rc) { | ||
2333 | dev_warn(&card->gdev->dev, "The lcs device driver " | ||
2334 | "failed to recover the device\n"); | ||
2335 | } | ||
2336 | return rc; | ||
2337 | } | ||
2338 | |||
2339 | static int lcs_prepare(struct ccwgroup_device *gdev) | ||
2340 | { | ||
2341 | return 0; | ||
2342 | } | ||
2343 | |||
2344 | static void lcs_complete(struct ccwgroup_device *gdev) | ||
2345 | { | ||
2346 | return; | ||
2347 | } | ||
2348 | |||
2349 | static int lcs_freeze(struct ccwgroup_device *gdev) | ||
2350 | { | ||
2351 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2352 | return lcs_pm_suspend(card); | ||
2353 | } | ||
2354 | |||
2355 | static int lcs_thaw(struct ccwgroup_device *gdev) | ||
2356 | { | ||
2357 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2358 | return lcs_pm_resume(card); | ||
2359 | } | ||
2360 | |||
2361 | static int lcs_restore(struct ccwgroup_device *gdev) | ||
2362 | { | ||
2363 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2364 | return lcs_pm_resume(card); | ||
2365 | } | ||
2366 | |||
2316 | /** | 2367 | /** |
2317 | * LCS ccwgroup driver registration | 2368 | * LCS ccwgroup driver registration |
2318 | */ | 2369 | */ |
@@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = { | |||
2325 | .remove = lcs_remove_device, | 2376 | .remove = lcs_remove_device, |
2326 | .set_online = lcs_new_device, | 2377 | .set_online = lcs_new_device, |
2327 | .set_offline = lcs_shutdown_device, | 2378 | .set_offline = lcs_shutdown_device, |
2379 | .prepare = lcs_prepare, | ||
2380 | .complete = lcs_complete, | ||
2381 | .freeze = lcs_freeze, | ||
2382 | .thaw = lcs_thaw, | ||
2383 | .restore = lcs_restore, | ||
2328 | }; | 2384 | }; |
2329 | 2385 | ||
2330 | /** | 2386 | /** |
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index be716e45f7ac..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. |
@@ -1315,9 +1403,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | |||
1315 | return NETDEV_TX_BUSY; | 1403 | return NETDEV_TX_BUSY; |
1316 | } | 1404 | } |
1317 | dev->trans_start = jiffies; | 1405 | dev->trans_start = jiffies; |
1318 | rc = netiucv_transmit_skb(privptr->conn, skb) != 0; | 1406 | rc = netiucv_transmit_skb(privptr->conn, skb); |
1319 | netiucv_clear_busy(dev); | 1407 | netiucv_clear_busy(dev); |
1320 | return rc; | 1408 | return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK; |
1321 | } | 1409 | } |
1322 | 1410 | ||
1323 | /** | 1411 | /** |
@@ -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: |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c827d69b5a91..d53621c4acbb 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_core_main.c | 2 | * drivers/s390/net/qeth_core_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -952,6 +952,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, | |||
952 | buf->buffer->element[i].addr = NULL; | 952 | buf->buffer->element[i].addr = NULL; |
953 | buf->buffer->element[i].flags = 0; | 953 | buf->buffer->element[i].flags = 0; |
954 | } | 954 | } |
955 | buf->buffer->element[15].flags = 0; | ||
955 | buf->next_element_to_fill = 0; | 956 | buf->next_element_to_fill = 0; |
956 | atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); | 957 | atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); |
957 | } | 958 | } |
@@ -1140,6 +1141,8 @@ static int qeth_setup_card(struct qeth_card *card) | |||
1140 | card->ipato.enabled = 0; | 1141 | card->ipato.enabled = 0; |
1141 | card->ipato.invert4 = 0; | 1142 | card->ipato.invert4 = 0; |
1142 | card->ipato.invert6 = 0; | 1143 | card->ipato.invert6 = 0; |
1144 | if (card->info.type == QETH_CARD_TYPE_IQD) | ||
1145 | card->options.checksum_type = NO_CHECKSUMMING; | ||
1143 | /* init QDIO stuff */ | 1146 | /* init QDIO stuff */ |
1144 | qeth_init_qdio_info(card); | 1147 | qeth_init_qdio_info(card); |
1145 | return 0; | 1148 | return 0; |
@@ -2934,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) | |||
2934 | if (card->info.type == QETH_CARD_TYPE_OSN) | 2937 | if (card->info.type == QETH_CARD_TYPE_OSN) |
2935 | return cast_type; | 2938 | return cast_type; |
2936 | 2939 | ||
2937 | if (skb->dst && skb->dst->neighbour) { | 2940 | if (skb_dst(skb) && skb_dst(skb)->neighbour) { |
2938 | cast_type = skb->dst->neighbour->type; | 2941 | cast_type = skb_dst(skb)->neighbour->type; |
2939 | if ((cast_type == RTN_BROADCAST) || | 2942 | if ((cast_type == RTN_BROADCAST) || |
2940 | (cast_type == RTN_MULTICAST) || | 2943 | (cast_type == RTN_MULTICAST) || |
2941 | (cast_type == RTN_ANYCAST)) | 2944 | (cast_type == RTN_ANYCAST)) |
@@ -4192,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev) | |||
4192 | card->discipline.ccwgdriver->shutdown(gdev); | 4195 | card->discipline.ccwgdriver->shutdown(gdev); |
4193 | } | 4196 | } |
4194 | 4197 | ||
4198 | static int qeth_core_prepare(struct ccwgroup_device *gdev) | ||
4199 | { | ||
4200 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4201 | if (card->discipline.ccwgdriver && | ||
4202 | card->discipline.ccwgdriver->prepare) | ||
4203 | return card->discipline.ccwgdriver->prepare(gdev); | ||
4204 | return 0; | ||
4205 | } | ||
4206 | |||
4207 | static void qeth_core_complete(struct ccwgroup_device *gdev) | ||
4208 | { | ||
4209 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4210 | if (card->discipline.ccwgdriver && | ||
4211 | card->discipline.ccwgdriver->complete) | ||
4212 | card->discipline.ccwgdriver->complete(gdev); | ||
4213 | } | ||
4214 | |||
4215 | static int qeth_core_freeze(struct ccwgroup_device *gdev) | ||
4216 | { | ||
4217 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4218 | if (card->discipline.ccwgdriver && | ||
4219 | card->discipline.ccwgdriver->freeze) | ||
4220 | return card->discipline.ccwgdriver->freeze(gdev); | ||
4221 | return 0; | ||
4222 | } | ||
4223 | |||
4224 | static int qeth_core_thaw(struct ccwgroup_device *gdev) | ||
4225 | { | ||
4226 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4227 | if (card->discipline.ccwgdriver && | ||
4228 | card->discipline.ccwgdriver->thaw) | ||
4229 | return card->discipline.ccwgdriver->thaw(gdev); | ||
4230 | return 0; | ||
4231 | } | ||
4232 | |||
4233 | static int qeth_core_restore(struct ccwgroup_device *gdev) | ||
4234 | { | ||
4235 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4236 | if (card->discipline.ccwgdriver && | ||
4237 | card->discipline.ccwgdriver->restore) | ||
4238 | return card->discipline.ccwgdriver->restore(gdev); | ||
4239 | return 0; | ||
4240 | } | ||
4241 | |||
4195 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | 4242 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { |
4196 | .owner = THIS_MODULE, | 4243 | .owner = THIS_MODULE, |
4197 | .name = "qeth", | 4244 | .name = "qeth", |
@@ -4201,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | |||
4201 | .set_online = qeth_core_set_online, | 4248 | .set_online = qeth_core_set_online, |
4202 | .set_offline = qeth_core_set_offline, | 4249 | .set_offline = qeth_core_set_offline, |
4203 | .shutdown = qeth_core_shutdown, | 4250 | .shutdown = qeth_core_shutdown, |
4251 | .prepare = qeth_core_prepare, | ||
4252 | .complete = qeth_core_complete, | ||
4253 | .freeze = qeth_core_freeze, | ||
4254 | .thaw = qeth_core_thaw, | ||
4255 | .restore = qeth_core_restore, | ||
4204 | }; | 4256 | }; |
4205 | 4257 | ||
4206 | static ssize_t | 4258 | static ssize_t |
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index 06f4de1f0507..ec24901c802c 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c | |||
@@ -181,6 +181,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { | |||
181 | {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, | 181 | {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, |
182 | {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, | 182 | {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, |
183 | {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, | 183 | {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, |
184 | {IPA_RC_L2_MAC_NOT_AUTH_BY_HYP, "L2 mac not authorized by hypervisor"}, | ||
185 | {IPA_RC_L2_MAC_NOT_AUTH_BY_ADP, "L2 mac not authorized by adapter"}, | ||
184 | {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, | 186 | {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, |
185 | {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, | 187 | {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, |
186 | {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, | 188 | {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, |
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 18548822e37c..eecb2ee62e85 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h | |||
@@ -168,6 +168,8 @@ enum qeth_ipa_return_codes { | |||
168 | IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, | 168 | IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, |
169 | IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, | 169 | IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, |
170 | IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, | 170 | IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, |
171 | IPA_RC_L2_MAC_NOT_AUTH_BY_HYP = 0x200c, | ||
172 | IPA_RC_L2_MAC_NOT_AUTH_BY_ADP = 0x200d, | ||
171 | IPA_RC_L2_MAC_NOT_FOUND = 0x2010, | 173 | IPA_RC_L2_MAC_NOT_FOUND = 0x2010, |
172 | IPA_RC_L2_INVALID_VLAN_ID = 0x2015, | 174 | IPA_RC_L2_INVALID_VLAN_ID = 0x2015, |
173 | IPA_RC_L2_DUP_VLAN_ID = 0x2016, | 175 | IPA_RC_L2_DUP_VLAN_ID = 0x2016, |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 172031baedc1..81d7f268418a 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_l2_main.c | 2 | * drivers/s390/net/qeth_l2_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/mii.h> | 20 | #include <linux/mii.h> |
21 | #include <linux/ip.h> | 21 | #include <linux/ip.h> |
22 | #include <linux/list.h> | ||
22 | 23 | ||
23 | #include "qeth_core.h" | 24 | #include "qeth_core.h" |
24 | 25 | ||
@@ -130,7 +131,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, | |||
130 | cmd = (struct qeth_ipa_cmd *) data; | 131 | cmd = (struct qeth_ipa_cmd *) data; |
131 | mac = &cmd->data.setdelmac.mac[0]; | 132 | mac = &cmd->data.setdelmac.mac[0]; |
132 | /* MAC already registered, needed in couple/uncouple case */ | 133 | /* MAC already registered, needed in couple/uncouple case */ |
133 | if (cmd->hdr.return_code == 0x2005) { | 134 | if (cmd->hdr.return_code == IPA_RC_L2_DUP_MAC) { |
134 | QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", | 135 | QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", |
135 | mac, QETH_CARD_IFNAME(card)); | 136 | mac, QETH_CARD_IFNAME(card)); |
136 | cmd->hdr.return_code = 0; | 137 | cmd->hdr.return_code = 0; |
@@ -502,6 +503,30 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, | |||
502 | if (cmd->hdr.return_code) { | 503 | if (cmd->hdr.return_code) { |
503 | QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); | 504 | QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); |
504 | card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; | 505 | card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; |
506 | switch (cmd->hdr.return_code) { | ||
507 | case IPA_RC_L2_DUP_MAC: | ||
508 | case IPA_RC_L2_DUP_LAYER3_MAC: | ||
509 | dev_warn(&card->gdev->dev, | ||
510 | "MAC address " | ||
511 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | ||
512 | "already exists\n", | ||
513 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
514 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
515 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
516 | break; | ||
517 | case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: | ||
518 | case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: | ||
519 | dev_warn(&card->gdev->dev, | ||
520 | "MAC address " | ||
521 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | ||
522 | "is not authorized\n", | ||
523 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
524 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
525 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
526 | break; | ||
527 | default: | ||
528 | break; | ||
529 | } | ||
505 | cmd->hdr.return_code = -EIO; | 530 | cmd->hdr.return_code = -EIO; |
506 | } else { | 531 | } else { |
507 | card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; | 532 | card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; |
@@ -616,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) | |||
616 | { | 641 | { |
617 | struct qeth_card *card = dev->ml_priv; | 642 | struct qeth_card *card = dev->ml_priv; |
618 | struct dev_addr_list *dm; | 643 | struct dev_addr_list *dm; |
644 | struct netdev_hw_addr *ha; | ||
619 | 645 | ||
620 | if (card->info.type == QETH_CARD_TYPE_OSN) | 646 | if (card->info.type == QETH_CARD_TYPE_OSN) |
621 | return ; | 647 | return ; |
@@ -629,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) | |||
629 | for (dm = dev->mc_list; dm; dm = dm->next) | 655 | for (dm = dev->mc_list; dm; dm = dm->next) |
630 | qeth_l2_add_mc(card, dm->da_addr, 0); | 656 | qeth_l2_add_mc(card, dm->da_addr, 0); |
631 | 657 | ||
632 | for (dm = dev->uc_list; dm; dm = dm->next) | 658 | list_for_each_entry(ha, &dev->uc_list, list) |
633 | qeth_l2_add_mc(card, dm->da_addr, 1); | 659 | qeth_l2_add_mc(card, ha->addr, 1); |
634 | 660 | ||
635 | spin_unlock_bh(&card->mclock); | 661 | spin_unlock_bh(&card->mclock); |
636 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | 662 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) |
@@ -839,6 +865,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) | |||
839 | { | 865 | { |
840 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); | 866 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); |
841 | 867 | ||
868 | qeth_set_allowed_threads(card, 0, 1); | ||
842 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | 869 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); |
843 | 870 | ||
844 | if (cgdev->state == CCWGROUP_ONLINE) { | 871 | if (cgdev->state == CCWGROUP_ONLINE) { |
@@ -974,8 +1001,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
974 | dev_warn(&card->gdev->dev, | 1001 | dev_warn(&card->gdev->dev, |
975 | "The LAN is offline\n"); | 1002 | "The LAN is offline\n"); |
976 | card->lan_online = 0; | 1003 | card->lan_online = 0; |
1004 | return 0; | ||
977 | } | 1005 | } |
978 | return rc; | 1006 | goto out_remove; |
979 | } else | 1007 | } else |
980 | card->lan_online = 1; | 1008 | card->lan_online = 1; |
981 | 1009 | ||
@@ -1113,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) | |||
1113 | qeth_clear_qdio_buffers(card); | 1141 | qeth_clear_qdio_buffers(card); |
1114 | } | 1142 | } |
1115 | 1143 | ||
1144 | static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) | ||
1145 | { | ||
1146 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
1147 | |||
1148 | if (card->dev) | ||
1149 | netif_device_detach(card->dev); | ||
1150 | qeth_set_allowed_threads(card, 0, 1); | ||
1151 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | ||
1152 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1153 | return 0; | ||
1154 | if (card->state == CARD_STATE_UP) { | ||
1155 | card->use_hard_stop = 1; | ||
1156 | __qeth_l2_set_offline(card->gdev, 1); | ||
1157 | } else | ||
1158 | __qeth_l2_set_offline(card->gdev, 0); | ||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
1162 | static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) | ||
1163 | { | ||
1164 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
1165 | int rc = 0; | ||
1166 | |||
1167 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1168 | goto out; | ||
1169 | |||
1170 | if (card->state == CARD_STATE_RECOVER) { | ||
1171 | rc = __qeth_l2_set_online(card->gdev, 1); | ||
1172 | if (rc) { | ||
1173 | if (card->dev) { | ||
1174 | rtnl_lock(); | ||
1175 | dev_close(card->dev); | ||
1176 | rtnl_unlock(); | ||
1177 | } | ||
1178 | } | ||
1179 | } else | ||
1180 | rc = __qeth_l2_set_online(card->gdev, 0); | ||
1181 | out: | ||
1182 | qeth_set_allowed_threads(card, 0xffffffff, 0); | ||
1183 | if (card->dev) | ||
1184 | netif_device_attach(card->dev); | ||
1185 | if (rc) | ||
1186 | dev_warn(&card->gdev->dev, "The qeth device driver " | ||
1187 | "failed to recover an error on the device\n"); | ||
1188 | return rc; | ||
1189 | } | ||
1190 | |||
1116 | struct ccwgroup_driver qeth_l2_ccwgroup_driver = { | 1191 | struct ccwgroup_driver qeth_l2_ccwgroup_driver = { |
1117 | .probe = qeth_l2_probe_device, | 1192 | .probe = qeth_l2_probe_device, |
1118 | .remove = qeth_l2_remove_device, | 1193 | .remove = qeth_l2_remove_device, |
1119 | .set_online = qeth_l2_set_online, | 1194 | .set_online = qeth_l2_set_online, |
1120 | .set_offline = qeth_l2_set_offline, | 1195 | .set_offline = qeth_l2_set_offline, |
1121 | .shutdown = qeth_l2_shutdown, | 1196 | .shutdown = qeth_l2_shutdown, |
1197 | .freeze = qeth_l2_pm_suspend, | ||
1198 | .thaw = qeth_l2_pm_resume, | ||
1199 | .restore = qeth_l2_pm_resume, | ||
1122 | }; | 1200 | }; |
1123 | EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); | 1201 | EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); |
1124 | 1202 | ||
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 0ba3817cb6a7..54872406864e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_l3_main.c | 2 | * drivers/s390/net/qeth_l3_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -1920,16 +1920,22 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
1920 | hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); | 1920 | hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); |
1921 | } | 1921 | } |
1922 | 1922 | ||
1923 | skb->ip_summed = card->options.checksum_type; | 1923 | switch (card->options.checksum_type) { |
1924 | if (card->options.checksum_type == HW_CHECKSUMMING) { | 1924 | case SW_CHECKSUMMING: |
1925 | skb->ip_summed = CHECKSUM_NONE; | ||
1926 | break; | ||
1927 | case NO_CHECKSUMMING: | ||
1928 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1929 | break; | ||
1930 | case HW_CHECKSUMMING: | ||
1925 | if ((hdr->hdr.l3.ext_flags & | 1931 | if ((hdr->hdr.l3.ext_flags & |
1926 | (QETH_HDR_EXT_CSUM_HDR_REQ | | 1932 | (QETH_HDR_EXT_CSUM_HDR_REQ | |
1927 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == | 1933 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == |
1928 | (QETH_HDR_EXT_CSUM_HDR_REQ | | 1934 | (QETH_HDR_EXT_CSUM_HDR_REQ | |
1929 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) | 1935 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) |
1930 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1936 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1931 | else | 1937 | else |
1932 | skb->ip_summed = SW_CHECKSUMMING; | 1938 | skb->ip_summed = CHECKSUM_NONE; |
1933 | } | 1939 | } |
1934 | 1940 | ||
1935 | return vlan_id; | 1941 | return vlan_id; |
@@ -2543,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
2543 | /* IPv4 */ | 2549 | /* IPv4 */ |
2544 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); | 2550 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); |
2545 | memset(hdr->hdr.l3.dest_addr, 0, 12); | 2551 | memset(hdr->hdr.l3.dest_addr, 0, 12); |
2546 | if ((skb->dst) && (skb->dst->neighbour)) { | 2552 | if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { |
2547 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = | 2553 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = |
2548 | *((u32 *) skb->dst->neighbour->primary_key); | 2554 | *((u32 *) skb_dst(skb)->neighbour->primary_key); |
2549 | } else { | 2555 | } else { |
2550 | /* fill in destination address used in ip header */ | 2556 | /* fill in destination address used in ip header */ |
2551 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = | 2557 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = |
@@ -2556,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
2556 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); | 2562 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); |
2557 | if (card->info.type == QETH_CARD_TYPE_IQD) | 2563 | if (card->info.type == QETH_CARD_TYPE_IQD) |
2558 | hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; | 2564 | hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; |
2559 | if ((skb->dst) && (skb->dst->neighbour)) { | 2565 | if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { |
2560 | memcpy(hdr->hdr.l3.dest_addr, | 2566 | memcpy(hdr->hdr.l3.dest_addr, |
2561 | skb->dst->neighbour->primary_key, 16); | 2567 | skb_dst(skb)->neighbour->primary_key, 16); |
2562 | } else { | 2568 | } else { |
2563 | /* fill in destination address used in ip header */ | 2569 | /* fill in destination address used in ip header */ |
2564 | memcpy(hdr->hdr.l3.dest_addr, | 2570 | memcpy(hdr->hdr.l3.dest_addr, |
@@ -3006,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
3006 | card->dev->features |= NETIF_F_HW_VLAN_TX | | 3012 | card->dev->features |= NETIF_F_HW_VLAN_TX | |
3007 | NETIF_F_HW_VLAN_RX | | 3013 | NETIF_F_HW_VLAN_RX | |
3008 | NETIF_F_HW_VLAN_FILTER; | 3014 | NETIF_F_HW_VLAN_FILTER; |
3015 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
3009 | 3016 | ||
3010 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 3017 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
3011 | return register_netdev(card->dev); | 3018 | return register_netdev(card->dev); |
@@ -3070,6 +3077,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) | |||
3070 | { | 3077 | { |
3071 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); | 3078 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); |
3072 | 3079 | ||
3080 | qeth_set_allowed_threads(card, 0, 1); | ||
3073 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | 3081 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); |
3074 | 3082 | ||
3075 | if (cgdev->state == CCWGROUP_ONLINE) { | 3083 | if (cgdev->state == CCWGROUP_ONLINE) { |
@@ -3141,8 +3149,9 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3141 | dev_warn(&card->gdev->dev, | 3149 | dev_warn(&card->gdev->dev, |
3142 | "The LAN is offline\n"); | 3150 | "The LAN is offline\n"); |
3143 | card->lan_online = 0; | 3151 | card->lan_online = 0; |
3152 | return 0; | ||
3144 | } | 3153 | } |
3145 | return rc; | 3154 | goto out_remove; |
3146 | } else | 3155 | } else |
3147 | card->lan_online = 1; | 3156 | card->lan_online = 1; |
3148 | qeth_set_large_send(card, card->options.large_send); | 3157 | qeth_set_large_send(card, card->options.large_send); |
@@ -3274,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev) | |||
3274 | qeth_clear_qdio_buffers(card); | 3283 | qeth_clear_qdio_buffers(card); |
3275 | } | 3284 | } |
3276 | 3285 | ||
3286 | static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) | ||
3287 | { | ||
3288 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
3289 | |||
3290 | if (card->dev) | ||
3291 | netif_device_detach(card->dev); | ||
3292 | qeth_set_allowed_threads(card, 0, 1); | ||
3293 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | ||
3294 | if (gdev->state == CCWGROUP_OFFLINE) | ||
3295 | return 0; | ||
3296 | if (card->state == CARD_STATE_UP) { | ||
3297 | card->use_hard_stop = 1; | ||
3298 | __qeth_l3_set_offline(card->gdev, 1); | ||
3299 | } else | ||
3300 | __qeth_l3_set_offline(card->gdev, 0); | ||
3301 | return 0; | ||
3302 | } | ||
3303 | |||
3304 | static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) | ||
3305 | { | ||
3306 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
3307 | int rc = 0; | ||
3308 | |||
3309 | if (gdev->state == CCWGROUP_OFFLINE) | ||
3310 | goto out; | ||
3311 | |||
3312 | if (card->state == CARD_STATE_RECOVER) { | ||
3313 | rc = __qeth_l3_set_online(card->gdev, 1); | ||
3314 | if (rc) { | ||
3315 | if (card->dev) { | ||
3316 | rtnl_lock(); | ||
3317 | dev_close(card->dev); | ||
3318 | rtnl_unlock(); | ||
3319 | } | ||
3320 | } | ||
3321 | } else | ||
3322 | rc = __qeth_l3_set_online(card->gdev, 0); | ||
3323 | out: | ||
3324 | qeth_set_allowed_threads(card, 0xffffffff, 0); | ||
3325 | if (card->dev) | ||
3326 | netif_device_attach(card->dev); | ||
3327 | if (rc) | ||
3328 | dev_warn(&card->gdev->dev, "The qeth device driver " | ||
3329 | "failed to recover an error on the device\n"); | ||
3330 | return rc; | ||
3331 | } | ||
3332 | |||
3277 | struct ccwgroup_driver qeth_l3_ccwgroup_driver = { | 3333 | struct ccwgroup_driver qeth_l3_ccwgroup_driver = { |
3278 | .probe = qeth_l3_probe_device, | 3334 | .probe = qeth_l3_probe_device, |
3279 | .remove = qeth_l3_remove_device, | 3335 | .remove = qeth_l3_remove_device, |
3280 | .set_online = qeth_l3_set_online, | 3336 | .set_online = qeth_l3_set_online, |
3281 | .set_offline = qeth_l3_set_offline, | 3337 | .set_offline = qeth_l3_set_offline, |
3282 | .shutdown = qeth_l3_shutdown, | 3338 | .shutdown = qeth_l3_shutdown, |
3339 | .freeze = qeth_l3_pm_suspend, | ||
3340 | .thaw = qeth_l3_pm_resume, | ||
3341 | .restore = qeth_l3_pm_resume, | ||
3283 | }; | 3342 | }; |
3284 | EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); | 3343 | EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); |
3285 | 3344 | ||
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090c2625..e76a320d373b 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: |