]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Jan 2013 12:57:41 +0000 (04:57 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Jan 2013 12:57:41 +0000 (04:57 -0800)
added patches:
usb-allow-usb-3.0-ports-to-be-disabled.patch
usb-handle-auto-transition-from-hot-to-warm-reset.patch
usb-ignore-xhci-reset-device-status.patch
usb-increase-reset-timeout.patch

queue-3.4/series
queue-3.4/usb-allow-usb-3.0-ports-to-be-disabled.patch [new file with mode: 0644]
queue-3.4/usb-handle-auto-transition-from-hot-to-warm-reset.patch [new file with mode: 0644]
queue-3.4/usb-ignore-xhci-reset-device-status.patch [new file with mode: 0644]
queue-3.4/usb-increase-reset-timeout.patch [new file with mode: 0644]

index 486b65b2f31c970d842af4f52d102cbdc75160d1..e295ea8ce05c91545c4f0f71a856a2bc6c909849 100644 (file)
@@ -97,3 +97,7 @@ usb-cdc-acm-add-support-for-psc-scanning-magellan-800i.patch
 usb-gadget-dummy-fix-enumeration-with-g_multi.patch
 usb-musb-core-print-new-line-in-the-driver-banner-again.patch
 drm-nouveau-fix-blank-lvds-screen-regression-on-pre-nv50-cards.patch
+usb-handle-auto-transition-from-hot-to-warm-reset.patch
+usb-ignore-xhci-reset-device-status.patch
+usb-allow-usb-3.0-ports-to-be-disabled.patch
+usb-increase-reset-timeout.patch
diff --git a/queue-3.4/usb-allow-usb-3.0-ports-to-be-disabled.patch b/queue-3.4/usb-allow-usb-3.0-ports-to-be-disabled.patch
new file mode 100644 (file)
index 0000000..5604420
--- /dev/null
@@ -0,0 +1,170 @@
+From 41e7e056cdc662f704fa9262e5c6e213b4ab45dd Mon Sep 17 00:00:00 2001
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 14 Nov 2012 16:42:32 -0800
+Subject: USB: Allow USB 3.0 ports to be disabled.
+
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+
+commit 41e7e056cdc662f704fa9262e5c6e213b4ab45dd upstream.
+
+If hot and warm reset fails, or a port remains in the Compliance Mode,
+the USB core needs to be able to disable a USB 3.0 port.  Unlike USB 2.0
+ports, once the port is placed into the Disabled link state, it will not
+report any new device connects.  To get device connect notifications, we
+need to put the link into the Disabled state, and then the RxDetect
+state.
+
+The xHCI driver needs to atomically clear all change bits on USB 3.0
+port disable, so that we get Port Status Change Events for future port
+changes.  We could technically do this in the USB core instead of in the
+xHCI roothub code, since the port state machine can't advance out of the
+disabled state until we set the link state to RxDetect.  However,
+external USB 3.0 hubs don't need this code.  They are level-triggered,
+not edge-triggered like xHCI, so they will continue to send interrupt
+events when any change bit is set.  Therefore it doesn't make sense to
+put this code in the USB core.
+
+This patch is part of a series to fix several reports of infinite loops
+on device enumeration failure.  This includes John, when he boots with
+a USB 3.0 device (Roseweil eusb3 enclosure) attached to his NEC 0.96
+host controller.  The fix requires warm reset support, so it does not
+make sense to backport this patch to stable kernels without warm reset
+support.
+
+This patch should be backported to kernels as old as 3.2, contain the
+commit ID 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm
+reset logic"
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Reported-by: John Covici <covici@ccs.covici.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/hub.c      |   63 ++++++++++++++++++++++++++++++++++++++++++--
+ drivers/usb/host/xhci-hub.c |   31 ++++++++++++++++++++-
+ 2 files changed, 90 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -644,6 +644,60 @@ static int hub_hub_status(struct usb_hub
+       return ret;
+ }
++static int hub_set_port_link_state(struct usb_hub *hub, int port1,
++                      unsigned int link_status)
++{
++      return set_port_feature(hub->hdev,
++                      port1 | (link_status << 3),
++                      USB_PORT_FEAT_LINK_STATE);
++}
++
++/*
++ * If USB 3.0 ports are placed into the Disabled state, they will no longer
++ * detect any device connects or disconnects.  This is generally not what the
++ * USB core wants, since it expects a disabled port to produce a port status
++ * change event when a new device connects.
++ *
++ * Instead, set the link state to Disabled, wait for the link to settle into
++ * that state, clear any change bits, and then put the port into the RxDetect
++ * state.
++ */
++static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
++{
++      int ret;
++      int total_time;
++      u16 portchange, portstatus;
++
++      if (!hub_is_superspeed(hub->hdev))
++              return -EINVAL;
++
++      ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
++      if (ret) {
++              dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
++                              port1, ret);
++              return ret;
++      }
++
++      /* Wait for the link to enter the disabled state. */
++      for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
++              ret = hub_port_status(hub, port1, &portstatus, &portchange);
++              if (ret < 0)
++                      return ret;
++
++              if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
++                              USB_SS_PORT_LS_SS_DISABLED)
++                      break;
++              if (total_time >= HUB_DEBOUNCE_TIMEOUT)
++                      break;
++              msleep(HUB_DEBOUNCE_STEP);
++      }
++      if (total_time >= HUB_DEBOUNCE_TIMEOUT)
++              dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n",
++                              port1, total_time);
++
++      return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);
++}
++
+ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
+ {
+       struct usb_device *hdev = hub->hdev;
+@@ -652,8 +706,13 @@ static int hub_port_disable(struct usb_h
+       if (hdev->children[port1-1] && set_state)
+               usb_set_device_state(hdev->children[port1-1],
+                               USB_STATE_NOTATTACHED);
+-      if (!hub->error && !hub_is_superspeed(hub->hdev))
+-              ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
++      if (!hub->error) {
++              if (hub_is_superspeed(hub->hdev))
++                      ret = hub_usb3_port_disable(hub, port1);
++              else
++                      ret = clear_port_feature(hdev, port1,
++                                      USB_PORT_FEAT_ENABLE);
++      }
+       if (ret)
+               dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
+                               port1, ret);
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -753,12 +753,39 @@ int xhci_hub_control(struct usb_hcd *hcd
+                       break;
+               case USB_PORT_FEAT_LINK_STATE:
+                       temp = xhci_readl(xhci, port_array[wIndex]);
++
++                      /* Disable port */
++                      if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
++                              xhci_dbg(xhci, "Disable port %d\n", wIndex);
++                              temp = xhci_port_state_to_neutral(temp);
++                              /*
++                               * Clear all change bits, so that we get a new
++                               * connection event.
++                               */
++                              temp |= PORT_CSC | PORT_PEC | PORT_WRC |
++                                      PORT_OCC | PORT_RC | PORT_PLC |
++                                      PORT_CEC;
++                              xhci_writel(xhci, temp | PORT_PE,
++                                      port_array[wIndex]);
++                              temp = xhci_readl(xhci, port_array[wIndex]);
++                              break;
++                      }
++
++                      /* Put link in RxDetect (enable port) */
++                      if (link_state == USB_SS_PORT_LS_RX_DETECT) {
++                              xhci_dbg(xhci, "Enable port %d\n", wIndex);
++                              xhci_set_link_state(xhci, port_array, wIndex,
++                                              link_state);
++                              temp = xhci_readl(xhci, port_array[wIndex]);
++                              break;
++                      }
++
+                       /* Software should not attempt to set
+-                       * port link state above '5' (Rx.Detect) and the port
++                       * port link state above '3' (U3) and the port
+                        * must be enabled.
+                        */
+                       if ((temp & PORT_PE) == 0 ||
+-                              (link_state > USB_SS_PORT_LS_RX_DETECT)) {
++                              (link_state > USB_SS_PORT_LS_U3)) {
+                               xhci_warn(xhci, "Cannot set link state.\n");
+                               goto error;
+                       }
diff --git a/queue-3.4/usb-handle-auto-transition-from-hot-to-warm-reset.patch b/queue-3.4/usb-handle-auto-transition-from-hot-to-warm-reset.patch
new file mode 100644 (file)
index 0000000..93c94f4
--- /dev/null
@@ -0,0 +1,50 @@
+From 1c7439c61fa6516419c32a9824976334ea969d47 Mon Sep 17 00:00:00 2001
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 14 Nov 2012 15:58:52 -0800
+Subject: USB: Handle auto-transition from hot to warm reset.
+
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+
+commit 1c7439c61fa6516419c32a9824976334ea969d47 upstream.
+
+USB 3.0 hubs and roothubs will automatically transition a failed hot
+reset to a warm (BH) reset.  In that case, the warm reset change bit
+will be set, and the link state change bit may also be set.  Change
+hub_port_finish_reset to unconditionally clear those change bits for USB
+3.0 hubs.  If these bits are not cleared, we may lose port change events
+from the roothub.
+
+This commit should be backported to kernels as old as 3.2, that contain
+the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine
+warm reset logic".
+
+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 |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -2249,16 +2249,16 @@ static void hub_port_finish_reset(struct
+               clear_port_feature(hub->hdev,
+                               port1, USB_PORT_FEAT_C_RESET);
+               /* FIXME need disconnect() for NOTATTACHED device */
+-              if (warm) {
++              if (hub_is_superspeed(hub->hdev)) {
+                       clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_BH_PORT_RESET);
+                       clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_PORT_LINK_STATE);
+-              } else {
++              }
++              if (!warm)
+                       usb_set_device_state(udev, *status
+                                       ? USB_STATE_NOTATTACHED
+                                       : USB_STATE_DEFAULT);
+-              }
+               break;
+       }
+ }
diff --git a/queue-3.4/usb-ignore-xhci-reset-device-status.patch b/queue-3.4/usb-ignore-xhci-reset-device-status.patch
new file mode 100644 (file)
index 0000000..60940eb
--- /dev/null
@@ -0,0 +1,67 @@
+From 8b8132bc3d1cc3d4c0687e4d638a482fa920d98a Mon Sep 17 00:00:00 2001
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 14 Nov 2012 16:10:49 -0800
+Subject: USB: Ignore xHCI Reset Device status.
+
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+
+commit 8b8132bc3d1cc3d4c0687e4d638a482fa920d98a upstream.
+
+When the USB core finishes reseting a USB device, the xHCI driver sends
+a Reset Device command to the host.  The xHC then updates its internal
+representation of the USB device to the 'Default' device state.  If the
+device was already in the Default state, the xHC will complete the
+command with an error status.
+
+If a device needs to be reset several times during enumeration, the
+second reset will always fail because of the xHCI Reset Device command.
+This can cause issues during enumeration.
+
+For example, usb_reset_and_verify_device calls into hub_port_init in a
+loop.  Say that on the first call into hub_port_init, the device is
+successfully reset, but doesn't respond to several set address control
+transfers.  Then the port will be disabled, but the udev will remain in
+tact.  usb_reset_and_verify_device will call into hub_port_init again.
+
+On the second call into hub_port_init, the device will be reset, and the
+xHCI driver will issue a Reset Device command.  This command will fail
+(because the device is already in the Default state), and
+usb_reset_and_verify_device will fail.  The port will be disabled, and
+the device won't be able to enumerate.
+
+Fix this by ignoring the return value of the HCD reset_device callback.
+
+This commit should be backported to kernels as old as 3.2, that contain
+the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine
+warm reset logic".
+
+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 |   13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -2234,14 +2234,11 @@ static void hub_port_finish_reset(struct
+                       msleep(10 + 40);
+                       update_devnum(udev, 0);
+                       hcd = bus_to_hcd(udev->bus);
+-                      if (hcd->driver->reset_device) {
+-                              *status = hcd->driver->reset_device(hcd, udev);
+-                              if (*status < 0) {
+-                                      dev_err(&udev->dev, "Cannot reset "
+-                                                      "HCD device state\n");
+-                                      break;
+-                              }
+-                      }
++                      /* The xHC may think the device is already reset,
++                       * so ignore the status.
++                       */
++                      if (hcd->driver->reset_device)
++                              hcd->driver->reset_device(hcd, udev);
+               }
+               /* FALL THROUGH */
+       case -ENOTCONN:
diff --git a/queue-3.4/usb-increase-reset-timeout.patch b/queue-3.4/usb-increase-reset-timeout.patch
new file mode 100644 (file)
index 0000000..9e8e48d
--- /dev/null
@@ -0,0 +1,37 @@
+From 77c7f072c87fa951e9a74805febf26466f31170c Mon Sep 17 00:00:00 2001
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Wed, 14 Nov 2012 17:16:52 -0800
+Subject: USB: Increase reset timeout.
+
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+
+commit 77c7f072c87fa951e9a74805febf26466f31170c upstream.
+
+John's NEC 0.96 xHCI host controller needs a longer timeout for a warm
+reset to complete.  The logs show it takes 650ms to complete the warm
+reset, so extend the hub reset timeout to 800ms to be on the safe side.
+
+This commit should be backported to kernels as old as 3.2, that contain
+the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine
+warm reset logic".
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Reported-by: John Covici <covici@ccs.covici.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/hub.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -2168,7 +2168,7 @@ static unsigned hub_is_wusb(struct usb_h
+ #define HUB_SHORT_RESET_TIME  10
+ #define HUB_BH_RESET_TIME     50
+ #define HUB_LONG_RESET_TIME   200
+-#define HUB_RESET_TIMEOUT     500
++#define HUB_RESET_TIMEOUT     800
+ static int hub_port_reset(struct usb_hub *hub, int port1,
+                       struct usb_device *udev, unsigned int delay, bool warm);