diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2010-11-15 15:57:51 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-16 17:03:41 -0500 |
commit | fcc4a01eb8661226e80632327673f67bf6a5840b (patch) | |
tree | dc05c200ccfac2daad6d1efe413ae6fa92f1638d /drivers/usb/core | |
parent | 6ddf27cdbc218a412d7e993fdc08e30eec2042ce (diff) |
USB: use the runtime-PM autosuspend implementation
This patch (as1428) converts USB over to the new runtime-PM core
autosuspend framework. One slightly awkward aspect of the conversion
is that USB devices will now have two suspend-delay attributes: the
old power/autosuspend file and the new power/autosuspend_delay_ms
file. One expresses the delay time in seconds and the other in
milliseconds, but otherwise they do the same thing. The old attribute
can be deprecated and then removed eventually.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/driver.c | 77 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 6 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 34 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 2 |
6 files changed, 13 insertions, 110 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 0a63e968c683..43c25c29ac1f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -1397,32 +1397,7 @@ void usb_autosuspend_device(struct usb_device *udev) | |||
1397 | int status; | 1397 | int status; |
1398 | 1398 | ||
1399 | usb_mark_last_busy(udev); | 1399 | usb_mark_last_busy(udev); |
1400 | status = pm_runtime_put_sync(&udev->dev); | 1400 | status = pm_runtime_put_sync_autosuspend(&udev->dev); |
1401 | dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", | ||
1402 | __func__, atomic_read(&udev->dev.power.usage_count), | ||
1403 | status); | ||
1404 | } | ||
1405 | |||
1406 | /** | ||
1407 | * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces | ||
1408 | * @udev: the usb_device to autosuspend | ||
1409 | * | ||
1410 | * This routine should be called when a core subsystem thinks @udev may | ||
1411 | * be ready to autosuspend. | ||
1412 | * | ||
1413 | * @udev's usage counter left unchanged. If it is 0 and all the interfaces | ||
1414 | * are inactive then an autosuspend will be attempted. The attempt may | ||
1415 | * fail or be delayed. | ||
1416 | * | ||
1417 | * The caller must hold @udev's device lock. | ||
1418 | * | ||
1419 | * This routine can run only in process context. | ||
1420 | */ | ||
1421 | void usb_try_autosuspend_device(struct usb_device *udev) | ||
1422 | { | ||
1423 | int status; | ||
1424 | |||
1425 | status = pm_runtime_idle(&udev->dev); | ||
1426 | dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", | 1401 | dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", |
1427 | __func__, atomic_read(&udev->dev.power.usage_count), | 1402 | __func__, atomic_read(&udev->dev.power.usage_count), |
1428 | status); | 1403 | status); |
@@ -1508,32 +1483,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface); | |||
1508 | void usb_autopm_put_interface_async(struct usb_interface *intf) | 1483 | void usb_autopm_put_interface_async(struct usb_interface *intf) |
1509 | { | 1484 | { |
1510 | struct usb_device *udev = interface_to_usbdev(intf); | 1485 | struct usb_device *udev = interface_to_usbdev(intf); |
1511 | unsigned long last_busy; | 1486 | int status; |
1512 | int status = 0; | ||
1513 | 1487 | ||
1514 | last_busy = udev->dev.power.last_busy; | ||
1515 | usb_mark_last_busy(udev); | 1488 | usb_mark_last_busy(udev); |
1516 | atomic_dec(&intf->pm_usage_cnt); | 1489 | atomic_dec(&intf->pm_usage_cnt); |
1517 | pm_runtime_put_noidle(&intf->dev); | 1490 | status = pm_runtime_put(&intf->dev); |
1518 | |||
1519 | if (udev->dev.power.runtime_auto) { | ||
1520 | /* Optimization: Don't schedule a delayed autosuspend if | ||
1521 | * the timer is already running and the expiration time | ||
1522 | * wouldn't change. | ||
1523 | * | ||
1524 | * We have to use the interface's timer. Attempts to | ||
1525 | * schedule a suspend for the device would fail because | ||
1526 | * the interface is still active. | ||
1527 | */ | ||
1528 | if (intf->dev.power.timer_expires == 0 || | ||
1529 | round_jiffies_up(last_busy) != | ||
1530 | round_jiffies_up(jiffies)) { | ||
1531 | status = pm_schedule_suspend(&intf->dev, | ||
1532 | jiffies_to_msecs( | ||
1533 | round_jiffies_up_relative( | ||
1534 | udev->autosuspend_delay))); | ||
1535 | } | ||
1536 | } | ||
1537 | dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", | 1491 | dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", |
1538 | __func__, atomic_read(&intf->dev.power.usage_count), | 1492 | __func__, atomic_read(&intf->dev.power.usage_count), |
1539 | status); | 1493 | status); |
@@ -1651,7 +1605,6 @@ static int autosuspend_check(struct usb_device *udev) | |||
1651 | { | 1605 | { |
1652 | int w, i; | 1606 | int w, i; |
1653 | struct usb_interface *intf; | 1607 | struct usb_interface *intf; |
1654 | unsigned long suspend_time, j; | ||
1655 | 1608 | ||
1656 | /* Fail if autosuspend is disabled, or any interfaces are in use, or | 1609 | /* Fail if autosuspend is disabled, or any interfaces are in use, or |
1657 | * any interface drivers require remote wakeup but it isn't available. | 1610 | * any interface drivers require remote wakeup but it isn't available. |
@@ -1691,17 +1644,6 @@ static int autosuspend_check(struct usb_device *udev) | |||
1691 | return -EOPNOTSUPP; | 1644 | return -EOPNOTSUPP; |
1692 | } | 1645 | } |
1693 | udev->do_remote_wakeup = w; | 1646 | udev->do_remote_wakeup = w; |
1694 | |||
1695 | /* If everything is okay but the device hasn't been idle for long | ||
1696 | * enough, queue a delayed autosuspend request. | ||
1697 | */ | ||
1698 | j = ACCESS_ONCE(jiffies); | ||
1699 | suspend_time = udev->dev.power.last_busy + udev->autosuspend_delay; | ||
1700 | if (time_before(j, suspend_time)) { | ||
1701 | pm_schedule_suspend(&udev->dev, jiffies_to_msecs( | ||
1702 | round_jiffies_up_relative(suspend_time - j))); | ||
1703 | return -EAGAIN; | ||
1704 | } | ||
1705 | return 0; | 1647 | return 0; |
1706 | } | 1648 | } |
1707 | 1649 | ||
@@ -1719,17 +1661,8 @@ static int usb_runtime_suspend(struct device *dev) | |||
1719 | 1661 | ||
1720 | status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); | 1662 | status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); |
1721 | 1663 | ||
1722 | /* If an interface fails the suspend, adjust the last_busy | ||
1723 | * time so that we don't get another suspend attempt right | ||
1724 | * away. | ||
1725 | */ | ||
1726 | if (status) { | ||
1727 | udev->dev.power.last_busy = jiffies + | ||
1728 | (udev->autosuspend_delay == 0 ? HZ/2 : 0); | ||
1729 | } | ||
1730 | |||
1731 | /* Prevent the parent from suspending immediately after */ | 1664 | /* Prevent the parent from suspending immediately after */ |
1732 | else if (udev->parent) | 1665 | if (status == 0 && udev->parent) |
1733 | usb_mark_last_busy(udev->parent); | 1666 | usb_mark_last_busy(udev->parent); |
1734 | 1667 | ||
1735 | return status; | 1668 | return status; |
@@ -1756,7 +1689,7 @@ static int usb_runtime_idle(struct device *dev) | |||
1756 | * autosuspend checks. | 1689 | * autosuspend checks. |
1757 | */ | 1690 | */ |
1758 | if (autosuspend_check(udev) == 0) | 1691 | if (autosuspend_check(udev) == 0) |
1759 | pm_runtime_suspend(dev); | 1692 | pm_runtime_autosuspend(dev); |
1760 | return 0; | 1693 | return 0; |
1761 | } | 1694 | } |
1762 | 1695 | ||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7c2405eccc4b..fdb62ca10d86 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1803,6 +1803,7 @@ int usb_new_device(struct usb_device *udev) | |||
1803 | 1803 | ||
1804 | /* Tell the runtime-PM framework the device is active */ | 1804 | /* Tell the runtime-PM framework the device is active */ |
1805 | pm_runtime_set_active(&udev->dev); | 1805 | pm_runtime_set_active(&udev->dev); |
1806 | pm_runtime_use_autosuspend(&udev->dev); | ||
1806 | pm_runtime_enable(&udev->dev); | 1807 | pm_runtime_enable(&udev->dev); |
1807 | 1808 | ||
1808 | err = usb_enumerate_device(udev); /* Read descriptors */ | 1809 | err = usb_enumerate_device(udev); /* Read descriptors */ |
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 25719da45e33..e3531da16137 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
@@ -124,12 +124,6 @@ void usb_detect_quirks(struct usb_device *udev) | |||
124 | */ | 124 | */ |
125 | usb_disable_autosuspend(udev); | 125 | usb_disable_autosuspend(udev); |
126 | 126 | ||
127 | /* Autosuspend can also be disabled if the initial autosuspend_delay | ||
128 | * is negative. | ||
129 | */ | ||
130 | if (udev->autosuspend_delay < 0) | ||
131 | usb_autoresume_device(udev); | ||
132 | |||
133 | #endif | 127 | #endif |
134 | 128 | ||
135 | /* For the present, all devices default to USB-PERSIST enabled */ | 129 | /* For the present, all devices default to USB-PERSIST enabled */ |
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 9561e087907d..6781c369ce2d 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
@@ -334,44 +334,20 @@ static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL); | |||
334 | static ssize_t | 334 | static ssize_t |
335 | show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) | 335 | show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) |
336 | { | 336 | { |
337 | struct usb_device *udev = to_usb_device(dev); | 337 | return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000); |
338 | |||
339 | return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ); | ||
340 | } | 338 | } |
341 | 339 | ||
342 | static ssize_t | 340 | static ssize_t |
343 | set_autosuspend(struct device *dev, struct device_attribute *attr, | 341 | set_autosuspend(struct device *dev, struct device_attribute *attr, |
344 | const char *buf, size_t count) | 342 | const char *buf, size_t count) |
345 | { | 343 | { |
346 | struct usb_device *udev = to_usb_device(dev); | 344 | int value; |
347 | int value, old_delay; | ||
348 | int rc; | ||
349 | 345 | ||
350 | if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ || | 346 | if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/1000 || |
351 | value <= - INT_MAX/HZ) | 347 | value <= -INT_MAX/1000) |
352 | return -EINVAL; | 348 | return -EINVAL; |
353 | value *= HZ; | ||
354 | |||
355 | usb_lock_device(udev); | ||
356 | old_delay = udev->autosuspend_delay; | ||
357 | udev->autosuspend_delay = value; | ||
358 | |||
359 | if (old_delay < 0) { /* Autosuspend wasn't allowed */ | ||
360 | if (value >= 0) | ||
361 | usb_autosuspend_device(udev); | ||
362 | } else { /* Autosuspend was allowed */ | ||
363 | if (value < 0) { | ||
364 | rc = usb_autoresume_device(udev); | ||
365 | if (rc < 0) { | ||
366 | count = rc; | ||
367 | udev->autosuspend_delay = old_delay; | ||
368 | } | ||
369 | } else { | ||
370 | usb_try_autosuspend_device(udev); | ||
371 | } | ||
372 | } | ||
373 | 349 | ||
374 | usb_unlock_device(udev); | 350 | pm_runtime_set_autosuspend_delay(dev, value * 1000); |
375 | return count; | 351 | return count; |
376 | } | 352 | } |
377 | 353 | ||
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index fdd4130fbb7d..079cb57bab4f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
@@ -445,7 +445,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, | |||
445 | INIT_LIST_HEAD(&dev->filelist); | 445 | INIT_LIST_HEAD(&dev->filelist); |
446 | 446 | ||
447 | #ifdef CONFIG_PM | 447 | #ifdef CONFIG_PM |
448 | dev->autosuspend_delay = usb_autosuspend_delay * HZ; | 448 | pm_runtime_set_autosuspend_delay(&dev->dev, |
449 | usb_autosuspend_delay * 1000); | ||
449 | dev->connect_time = jiffies; | 450 | dev->connect_time = jiffies; |
450 | dev->active_duration = -jiffies; | 451 | dev->active_duration = -jiffies; |
451 | #endif | 452 | #endif |
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index cd882203ad34..b975450f403e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
@@ -75,14 +75,12 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) | |||
75 | #ifdef CONFIG_USB_SUSPEND | 75 | #ifdef CONFIG_USB_SUSPEND |
76 | 76 | ||
77 | extern void usb_autosuspend_device(struct usb_device *udev); | 77 | extern void usb_autosuspend_device(struct usb_device *udev); |
78 | extern void usb_try_autosuspend_device(struct usb_device *udev); | ||
79 | extern int usb_autoresume_device(struct usb_device *udev); | 78 | extern int usb_autoresume_device(struct usb_device *udev); |
80 | extern int usb_remote_wakeup(struct usb_device *dev); | 79 | extern int usb_remote_wakeup(struct usb_device *dev); |
81 | 80 | ||
82 | #else | 81 | #else |
83 | 82 | ||
84 | #define usb_autosuspend_device(udev) do {} while (0) | 83 | #define usb_autosuspend_device(udev) do {} while (0) |
85 | #define usb_try_autosuspend_device(udev) do {} while (0) | ||
86 | static inline int usb_autoresume_device(struct usb_device *udev) | 84 | static inline int usb_autoresume_device(struct usb_device *udev) |
87 | { | 85 | { |
88 | return 0; | 86 | return 0; |