linux/drivers/usb/core
Sarah Sharp 85f0ff4696 usb: Fix issue with USB 3.0 devices after system resume
When the system suspends and a host controller's power is lost, the USB
core attempts to revive any USB devices that had the persist_enabled flag
set.  For non-SuperSpeed devices, it will disable the port, and then set
the udev->reset_resume flag.  This will cause the USB core to reset the
device, verify the device descriptors to make sure it's the same device,
and re-install any non-default configurations or alternate interface
settings.

However, we can't disable SuperSpeed root hub ports because that turns off
SuperSpeed terminations, which will inhibit any devices connecting at USB
3.0 speeds.  (Plus external hubs don't allow SuperSpeed ports to be
disabled.)

Because of this logic in hub_activate():
                /* We can forget about a "removed" device when there's a
                 * physical disconnect or the connect status changes.
                 */
                if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
                                (portchange & USB_PORT_STAT_C_CONNECTION))
                        clear_bit(port1, hub->removed_bits);

                if (!udev || udev->state == USB_STATE_NOTATTACHED) {
                        /* Tell khubd to disconnect the device or
                         * check for a new connection
                         */
                        if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
                                set_bit(port1, hub->change_bits);

                } else if (portstatus & USB_PORT_STAT_ENABLE) {
                        /* The power session apparently survived the resume.
                         * If there was an overcurrent or suspend change
                         * (i.e., remote wakeup request), have khubd
                         * take care of it.
                         */
                        if (portchange)
                                set_bit(port1, hub->change_bits);

                } else if (udev->persist_enabled) {
                        udev->reset_resume = 1;
                        set_bit(port1, hub->change_bits);

                } else {
                        /* The power session is gone; tell khubd */
                        usb_set_device_state(udev, USB_STATE_NOTATTACHED);
                        set_bit(port1, hub->change_bits);
                }

a SuperSpeed device after a resume with a loss of power will never get the
reset_resume flag set.  Instead the core will assume the power session
survived and that the device still has the same address, configuration,
and alternate interface settings.  The xHCI host controller will have no
knowledge of the device (since all xhci_virt_devices were destroyed when
power loss was discovered, and xhci_discover_or_reset_device() has not
been called), and all URBs to the device will fail.

If the device driver responds by resetting the device, everything will
continue smoothly.  However, if lsusb is used before the device driver
resets the device (or there is no driver), then all lsusb descriptor
fetches will fail.

The quick fix is to pretend the port is disabled in hub_activate(), by
clearing the local variable.  But I'm not sure what other parts of the hub
driver need to be changed because they have assumptions about when ports
will be disabled.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-10-22 10:22:12 -07:00
..
buffer.c USB: make hcd.h public (drivers dependency) 2010-05-20 13:21:30 -07:00
config.c USB: remove the usb_host_ss_ep_comp structure 2010-05-20 13:21:40 -07:00
devices.c USB: teach "devices" file about Wireless and SuperSpeed USB 2010-10-22 10:21:40 -07:00
devio.c USB-BKL: Convert usb_driver ioctl to unlocked_ioctl 2010-08-10 14:35:35 -07:00
driver.c USB: do not print -ESHUTDOWN message if usb at otg device mode 2010-10-22 10:22:05 -07:00
endpoint.c usb: core: endpoint: Fix error path 2010-10-22 10:22:06 -07:00
file.c USB: fix bug in initialization of interface minor numbers 2010-09-24 11:05:00 -07:00
generic.c USB: accept RNDIS configs if there's no alternative 2010-08-10 14:35:43 -07:00
hcd-pci.c OHCI: work around for nVidia shutdown problem 2010-10-22 10:21:36 -07:00
hcd.c USB: introduce unmap_urb_setup_for_dma() 2010-10-22 10:22:03 -07:00
hub.c usb: Fix issue with USB 3.0 devices after system resume 2010-10-22 10:22:12 -07:00
inode.c USB-BKL: Remove lock_kernel in usbfs update_sb() 2010-08-10 14:35:35 -07:00
Kconfig USB: update Kconfig help text for CONFIG_USB_SUSPEND 2010-09-24 11:05:01 -07:00
Makefile usb: makefile cleanup 2010-10-22 10:22:07 -07:00
message.c USB: disable endpoints after unbinding interfaces, not before 2010-10-22 10:22:01 -07:00
notify.c USB : correct comments in usb/core/notify.c 2008-02-01 14:34:44 -08:00
otg_whitelist.h USB: fix codingstyle issues in drivers/usb/core/*.h 2008-02-01 14:35:07 -08:00
quirks.c USB delay init quirk for logitech Harmony 700-series devices 2010-08-10 14:35:41 -07:00
sysfs.c sysfs: add struct file* to bin_attr callbacks 2010-05-21 09:37:31 -07:00
urb.c USB: output an error message when the pipe type doesn't match the endpoint type 2010-10-22 10:21:27 -07:00
usb.c USB: remove fake "address-of" expressions 2010-08-10 14:35:45 -07:00
usb.h USB: convert to the runtime PM framework 2010-03-02 14:54:12 -08:00