diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/core/hub.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c376c8bad40c..0416f835cfee 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2948,7 +2948,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; @@ -2966,7 +2965,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; } } @@ -2975,14 +2974,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 */ @@ -3010,17 +3011,19 @@ 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) - (void) usb_disable_remote_wakeup(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) + (void) usb_disable_remote_wakeup(udev); + err_wakeup: /* System sleep transitions should never fail */ if (!PMSG_IS_AUTO(msg)) @@ -3042,14 +3045,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); |