|
@@ -2918,7 +2918,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
{
|
|
|
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
|
|
|
struct usb_port *port_dev = hub->ports[udev->portnum - 1];
|
|
|
- enum pm_qos_flags_status pm_qos_stat;
|
|
|
int port1 = udev->portnum;
|
|
|
int status;
|
|
|
bool really_suspend = true;
|
|
@@ -2956,7 +2955,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
status);
|
|
|
/* bail if autosuspend is requested */
|
|
|
if (PMSG_IS_AUTO(msg))
|
|
|
- return status;
|
|
|
+ goto err_wakeup;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2965,14 +2964,16 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
usb_set_usb2_hardware_lpm(udev, 0);
|
|
|
|
|
|
if (usb_disable_ltm(udev)) {
|
|
|
- dev_err(&udev->dev, "%s Failed to disable LTM before suspend\n.",
|
|
|
- __func__);
|
|
|
- return -ENOMEM;
|
|
|
+ dev_err(&udev->dev, "Failed to disable LTM before suspend\n.");
|
|
|
+ status = -ENOMEM;
|
|
|
+ if (PMSG_IS_AUTO(msg))
|
|
|
+ goto err_ltm;
|
|
|
}
|
|
|
if (usb_unlocked_disable_lpm(udev)) {
|
|
|
- dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
|
|
|
- __func__);
|
|
|
- return -ENOMEM;
|
|
|
+ dev_err(&udev->dev, "Failed to disable LPM before suspend\n.");
|
|
|
+ status = -ENOMEM;
|
|
|
+ if (PMSG_IS_AUTO(msg))
|
|
|
+ goto err_lpm3;
|
|
|
}
|
|
|
|
|
|
/* see 7.1.7.6 */
|
|
@@ -3000,28 +3001,31 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
if (status) {
|
|
|
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
|
|
|
port1, status);
|
|
|
- /* paranoia: "should not happen" */
|
|
|
- if (udev->do_remote_wakeup) {
|
|
|
- if (!hub_is_superspeed(hub->hdev)) {
|
|
|
- (void) usb_control_msg(udev,
|
|
|
- usb_sndctrlpipe(udev, 0),
|
|
|
- USB_REQ_CLEAR_FEATURE,
|
|
|
- USB_RECIP_DEVICE,
|
|
|
- USB_DEVICE_REMOTE_WAKEUP, 0,
|
|
|
- NULL, 0,
|
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
|
- } else
|
|
|
- (void) usb_disable_function_remotewakeup(udev);
|
|
|
-
|
|
|
- }
|
|
|
|
|
|
+ /* Try to enable USB3 LPM and LTM again */
|
|
|
+ usb_unlocked_enable_lpm(udev);
|
|
|
+ err_lpm3:
|
|
|
+ usb_enable_ltm(udev);
|
|
|
+ err_ltm:
|
|
|
/* Try to enable USB2 hardware LPM again */
|
|
|
if (udev->usb2_hw_lpm_capable == 1)
|
|
|
usb_set_usb2_hardware_lpm(udev, 1);
|
|
|
|
|
|
- /* Try to enable USB3 LTM and LPM again */
|
|
|
- usb_enable_ltm(udev);
|
|
|
- usb_unlocked_enable_lpm(udev);
|
|
|
+ if (udev->do_remote_wakeup) {
|
|
|
+ if (udev->speed < USB_SPEED_SUPER)
|
|
|
+ usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
|
|
+ USB_REQ_CLEAR_FEATURE,
|
|
|
+ USB_RECIP_DEVICE,
|
|
|
+ USB_DEVICE_REMOTE_WAKEUP, 0,
|
|
|
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
|
|
|
+ else
|
|
|
+ usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
|
|
+ USB_REQ_CLEAR_FEATURE,
|
|
|
+ USB_RECIP_INTERFACE,
|
|
|
+ USB_INTRF_FUNC_SUSPEND, 0,
|
|
|
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
|
|
|
+ }
|
|
|
+ err_wakeup:
|
|
|
|
|
|
/* System sleep transitions should never fail */
|
|
|
if (!PMSG_IS_AUTO(msg))
|
|
@@ -3043,14 +3047,15 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|
|
* Check whether current status meets the requirement of
|
|
|
* usb port power off mechanism
|
|
|
*/
|
|
|
- pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
|
|
|
- PM_QOS_FLAG_NO_POWER_OFF);
|
|
|
- if (!udev->do_remote_wakeup
|
|
|
- && pm_qos_stat != PM_QOS_FLAGS_ALL
|
|
|
- && udev->persist_enabled
|
|
|
- && !status) {
|
|
|
- pm_runtime_put_sync(&port_dev->dev);
|
|
|
- port_dev->did_runtime_put = true;
|
|
|
+ if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) {
|
|
|
+ enum pm_qos_flags_status pm_qos_stat;
|
|
|
+
|
|
|
+ pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
|
|
|
+ PM_QOS_FLAG_NO_POWER_OFF);
|
|
|
+ if (pm_qos_stat != PM_QOS_FLAGS_ALL) {
|
|
|
+ pm_runtime_put_sync(&port_dev->dev);
|
|
|
+ port_dev->did_runtime_put = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
usb_mark_last_busy(hub->hdev);
|