diff options
author | Steve Glendinning <steve.glendinning@shawell.net> | 2012-11-28 00:59:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-28 11:17:31 -0500 |
commit | eacdd6c223d699938c56e7c991877433454d3ebc (patch) | |
tree | 8eef1e0f1350201d496b0761632a831ee1204c07 /drivers/net | |
parent | f329ccdc6cd9ef866045af7ccc5fa7d2a9a1f6bb (diff) |
smsc75xx: fix error handling in suspend failure case
This patch ensures that if we fail to suspend the LAN7500 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')
-rw-r--r-- | drivers/net/usb/smsc75xx.c | 69 |
1 files changed, 38 insertions, 31 deletions
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 3e3b1014141..649bf2a4262 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c | |||
@@ -1346,7 +1346,7 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1346 | int ret; | 1346 | int ret; |
1347 | 1347 | ||
1348 | ret = usbnet_suspend(intf, message); | 1348 | ret = usbnet_suspend(intf, message); |
1349 | check_warn_return(ret, "usbnet_suspend error\n"); | 1349 | check_warn_goto_done(ret, "usbnet_suspend error\n"); |
1350 | 1350 | ||
1351 | /* determine if link is up using only _nopm functions */ | 1351 | /* determine if link is up using only _nopm functions */ |
1352 | link_up = smsc75xx_link_ok_nopm(dev); | 1352 | link_up = smsc75xx_link_ok_nopm(dev); |
@@ -1360,28 +1360,29 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1360 | 1360 | ||
1361 | /* disable energy detect (link up) & wake up events */ | 1361 | /* disable energy detect (link up) & wake up events */ |
1362 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1362 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1363 | check_warn_return(ret, "Error reading WUCSR\n"); | 1363 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1364 | 1364 | ||
1365 | val &= ~(WUCSR_MPEN | WUCSR_WUEN); | 1365 | val &= ~(WUCSR_MPEN | WUCSR_WUEN); |
1366 | 1366 | ||
1367 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1367 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1368 | check_warn_return(ret, "Error writing WUCSR\n"); | 1368 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1369 | 1369 | ||
1370 | ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | 1370 | ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); |
1371 | check_warn_return(ret, "Error reading PMT_CTL\n"); | 1371 | check_warn_goto_done(ret, "Error reading PMT_CTL\n"); |
1372 | 1372 | ||
1373 | val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN); | 1373 | val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN); |
1374 | 1374 | ||
1375 | ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | 1375 | ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); |
1376 | check_warn_return(ret, "Error writing PMT_CTL\n"); | 1376 | check_warn_goto_done(ret, "Error writing PMT_CTL\n"); |
1377 | 1377 | ||
1378 | return smsc75xx_enter_suspend2(dev); | 1378 | ret = smsc75xx_enter_suspend2(dev); |
1379 | goto done; | ||
1379 | } | 1380 | } |
1380 | 1381 | ||
1381 | if (pdata->wolopts & WAKE_PHY) { | 1382 | if (pdata->wolopts & WAKE_PHY) { |
1382 | ret = smsc75xx_enable_phy_wakeup_interrupts(dev, | 1383 | ret = smsc75xx_enable_phy_wakeup_interrupts(dev, |
1383 | (PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN)); | 1384 | (PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN)); |
1384 | check_warn_return(ret, "error enabling PHY wakeup ints\n"); | 1385 | check_warn_goto_done(ret, "error enabling PHY wakeup ints\n"); |
1385 | 1386 | ||
1386 | /* if link is down then configure EDPD and enter SUSPEND1, | 1387 | /* if link is down then configure EDPD and enter SUSPEND1, |
1387 | * otherwise enter SUSPEND0 below | 1388 | * otherwise enter SUSPEND0 below |
@@ -1393,7 +1394,7 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1393 | /* enable energy detect power-down mode */ | 1394 | /* enable energy detect power-down mode */ |
1394 | ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, | 1395 | ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, |
1395 | PHY_MODE_CTRL_STS); | 1396 | PHY_MODE_CTRL_STS); |
1396 | check_warn_return(ret, "Error reading PHY_MODE_CTRL_STS\n"); | 1397 | check_warn_goto_done(ret, "Error reading PHY_MODE_CTRL_STS\n"); |
1397 | 1398 | ||
1398 | ret |= MODE_CTRL_STS_EDPWRDOWN; | 1399 | ret |= MODE_CTRL_STS_EDPWRDOWN; |
1399 | 1400 | ||
@@ -1401,7 +1402,8 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1401 | PHY_MODE_CTRL_STS, ret); | 1402 | PHY_MODE_CTRL_STS, ret); |
1402 | 1403 | ||
1403 | /* enter SUSPEND1 mode */ | 1404 | /* enter SUSPEND1 mode */ |
1404 | return smsc75xx_enter_suspend1(dev); | 1405 | ret = smsc75xx_enter_suspend1(dev); |
1406 | goto done; | ||
1405 | } | 1407 | } |
1406 | } | 1408 | } |
1407 | 1409 | ||
@@ -1411,7 +1413,7 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1411 | /* disable all filters */ | 1413 | /* disable all filters */ |
1412 | for (i = 0; i < WUF_NUM; i++) { | 1414 | for (i = 0; i < WUF_NUM; i++) { |
1413 | ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0); | 1415 | ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0); |
1414 | check_warn_return(ret, "Error writing WUF_CFGX\n"); | 1416 | check_warn_goto_done(ret, "Error writing WUF_CFGX\n"); |
1415 | } | 1417 | } |
1416 | 1418 | ||
1417 | if (pdata->wolopts & WAKE_MCAST) { | 1419 | if (pdata->wolopts & WAKE_MCAST) { |
@@ -1421,7 +1423,7 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1421 | val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST | 1423 | val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST |
1422 | | smsc_crc(mcast, 3); | 1424 | | smsc_crc(mcast, 3); |
1423 | ret = smsc75xx_write_wuff(dev, filter++, val, 0x0007); | 1425 | ret = smsc75xx_write_wuff(dev, filter++, val, 0x0007); |
1424 | check_warn_return(ret, "Error writing wakeup filter\n"); | 1426 | check_warn_goto_done(ret, "Error writing wakeup filter\n"); |
1425 | } | 1427 | } |
1426 | 1428 | ||
1427 | if (pdata->wolopts & WAKE_ARP) { | 1429 | if (pdata->wolopts & WAKE_ARP) { |
@@ -1431,106 +1433,111 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |||
1431 | val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16) | 1433 | val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16) |
1432 | | smsc_crc(arp, 2); | 1434 | | smsc_crc(arp, 2); |
1433 | ret = smsc75xx_write_wuff(dev, filter++, val, 0x0003); | 1435 | ret = smsc75xx_write_wuff(dev, filter++, val, 0x0003); |
1434 | check_warn_return(ret, "Error writing wakeup filter\n"); | 1436 | check_warn_goto_done(ret, "Error writing wakeup filter\n"); |
1435 | } | 1437 | } |
1436 | 1438 | ||
1437 | /* clear any pending pattern match packet status */ | 1439 | /* clear any pending pattern match packet status */ |
1438 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1440 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1439 | check_warn_return(ret, "Error reading WUCSR\n"); | 1441 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1440 | 1442 | ||
1441 | val |= WUCSR_WUFR; | 1443 | val |= WUCSR_WUFR; |
1442 | 1444 | ||
1443 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1445 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1444 | check_warn_return(ret, "Error writing WUCSR\n"); | 1446 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1445 | 1447 | ||
1446 | netdev_info(dev->net, "enabling packet match detection\n"); | 1448 | netdev_info(dev->net, "enabling packet match detection\n"); |
1447 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1449 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1448 | check_warn_return(ret, "Error reading WUCSR\n"); | 1450 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1449 | 1451 | ||
1450 | val |= WUCSR_WUEN; | 1452 | val |= WUCSR_WUEN; |
1451 | 1453 | ||
1452 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1454 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1453 | check_warn_return(ret, "Error writing WUCSR\n"); | 1455 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1454 | } else { | 1456 | } else { |
1455 | netdev_info(dev->net, "disabling packet match detection\n"); | 1457 | netdev_info(dev->net, "disabling packet match detection\n"); |
1456 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1458 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1457 | check_warn_return(ret, "Error reading WUCSR\n"); | 1459 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1458 | 1460 | ||
1459 | val &= ~WUCSR_WUEN; | 1461 | val &= ~WUCSR_WUEN; |
1460 | 1462 | ||
1461 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1463 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1462 | check_warn_return(ret, "Error writing WUCSR\n"); | 1464 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1463 | } | 1465 | } |
1464 | 1466 | ||
1465 | /* disable magic, bcast & unicast wakeup sources */ | 1467 | /* disable magic, bcast & unicast wakeup sources */ |
1466 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1468 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1467 | check_warn_return(ret, "Error reading WUCSR\n"); | 1469 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1468 | 1470 | ||
1469 | val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN); | 1471 | val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN); |
1470 | 1472 | ||
1471 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1473 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1472 | check_warn_return(ret, "Error writing WUCSR\n"); | 1474 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1473 | 1475 | ||
1474 | if (pdata->wolopts & WAKE_PHY) { | 1476 | if (pdata->wolopts & WAKE_PHY) { |
1475 | netdev_info(dev->net, "enabling PHY wakeup\n"); | 1477 | netdev_info(dev->net, "enabling PHY wakeup\n"); |
1476 | 1478 | ||
1477 | ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | 1479 | ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); |
1478 | check_warn_return(ret, "Error reading PMT_CTL\n"); | 1480 | check_warn_goto_done(ret, "Error reading PMT_CTL\n"); |
1479 | 1481 | ||
1480 | /* clear wol status, enable energy detection */ | 1482 | /* clear wol status, enable energy detection */ |
1481 | val &= ~PMT_CTL_WUPS; | 1483 | val &= ~PMT_CTL_WUPS; |
1482 | val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN); | 1484 | val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN); |
1483 | 1485 | ||
1484 | ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | 1486 | ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); |
1485 | check_warn_return(ret, "Error writing PMT_CTL\n"); | 1487 | check_warn_goto_done(ret, "Error writing PMT_CTL\n"); |
1486 | } | 1488 | } |
1487 | 1489 | ||
1488 | if (pdata->wolopts & WAKE_MAGIC) { | 1490 | if (pdata->wolopts & WAKE_MAGIC) { |
1489 | netdev_info(dev->net, "enabling magic packet wakeup\n"); | 1491 | netdev_info(dev->net, "enabling magic packet wakeup\n"); |
1490 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1492 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1491 | check_warn_return(ret, "Error reading WUCSR\n"); | 1493 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1492 | 1494 | ||
1493 | /* clear any pending magic packet status */ | 1495 | /* clear any pending magic packet status */ |
1494 | val |= WUCSR_MPR | WUCSR_MPEN; | 1496 | val |= WUCSR_MPR | WUCSR_MPEN; |
1495 | 1497 | ||
1496 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1498 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1497 | check_warn_return(ret, "Error writing WUCSR\n"); | 1499 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1498 | } | 1500 | } |
1499 | 1501 | ||
1500 | if (pdata->wolopts & WAKE_BCAST) { | 1502 | if (pdata->wolopts & WAKE_BCAST) { |
1501 | netdev_info(dev->net, "enabling broadcast detection\n"); | 1503 | netdev_info(dev->net, "enabling broadcast detection\n"); |
1502 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1504 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1503 | check_warn_return(ret, "Error reading WUCSR\n"); | 1505 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1504 | 1506 | ||
1505 | val |= WUCSR_BCAST_FR | WUCSR_BCST_EN; | 1507 | val |= WUCSR_BCAST_FR | WUCSR_BCST_EN; |
1506 | 1508 | ||
1507 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1509 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1508 | check_warn_return(ret, "Error writing WUCSR\n"); | 1510 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1509 | } | 1511 | } |
1510 | 1512 | ||
1511 | if (pdata->wolopts & WAKE_UCAST) { | 1513 | if (pdata->wolopts & WAKE_UCAST) { |
1512 | netdev_info(dev->net, "enabling unicast detection\n"); | 1514 | netdev_info(dev->net, "enabling unicast detection\n"); |
1513 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | 1515 | ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); |
1514 | check_warn_return(ret, "Error reading WUCSR\n"); | 1516 | check_warn_goto_done(ret, "Error reading WUCSR\n"); |
1515 | 1517 | ||
1516 | val |= WUCSR_WUFR | WUCSR_PFDA_EN; | 1518 | val |= WUCSR_WUFR | WUCSR_PFDA_EN; |
1517 | 1519 | ||
1518 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | 1520 | ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); |
1519 | check_warn_return(ret, "Error writing WUCSR\n"); | 1521 | check_warn_goto_done(ret, "Error writing WUCSR\n"); |
1520 | } | 1522 | } |
1521 | 1523 | ||
1522 | /* enable receiver to enable frame reception */ | 1524 | /* enable receiver to enable frame reception */ |
1523 | ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val); | 1525 | ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val); |
1524 | check_warn_return(ret, "Failed to read MAC_RX: %d\n", ret); | 1526 | check_warn_goto_done(ret, "Failed to read MAC_RX: %d\n", ret); |
1525 | 1527 | ||
1526 | val |= MAC_RX_RXEN; | 1528 | val |= MAC_RX_RXEN; |
1527 | 1529 | ||
1528 | ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val); | 1530 | ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val); |
1529 | check_warn_return(ret, "Failed to write MAC_RX: %d\n", ret); | 1531 | check_warn_goto_done(ret, "Failed to write MAC_RX: %d\n", ret); |
1530 | 1532 | ||
1531 | /* some wol options are enabled, so enter SUSPEND0 */ | 1533 | /* some wol options are enabled, so enter SUSPEND0 */ |
1532 | netdev_info(dev->net, "entering SUSPEND0 mode\n"); | 1534 | netdev_info(dev->net, "entering SUSPEND0 mode\n"); |
1533 | return smsc75xx_enter_suspend0(dev); | 1535 | ret = smsc75xx_enter_suspend0(dev); |
1536 | |||
1537 | done: | ||
1538 | if (ret) | ||
1539 | usbnet_resume(intf); | ||
1540 | return ret; | ||
1534 | } | 1541 | } |
1535 | 1542 | ||
1536 | static int smsc75xx_resume(struct usb_interface *intf) | 1543 | static int smsc75xx_resume(struct usb_interface *intf) |