26
26
#include <linux/ethtool.h>
27
27
#include <linux/mii.h>
28
28
#include <linux/usb.h>
29
+ #include <linux/bitrev.h>
30
+ #include <linux/crc16.h>
29
31
#include <linux/crc32.h>
30
32
#include <linux/usb/usbnet.h>
31
33
#include <linux/slab.h>
52
54
#define USB_PRODUCT_ID_LAN7500 (0x7500)
53
55
#define USB_PRODUCT_ID_LAN7505 (0x7505)
54
56
#define RXW_PADDING 2
55
- #define SUPPORTED_WAKE (WAKE_MAGIC)
57
+ #define SUPPORTED_WAKE (WAKE_UCAST | WAKE_BCAST | \
58
+ WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
56
59
57
60
#define check_warn (ret , fmt , args ...) \
58
61
({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
@@ -1143,6 +1146,36 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
1143
1146
}
1144
1147
}
1145
1148
1149
+ static u16 smsc_crc (const u8 * buffer , size_t len )
1150
+ {
1151
+ return bitrev16 (crc16 (0xFFFF , buffer , len ));
1152
+ }
1153
+
1154
+ static int smsc75xx_write_wuff (struct usbnet * dev , int filter , u32 wuf_cfg ,
1155
+ u32 wuf_mask1 )
1156
+ {
1157
+ int cfg_base = WUF_CFGX + filter * 4 ;
1158
+ int mask_base = WUF_MASKX + filter * 16 ;
1159
+ int ret ;
1160
+
1161
+ ret = smsc75xx_write_reg (dev , cfg_base , wuf_cfg );
1162
+ check_warn_return (ret , "Error writing WUF_CFGX" );
1163
+
1164
+ ret = smsc75xx_write_reg (dev , mask_base , wuf_mask1 );
1165
+ check_warn_return (ret , "Error writing WUF_MASKX" );
1166
+
1167
+ ret = smsc75xx_write_reg (dev , mask_base + 4 , 0 );
1168
+ check_warn_return (ret , "Error writing WUF_MASKX" );
1169
+
1170
+ ret = smsc75xx_write_reg (dev , mask_base + 8 , 0 );
1171
+ check_warn_return (ret , "Error writing WUF_MASKX" );
1172
+
1173
+ ret = smsc75xx_write_reg (dev , mask_base + 12 , 0 );
1174
+ check_warn_return (ret , "Error writing WUF_MASKX" );
1175
+
1176
+ return 0 ;
1177
+ }
1178
+
1146
1179
static int smsc75xx_suspend (struct usb_interface * intf , pm_message_t message )
1147
1180
{
1148
1181
struct usbnet * dev = usb_get_intfdata (intf );
@@ -1187,42 +1220,107 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
1187
1220
return 0 ;
1188
1221
}
1189
1222
1190
- if (pdata -> wolopts & WAKE_MAGIC ) {
1191
- /* clear any pending magic packet status */
1223
+ if (pdata -> wolopts & (WAKE_MCAST | WAKE_ARP )) {
1224
+ int i , filter = 0 ;
1225
+
1226
+ /* disable all filters */
1227
+ for (i = 0 ; i < WUF_NUM ; i ++ ) {
1228
+ ret = smsc75xx_write_reg (dev , WUF_CFGX + i * 4 , 0 );
1229
+ check_warn_return (ret , "Error writing WUF_CFGX" );
1230
+ }
1231
+
1232
+ if (pdata -> wolopts & WAKE_MCAST ) {
1233
+ const u8 mcast [] = {0x01 , 0x00 , 0x5E };
1234
+ netdev_info (dev -> net , "enabling multicast detection" );
1235
+
1236
+ val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST
1237
+ | smsc_crc (mcast , 3 );
1238
+ ret = smsc75xx_write_wuff (dev , filter ++ , val , 0x0007 );
1239
+ check_warn_return (ret , "Error writing wakeup filter" );
1240
+ }
1241
+
1242
+ if (pdata -> wolopts & WAKE_ARP ) {
1243
+ const u8 arp [] = {0x08 , 0x06 };
1244
+ netdev_info (dev -> net , "enabling ARP detection" );
1245
+
1246
+ val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16 )
1247
+ | smsc_crc (arp , 2 );
1248
+ ret = smsc75xx_write_wuff (dev , filter ++ , val , 0x0003 );
1249
+ check_warn_return (ret , "Error writing wakeup filter" );
1250
+ }
1251
+
1252
+ /* clear any pending pattern match packet status */
1253
+ ret = smsc75xx_read_reg (dev , WUCSR , & val );
1254
+ check_warn_return (ret , "Error reading WUCSR" );
1255
+
1256
+ val |= WUCSR_WUFR ;
1257
+
1258
+ ret = smsc75xx_write_reg (dev , WUCSR , val );
1259
+ check_warn_return (ret , "Error writing WUCSR" );
1260
+
1261
+ netdev_info (dev -> net , "enabling packet match detection" );
1262
+ ret = smsc75xx_read_reg (dev , WUCSR , & val );
1263
+ check_warn_return (ret , "Error reading WUCSR" );
1264
+
1265
+ val |= WUCSR_WUEN ;
1266
+
1267
+ ret = smsc75xx_write_reg (dev , WUCSR , val );
1268
+ check_warn_return (ret , "Error writing WUCSR" );
1269
+ } else {
1270
+ netdev_info (dev -> net , "disabling packet match detection" );
1192
1271
ret = smsc75xx_read_reg (dev , WUCSR , & val );
1193
1272
check_warn_return (ret , "Error reading WUCSR" );
1194
1273
1195
- val |= WUCSR_MPR ;
1274
+ val &= ~ WUCSR_WUEN ;
1196
1275
1197
1276
ret = smsc75xx_write_reg (dev , WUCSR , val );
1198
1277
check_warn_return (ret , "Error writing WUCSR" );
1199
1278
}
1200
1279
1201
- /* enable/ disable magic packup wake */
1280
+ /* disable magic, bcast & unicast wakeup sources */
1202
1281
ret = smsc75xx_read_reg (dev , WUCSR , & val );
1203
1282
check_warn_return (ret , "Error reading WUCSR" );
1204
1283
1284
+ val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN );
1285
+
1286
+ ret = smsc75xx_write_reg (dev , WUCSR , val );
1287
+ check_warn_return (ret , "Error writing WUCSR" );
1288
+
1205
1289
if (pdata -> wolopts & WAKE_MAGIC ) {
1206
1290
netdev_info (dev -> net , "enabling magic packet wakeup" );
1207
- val |= WUCSR_MPEN ;
1208
- } else {
1209
- netdev_info (dev -> net , "disabling magic packet wakeup" );
1210
- val &= ~WUCSR_MPEN ;
1291
+ ret = smsc75xx_read_reg (dev , WUCSR , & val );
1292
+ check_warn_return (ret , "Error reading WUCSR" );
1293
+
1294
+ /* clear any pending magic packet status */
1295
+ val |= WUCSR_MPR | WUCSR_MPEN ;
1296
+
1297
+ ret = smsc75xx_write_reg (dev , WUCSR , val );
1298
+ check_warn_return (ret , "Error writing WUCSR" );
1211
1299
}
1212
1300
1213
- ret = smsc75xx_write_reg (dev , WUCSR , val );
1214
- check_warn_return (ret , "Error writing WUCSR" );
1301
+ if (pdata -> wolopts & WAKE_BCAST ) {
1302
+ netdev_info (dev -> net , "enabling broadcast detection" );
1303
+ ret = smsc75xx_read_reg (dev , WUCSR , & val );
1304
+ check_warn_return (ret , "Error reading WUCSR" );
1215
1305
1216
- /* enable wol wakeup source */
1217
- ret = smsc75xx_read_reg (dev , PMT_CTL , & val );
1218
- check_warn_return (ret , "Error reading PMT_CTL" );
1306
+ val |= WUCSR_BCAST_FR | WUCSR_BCST_EN ;
1219
1307
1220
- val |= PMT_CTL_WOL_EN ;
1308
+ ret = smsc75xx_write_reg (dev , WUCSR , val );
1309
+ check_warn_return (ret , "Error writing WUCSR" );
1310
+ }
1221
1311
1222
- ret = smsc75xx_write_reg (dev , PMT_CTL , val );
1223
- check_warn_return (ret , "Error writing PMT_CTL" );
1312
+ if (pdata -> wolopts & WAKE_UCAST ) {
1313
+ netdev_info (dev -> net , "enabling unicast detection" );
1314
+ ret = smsc75xx_read_reg (dev , WUCSR , & val );
1315
+ check_warn_return (ret , "Error reading WUCSR" );
1316
+
1317
+ val |= WUCSR_WUFR | WUCSR_PFDA_EN ;
1224
1318
1225
- /* enable receiver */
1319
+ ret = smsc75xx_write_reg (dev , WUCSR , val );
1320
+ check_warn_return (ret , "Error writing WUCSR" );
1321
+ }
1322
+
1323
+ /* enable receiver to enable frame reception */
1226
1324
ret = smsc75xx_read_reg (dev , MAC_RX , & val );
1227
1325
check_warn_return (ret , "Failed to read MAC_RX: %d" , ret );
1228
1326
@@ -1237,22 +1335,12 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
1237
1335
ret = smsc75xx_read_reg (dev , PMT_CTL , & val );
1238
1336
check_warn_return (ret , "Error reading PMT_CTL" );
1239
1337
1240
- val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST ));
1241
- val |= PMT_CTL_SUS_MODE_0 ;
1242
-
1243
- ret = smsc75xx_write_reg (dev , PMT_CTL , val );
1244
- check_warn_return (ret , "Error writing PMT_CTL" );
1338
+ val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_PHY_RST ));
1339
+ val |= PMT_CTL_SUS_MODE_0 | PMT_CTL_WOL_EN | PMT_CTL_WUPS ;
1245
1340
1246
- /* clear wol status */
1247
- val &= ~PMT_CTL_WUPS ;
1248
- val |= PMT_CTL_WUPS_WOL ;
1249
1341
ret = smsc75xx_write_reg (dev , PMT_CTL , val );
1250
1342
check_warn_return (ret , "Error writing PMT_CTL" );
1251
1343
1252
- /* read back PMT_CTL */
1253
- ret = smsc75xx_read_reg (dev , PMT_CTL , & val );
1254
- check_warn_return (ret , "Error reading PMT_CTL" );
1255
-
1256
1344
smsc75xx_set_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1257
1345
1258
1346
return 0 ;
@@ -1265,16 +1353,17 @@ static int smsc75xx_resume(struct usb_interface *intf)
1265
1353
int ret ;
1266
1354
u32 val ;
1267
1355
1268
- if (pdata -> wolopts & WAKE_MAGIC ) {
1356
+ if (pdata -> wolopts ) {
1269
1357
netdev_info (dev -> net , "resuming from SUSPEND0" );
1270
1358
1271
1359
smsc75xx_clear_feature (dev , USB_DEVICE_REMOTE_WAKEUP );
1272
1360
1273
- /* Disable magic packup wake */
1361
+ /* Disable wakeup sources */
1274
1362
ret = smsc75xx_read_reg (dev , WUCSR , & val );
1275
1363
check_warn_return (ret , "Error reading WUCSR" );
1276
1364
1277
- val &= ~WUCSR_MPEN ;
1365
+ val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN
1366
+ | WUCSR_BCST_EN );
1278
1367
1279
1368
ret = smsc75xx_write_reg (dev , WUCSR , val );
1280
1369
check_warn_return (ret , "Error writing WUCSR" );
0 commit comments