diff options
author | Steve Glendinning <steve.glendinning@shawell.net> | 2012-11-30 00:55:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-30 12:27:20 -0500 |
commit | 3b9f7d8cdb6db2b6ba78c149dacec3d72591c544 (patch) | |
tree | 8ca72360b184ba56f9d65de6caaef005735eb999 /drivers/net/usb/smsc95xx.c | |
parent | eed9a72914a2b2737a0d91b80579f878999574ef (diff) |
smsc95xx: fix error handling in suspend failure case
This patch ensures that if we fail to suspend the LAN9500 device
we call usbnet_resume before returning failure, instead of
leaving the usbnet driver in an unusable state.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/smsc95xx.c')
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 50 |
1 files changed, 29 insertions, 21 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index c397b3a04f10..ffeaf131baa7 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -1248,35 +1248,37 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1248 | 1248 | ||
1249 | /* disable energy detect (link up) & wake up events */ | 1249 | /* disable energy detect (link up) & wake up events */ |
1250 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | 1250 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); |
1251 | check_warn_return(ret, "Error reading WUCSR\n"); | 1251 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1252 | 1252 | ||
1253 | val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_); | 1253 | val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_); |
1254 | 1254 | ||
1255 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | 1255 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); |
1256 | check_warn_return(ret, "Error writing WUCSR\n"); | 1256 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1257 | 1257 | ||
1258 | ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | 1258 | ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); |
1259 | check_warn_return(ret, "Error reading PM_CTRL\n"); | 1259 | check_warn_goto_done(ret, "Error reading PM_CTRL\n"); |
1260 | 1260 | ||
1261 | val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_); | 1261 | val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_); |
1262 | 1262 | ||
1263 | ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | 1263 | ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); |
1264 | check_warn_return(ret, "Error writing PM_CTRL\n"); | 1264 | check_warn_goto_done(ret, "Error writing PM_CTRL\n"); |
1265 | 1265 | ||
1266 | return smsc95xx_enter_suspend2(dev); | 1266 | ret = smsc95xx_enter_suspend2(dev); |
1267 | goto done; | ||
1267 | } | 1268 | } |
1268 | 1269 | ||
1269 | if (pdata->wolopts & WAKE_PHY) { | 1270 | if (pdata->wolopts & WAKE_PHY) { |
1270 | ret = smsc95xx_enable_phy_wakeup_interrupts(dev, | 1271 | ret = smsc95xx_enable_phy_wakeup_interrupts(dev, |
1271 | (PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_LINK_DOWN_)); | 1272 | (PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_LINK_DOWN_)); |
1272 | check_warn_return(ret, "error enabling PHY wakeup ints\n"); | 1273 | check_warn_goto_done(ret, "error enabling PHY wakeup ints\n"); |
1273 | 1274 | ||
1274 | /* if link is down then configure EDPD and enter SUSPEND1, | 1275 | /* if link is down then configure EDPD and enter SUSPEND1, |
1275 | * otherwise enter SUSPEND0 below | 1276 | * otherwise enter SUSPEND0 below |
1276 | */ | 1277 | */ |
1277 | if (!link_up) { | 1278 | if (!link_up) { |
1278 | netdev_info(dev->net, "entering SUSPEND1 mode\n"); | 1279 | netdev_info(dev->net, "entering SUSPEND1 mode\n"); |
1279 | return smsc95xx_enter_suspend1(dev); | 1280 | ret = smsc95xx_enter_suspend1(dev); |
1281 | goto done; | ||
1280 | } | 1282 | } |
1281 | } | 1283 | } |
1282 | 1284 | ||
@@ -1292,7 +1294,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1292 | 1294 | ||
1293 | if (!filter_mask) { | 1295 | if (!filter_mask) { |
1294 | netdev_warn(dev->net, "Unable to allocate filter_mask\n"); | 1296 | netdev_warn(dev->net, "Unable to allocate filter_mask\n"); |
1295 | return -ENOMEM; | 1297 | ret = -ENOMEM; |
1298 | goto done; | ||
1296 | } | 1299 | } |
1297 | 1300 | ||
1298 | memset(command, 0, sizeof(command)); | 1301 | memset(command, 0, sizeof(command)); |
@@ -1354,49 +1357,49 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1354 | ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]); | 1357 | ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]); |
1355 | if (ret < 0) | 1358 | if (ret < 0) |
1356 | kfree(filter_mask); | 1359 | kfree(filter_mask); |
1357 | check_warn_return(ret, "Error writing WUFF\n"); | 1360 | check_warn_goto_done(ret, "Error writing WUFF\n"); |
1358 | } | 1361 | } |
1359 | kfree(filter_mask); | 1362 | kfree(filter_mask); |
1360 | 1363 | ||
1361 | for (i = 0; i < (wuff_filter_count / 4); i++) { | 1364 | for (i = 0; i < (wuff_filter_count / 4); i++) { |
1362 | ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]); | 1365 | ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]); |
1363 | check_warn_return(ret, "Error writing WUFF\n"); | 1366 | check_warn_goto_done(ret, "Error writing WUFF\n"); |
1364 | } | 1367 | } |
1365 | 1368 | ||
1366 | for (i = 0; i < (wuff_filter_count / 4); i++) { | 1369 | for (i = 0; i < (wuff_filter_count / 4); i++) { |
1367 | ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]); | 1370 | ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]); |
1368 | check_warn_return(ret, "Error writing WUFF\n"); | 1371 | check_warn_goto_done(ret, "Error writing WUFF\n"); |
1369 | } | 1372 | } |
1370 | 1373 | ||
1371 | for (i = 0; i < (wuff_filter_count / 2); i++) { | 1374 | for (i = 0; i < (wuff_filter_count / 2); i++) { |
1372 | ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]); | 1375 | ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]); |
1373 | check_warn_return(ret, "Error writing WUFF\n"); | 1376 | check_warn_goto_done(ret, "Error writing WUFF\n"); |
1374 | } | 1377 | } |
1375 | 1378 | ||
1376 | /* clear any pending pattern match packet status */ | 1379 | /* clear any pending pattern match packet status */ |
1377 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | 1380 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); |
1378 | check_warn_return(ret, "Error reading WUCSR\n"); | 1381 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1379 | 1382 | ||
1380 | val |= WUCSR_WUFR_; | 1383 | val |= WUCSR_WUFR_; |
1381 | 1384 | ||
1382 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | 1385 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); |
1383 | check_warn_return(ret, "Error writing WUCSR\n"); | 1386 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1384 | } | 1387 | } |
1385 | 1388 | ||
1386 | if (pdata->wolopts & WAKE_MAGIC) { | 1389 | if (pdata->wolopts & WAKE_MAGIC) { |
1387 | /* clear any pending magic packet status */ | 1390 | /* clear any pending magic packet status */ |
1388 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | 1391 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); |
1389 | check_warn_return(ret, "Error reading WUCSR\n"); | 1392 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1390 | 1393 | ||
1391 | val |= WUCSR_MPR_; | 1394 | val |= WUCSR_MPR_; |
1392 | 1395 | ||
1393 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | 1396 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); |
1394 | check_warn_return(ret, "Error writing WUCSR\n"); | 1397 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1395 | } | 1398 | } |
1396 | 1399 | ||
1397 | /* enable/disable wakeup sources */ | 1400 | /* enable/disable wakeup sources */ |
1398 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | 1401 | ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); |
1399 | check_warn_return(ret, "Error reading WUCSR\n"); | 1402 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1400 | 1403 | ||
1401 | if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) { | 1404 | if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) { |
1402 | netdev_info(dev->net, "enabling pattern match wakeup\n"); | 1405 | netdev_info(dev->net, "enabling pattern match wakeup\n"); |
@@ -1415,11 +1418,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1415 | } | 1418 | } |
1416 | 1419 | ||
1417 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | 1420 | ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); |
1418 | check_warn_return(ret, "Error writing WUCSR\n"); | 1421 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1419 | 1422 | ||
1420 | /* enable wol wakeup source */ | 1423 | /* enable wol wakeup source */ |
1421 | ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | 1424 | ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); |
1422 | check_warn_return(ret, "Error reading PM_CTRL\n"); | 1425 | check_warn_goto_done(ret, "Error reading PM_CTRL\n"); |
1423 | 1426 | ||
1424 | val |= PM_CTL_WOL_EN_; | 1427 | val |= PM_CTL_WOL_EN_; |
1425 | 1428 | ||
@@ -1428,14 +1431,19 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1428 | val |= PM_CTL_ED_EN_; | 1431 | val |= PM_CTL_ED_EN_; |
1429 | 1432 | ||
1430 | ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | 1433 | ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); |
1431 | check_warn_return(ret, "Error writing PM_CTRL\n"); | 1434 | check_warn_goto_done(ret, "Error writing PM_CTRL\n"); |
1432 | 1435 | ||
1433 | /* enable receiver to enable frame reception */ | 1436 | /* enable receiver to enable frame reception */ |
1434 | smsc95xx_start_rx_path(dev, 1); | 1437 | smsc95xx_start_rx_path(dev, 1); |
1435 | 1438 | ||
1436 | /* some wol options are enabled, so enter SUSPEND0 */ | 1439 | /* some wol options are enabled, so enter SUSPEND0 */ |
1437 | netdev_info(dev->net, "entering SUSPEND0 mode\n"); | 1440 | netdev_info(dev->net, "entering SUSPEND0 mode\n"); |
1438 | return smsc95xx_enter_suspend0(dev); | 1441 | ret = smsc95xx_enter_suspend0(dev); |
1442 | |||
1443 | done: | ||
1444 | if (ret) | ||
1445 | usbnet_resume(intf); | ||
1446 | return ret; | ||
1439 | } | 1447 | } |
1440 | 1448 | ||
1441 | static int smsc95xx_resume(struct usb_interface *intf) | 1449 | static int smsc95xx_resume(struct usb_interface *intf) |