aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-04-27 22:54:26 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:48 -0400
commite7b7717247f61e2cf18ec47f91999065c59d1607 (patch)
treee644aa7eb5aa1063aaece0fddb14598c2f7404f3 /drivers/usb
parentd2e9b4d6734db2327af3149d8ca7555307e10828 (diff)
USB: Don't reset USB 3.0 devices on port change detection.
The USB 3.0 bus specification defines a new connection sequence for USB 3.0 hubs and roothubs. USB 3.0 devices are reset and link trained by the hub before the port status change notification is sent to the host OS. This means that an entire tree of devices can be trained in parallel on power up, and the OS no longer needs to reset USB 3.0 devices. Change the USB core's hub port init sequence so that it does not reset USB 3.0 devices. The port status change from the roothub and from the USB 3.0 hub will report the SuperSpeed connect correctly. This patch currently only handles the roothub case. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/hub.c42
1 files changed, 36 insertions, 6 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f3fe8dfaaad1..3c28bde6cbd5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2435,6 +2435,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
2435 static DEFINE_MUTEX(usb_address0_mutex); 2435 static DEFINE_MUTEX(usb_address0_mutex);
2436 2436
2437 struct usb_device *hdev = hub->hdev; 2437 struct usb_device *hdev = hub->hdev;
2438 struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
2438 int i, j, retval; 2439 int i, j, retval;
2439 unsigned delay = HUB_SHORT_RESET_TIME; 2440 unsigned delay = HUB_SHORT_RESET_TIME;
2440 enum usb_device_speed oldspeed = udev->speed; 2441 enum usb_device_speed oldspeed = udev->speed;
@@ -2457,11 +2458,24 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
2457 2458
2458 mutex_lock(&usb_address0_mutex); 2459 mutex_lock(&usb_address0_mutex);
2459 2460
2460 /* Reset the device; full speed may morph to high speed */ 2461 if ((hcd->driver->flags & HCD_USB3) && udev->config) {
2461 retval = hub_port_reset(hub, port1, udev, delay); 2462 /* FIXME this will need special handling by the xHCI driver. */
2462 if (retval < 0) /* error or disconnect */ 2463 dev_dbg(&udev->dev,
2464 "xHCI reset of configured device "
2465 "not supported yet.\n");
2466 retval = -EINVAL;
2463 goto fail; 2467 goto fail;
2464 /* success, speed is known */ 2468 } else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
2469 /* Don't reset USB 3.0 devices during an initial setup */
2470 usb_set_device_state(udev, USB_STATE_DEFAULT);
2471 } else {
2472 /* Reset the device; full speed may morph to high speed */
2473 /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
2474 retval = hub_port_reset(hub, port1, udev, delay);
2475 if (retval < 0) /* error or disconnect */
2476 goto fail;
2477 /* success, speed is known */
2478 }
2465 retval = -ENODEV; 2479 retval = -ENODEV;
2466 2480
2467 if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { 2481 if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
@@ -2859,7 +2873,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
2859 } 2873 }
2860 2874
2861 usb_set_device_state(udev, USB_STATE_POWERED); 2875 usb_set_device_state(udev, USB_STATE_POWERED);
2862 udev->speed = USB_SPEED_UNKNOWN;
2863 udev->bus_mA = hub->mA_per_port; 2876 udev->bus_mA = hub->mA_per_port;
2864 udev->level = hdev->level + 1; 2877 udev->level = hdev->level + 1;
2865 udev->wusb = hub_is_wusb(hub); 2878 udev->wusb = hub_is_wusb(hub);
@@ -2871,7 +2884,24 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
2871 goto loop; 2884 goto loop;
2872 } 2885 }
2873 2886
2874 /* reset and get descriptor */ 2887 /*
2888 * USB 3.0 devices are reset automatically before the connect
2889 * port status change appears, and the root hub port status
2890 * shows the correct speed. We also get port change
2891 * notifications for USB 3.0 devices from the USB 3.0 portion of
2892 * an external USB 3.0 hub, but this isn't handled correctly yet
2893 * FIXME.
2894 */
2895
2896 if (!(hcd->driver->flags & HCD_USB3))
2897 udev->speed = USB_SPEED_UNKNOWN;
2898 else if ((hdev->parent == NULL) &&
2899 (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
2900 udev->speed = USB_SPEED_SUPER;
2901 else
2902 udev->speed = USB_SPEED_UNKNOWN;
2903
2904 /* reset (non-USB 3.0 devices) and get descriptor */
2875 status = hub_port_init(hub, udev, port1, i); 2905 status = hub_port_init(hub, udev, port1, i);
2876 if (status < 0) 2906 if (status < 0)
2877 goto loop; 2907 goto loop;