staging: rtl8712: Improve suspend/resume functionality.
authorHemmo Nieminen <hemmo.nieminen@iki.fi>
Thu, 3 Dec 2015 22:11:32 +0000 (00:11 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Feb 2016 03:52:30 +0000 (19:52 -0800)
Cancel pending URBs during suspend operation to avoid receiving ESHUTDOWN
in read/write completion callbacks while the device is suspended.

Receiving ESHUTDOWN in read/write completion callbacks will cause the
driver to enter a non-functioning "stopped" state from which the driver is
unable to recover without reloading the module.

Signed-off-by: Hemmo Nieminen <hemmo.nieminen@iki.fi>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/rtl8712/drv_types.h
drivers/staging/rtl8712/usb_intf.c
drivers/staging/rtl8712/usb_ops_linux.c

index 3d64fee..29e47e1 100644 (file)
@@ -159,6 +159,7 @@ struct _adapter {
        struct mp_priv  mppriv;
        s32     bDriverStopped;
        s32     bSurpriseRemoved;
+       s32     bSuspended;
        u32     IsrContent;
        u32     ImrContent;
        u8      EepromAddressSize;
index c71333f..b64f10b 100644 (file)
@@ -205,12 +205,15 @@ struct drv_priv {
 static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state)
 {
        struct net_device *pnetdev = usb_get_intfdata(pusb_intf);
+       struct _adapter *padapter = netdev_priv(pnetdev);
 
        netdev_info(pnetdev, "Suspending...\n");
        if (!pnetdev || !netif_running(pnetdev)) {
                netdev_info(pnetdev, "Unable to suspend\n");
                return 0;
        }
+       padapter->bSuspended = true;
+       rtl871x_intf_stop(padapter);
        if (pnetdev->netdev_ops->ndo_stop)
                pnetdev->netdev_ops->ndo_stop(pnetdev);
        mdelay(10);
@@ -218,9 +221,16 @@ static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state)
        return 0;
 }
 
+void rtl871x_intf_resume(struct _adapter *padapter)
+{
+       if (padapter->dvobjpriv.inirp_init)
+               padapter->dvobjpriv.inirp_init(padapter);
+}
+
 static int r871x_resume(struct usb_interface *pusb_intf)
 {
        struct net_device *pnetdev = usb_get_intfdata(pusb_intf);
+       struct _adapter *padapter = netdev_priv(pnetdev);
 
        netdev_info(pnetdev,  "Resuming...\n");
        if (!pnetdev || !netif_running(pnetdev)) {
@@ -230,6 +240,8 @@ static int r871x_resume(struct usb_interface *pusb_intf)
        netif_device_attach(pnetdev);
        if (pnetdev->netdev_ops->ndo_open)
                pnetdev->netdev_ops->ndo_open(pnetdev);
+       padapter->bSuspended = false;
+       rtl871x_intf_resume(padapter);
        return 0;
 }
 
index 489a9e6..e77be2a 100644 (file)
@@ -228,11 +228,14 @@ static void r8712_usb_read_port_complete(struct urb *purb)
                }
        } else {
                switch (purb->status) {
+               case -ENOENT:
+                       if (padapter->bSuspended)
+                               break;
+                       /* Fall through. */
                case -EINVAL:
                case -EPIPE:
                case -ENODEV:
                case -ESHUTDOWN:
-               case -ENOENT:
                        padapter->bDriverStopped = true;
                        break;
                case -EPROTO: