Skip to content

Commit 899a391

Browse files
steveglendavem330
authored andcommitted
smsc75xx: add wol support for more frame types
This patch adds support for wol wakeup on unicast, broadcast, multicast and arp frames. Signed-off-by: Steve Glendinning <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4f99ad5 commit 899a391

File tree

2 files changed

+124
-33
lines changed

2 files changed

+124
-33
lines changed

drivers/net/usb/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ config USB_NET_DM9601
248248
config USB_NET_SMSC75XX
249249
tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
250250
depends on USB_USBNET
251+
select BITREVERSE
252+
select CRC16
251253
select CRC32
252254
help
253255
This option adds support for SMSC LAN95XX based USB 2.0

drivers/net/usb/smsc75xx.c

Lines changed: 122 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <linux/ethtool.h>
2727
#include <linux/mii.h>
2828
#include <linux/usb.h>
29+
#include <linux/bitrev.h>
30+
#include <linux/crc16.h>
2931
#include <linux/crc32.h>
3032
#include <linux/usb/usbnet.h>
3133
#include <linux/slab.h>
@@ -52,7 +54,8 @@
5254
#define USB_PRODUCT_ID_LAN7500 (0x7500)
5355
#define USB_PRODUCT_ID_LAN7505 (0x7505)
5456
#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)
5659

5760
#define check_warn(ret, fmt, args...) \
5861
({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
@@ -1143,6 +1146,36 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
11431146
}
11441147
}
11451148

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+
11461179
static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
11471180
{
11481181
struct usbnet *dev = usb_get_intfdata(intf);
@@ -1187,42 +1220,107 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
11871220
return 0;
11881221
}
11891222

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");
11921271
ret = smsc75xx_read_reg(dev, WUCSR, &val);
11931272
check_warn_return(ret, "Error reading WUCSR");
11941273

1195-
val |= WUCSR_MPR;
1274+
val &= ~WUCSR_WUEN;
11961275

11971276
ret = smsc75xx_write_reg(dev, WUCSR, val);
11981277
check_warn_return(ret, "Error writing WUCSR");
11991278
}
12001279

1201-
/* enable/disable magic packup wake */
1280+
/* disable magic, bcast & unicast wakeup sources */
12021281
ret = smsc75xx_read_reg(dev, WUCSR, &val);
12031282
check_warn_return(ret, "Error reading WUCSR");
12041283

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+
12051289
if (pdata->wolopts & WAKE_MAGIC) {
12061290
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");
12111299
}
12121300

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");
12151305

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;
12191307

1220-
val |= PMT_CTL_WOL_EN;
1308+
ret = smsc75xx_write_reg(dev, WUCSR, val);
1309+
check_warn_return(ret, "Error writing WUCSR");
1310+
}
12211311

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;
12241318

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 */
12261324
ret = smsc75xx_read_reg(dev, MAC_RX, &val);
12271325
check_warn_return(ret, "Failed to read MAC_RX: %d", ret);
12281326

@@ -1237,22 +1335,12 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
12371335
ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
12381336
check_warn_return(ret, "Error reading PMT_CTL");
12391337

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;
12451340

1246-
/* clear wol status */
1247-
val &= ~PMT_CTL_WUPS;
1248-
val |= PMT_CTL_WUPS_WOL;
12491341
ret = smsc75xx_write_reg(dev, PMT_CTL, val);
12501342
check_warn_return(ret, "Error writing PMT_CTL");
12511343

1252-
/* read back PMT_CTL */
1253-
ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
1254-
check_warn_return(ret, "Error reading PMT_CTL");
1255-
12561344
smsc75xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
12571345

12581346
return 0;
@@ -1265,16 +1353,17 @@ static int smsc75xx_resume(struct usb_interface *intf)
12651353
int ret;
12661354
u32 val;
12671355

1268-
if (pdata->wolopts & WAKE_MAGIC) {
1356+
if (pdata->wolopts) {
12691357
netdev_info(dev->net, "resuming from SUSPEND0");
12701358

12711359
smsc75xx_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
12721360

1273-
/* Disable magic packup wake */
1361+
/* Disable wakeup sources */
12741362
ret = smsc75xx_read_reg(dev, WUCSR, &val);
12751363
check_warn_return(ret, "Error reading WUCSR");
12761364

1277-
val &= ~WUCSR_MPEN;
1365+
val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN
1366+
| WUCSR_BCST_EN);
12781367

12791368
ret = smsc75xx_write_reg(dev, WUCSR, val);
12801369
check_warn_return(ret, "Error writing WUCSR");

0 commit comments

Comments
 (0)