]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Mar 2013 18:29:25 +0000 (11:29 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Mar 2013 18:29:25 +0000 (11:29 -0700)
added patches:
usb-fix-connected-device-switch-to-inactive-state.patch

queue-3.4/series
queue-3.4/usb-fix-connected-device-switch-to-inactive-state.patch [new file with mode: 0644]

index 59b43987f48d7608d2661af90e35b597fe784947..659c480dbecc53361fe7384ebaab363af44d942e 100644 (file)
@@ -37,3 +37,4 @@ usb-don-t-use-ehci-port-sempahore-for-usb-3.0-hubs.patch
 usb-prepare-for-refactoring-by-adding-extra-udev-checks.patch
 usb-rip-out-recursive-call-on-warm-port-reset.patch
 revert-alsa-hda-hdmi-make-jacks-phantom-if-they-re-not-detectable.patch
+usb-fix-connected-device-switch-to-inactive-state.patch
diff --git a/queue-3.4/usb-fix-connected-device-switch-to-inactive-state.patch b/queue-3.4/usb-fix-connected-device-switch-to-inactive-state.patch
new file mode 100644 (file)
index 0000000..4a71b3e
--- /dev/null
@@ -0,0 +1,91 @@
+From sarah.a.sharp@linux.intel.com  Wed Mar 13 11:27:06 2013
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 13 Mar 2013 10:59:21 -0700
+Subject: USB: Fix connected device switch to Inactive state.
+To: Greg KH <gregkh@linuxfoundation.org>
+Cc: stable@vger.kernel.org, sarah.a.sharp@linux.intel.com
+Message-ID: <20130313175801.GA5604@xanatos>
+
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+
+[This is upstream commit d3b9d7a9051d7024a93c76a84b2f84b3b66ad6d5.
+It needs to be backported to kernels as old as 3.2, because it fixes the
+buggy commit 9dbcaec830cd97f44a0b91b315844e0d7144746b "USB: Handle warm
+reset failure on empty port."]
+
+A USB 3.0 device can transition to the Inactive state if a U1 or U2 exit
+transition fails.  The current code in hub_events simply issues a warm
+reset, but does not call any pre-reset or post-reset driver methods (or
+unbind/rebind drivers without them).  Therefore the drivers won't know
+their device has just been reset.
+
+hub_events should instead call usb_reset_device.  This means
+hub_port_reset now needs to figure out whether it should issue a warm
+reset or a hot reset.
+
+Remove the FIXME note about needing disconnect() for a NOTATTACHED
+device.  This patch fixes that.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/hub.c |   30 +++++++++++++++++++++++++-----
+ 1 file changed, 25 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -2274,7 +2274,6 @@ static void hub_port_finish_reset(struct
+       case -ENODEV:
+               clear_port_feature(hub->hdev,
+                               port1, USB_PORT_FEAT_C_RESET);
+-              /* FIXME need disconnect() for NOTATTACHED device */
+               if (hub_is_superspeed(hub->hdev)) {
+                       clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_BH_PORT_RESET);
+@@ -2308,6 +2307,18 @@ static int hub_port_reset(struct usb_hub
+                * Some companion controllers don't like it when they mix.
+                */
+               down_read(&ehci_cf_port_reset_rwsem);
++      } else if (!warm) {
++              /*
++               * If the caller hasn't explicitly requested a warm reset,
++               * double check and see if one is needed.
++               */
++              status = hub_port_status(hub, port1,
++                                      &portstatus, &portchange);
++              if (status < 0)
++                      goto done;
++
++              if (hub_port_warm_reset_required(hub, portstatus))
++                      warm = true;
+       }
+       /* Reset the port */
+@@ -3866,12 +3877,21 @@ static void hub_events(void)
+                        */
+                       if (hub_port_warm_reset_required(hub, portstatus)) {
+                               int status;
++                              struct usb_device *udev =
++                                      hub->hdev->children[i - 1];
+                               dev_dbg(hub_dev, "warm reset port %d\n", i);
+-                              status = hub_port_reset(hub, i, NULL,
+-                                              HUB_BH_RESET_TIME, true);
+-                              if (status < 0)
+-                                      hub_port_disable(hub, i, 1);
++                              if (!udev) {
++                                      status = hub_port_reset(hub, i,
++                                                      NULL, HUB_BH_RESET_TIME,
++                                                      true);
++                                      if (status < 0)
++                                              hub_port_disable(hub, i, 1);
++                              } else {
++                                      usb_lock_device(udev);
++                                      status = usb_reset_device(udev);
++                                      usb_unlock_device(udev);
++                              }
+                               connect_change = 0;
+                       }