--- /dev/null
+From fb7ad4f93d9f0f7d49beda32f5e7becb94b29a4d Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:18 +0200
+Subject: USB: usb_wwan: fix potential blocked I/O after resume
+
+From: Johan Hovold <jhovold@gmail.com>
+
+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>
+
+---
+ drivers/usb/serial/usb_wwan.c | 25 +++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/serial/usb_wwan.c
++++ b/drivers/usb/serial/usb_wwan.c
+@@ -623,12 +623,12 @@ int usb_wwan_suspend(struct usb_serial *
+ }
+ 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;
+@@ -645,6 +645,8 @@ static void play_delayed(struct usb_seri
+ break;
+ }
+ }
++
++ return err;
+ }
+
+ int usb_wwan_resume(struct usb_serial *serial)
+@@ -654,7 +656,8 @@ int usb_wwan_resume(struct usb_serial *s
+ 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;
+
+ spin_lock_irq(&intfdata->susp_lock);
+ for (i = 0; i < serial->num_ports; i++) {
+@@ -673,25 +676,31 @@ int usb_wwan_resume(struct usb_serial *s
+ 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) {
+ dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
+ __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
--- /dev/null
+From 9096f1fbba916c2e052651e9de82fcfb98d4bea7 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:17 +0200
+Subject: USB: usb_wwan: fix potential NULL-deref at resume
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 9096f1fbba916c2e052651e9de82fcfb98d4bea7 upstream.
+
+The interrupt urb was submitted unconditionally at resume, something
+which could lead to a NULL-pointer dereference in the urb completion
+handler as resume may be called after the port and port data is gone.
+
+Fix this by making sure the interrupt urb is only submitted and active
+when the port is open.
+
+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>
+
+---
+ drivers/usb/serial/usb_wwan.c | 43 ++++++++++++++++++------------------------
+ 1 file changed, 19 insertions(+), 24 deletions(-)
+
+--- a/drivers/usb/serial/usb_wwan.c
++++ b/drivers/usb/serial/usb_wwan.c
+@@ -388,6 +388,14 @@ int usb_wwan_open(struct tty_struct *tty
+ portdata = usb_get_serial_port_data(port);
+ intfdata = serial->private;
+
++ if (port->interrupt_in_urb) {
++ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
++ if (err) {
++ dev_dbg(&port->dev, "%s: submit int urb failed: %d\n",
++ __func__, err);
++ }
++ }
++
+ /* Start reading from the IN endpoint */
+ for (i = 0; i < N_IN_URB; i++) {
+ urb = portdata->in_urbs[i];
+@@ -454,6 +462,7 @@ void usb_wwan_close(struct usb_serial_po
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
++ usb_kill_urb(port->interrupt_in_urb);
+
+ /* balancing - important as an error cannot be handled*/
+ usb_autopm_get_interface_no_resume(serial->interface);
+@@ -491,7 +500,6 @@ int usb_wwan_port_probe(struct usb_seria
+ struct usb_wwan_port_private *portdata;
+ struct urb *urb;
+ u8 *buffer;
+- int err;
+ int i;
+
+ if (!port->bulk_in_size || !port->bulk_out_size)
+@@ -531,13 +539,6 @@ int usb_wwan_port_probe(struct usb_seria
+
+ usb_set_serial_port_data(port, portdata);
+
+- if (port->interrupt_in_urb) {
+- err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+- if (err)
+- dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n",
+- __func__, err);
+- }
+-
+ return 0;
+
+ bail_out_error2:
+@@ -655,22 +656,6 @@ int usb_wwan_resume(struct usb_serial *s
+ struct urb *urb;
+ int err = 0;
+
+- /* get the interrupt URBs resubmitted unconditionally */
+- for (i = 0; i < serial->num_ports; i++) {
+- port = serial->port[i];
+- if (!port->interrupt_in_urb) {
+- dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__);
+- continue;
+- }
+- err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+- dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err);
+- if (err < 0) {
+- dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
+- __func__, err);
+- goto err_out;
+- }
+- }
+-
+ spin_lock_irq(&intfdata->susp_lock);
+ for (i = 0; i < serial->num_ports; i++) {
+ /* walk all ports */
+@@ -681,6 +666,16 @@ int usb_wwan_resume(struct usb_serial *s
+ if (!portdata || !portdata->opened)
+ continue;
+
++ if (port->interrupt_in_urb) {
++ err = usb_submit_urb(port->interrupt_in_urb,
++ GFP_ATOMIC);
++ if (err) {
++ dev_err(&port->dev,
++ "%s: submit int urb failed: %d\n",
++ __func__, err);
++ }
++ }
++
+ for (j = 0; j < N_IN_URB; j++) {
+ urb = portdata->in_urbs[j];
+ err = usb_submit_urb(urb, GFP_ATOMIC);