aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-01-06 13:34:31 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-02-14 15:12:24 -0500
commit4296c70a5ec316903ef037ed15f154dd3d354ad7 (patch)
tree9e56518a0470c2884420864dda4717cf4bd2d0cb /drivers/usb/core
parent3b9b6acd4798aafe9b9f64ccb7e8eb76f27f904a (diff)
USB/xHCI: Enable USB 3.0 hub remote wakeup.
USB 3.0 hubs have a different remote wakeup policy than USB 2.0 hubs. USB 2.0 hubs, once they have remote wakeup enabled, will always send remote wakes when anything changes on a port. However, USB 3.0 hubs have a per-port remote wake up policy that is off by default. The Set Feature remote wake mask can be changed for any port, enabling remote wakeup for a connect, disconnect, or overcurrent event, much like EHCI and xHCI host controller "wake on" port status bits. The bits are cleared to zero on the initial hub power on, or after the hub has been reset. Without this patch, when a USB 3.0 hub gets suspended, it will not send a remote wakeup on device connect or disconnect. This would show up to the user as "dead ports" unless they ran lsusb -v (since newer versions of lsusb use the sysfs files, rather than sending control transfers). Change the hub driver's suspend method to enable remote wake up for disconnect, connect, and overcurrent for all ports on the hub. Modify the xHCI driver's roothub code to handle that request, and set the "wake on" bits in the port status registers accordingly. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 70622d633fda..b3137fa65f2a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2731,6 +2731,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
2731 struct usb_hub *hub = usb_get_intfdata (intf); 2731 struct usb_hub *hub = usb_get_intfdata (intf);
2732 struct usb_device *hdev = hub->hdev; 2732 struct usb_device *hdev = hub->hdev;
2733 unsigned port1; 2733 unsigned port1;
2734 int status;
2734 2735
2735 /* Warn if children aren't already suspended */ 2736 /* Warn if children aren't already suspended */
2736 for (port1 = 1; port1 <= hdev->maxchild; port1++) { 2737 for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@ -2743,6 +2744,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
2743 return -EBUSY; 2744 return -EBUSY;
2744 } 2745 }
2745 } 2746 }
2747 if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
2748 /* Enable hub to send remote wakeup for all ports. */
2749 for (port1 = 1; port1 <= hdev->maxchild; port1++) {
2750 status = set_port_feature(hdev,
2751 port1 |
2752 USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
2753 USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
2754 USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
2755 USB_PORT_FEAT_REMOTE_WAKE_MASK);
2756 }
2757 }
2746 2758
2747 dev_dbg(&intf->dev, "%s\n", __func__); 2759 dev_dbg(&intf->dev, "%s\n", __func__);
2748 2760