usb: ehci: Reduce overhead of the scan_periodic loop
authorBenoit Goby <benoit@android.com>
Thu, 9 Dec 2010 02:28:39 +0000 (18:28 -0800)
committerBenoit Goby <benoit@android.com>
Thu, 9 Dec 2010 21:14:21 +0000 (13:14 -0800)
scan_periodic is called with irq disabled. Merged Alan Stern's patch
to reduce the overhead of scan_periodic:

http://article.gmane.org/gmane.linux.usb.general/37441
Here is a patch which ought to reduce the overhead of the loop. It
avoids doing the expensive call to qh_completions() more than once
for each qh.

Change-Id: I218c75a1ce21edd3d58c7e8abd3e7f75880b6ad0
Signed-off-by: Benoit Goby <benoit@android.com>
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h

index 760118370e733ad5da82ec4e01c70cfe7443ebb0..95bd514c0d069cd2218883aee085e37e3b9e3e64 100644 (file)
@@ -838,6 +838,7 @@ qh_make (
                                is_input, 0,
                                hb_mult(maxp) * max_packet(maxp)));
                qh->start = NO_FRAME;
+               qh->stamp = ehci->periodic_stamp;
 
                if (urb->dev->speed == USB_SPEED_HIGH) {
                        qh->c_usecs = 0;
index a92526d6e5aeb4a306442df77d27b702e00c0d0c..fa442c5ec16beb44c10210f848e1f81644995699 100644 (file)
@@ -2261,6 +2261,7 @@ scan_periodic (struct ehci_hcd *ehci)
        }
        clock &= mod - 1;
        clock_frame = clock >> 3;
+       ++ehci->periodic_stamp;
 
        for (;;) {
                union ehci_shadow       q, *q_p;
@@ -2289,10 +2290,14 @@ restart:
                                temp.qh = qh_get (q.qh);
                                type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
                                q = q.qh->qh_next;
-                               modified = qh_completions (ehci, temp.qh);
-                               if (unlikely(list_empty(&temp.qh->qtd_list) ||
-                                               temp.qh->needs_rescan))
-                                       intr_deschedule (ehci, temp.qh);
+                               if (temp.qh->stamp != ehci->periodic_stamp) {
+                                       modified = qh_completions(ehci, temp.qh);
+                                       if (!modified)
+                                               temp.qh->stamp = ehci->periodic_stamp;
+                                       if (unlikely(list_empty(&temp.qh->qtd_list) ||
+                                                       temp.qh->needs_rescan))
+                                               intr_deschedule(ehci, temp.qh);
+                               }
                                qh_put (temp.qh);
                                break;
                        case Q_TYPE_FSTN:
@@ -2427,6 +2432,7 @@ restart:
                                free_cached_lists(ehci);
                                ehci->clock_frame = clock_frame;
                        }
+                       ++ehci->periodic_stamp;
                } else {
                        now_uframe++;
                        now_uframe &= mod - 1;
index 9dd486abd6212287035cc3594da7c314e82ab9c5..530540a4bdd4f7d4ef61760a67fc5238c86e4e53 100644 (file)
@@ -117,6 +117,7 @@ struct ehci_hcd {                   /* one per controller */
        struct timer_list       watchdog;
        unsigned long           actions;
        unsigned                stamp;
+       unsigned                periodic_stamp;
        unsigned                random_frame;
        unsigned long           next_statechange;
        ktime_t                 last_periodic_enable;