|
@@ -2848,6 +2848,15 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
|
|
|
USB_CTRL_SET_TIMEOUT);
|
|
|
}
|
|
|
|
|
|
+/* Count of wakeup-enabled devices at or below udev */
|
|
|
+static unsigned wakeup_enabled_descendants(struct usb_device *udev)
|
|
|
+{
|
|
|
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev);
|
|
|
+
|
|
|
+ return udev->do_remote_wakeup +
|
|
|
+ (hub ? hub->wakeup_enabled_descendants : 0);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* usb_port_suspend - suspend a usb device's upstream port
|
|
|
* @udev: device that's no longer in active use, not a root hub
|
|
@@ -2888,8 +2897,8 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
|
|
|
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
|
|
|
* timer, no SRP, no requests through sysfs.
|
|
|
*
|
|
|
- * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
|
|
|
- * suspended only when their bus goes into global suspend (i.e., the root
|
|
|
+ * If Runtime PM isn't enabled or used, non-SuperSpeed devices may not get
|
|
|
+ * suspended until their bus goes into global suspend (i.e., the root
|
|
|
* hub is suspended). Nevertheless, we change @udev->state to
|
|
|
* USB_STATE_SUSPENDED as this is the device's "logical" state. The actual
|
|
|
* upstream port setting is stored in @udev->port_is_suspended.
|
|
@@ -2960,15 +2969,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
/* see 7.1.7.6 */
|
|
|
if (hub_is_superspeed(hub->hdev))
|
|
|
status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
|
|
|
- else if (PMSG_IS_AUTO(msg))
|
|
|
- status = set_port_feature(hub->hdev, port1,
|
|
|
- USB_PORT_FEAT_SUSPEND);
|
|
|
+
|
|
|
/*
|
|
|
* For system suspend, we do not need to enable the suspend feature
|
|
|
* on individual USB-2 ports. The devices will automatically go
|
|
|
* into suspend a few ms after the root hub stops sending packets.
|
|
|
* The USB 2.0 spec calls this "global suspend".
|
|
|
+ *
|
|
|
+ * However, many USB hubs have a bug: They don't relay wakeup requests
|
|
|
+ * from a downstream port if the port's suspend feature isn't on.
|
|
|
+ * Therefore we will turn on the suspend feature if udev or any of its
|
|
|
+ * descendants is enabled for remote wakeup.
|
|
|
*/
|
|
|
+ else if (PMSG_IS_AUTO(msg) || wakeup_enabled_descendants(udev) > 0)
|
|
|
+ status = set_port_feature(hub->hdev, port1,
|
|
|
+ USB_PORT_FEAT_SUSPEND);
|
|
|
else {
|
|
|
really_suspend = false;
|
|
|
status = 0;
|
|
@@ -3003,15 +3018,16 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
if (!PMSG_IS_AUTO(msg))
|
|
|
status = 0;
|
|
|
} else {
|
|
|
- /* device has up to 10 msec to fully suspend */
|
|
|
dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
|
|
|
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
|
|
|
udev->do_remote_wakeup);
|
|
|
- usb_set_device_state(udev, USB_STATE_SUSPENDED);
|
|
|
if (really_suspend) {
|
|
|
udev->port_is_suspended = 1;
|
|
|
+
|
|
|
+ /* device has up to 10 msec to fully suspend */
|
|
|
msleep(10);
|
|
|
}
|
|
|
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -3293,7 +3309,11 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
|
|
unsigned port1;
|
|
|
int status;
|
|
|
|
|
|
- /* Warn if children aren't already suspended */
|
|
|
+ /*
|
|
|
+ * Warn if children aren't already suspended.
|
|
|
+ * Also, add up the number of wakeup-enabled descendants.
|
|
|
+ */
|
|
|
+ hub->wakeup_enabled_descendants = 0;
|
|
|
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
|
|
|
struct usb_device *udev;
|
|
|
|
|
@@ -3303,6 +3323,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
|
|
if (PMSG_IS_AUTO(msg))
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
+ if (udev)
|
|
|
+ hub->wakeup_enabled_descendants +=
|
|
|
+ wakeup_enabled_descendants(udev);
|
|
|
}
|
|
|
|
|
|
if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) {
|