aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2014-05-26 19:23:18 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-06-30 20:01:32 -0700
commit9e91351f9626fe1822c5d6e8c10cece4d5e92d1d (patch)
tree00209db7e84328f0bd28a536939cf00c8532f8da
parent0886f4e9008835a02210f30a0850ddb7297a9ece (diff)
USB: usb_wwan: fix potential blocked I/O after resume
commit fb7ad4f93d9f0f7d49beda32f5e7becb94b29a4d upstream. Keep trying to submit urbs rather than bail out on first read-urb submission error, which would also prevent I/O for any further ports from being resumed. Instead keep an error count, for all types of failed submissions, and let USB core know that something went wrong. Also make sure to always clear the suspended flag. Currently a failed read-urb submission would prevent cached writes as well as any subsequent writes from being submitted until next suspend-resume cycle, something which may not even necessarily happen. Note that USB core currently only logs an error if an interface resume failed. Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the option driver") Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/serial/usb_wwan.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 8554ef80eae8..7e92f50965f6 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -692,12 +692,12 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
}
EXPORT_SYMBOL(usb_wwan_suspend);
-static void play_delayed(struct usb_serial_port *port)
+static int play_delayed(struct usb_serial_port *port)
{
struct usb_wwan_intf_private *data;
struct usb_wwan_port_private *portdata;
struct urb *urb;
- int err;
+ int err = 0;
portdata = usb_get_serial_port_data(port);
data = port->serial->private;
@@ -714,6 +714,8 @@ static void play_delayed(struct usb_serial_port *port)
break;
}
}
+
+ return err;
}
int usb_wwan_resume(struct usb_serial *serial)
@@ -723,7 +725,8 @@ int usb_wwan_resume(struct usb_serial *serial)
struct usb_wwan_intf_private *intfdata = serial->private;
struct usb_wwan_port_private *portdata;
struct urb *urb;
- int err = 0;
+ int err;
+ int err_count = 0;
dbg("%s entered", __func__);
@@ -744,25 +747,31 @@ int usb_wwan_resume(struct usb_serial *serial)
dev_err(&port->dev,
"%s: submit int urb failed: %d\n",
__func__, err);
+ err_count++;
}
}
+ err = play_delayed(port);
+ if (err)
+ err_count++;
+
for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
err("%s: Error %d for bulk URB %d",
__func__, err, i);
- spin_unlock_irq(&intfdata->susp_lock);
- goto err_out;
+ err_count++;
}
}
- play_delayed(port);
}
intfdata->suspended = 0;
spin_unlock_irq(&intfdata->susp_lock);
-err_out:
- return err;
+
+ if (err_count)
+ return -EIO;
+
+ return 0;
}
EXPORT_SYMBOL(usb_wwan_resume);
#endif