57
57
#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \
58
58
WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
59
59
60
+ #define SUSPEND_SUSPEND0 (0x01)
61
+ #define SUSPEND_SUSPEND1 (0x02)
62
+ #define SUSPEND_SUSPEND2 (0x04)
63
+ #define SUSPEND_SUSPEND3 (0x08)
64
+ #define SUSPEND_REMOTEWAKE (0x10)
65
+ #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
66
+ SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
67
+
60
68
#define check_warn (ret , fmt , args ...) \
61
69
({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
62
70
@@ -74,6 +82,7 @@ struct smsc75xx_priv {
74
82
struct mutex dataport_mutex ;
75
83
spinlock_t rfe_ctl_lock ;
76
84
struct work_struct set_multicast ;
85
+ u8 suspend_flags ;
77
86
};
78
87
79
88
struct usb_context {
@@ -1241,6 +1250,7 @@ static int smsc75xx_write_wuff(struct usbnet *dev, int filter, u32 wuf_cfg,
1241
1250
1242
1251
static int smsc75xx_enter_suspend0 (struct usbnet * dev )
1243
1252
{
1253
+ struct smsc75xx_priv * pdata = (struct smsc75xx_priv * )(dev -> data [0 ]);
1244
1254
u32 val ;
1245
1255
int ret ;
1246
1256
@@ -1255,11 +1265,14 @@ static int smsc75xx_enter_suspend0(struct usbnet *dev)
1255
1265
1256
1266
smsc75xx_set_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1257
1267
1268
+ pdata -> suspend_flags |= SUSPEND_SUSPEND0 | SUSPEND_REMOTEWAKE ;
1269
+
1258
1270
return 0 ;
1259
1271
}
1260
1272
1261
1273
static int smsc75xx_enter_suspend1 (struct usbnet * dev )
1262
1274
{
1275
+ struct smsc75xx_priv * pdata = (struct smsc75xx_priv * )(dev -> data [0 ]);
1263
1276
u32 val ;
1264
1277
int ret ;
1265
1278
@@ -1281,11 +1294,14 @@ static int smsc75xx_enter_suspend1(struct usbnet *dev)
1281
1294
1282
1295
smsc75xx_set_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1283
1296
1297
+ pdata -> suspend_flags |= SUSPEND_SUSPEND1 | SUSPEND_REMOTEWAKE ;
1298
+
1284
1299
return 0 ;
1285
1300
}
1286
1301
1287
1302
static int smsc75xx_enter_suspend2 (struct usbnet * dev )
1288
1303
{
1304
+ struct smsc75xx_priv * pdata = (struct smsc75xx_priv * )(dev -> data [0 ]);
1289
1305
u32 val ;
1290
1306
int ret ;
1291
1307
@@ -1298,6 +1314,45 @@ static int smsc75xx_enter_suspend2(struct usbnet *dev)
1298
1314
ret = smsc75xx_write_reg_nopm (dev , PMT_CTL , val );
1299
1315
check_warn_return (ret , "Error writing PMT_CTL\n" );
1300
1316
1317
+ pdata -> suspend_flags |= SUSPEND_SUSPEND2 ;
1318
+
1319
+ return 0 ;
1320
+ }
1321
+
1322
+ static int smsc75xx_enter_suspend3 (struct usbnet * dev )
1323
+ {
1324
+ struct smsc75xx_priv * pdata = (struct smsc75xx_priv * )(dev -> data [0 ]);
1325
+ u32 val ;
1326
+ int ret ;
1327
+
1328
+ ret = smsc75xx_read_reg_nopm (dev , FCT_RX_CTL , & val );
1329
+ check_warn_return (ret , "Error reading FCT_RX_CTL\n" );
1330
+
1331
+ if (val & FCT_RX_CTL_RXUSED ) {
1332
+ netdev_dbg (dev -> net , "rx fifo not empty in autosuspend\n" );
1333
+ return - EBUSY ;
1334
+ }
1335
+
1336
+ ret = smsc75xx_read_reg_nopm (dev , PMT_CTL , & val );
1337
+ check_warn_return (ret , "Error reading PMT_CTL\n" );
1338
+
1339
+ val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST );
1340
+ val |= PMT_CTL_SUS_MODE_3 | PMT_CTL_RES_CLR_WKP_EN ;
1341
+
1342
+ ret = smsc75xx_write_reg_nopm (dev , PMT_CTL , val );
1343
+ check_warn_return (ret , "Error writing PMT_CTL\n" );
1344
+
1345
+ /* clear wol status */
1346
+ val &= ~PMT_CTL_WUPS ;
1347
+ val |= PMT_CTL_WUPS_WOL ;
1348
+
1349
+ ret = smsc75xx_write_reg_nopm (dev , PMT_CTL , val );
1350
+ check_warn_return (ret , "Error writing PMT_CTL\n" );
1351
+
1352
+ smsc75xx_set_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1353
+
1354
+ pdata -> suspend_flags |= SUSPEND_SUSPEND3 | SUSPEND_REMOTEWAKE ;
1355
+
1301
1356
return 0 ;
1302
1357
}
1303
1358
@@ -1338,6 +1393,38 @@ static int smsc75xx_link_ok_nopm(struct usbnet *dev)
1338
1393
return !!(ret & BMSR_LSTATUS );
1339
1394
}
1340
1395
1396
+ static int smsc75xx_autosuspend (struct usbnet * dev , u32 link_up )
1397
+ {
1398
+ int ret ;
1399
+
1400
+ if (!netif_running (dev -> net )) {
1401
+ /* interface is ifconfig down so fully power down hw */
1402
+ netdev_dbg (dev -> net , "autosuspend entering SUSPEND2\n" );
1403
+ return smsc75xx_enter_suspend2 (dev );
1404
+ }
1405
+
1406
+ if (!link_up ) {
1407
+ /* link is down so enter EDPD mode */
1408
+ netdev_dbg (dev -> net , "autosuspend entering SUSPEND1\n" );
1409
+
1410
+ /* enable PHY wakeup events for if cable is attached */
1411
+ ret = smsc75xx_enable_phy_wakeup_interrupts (dev ,
1412
+ PHY_INT_MASK_ANEG_COMP );
1413
+ check_warn_return (ret , "error enabling PHY wakeup ints\n" );
1414
+
1415
+ netdev_info (dev -> net , "entering SUSPEND1 mode\n" );
1416
+ return smsc75xx_enter_suspend1 (dev );
1417
+ }
1418
+
1419
+ /* enable PHY wakeup events so we remote wakeup if cable is pulled */
1420
+ ret = smsc75xx_enable_phy_wakeup_interrupts (dev ,
1421
+ PHY_INT_MASK_LINK_DOWN );
1422
+ check_warn_return (ret , "error enabling PHY wakeup ints\n" );
1423
+
1424
+ netdev_dbg (dev -> net , "autosuspend entering SUSPEND3\n" );
1425
+ return smsc75xx_enter_suspend3 (dev );
1426
+ }
1427
+
1341
1428
static int smsc75xx_suspend (struct usb_interface * intf , pm_message_t message )
1342
1429
{
1343
1430
struct usbnet * dev = usb_get_intfdata (intf );
@@ -1348,9 +1435,20 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
1348
1435
ret = usbnet_suspend (intf , message );
1349
1436
check_warn_goto_done (ret , "usbnet_suspend error\n" );
1350
1437
1438
+ if (pdata -> suspend_flags ) {
1439
+ netdev_warn (dev -> net , "error during last resume\n" );
1440
+ pdata -> suspend_flags = 0 ;
1441
+ }
1442
+
1351
1443
/* determine if link is up using only _nopm functions */
1352
1444
link_up = smsc75xx_link_ok_nopm (dev );
1353
1445
1446
+ if (message .event == PM_EVENT_AUTO_SUSPEND ) {
1447
+ ret = smsc75xx_autosuspend (dev , link_up );
1448
+ goto done ;
1449
+ }
1450
+
1451
+ /* if we get this far we're not autosuspending */
1354
1452
/* if no wol options set, or if link is down and we're not waking on
1355
1453
* PHY activity, enter lowest power SUSPEND2 mode
1356
1454
*/
@@ -1544,14 +1642,21 @@ static int smsc75xx_resume(struct usb_interface *intf)
1544
1642
{
1545
1643
struct usbnet * dev = usb_get_intfdata (intf );
1546
1644
struct smsc75xx_priv * pdata = (struct smsc75xx_priv * )(dev -> data [0 ]);
1645
+ u8 suspend_flags = pdata -> suspend_flags ;
1547
1646
int ret ;
1548
1647
u32 val ;
1549
1648
1550
- if (pdata -> wolopts ) {
1551
- netdev_info (dev -> net , "resuming from SUSPEND0\n" );
1649
+ netdev_dbg (dev -> net , "resume suspend_flags=0x%02x\n" , suspend_flags );
1552
1650
1553
- smsc75xx_clear_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1651
+ /* do this first to ensure it's cleared even in error case */
1652
+ pdata -> suspend_flags = 0 ;
1653
+
1654
+ if (suspend_flags & SUSPEND_REMOTEWAKE ) {
1655
+ ret = smsc75xx_clear_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1656
+ check_warn_return (ret , "Error disabling remote wakeup\n" );
1657
+ }
1554
1658
1659
+ if (suspend_flags & SUSPEND_ALLMODES ) {
1555
1660
/* Disable wakeup sources */
1556
1661
ret = smsc75xx_read_reg_nopm (dev , WUCSR , & val );
1557
1662
check_warn_return (ret , "Error reading WUCSR\n" );
@@ -1571,7 +1676,9 @@ static int smsc75xx_resume(struct usb_interface *intf)
1571
1676
1572
1677
ret = smsc75xx_write_reg_nopm (dev , PMT_CTL , val );
1573
1678
check_warn_return (ret , "Error writing PMT_CTL\n" );
1574
- } else {
1679
+ }
1680
+
1681
+ if (suspend_flags & SUSPEND_SUSPEND2 ) {
1575
1682
netdev_info (dev -> net , "resuming from SUSPEND2\n" );
1576
1683
1577
1684
ret = smsc75xx_read_reg_nopm (dev , PMT_CTL , & val );
@@ -1727,6 +1834,12 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
1727
1834
return skb ;
1728
1835
}
1729
1836
1837
+ static int smsc75xx_manage_power (struct usbnet * dev , int on )
1838
+ {
1839
+ dev -> intf -> needs_remote_wakeup = on ;
1840
+ return 0 ;
1841
+ }
1842
+
1730
1843
static const struct driver_info smsc75xx_info = {
1731
1844
.description = "smsc75xx USB 2.0 Gigabit Ethernet" ,
1732
1845
.bind = smsc75xx_bind ,
@@ -1736,6 +1849,7 @@ static const struct driver_info smsc75xx_info = {
1736
1849
.rx_fixup = smsc75xx_rx_fixup ,
1737
1850
.tx_fixup = smsc75xx_tx_fixup ,
1738
1851
.status = smsc75xx_status ,
1852
+ .manage_power = smsc75xx_manage_power ,
1739
1853
.flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR ,
1740
1854
};
1741
1855
@@ -1763,6 +1877,7 @@ static struct usb_driver smsc75xx_driver = {
1763
1877
.reset_resume = smsc75xx_resume ,
1764
1878
.disconnect = usbnet_disconnect ,
1765
1879
.disable_hub_initiated_lpm = 1 ,
1880
+ .supports_autosuspend = 1 ,
1766
1881
};
1767
1882
1768
1883
module_usb_driver (smsc75xx_driver );
0 commit comments