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/ _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel