|
@@ -85,18 +85,23 @@ static bool turbo_mode = true;
|
|
|
module_param(turbo_mode, bool, 0644);
|
|
|
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
|
|
|
|
|
|
-static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index,
|
|
|
- u32 *data)
|
|
|
+static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
|
|
|
+ u32 *data, int in_pm)
|
|
|
{
|
|
|
u32 buf;
|
|
|
int ret;
|
|
|
+ int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
|
|
|
|
|
|
BUG_ON(!dev);
|
|
|
|
|
|
- ret = usbnet_read_cmd(dev, USB_VENDOR_REQUEST_READ_REGISTER,
|
|
|
- USB_DIR_IN | USB_TYPE_VENDOR |
|
|
|
- USB_RECIP_DEVICE,
|
|
|
- 0, index, &buf, 4);
|
|
|
+ if (!in_pm)
|
|
|
+ fn = usbnet_read_cmd;
|
|
|
+ else
|
|
|
+ fn = usbnet_read_cmd_nopm;
|
|
|
+
|
|
|
+ ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
|
|
|
+ | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
|
+ 0, index, &buf, 4);
|
|
|
if (unlikely(ret < 0))
|
|
|
netdev_warn(dev->net,
|
|
|
"Failed to read reg index 0x%08x: %d", index, ret);
|
|
@@ -107,21 +112,26 @@ static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
|
|
|
- u32 data)
|
|
|
+static int __must_check __smsc75xx_write_reg(struct usbnet *dev, u32 index,
|
|
|
+ u32 data, int in_pm)
|
|
|
{
|
|
|
u32 buf;
|
|
|
int ret;
|
|
|
+ int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
|
|
|
|
|
|
BUG_ON(!dev);
|
|
|
|
|
|
+ if (!in_pm)
|
|
|
+ fn = usbnet_write_cmd;
|
|
|
+ else
|
|
|
+ fn = usbnet_write_cmd_nopm;
|
|
|
+
|
|
|
buf = data;
|
|
|
cpu_to_le32s(&buf);
|
|
|
|
|
|
- ret = usbnet_write_cmd(dev, USB_VENDOR_REQUEST_WRITE_REGISTER,
|
|
|
- USB_DIR_OUT | USB_TYPE_VENDOR |
|
|
|
- USB_RECIP_DEVICE,
|
|
|
- 0, index, &buf, 4);
|
|
|
+ ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT
|
|
|
+ | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
|
+ 0, index, &buf, 4);
|
|
|
if (unlikely(ret < 0))
|
|
|
netdev_warn(dev->net,
|
|
|
"Failed to write reg index 0x%08x: %d", index, ret);
|
|
@@ -129,16 +139,38 @@ static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int __must_check smsc75xx_read_reg_nopm(struct usbnet *dev, u32 index,
|
|
|
+ u32 *data)
|
|
|
+{
|
|
|
+ return __smsc75xx_read_reg(dev, index, data, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static int __must_check smsc75xx_write_reg_nopm(struct usbnet *dev, u32 index,
|
|
|
+ u32 data)
|
|
|
+{
|
|
|
+ return __smsc75xx_write_reg(dev, index, data, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index,
|
|
|
+ u32 *data)
|
|
|
+{
|
|
|
+ return __smsc75xx_read_reg(dev, index, data, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
|
|
|
+ u32 data)
|
|
|
+{
|
|
|
+ return __smsc75xx_write_reg(dev, index, data, 0);
|
|
|
+}
|
|
|
+
|
|
|
static int smsc75xx_set_feature(struct usbnet *dev, u32 feature)
|
|
|
{
|
|
|
if (WARN_ON_ONCE(!dev))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- cpu_to_le32s(&feature);
|
|
|
-
|
|
|
- return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
|
|
|
- USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
|
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
|
+ return usbnet_write_cmd_nopm(dev, USB_REQ_SET_FEATURE,
|
|
|
+ USB_DIR_OUT | USB_RECIP_DEVICE,
|
|
|
+ feature, 0, NULL, 0);
|
|
|
}
|
|
|
|
|
|
static int smsc75xx_clear_feature(struct usbnet *dev, u32 feature)
|
|
@@ -146,11 +178,9 @@ static int smsc75xx_clear_feature(struct usbnet *dev, u32 feature)
|
|
|
if (WARN_ON_ONCE(!dev))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- cpu_to_le32s(&feature);
|
|
|
-
|
|
|
- return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
|
|
|
- USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, feature, 0, NULL, 0,
|
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
|
+ return usbnet_write_cmd_nopm(dev, USB_REQ_CLEAR_FEATURE,
|
|
|
+ USB_DIR_OUT | USB_RECIP_DEVICE,
|
|
|
+ feature, 0, NULL, 0);
|
|
|
}
|
|
|
|
|
|
/* Loop until the read is completed with timeout
|
|
@@ -796,13 +826,16 @@ static int smsc75xx_set_features(struct net_device *netdev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int smsc75xx_wait_ready(struct usbnet *dev)
|
|
|
+static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
|
|
|
{
|
|
|
int timeout = 0;
|
|
|
|
|
|
do {
|
|
|
u32 buf;
|
|
|
- int ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = __smsc75xx_read_reg(dev, PMT_CTL, &buf, in_pm);
|
|
|
+
|
|
|
check_warn_return(ret, "Failed to read PMT_CTL: %d", ret);
|
|
|
|
|
|
if (buf & PMT_CTL_DEV_RDY)
|
|
@@ -824,7 +857,7 @@ static int smsc75xx_reset(struct usbnet *dev)
|
|
|
|
|
|
netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset");
|
|
|
|
|
|
- ret = smsc75xx_wait_ready(dev);
|
|
|
+ ret = smsc75xx_wait_ready(dev, 0);
|
|
|
check_warn_return(ret, "device not ready in smsc75xx_reset");
|
|
|
|
|
|
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
|
|
@@ -1191,30 +1224,30 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
|
|
|
netdev_info(dev->net, "entering SUSPEND2 mode");
|
|
|
|
|
|
/* disable energy detect (link up) & wake up events */
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val &= ~(WUCSR_MPEN | WUCSR_WUEN);
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
|
|
|
- ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
|
|
|
check_warn_return(ret, "Error reading PMT_CTL");
|
|
|
|
|
|
val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN);
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, PMT_CTL, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
|
|
|
check_warn_return(ret, "Error writing PMT_CTL");
|
|
|
|
|
|
/* enter suspend2 mode */
|
|
|
- ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
|
|
|
check_warn_return(ret, "Error reading PMT_CTL");
|
|
|
|
|
|
val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
|
|
|
val |= PMT_CTL_SUS_MODE_2;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, PMT_CTL, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
|
|
|
check_warn_return(ret, "Error writing PMT_CTL");
|
|
|
|
|
|
return 0;
|
|
@@ -1225,7 +1258,7 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
|
|
|
|
|
|
/* disable all filters */
|
|
|
for (i = 0; i < WUF_NUM; i++) {
|
|
|
- ret = smsc75xx_write_reg(dev, WUF_CFGX + i * 4, 0);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0);
|
|
|
check_warn_return(ret, "Error writing WUF_CFGX");
|
|
|
}
|
|
|
|
|
@@ -1250,95 +1283,95 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
|
|
|
}
|
|
|
|
|
|
/* clear any pending pattern match packet status */
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val |= WUCSR_WUFR;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
|
|
|
netdev_info(dev->net, "enabling packet match detection");
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val |= WUCSR_WUEN;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
} else {
|
|
|
netdev_info(dev->net, "disabling packet match detection");
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val &= ~WUCSR_WUEN;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
}
|
|
|
|
|
|
/* disable magic, bcast & unicast wakeup sources */
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN);
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
|
|
|
if (pdata->wolopts & WAKE_MAGIC) {
|
|
|
netdev_info(dev->net, "enabling magic packet wakeup");
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
/* clear any pending magic packet status */
|
|
|
val |= WUCSR_MPR | WUCSR_MPEN;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
}
|
|
|
|
|
|
if (pdata->wolopts & WAKE_BCAST) {
|
|
|
netdev_info(dev->net, "enabling broadcast detection");
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val |= WUCSR_BCAST_FR | WUCSR_BCST_EN;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
}
|
|
|
|
|
|
if (pdata->wolopts & WAKE_UCAST) {
|
|
|
netdev_info(dev->net, "enabling unicast detection");
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val |= WUCSR_WUFR | WUCSR_PFDA_EN;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
}
|
|
|
|
|
|
/* enable receiver to enable frame reception */
|
|
|
- ret = smsc75xx_read_reg(dev, MAC_RX, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val);
|
|
|
check_warn_return(ret, "Failed to read MAC_RX: %d", ret);
|
|
|
|
|
|
val |= MAC_RX_RXEN;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, MAC_RX, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val);
|
|
|
check_warn_return(ret, "Failed to write MAC_RX: %d", ret);
|
|
|
|
|
|
/* some wol options are enabled, so enter SUSPEND0 */
|
|
|
netdev_info(dev->net, "entering SUSPEND0 mode");
|
|
|
|
|
|
- ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
|
|
|
check_warn_return(ret, "Error reading PMT_CTL");
|
|
|
|
|
|
val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_PHY_RST));
|
|
|
val |= PMT_CTL_SUS_MODE_0 | PMT_CTL_WOL_EN | PMT_CTL_WUPS;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, PMT_CTL, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
|
|
|
check_warn_return(ret, "Error writing PMT_CTL");
|
|
|
|
|
|
smsc75xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
|
|
@@ -1359,37 +1392,37 @@ static int smsc75xx_resume(struct usb_interface *intf)
|
|
|
smsc75xx_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
|
|
|
|
|
|
/* Disable wakeup sources */
|
|
|
- ret = smsc75xx_read_reg(dev, WUCSR, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
|
|
|
check_warn_return(ret, "Error reading WUCSR");
|
|
|
|
|
|
val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN
|
|
|
| WUCSR_BCST_EN);
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, WUCSR, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
|
|
|
check_warn_return(ret, "Error writing WUCSR");
|
|
|
|
|
|
/* clear wake-up status */
|
|
|
- ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
|
|
|
check_warn_return(ret, "Error reading PMT_CTL");
|
|
|
|
|
|
val &= ~PMT_CTL_WOL_EN;
|
|
|
val |= PMT_CTL_WUPS;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, PMT_CTL, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
|
|
|
check_warn_return(ret, "Error writing PMT_CTL");
|
|
|
} else {
|
|
|
netdev_info(dev->net, "resuming from SUSPEND2");
|
|
|
|
|
|
- ret = smsc75xx_read_reg(dev, PMT_CTL, &val);
|
|
|
+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
|
|
|
check_warn_return(ret, "Error reading PMT_CTL");
|
|
|
|
|
|
val |= PMT_CTL_PHY_PWRUP;
|
|
|
|
|
|
- ret = smsc75xx_write_reg(dev, PMT_CTL, val);
|
|
|
+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
|
|
|
check_warn_return(ret, "Error writing PMT_CTL");
|
|
|
}
|
|
|
|
|
|
- ret = smsc75xx_wait_ready(dev);
|
|
|
+ ret = smsc75xx_wait_ready(dev, 1);
|
|
|
check_warn_return(ret, "device not ready in smsc75xx_resume");
|
|
|
|
|
|
return usbnet_resume(intf);
|