summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r--drivers/usb/core/driver.c150
1 files changed, 26 insertions, 124 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index c0e60fbcb048..b9278a1fb9e5 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -27,7 +27,6 @@
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h>
-#include <linux/pm_runtime.h>
#include "usb.h"
@@ -1262,6 +1261,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
udev->reset_resume);
}
}
+ usb_mark_last_busy(udev);
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
@@ -1329,7 +1329,6 @@ int usb_resume(struct device *dev, pm_message_t msg)
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- udev->last_busy = jiffies;
do_unbind_rebind(udev, DO_REBIND);
}
}
@@ -1397,33 +1396,8 @@ void usb_autosuspend_device(struct usb_device *udev)
{
int status;
- udev->last_busy = jiffies;
- status = pm_runtime_put_sync(&udev->dev);
- dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
- __func__, atomic_read(&udev->dev.power.usage_count),
- status);
-}
-
-/**
- * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
- * @udev: the usb_device to autosuspend
- *
- * This routine should be called when a core subsystem thinks @udev may
- * be ready to autosuspend.
- *
- * @udev's usage counter left unchanged. If it is 0 and all the interfaces
- * are inactive then an autosuspend will be attempted. The attempt may
- * fail or be delayed.
- *
- * The caller must hold @udev's device lock.
- *
- * This routine can run only in process context.
- */
-void usb_try_autosuspend_device(struct usb_device *udev)
-{
- int status;
-
- status = pm_runtime_idle(&udev->dev);
+ usb_mark_last_busy(udev);
+ status = pm_runtime_put_sync_autosuspend(&udev->dev);
dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&udev->dev.power.usage_count),
status);
@@ -1482,7 +1456,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
struct usb_device *udev = interface_to_usbdev(intf);
int status;
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
status = pm_runtime_put_sync(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
@@ -1509,32 +1483,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
void usb_autopm_put_interface_async(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- unsigned long last_busy;
- int status = 0;
+ int status;
- last_busy = udev->last_busy;
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
- pm_runtime_put_noidle(&intf->dev);
-
- if (udev->dev.power.runtime_auto) {
- /* Optimization: Don't schedule a delayed autosuspend if
- * the timer is already running and the expiration time
- * wouldn't change.
- *
- * We have to use the interface's timer. Attempts to
- * schedule a suspend for the device would fail because
- * the interface is still active.
- */
- if (intf->dev.power.timer_expires == 0 ||
- round_jiffies_up(last_busy) !=
- round_jiffies_up(jiffies)) {
- status = pm_schedule_suspend(&intf->dev,
- jiffies_to_msecs(
- round_jiffies_up_relative(
- udev->autosuspend_delay)));
- }
- }
+ status = pm_runtime_put(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&intf->dev.power.usage_count),
status);
@@ -1554,7 +1507,7 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_dec(&intf->pm_usage_cnt);
pm_runtime_put_noidle(&intf->dev);
}
@@ -1612,18 +1565,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
*/
int usb_autopm_get_interface_async(struct usb_interface *intf)
{
- int status = 0;
- enum rpm_status s;
-
- /* Don't request a resume unless the interface is already suspending
- * or suspended. Doing so would force a running suspend timer to be
- * cancelled.
- */
- pm_runtime_get_noresume(&intf->dev);
- s = ACCESS_ONCE(intf->dev.power.runtime_status);
- if (s == RPM_SUSPENDING || s == RPM_SUSPENDED)
- status = pm_request_resume(&intf->dev);
+ int status;
+ status = pm_runtime_get(&intf->dev);
if (status < 0 && status != -EINPROGRESS)
pm_runtime_put_noidle(&intf->dev);
else
@@ -1650,7 +1594,7 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- udev->last_busy = jiffies;
+ usb_mark_last_busy(udev);
atomic_inc(&intf->pm_usage_cnt);
pm_runtime_get_noresume(&intf->dev);
}
@@ -1661,7 +1605,6 @@ static int autosuspend_check(struct usb_device *udev)
{
int w, i;
struct usb_interface *intf;
- unsigned long suspend_time, j;
/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
@@ -1701,87 +1644,46 @@ static int autosuspend_check(struct usb_device *udev)
return -EOPNOTSUPP;
}
udev->do_remote_wakeup = w;
-
- /* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request.
- */
- j = ACCESS_ONCE(jiffies);
- suspend_time = udev->last_busy + udev->autosuspend_delay;
- if (time_before(j, suspend_time)) {
- pm_schedule_suspend(&udev->dev, jiffies_to_msecs(
- round_jiffies_up_relative(suspend_time - j)));
- return -EAGAIN;
- }
return 0;
}
static int usb_runtime_suspend(struct device *dev)
{
- int status = 0;
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
/* A USB device can be suspended if it passes the various autosuspend
* checks. Runtime suspend for a USB device means suspending all the
* interfaces and then the device itself.
*/
- if (is_usb_device(dev)) {
- struct usb_device *udev = to_usb_device(dev);
-
- if (autosuspend_check(udev) != 0)
- return -EAGAIN;
-
- status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
-
- /* If an interface fails the suspend, adjust the last_busy
- * time so that we don't get another suspend attempt right
- * away.
- */
- if (status) {
- udev->last_busy = jiffies +
- (udev->autosuspend_delay == 0 ?
- HZ/2 : 0);
- }
-
- /* Prevent the parent from suspending immediately after */
- else if (udev->parent)
- udev->parent->last_busy = jiffies;
- }
+ if (autosuspend_check(udev) != 0)
+ return -EAGAIN;
- /* Runtime suspend for a USB interface doesn't mean anything. */
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
return status;
}
static int usb_runtime_resume(struct device *dev)
{
+ struct usb_device *udev = to_usb_device(dev);
+ int status;
+
/* Runtime resume for a USB device means resuming both the device
* and all its interfaces.
*/
- if (is_usb_device(dev)) {
- struct usb_device *udev = to_usb_device(dev);
- int status;
-
- status = usb_resume_both(udev, PMSG_AUTO_RESUME);
- udev->last_busy = jiffies;
- return status;
- }
-
- /* Runtime resume for a USB interface doesn't mean anything. */
- return 0;
+ status = usb_resume_both(udev, PMSG_AUTO_RESUME);
+ return status;
}
static int usb_runtime_idle(struct device *dev)
{
+ struct usb_device *udev = to_usb_device(dev);
+
/* An idle USB device can be suspended if it passes the various
- * autosuspend checks. An idle interface can be suspended at
- * any time.
+ * autosuspend checks.
*/
- if (is_usb_device(dev)) {
- struct usb_device *udev = to_usb_device(dev);
-
- if (autosuspend_check(udev) != 0)
- return 0;
- }
-
- pm_runtime_suspend(dev);
+ if (autosuspend_check(udev) == 0)
+ pm_runtime_autosuspend(dev);
return 0;
}