{
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;
status);
/* bail if autosuspend is requested */
if (PMSG_IS_AUTO(msg))
- return status;
+ goto err_wakeup;
}
}
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 */
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))
* 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);