This patch (as929) adds usb_autopm_get_interface_burst() to the
autosuspend programming interface. It is intended for situations
where I/O events occur in bursts of activity; it reduces overhead by
not cancelling the device's autosuspend timer.
Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
---
Index: usb-2.6/drivers/usb/core/driver.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/driver.c
+++ usb-2.6/drivers/usb/core/driver.c
@@ -1126,6 +1126,7 @@ static int usb_suspend_both(struct usb_d
/**
* usb_resume_both - resume a USB device and its interfaces
* @udev: the usb_device to resume
+ * @burst: flag for burst-mode operation (don't disable the suspend timer)
*
* This is the central routine for resuming USB devices. It calls the
* the resume method for @udev and then calls the resume methods for all
@@ -1136,6 +1137,13 @@ static int usb_suspend_both(struct usb_d
* tree and assuring that @udev will be able to resume. If the parent is
* unable to resume successfully, the routine fails.
*
+ * If @burst is set then @udev's autosuspend timer isn't cancelled. This
+ * helps avoid timer overhead in situations where bursts of I/O requests
+ * occur during a short period of time. If the timer expires later while
+ * @udev is still busy, nothing will happen and the timer won't be restarted.
+ * If the timer expires after @udev has become idle again, it will either
+ * reschedule itself or perform an autosuspend as usual.
+ *
* The resume method calls are subject to mutual exclusion under control
* of @udev's pm_mutex. Many of these calls are also under the protection
* of @udev's device lock (including all requests originating outside the
@@ -1151,14 +1159,15 @@ static int usb_suspend_both(struct usb_d
*
* This routine can run only in process context.
*/
-static int usb_resume_both(struct usb_device *udev)
+static int usb_resume_both(struct usb_device *udev, int burst)
{
int status = 0;
int i;
struct usb_interface *intf;
struct usb_device *parent = udev->parent;
- cancel_delayed_work(&udev->autosuspend);
+ if (!burst)
+ cancel_delayed_work(&udev->autosuspend);
if (udev->state == USB_STATE_NOTATTACHED) {
status = -ENODEV;
goto done;
@@ -1233,7 +1242,7 @@ static int usb_autopm_do_device(struct u
WARN_ON(udev->pm_usage_cnt < 0);
if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
if (udev->state == USB_STATE_SUSPENDED)
- status = usb_resume_both(udev);
+ status = usb_resume_both(udev, 0);
if (status != 0)
udev->pm_usage_cnt -= inc_usage_cnt;
else if (inc_usage_cnt)
@@ -1338,7 +1347,7 @@ int usb_autoresume_device(struct usb_dev
* its device's autosuspend state.
*/
static int usb_autopm_do_interface(struct usb_interface *intf,
- int inc_usage_cnt)
+ int inc_usage_cnt, int burst)
{
struct usb_device *udev = interface_to_usbdev(intf);
int status = 0;
@@ -1351,7 +1360,7 @@ static int usb_autopm_do_interface(struc
intf->pm_usage_cnt += inc_usage_cnt;
if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
if (udev->state == USB_STATE_SUSPENDED)
- status = usb_resume_both(udev);
+ status = usb_resume_both(udev, burst);
if (status != 0)
intf->pm_usage_cnt -= inc_usage_cnt;
else if (inc_usage_cnt)
@@ -1401,7 +1410,7 @@ void usb_autopm_put_interface(struct usb
{
int status;
- status = usb_autopm_do_interface(intf, -1);
+ status = usb_autopm_do_interface(intf, -1, 0);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, intf->pm_usage_cnt);
}
@@ -1445,7 +1454,7 @@ int usb_autopm_get_interface(struct usb_
{
int status;
- status = usb_autopm_do_interface(intf, 1);
+ status = usb_autopm_do_interface(intf, 1, 0);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, intf->pm_usage_cnt);
return status;
@@ -1453,6 +1462,29 @@ int usb_autopm_get_interface(struct usb_
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
/**
+ * usb_autopm_get_interface_burst - increment a USB interface's PM-usage
counter for burst-mode operation
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine does almost exactly the same thing as
+ * usb_autopm_get_interface() above. The only difference is that it
+ * doesn't disable the device's autosuspend timer, so there's less
+ * overhead when the routine is called over and over again for a burst
+ * of I/O.
+ *
+ * This routine can run only in process context.
+ */
+int usb_autopm_get_interface_burst(struct usb_interface *intf)
+{
+ int status;
+
+ status = usb_autopm_do_interface(intf, 1, 1);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+ __FUNCTION__, status, intf->pm_usage_cnt);
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_burst);
+
+/**
* usb_autopm_set_interface - set a USB interface's autosuspend state
* @intf: the usb_interface whose state should be set
*
@@ -1467,7 +1499,7 @@ int usb_autopm_set_interface(struct usb_
{
int status;
- status = usb_autopm_do_interface(intf, 0);
+ status = usb_autopm_do_interface(intf, 0, 0);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, intf->pm_usage_cnt);
return status;
@@ -1524,7 +1556,7 @@ int usb_external_resume_device(struct us
usb_pm_lock(udev);
udev->auto_pm = 0;
- status = usb_resume_both(udev);
+ status = usb_resume_both(udev, 0);
udev->last_busy = jiffies;
usb_pm_unlock(udev);
Index: usb-2.6/include/linux/usb.h
===================================================================
--- usb-2.6.orig/include/linux/usb.h
+++ usb-2.6/include/linux/usb.h
@@ -432,6 +432,7 @@ extern struct usb_device *usb_find_devic
#ifdef CONFIG_USB_SUSPEND
extern int usb_autopm_set_interface(struct usb_interface *intf);
extern int usb_autopm_get_interface(struct usb_interface *intf);
+extern int usb_autopm_get_interface_burst(struct usb_interface *intf);
extern void usb_autopm_put_interface(struct usb_interface *intf);
static inline void usb_autopm_enable(struct usb_interface *intf)
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel