aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-11-12 16:19:49 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 12:59:53 -0500
commit9ac39f28b5237a629e41ccfc1f73d3a55723045c (patch)
treec161d5b62d11b6e73605a37b2562b90fff689d9e
parentd4f373e57d3916814110968c5ea1155a8d972b5a (diff)
USB: add asynchronous autosuspend/autoresume support
This patch (as1160b) adds support routines for asynchronous autosuspend and autoresume, with accompanying documentation updates. There already are several potential users of this interface, and others are likely to arise as autosuspend support becomes more widespread. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/usb/power-management.txt22
-rw-r--r--drivers/usb/core/driver.c86
-rw-r--r--drivers/usb/core/hub.c5
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--include/linux/usb.h9
6 files changed, 117 insertions, 7 deletions
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
index e48ea1d51010..ad642615ad4c 100644
--- a/Documentation/usb/power-management.txt
+++ b/Documentation/usb/power-management.txt
@@ -313,11 +313,13 @@ three of the methods listed above. In addition, a driver indicates
313that it supports autosuspend by setting the .supports_autosuspend flag 313that it supports autosuspend by setting the .supports_autosuspend flag
314in its usb_driver structure. It is then responsible for informing the 314in its usb_driver structure. It is then responsible for informing the
315USB core whenever one of its interfaces becomes busy or idle. The 315USB core whenever one of its interfaces becomes busy or idle. The
316driver does so by calling these three functions: 316driver does so by calling these five functions:
317 317
318 int usb_autopm_get_interface(struct usb_interface *intf); 318 int usb_autopm_get_interface(struct usb_interface *intf);
319 void usb_autopm_put_interface(struct usb_interface *intf); 319 void usb_autopm_put_interface(struct usb_interface *intf);
320 int usb_autopm_set_interface(struct usb_interface *intf); 320 int usb_autopm_set_interface(struct usb_interface *intf);
321 int usb_autopm_get_interface_async(struct usb_interface *intf);
322 void usb_autopm_put_interface_async(struct usb_interface *intf);
321 323
322The functions work by maintaining a counter in the usb_interface 324The functions work by maintaining a counter in the usb_interface
323structure. When intf->pm_usage_count is > 0 then the interface is 325structure. When intf->pm_usage_count is > 0 then the interface is
@@ -330,10 +332,12 @@ associated with the device itself rather than any of its interfaces.
330This field is used only by the USB core.) 332This field is used only by the USB core.)
331 333
332The driver owns intf->pm_usage_count; it can modify the value however 334The driver owns intf->pm_usage_count; it can modify the value however
333and whenever it likes. A nice aspect of the usb_autopm_* routines is 335and whenever it likes. A nice aspect of the non-async usb_autopm_*
334that the changes they make are protected by the usb_device structure's 336routines is that the changes they make are protected by the usb_device
335PM mutex (udev->pm_mutex); however drivers may change pm_usage_count 337structure's PM mutex (udev->pm_mutex); however drivers may change
336without holding the mutex. 338pm_usage_count without holding the mutex. Drivers using the async
339routines are responsible for their own synchronization and mutual
340exclusion.
337 341
338 usb_autopm_get_interface() increments pm_usage_count and 342 usb_autopm_get_interface() increments pm_usage_count and
339 attempts an autoresume if the new value is > 0 and the 343 attempts an autoresume if the new value is > 0 and the
@@ -348,6 +352,14 @@ without holding the mutex.
348 is suspended, and it attempts an autosuspend if the value is 352 is suspended, and it attempts an autosuspend if the value is
349 <= 0 and the device isn't suspended. 353 <= 0 and the device isn't suspended.
350 354
355 usb_autopm_get_interface_async() and
356 usb_autopm_put_interface_async() do almost the same things as
357 their non-async counterparts. The differences are: they do
358 not acquire the PM mutex, and they use a workqueue to do their
359 jobs. As a result they can be called in an atomic context,
360 such as an URB's completion handler, but when they return the
361 device will not generally not yet be in the desired state.
362
351There also are a couple of utility routines drivers can use: 363There also are a couple of utility routines drivers can use:
352 364
353 usb_autopm_enable() sets pm_usage_cnt to 0 and then calls 365 usb_autopm_enable() sets pm_usage_cnt to 0 and then calls
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 8c081308b0e2..23b3c7e79d4b 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1341,6 +1341,19 @@ void usb_autosuspend_work(struct work_struct *work)
1341 usb_autopm_do_device(udev, 0); 1341 usb_autopm_do_device(udev, 0);
1342} 1342}
1343 1343
1344/* usb_autoresume_work - callback routine to autoresume a USB device */
1345void usb_autoresume_work(struct work_struct *work)
1346{
1347 struct usb_device *udev =
1348 container_of(work, struct usb_device, autoresume);
1349
1350 /* Wake it up, let the drivers do their thing, and then put it
1351 * back to sleep.
1352 */
1353 if (usb_autopm_do_device(udev, 1) == 0)
1354 usb_autopm_do_device(udev, -1);
1355}
1356
1344/** 1357/**
1345 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces 1358 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
1346 * @udev: the usb_device to autosuspend 1359 * @udev: the usb_device to autosuspend
@@ -1492,6 +1505,45 @@ void usb_autopm_put_interface(struct usb_interface *intf)
1492EXPORT_SYMBOL_GPL(usb_autopm_put_interface); 1505EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
1493 1506
1494/** 1507/**
1508 * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
1509 * @intf: the usb_interface whose counter should be decremented
1510 *
1511 * This routine does essentially the same thing as
1512 * usb_autopm_put_interface(): it decrements @intf's usage counter and
1513 * queues a delayed autosuspend request if the counter is <= 0. The
1514 * difference is that it does not acquire the device's pm_mutex;
1515 * callers must handle all synchronization issues themselves.
1516 *
1517 * Typically a driver would call this routine during an URB's completion
1518 * handler, if no more URBs were pending.
1519 *
1520 * This routine can run in atomic context.
1521 */
1522void usb_autopm_put_interface_async(struct usb_interface *intf)
1523{
1524 struct usb_device *udev = interface_to_usbdev(intf);
1525 int status = 0;
1526
1527 if (intf->condition == USB_INTERFACE_UNBOUND) {
1528 status = -ENODEV;
1529 } else {
1530 udev->last_busy = jiffies;
1531 --intf->pm_usage_cnt;
1532 if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
1533 status = -EPERM;
1534 else if (intf->pm_usage_cnt <= 0 &&
1535 !timer_pending(&udev->autosuspend.timer)) {
1536 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1537 round_jiffies_relative(
1538 udev->autosuspend_delay));
1539 }
1540 }
1541 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1542 __func__, status, intf->pm_usage_cnt);
1543}
1544EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
1545
1546/**
1495 * usb_autopm_get_interface - increment a USB interface's PM-usage counter 1547 * usb_autopm_get_interface - increment a USB interface's PM-usage counter
1496 * @intf: the usb_interface whose counter should be incremented 1548 * @intf: the usb_interface whose counter should be incremented
1497 * 1549 *
@@ -1537,6 +1589,37 @@ int usb_autopm_get_interface(struct usb_interface *intf)
1537EXPORT_SYMBOL_GPL(usb_autopm_get_interface); 1589EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
1538 1590
1539/** 1591/**
1592 * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter
1593 * @intf: the usb_interface whose counter should be incremented
1594 *
1595 * This routine does much the same thing as
1596 * usb_autopm_get_interface(): it increments @intf's usage counter and
1597 * queues an autoresume request if the result is > 0. The differences
1598 * are that it does not acquire the device's pm_mutex (callers must
1599 * handle all synchronization issues themselves), and it does not
1600 * autoresume the device directly (it only queues a request). After a
1601 * successful call, the device will generally not yet be resumed.
1602 *
1603 * This routine can run in atomic context.
1604 */
1605int usb_autopm_get_interface_async(struct usb_interface *intf)
1606{
1607 struct usb_device *udev = interface_to_usbdev(intf);
1608 int status = 0;
1609
1610 if (intf->condition == USB_INTERFACE_UNBOUND)
1611 status = -ENODEV;
1612 else if (udev->autoresume_disabled)
1613 status = -EPERM;
1614 else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
1615 queue_work(ksuspend_usb_wq, &udev->autoresume);
1616 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1617 __func__, status, intf->pm_usage_cnt);
1618 return status;
1619}
1620EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
1621
1622/**
1540 * usb_autopm_set_interface - set a USB interface's autosuspend state 1623 * usb_autopm_set_interface - set a USB interface's autosuspend state
1541 * @intf: the usb_interface whose state should be set 1624 * @intf: the usb_interface whose state should be set
1542 * 1625 *
@@ -1563,6 +1646,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
1563void usb_autosuspend_work(struct work_struct *work) 1646void usb_autosuspend_work(struct work_struct *work)
1564{} 1647{}
1565 1648
1649void usb_autoresume_work(struct work_struct *work)
1650{}
1651
1566#endif /* CONFIG_USB_SUSPEND */ 1652#endif /* CONFIG_USB_SUSPEND */
1567 1653
1568/** 1654/**
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b19cbfcd51da..95fb3104ba4f 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1374,8 +1374,9 @@ static void usb_stop_pm(struct usb_device *udev)
1374 usb_autosuspend_device(udev->parent); 1374 usb_autosuspend_device(udev->parent);
1375 usb_pm_unlock(udev); 1375 usb_pm_unlock(udev);
1376 1376
1377 /* Stop any autosuspend requests already submitted */ 1377 /* Stop any autosuspend or autoresume requests already submitted */
1378 cancel_rearming_delayed_work(&udev->autosuspend); 1378 cancel_delayed_work_sync(&udev->autosuspend);
1379 cancel_work_sync(&udev->autoresume);
1379} 1380}
1380 1381
1381#else 1382#else
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 400fa4cc9a34..44f2fc750b6d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -402,6 +402,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
402#ifdef CONFIG_PM 402#ifdef CONFIG_PM
403 mutex_init(&dev->pm_mutex); 403 mutex_init(&dev->pm_mutex);
404 INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); 404 INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
405 INIT_WORK(&dev->autoresume, usb_autoresume_work);
405 dev->autosuspend_delay = usb_autosuspend_delay * HZ; 406 dev->autosuspend_delay = usb_autosuspend_delay * HZ;
406 dev->connect_time = jiffies; 407 dev->connect_time = jiffies;
407 dev->active_duration = -jiffies; 408 dev->active_duration = -jiffies;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 9a1a45ac3add..b60ebb4de1a8 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -45,6 +45,7 @@ extern int usb_suspend(struct device *dev, pm_message_t msg);
45extern int usb_resume(struct device *dev); 45extern int usb_resume(struct device *dev);
46 46
47extern void usb_autosuspend_work(struct work_struct *work); 47extern void usb_autosuspend_work(struct work_struct *work);
48extern void usb_autoresume_work(struct work_struct *work);
48extern int usb_port_suspend(struct usb_device *dev); 49extern int usb_port_suspend(struct usb_device *dev);
49extern int usb_port_resume(struct usb_device *dev); 50extern int usb_port_resume(struct usb_device *dev);
50extern int usb_external_suspend_device(struct usb_device *udev, 51extern int usb_external_suspend_device(struct usb_device *udev,
diff --git a/include/linux/usb.h b/include/linux/usb.h
index f72aa51f7bcd..859a88e6ce9c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -398,6 +398,7 @@ struct usb_tt;
398 * @urbnum: number of URBs submitted for the whole device 398 * @urbnum: number of URBs submitted for the whole device
399 * @active_duration: total time device is not suspended 399 * @active_duration: total time device is not suspended
400 * @autosuspend: for delayed autosuspends 400 * @autosuspend: for delayed autosuspends
401 * @autoresume: for autoresumes requested while in_interrupt
401 * @pm_mutex: protects PM operations 402 * @pm_mutex: protects PM operations
402 * @last_busy: time of last use 403 * @last_busy: time of last use
403 * @autosuspend_delay: in jiffies 404 * @autosuspend_delay: in jiffies
@@ -476,6 +477,7 @@ struct usb_device {
476 477
477#ifdef CONFIG_PM 478#ifdef CONFIG_PM
478 struct delayed_work autosuspend; 479 struct delayed_work autosuspend;
480 struct work_struct autoresume;
479 struct mutex pm_mutex; 481 struct mutex pm_mutex;
480 482
481 unsigned long last_busy; 483 unsigned long last_busy;
@@ -513,6 +515,8 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
513extern int usb_autopm_set_interface(struct usb_interface *intf); 515extern int usb_autopm_set_interface(struct usb_interface *intf);
514extern int usb_autopm_get_interface(struct usb_interface *intf); 516extern int usb_autopm_get_interface(struct usb_interface *intf);
515extern void usb_autopm_put_interface(struct usb_interface *intf); 517extern void usb_autopm_put_interface(struct usb_interface *intf);
518extern int usb_autopm_get_interface_async(struct usb_interface *intf);
519extern void usb_autopm_put_interface_async(struct usb_interface *intf);
516 520
517static inline void usb_autopm_enable(struct usb_interface *intf) 521static inline void usb_autopm_enable(struct usb_interface *intf)
518{ 522{
@@ -539,8 +543,13 @@ static inline int usb_autopm_set_interface(struct usb_interface *intf)
539static inline int usb_autopm_get_interface(struct usb_interface *intf) 543static inline int usb_autopm_get_interface(struct usb_interface *intf)
540{ return 0; } 544{ return 0; }
541 545
546static inline int usb_autopm_get_interface_async(struct usb_interface *intf)
547{ return 0; }
548
542static inline void usb_autopm_put_interface(struct usb_interface *intf) 549static inline void usb_autopm_put_interface(struct usb_interface *intf)
543{ } 550{ }
551static inline void usb_autopm_put_interface_async(struct usb_interface *intf)
552{ }
544static inline void usb_autopm_enable(struct usb_interface *intf) 553static inline void usb_autopm_enable(struct usb_interface *intf)
545{ } 554{ }
546static inline void usb_autopm_disable(struct usb_interface *intf) 555static inline void usb_autopm_disable(struct usb_interface *intf)