usbnet: smsc75xx: apply the introduced usbnet_{read|write}_cmd_nopm
authorMing Lei <ming.lei@canonical.com>
Tue, 6 Nov 2012 04:53:05 +0000 (04:53 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 7 Nov 2012 08:53:38 +0000 (03:53 -0500)
This patch applies the introduced usbnet_read_cmd_nopm() and
usbnet_write_cmd_nopm() in the callback of resume and suspend
to avoid deadlock if USB runtime PM is considered into
usbnet_read_cmd() and usbnet_write_cmd().

Cc: Steve Glendinning <steve.glendinning@shawell.net>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/smsc75xx.c

index 85d70c2dd3971131b873c89b2c12a2ede5fa32ae..c5353cfc9c8c870482aac9b06281b281b46a850e 100644 (file)
@@ -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);