aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/usb/smsc95xx.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 124e67f7eed3..6a74a68220be 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -55,6 +55,13 @@
55#define FEATURE_PHY_NLP_CROSSOVER (0x02) 55#define FEATURE_PHY_NLP_CROSSOVER (0x02)
56#define FEATURE_AUTOSUSPEND (0x04) 56#define FEATURE_AUTOSUSPEND (0x04)
57 57
58#define SUSPEND_SUSPEND0 (0x01)
59#define SUSPEND_SUSPEND1 (0x02)
60#define SUSPEND_SUSPEND2 (0x04)
61#define SUSPEND_SUSPEND3 (0x08)
62#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
63 SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
64
58struct smsc95xx_priv { 65struct smsc95xx_priv {
59 u32 mac_cr; 66 u32 mac_cr;
60 u32 hash_hi; 67 u32 hash_hi;
@@ -62,6 +69,7 @@ struct smsc95xx_priv {
62 u32 wolopts; 69 u32 wolopts;
63 spinlock_t mac_cr_lock; 70 spinlock_t mac_cr_lock;
64 u8 features; 71 u8 features;
72 u8 suspend_flags;
65}; 73};
66 74
67static bool turbo_mode = true; 75static bool turbo_mode = true;
@@ -1242,6 +1250,8 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
1242 /* read back PM_CTRL */ 1250 /* read back PM_CTRL */
1243 ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); 1251 ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
1244 1252
1253 pdata->suspend_flags |= SUSPEND_SUSPEND0;
1254
1245 return ret; 1255 return ret;
1246} 1256}
1247 1257
@@ -1286,11 +1296,14 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev)
1286 1296
1287 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); 1297 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1288 1298
1299 pdata->suspend_flags |= SUSPEND_SUSPEND1;
1300
1289 return ret; 1301 return ret;
1290} 1302}
1291 1303
1292static int smsc95xx_enter_suspend2(struct usbnet *dev) 1304static int smsc95xx_enter_suspend2(struct usbnet *dev)
1293{ 1305{
1306 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1294 u32 val; 1307 u32 val;
1295 int ret; 1308 int ret;
1296 1309
@@ -1303,9 +1316,97 @@ static int smsc95xx_enter_suspend2(struct usbnet *dev)
1303 1316
1304 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); 1317 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1305 1318
1319 pdata->suspend_flags |= SUSPEND_SUSPEND2;
1320
1306 return ret; 1321 return ret;
1307} 1322}
1308 1323
1324static int smsc95xx_enter_suspend3(struct usbnet *dev)
1325{
1326 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1327 u32 val;
1328 int ret;
1329
1330 ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val);
1331 if (ret < 0)
1332 return ret;
1333
1334 if (val & 0xFFFF) {
1335 netdev_info(dev->net, "rx fifo not empty in autosuspend\n");
1336 return -EBUSY;
1337 }
1338
1339 ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
1340 if (ret < 0)
1341 return ret;
1342
1343 val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
1344 val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
1345
1346 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1347 if (ret < 0)
1348 return ret;
1349
1350 /* clear wol status */
1351 val &= ~PM_CTL_WUPS_;
1352 val |= PM_CTL_WUPS_WOL_;
1353
1354 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1355 if (ret < 0)
1356 return ret;
1357
1358 pdata->suspend_flags |= SUSPEND_SUSPEND3;
1359
1360 return 0;
1361}
1362
1363static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up)
1364{
1365 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1366 int ret;
1367
1368 if (!netif_running(dev->net)) {
1369 /* interface is ifconfig down so fully power down hw */
1370 netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
1371 return smsc95xx_enter_suspend2(dev);
1372 }
1373
1374 if (!link_up) {
1375 /* link is down so enter EDPD mode, but only if device can
1376 * reliably resume from it. This check should be redundant
1377 * as current FEATURE_AUTOSUSPEND parts also support
1378 * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */
1379 if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) {
1380 netdev_warn(dev->net, "EDPD not supported\n");
1381 return -EBUSY;
1382 }
1383
1384 netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
1385
1386 /* enable PHY wakeup events for if cable is attached */
1387 ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
1388 PHY_INT_MASK_ANEG_COMP_);
1389 if (ret < 0) {
1390 netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
1391 return ret;
1392 }
1393
1394 netdev_info(dev->net, "entering SUSPEND1 mode\n");
1395 return smsc95xx_enter_suspend1(dev);
1396 }
1397
1398 /* enable PHY wakeup events so we remote wakeup if cable is pulled */
1399 ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
1400 PHY_INT_MASK_LINK_DOWN_);
1401 if (ret < 0) {
1402 netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
1403 return ret;
1404 }
1405
1406 netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
1407 return smsc95xx_enter_suspend3(dev);
1408}
1409
1309static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) 1410static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
1310{ 1411{
1311 struct usbnet *dev = usb_get_intfdata(intf); 1412 struct usbnet *dev = usb_get_intfdata(intf);
@@ -1313,15 +1414,35 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
1313 u32 val, link_up; 1414 u32 val, link_up;
1314 int ret; 1415 int ret;
1315 1416
1417 /* TODO: don't indicate this feature to usb framework if
1418 * our current hardware doesn't have the capability
1419 */
1420 if ((message.event == PM_EVENT_AUTO_SUSPEND) &&
1421 (!(pdata->features & FEATURE_AUTOSUSPEND))) {
1422 netdev_warn(dev->net, "autosuspend not supported\n");
1423 return -EBUSY;
1424 }
1425
1316 ret = usbnet_suspend(intf, message); 1426 ret = usbnet_suspend(intf, message);
1317 if (ret < 0) { 1427 if (ret < 0) {
1318 netdev_warn(dev->net, "usbnet_suspend error\n"); 1428 netdev_warn(dev->net, "usbnet_suspend error\n");
1319 return ret; 1429 return ret;
1320 } 1430 }
1321 1431
1432 if (pdata->suspend_flags) {
1433 netdev_warn(dev->net, "error during last resume\n");
1434 pdata->suspend_flags = 0;
1435 }
1436
1322 /* determine if link is up using only _nopm functions */ 1437 /* determine if link is up using only _nopm functions */
1323 link_up = smsc95xx_link_ok_nopm(dev); 1438 link_up = smsc95xx_link_ok_nopm(dev);
1324 1439
1440 if (message.event == PM_EVENT_AUTO_SUSPEND) {
1441 ret = smsc95xx_autosuspend(dev, link_up);
1442 goto done;
1443 }
1444
1445 /* if we get this far we're not autosuspending */
1325 /* if no wol options set, or if link is down and we're not waking on 1446 /* if no wol options set, or if link is down and we're not waking on
1326 * PHY activity, enter lowest power SUSPEND2 mode 1447 * PHY activity, enter lowest power SUSPEND2 mode
1327 */ 1448 */
@@ -1552,12 +1673,18 @@ static int smsc95xx_resume(struct usb_interface *intf)
1552{ 1673{
1553 struct usbnet *dev = usb_get_intfdata(intf); 1674 struct usbnet *dev = usb_get_intfdata(intf);
1554 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); 1675 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1676 u8 suspend_flags = pdata->suspend_flags;
1555 int ret; 1677 int ret;
1556 u32 val; 1678 u32 val;
1557 1679
1558 BUG_ON(!dev); 1680 BUG_ON(!dev);
1559 1681
1560 if (pdata->wolopts) { 1682 netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
1683
1684 /* do this first to ensure it's cleared even in error case */
1685 pdata->suspend_flags = 0;
1686
1687 if (suspend_flags & SUSPEND_ALLMODES) {
1561 /* clear wake-up sources */ 1688 /* clear wake-up sources */
1562 ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); 1689 ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
1563 if (ret < 0) 1690 if (ret < 0)
@@ -1741,6 +1868,26 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
1741 return skb; 1868 return skb;
1742} 1869}
1743 1870
1871static int smsc95xx_manage_power(struct usbnet *dev, int on)
1872{
1873 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1874
1875 dev->intf->needs_remote_wakeup = on;
1876
1877 if (pdata->features & FEATURE_AUTOSUSPEND)
1878 return 0;
1879
1880 /* this chip revision doesn't support autosuspend */
1881 netdev_info(dev->net, "hardware doesn't support USB autosuspend\n");
1882
1883 if (on)
1884 usb_autopm_get_interface_no_resume(dev->intf);
1885 else
1886 usb_autopm_put_interface(dev->intf);
1887
1888 return 0;
1889}
1890
1744static const struct driver_info smsc95xx_info = { 1891static const struct driver_info smsc95xx_info = {
1745 .description = "smsc95xx USB 2.0 Ethernet", 1892 .description = "smsc95xx USB 2.0 Ethernet",
1746 .bind = smsc95xx_bind, 1893 .bind = smsc95xx_bind,
@@ -1750,6 +1897,7 @@ static const struct driver_info smsc95xx_info = {
1750 .rx_fixup = smsc95xx_rx_fixup, 1897 .rx_fixup = smsc95xx_rx_fixup,
1751 .tx_fixup = smsc95xx_tx_fixup, 1898 .tx_fixup = smsc95xx_tx_fixup,
1752 .status = smsc95xx_status, 1899 .status = smsc95xx_status,
1900 .manage_power = smsc95xx_manage_power,
1753 .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, 1901 .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
1754}; 1902};
1755 1903
@@ -1857,6 +2005,7 @@ static struct usb_driver smsc95xx_driver = {
1857 .reset_resume = smsc95xx_resume, 2005 .reset_resume = smsc95xx_resume,
1858 .disconnect = usbnet_disconnect, 2006 .disconnect = usbnet_disconnect,
1859 .disable_hub_initiated_lpm = 1, 2007 .disable_hub_initiated_lpm = 1,
2008 .supports_autosuspend = 1,
1860}; 2009};
1861 2010
1862module_usb_driver(smsc95xx_driver); 2011module_usb_driver(smsc95xx_driver);