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

Reply via email to