aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-11-15 15:57:51 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-11-16 17:03:41 -0500
commitfcc4a01eb8661226e80632327673f67bf6a5840b (patch)
treedc05c200ccfac2daad6d1efe413ae6fa92f1638d /drivers/usb/core
parent6ddf27cdbc218a412d7e993fdc08e30eec2042ce (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.c77
-rw-r--r--drivers/usb/core/hub.c1
-rw-r--r--drivers/usb/core/quirks.c6
-rw-r--r--drivers/usb/core/sysfs.c34
-rw-r--r--drivers/usb/core/usb.c3
-rw-r--r--drivers/usb/core/usb.h2
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 */
1421void 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);
1508void usb_autopm_put_interface_async(struct usb_interface *intf) 1483void 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);
334static ssize_t 334static ssize_t
335show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) 335show_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
342static ssize_t 340static ssize_t
343set_autosuspend(struct device *dev, struct device_attribute *attr, 341set_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
77extern void usb_autosuspend_device(struct usb_device *udev); 77extern void usb_autosuspend_device(struct usb_device *udev);
78extern void usb_try_autosuspend_device(struct usb_device *udev);
79extern int usb_autoresume_device(struct usb_device *udev); 78extern int usb_autoresume_device(struct usb_device *udev);
80extern int usb_remote_wakeup(struct usb_device *dev); 79extern 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)
86static inline int usb_autoresume_device(struct usb_device *udev) 84static inline int usb_autoresume_device(struct usb_device *udev)
87{ 85{
88 return 0; 86 return 0;