Revert "Revert "usbnet: smsc95xx: Fix deadlock on runtime resume""
authorDom Cobley <popcornmix@gmail.com>
Mon, 5 Sep 2022 11:45:09 +0000 (12:45 +0100)
committerDom Cobley <popcornmix@gmail.com>
Mon, 5 Sep 2022 11:45:09 +0000 (12:45 +0100)
This reverts commit 2f82838ec69a86ffe786e57a37d4bcf746760017.

drivers/net/usb/smsc95xx.c

index 4fd95c8..cedd187 100644 (file)
@@ -70,6 +70,7 @@ struct smsc95xx_priv {
        struct fwnode_handle *irqfwnode;
        struct mii_bus *mdiobus;
        struct phy_device *phydev;
+       struct task_struct *pm_task;
 };
 
 static bool turbo_mode = true;
@@ -91,13 +92,14 @@ MODULE_PARM_DESC(macaddr, "MAC address");
 static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
                                            u32 *data, int in_pm)
 {
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        u32 buf;
        int ret;
        int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
 
        BUG_ON(!dev);
 
-       if (!in_pm)
+       if (current != pdata->pm_task)
                fn = usbnet_read_cmd;
        else
                fn = usbnet_read_cmd_nopm;
@@ -121,13 +123,14 @@ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
 static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index,
                                             u32 data, int in_pm)
 {
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        u32 buf;
        int ret;
        int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
 
        BUG_ON(!dev);
 
-       if (!in_pm)
+       if (current != pdata->pm_task)
                fn = usbnet_write_cmd;
        else
                fn = usbnet_write_cmd_nopm;
@@ -1546,9 +1549,12 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
        u32 val, link_up;
        int ret;
 
+       pdata->pm_task = current;
+
        ret = usbnet_suspend(intf, message);
        if (ret < 0) {
                netdev_warn(dev->net, "usbnet_suspend error\n");
+               pdata->pm_task = NULL;
                return ret;
        }
 
@@ -1788,6 +1794,7 @@ done:
        if (ret && PMSG_IS_AUTO(message))
                usbnet_resume(intf);
 
+       pdata->pm_task = NULL;
        return ret;
 }
 
@@ -1808,29 +1815,31 @@ static int smsc95xx_resume(struct usb_interface *intf)
        /* do this first to ensure it's cleared even in error case */
        pdata->suspend_flags = 0;
 
+       pdata->pm_task = current;
+
        if (suspend_flags & SUSPEND_ALLMODES) {
                /* clear wake-up sources */
                ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
 
                ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                /* clear wake-up status */
                ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                val &= ~PM_CTL_WOL_EN_;
                val |= PM_CTL_WUPS_;
 
                ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
                if (ret < 0)
-                       return ret;
+                       goto done;
        }
 
        phy_init_hw(pdata->phydev);
@@ -1839,15 +1848,20 @@ static int smsc95xx_resume(struct usb_interface *intf)
        if (ret < 0)
                netdev_warn(dev->net, "usbnet_resume error\n");
 
+done:
+       pdata->pm_task = NULL;
        return ret;
 }
 
 static int smsc95xx_reset_resume(struct usb_interface *intf)
 {
        struct usbnet *dev = usb_get_intfdata(intf);
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        int ret;
 
+       pdata->pm_task = current;
        ret = smsc95xx_reset(dev);
+       pdata->pm_task = NULL;
        if (ret < 0)
                return ret;