aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-05-17 10:40:51 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-17 14:20:24 -0400
commit1e12c910eed82da6971f1c0421a069c680faba2e (patch)
tree46851229d59c72fa10596f7cecd567918ce348eb /drivers
parent2b7aaf503d56216b847c8265421d2a7d9b42df3e (diff)
EHCI: don't rescan interrupt QHs needlessly
This patch (as1466) speeds up processing of ehci-hcd's periodic list. The existing code will pointlessly rescan an interrupt endpoint queue each time it encounters the queue's QH in the periodic list, which can happen quite a few times if the endpoint's period is low. On some embedded systems, this useless overhead can waste so much time that the driver falls hopelessly behind and loses events. The patch introduces a "periodic_stamp" variable, which gets incremented each time scan_periodic() runs and each time the scan advances to a new frame. If the corresponding stamp in an interrupt QH is equal to the current periodic_stamp, we assume the QH has already been scanned and skip over it. Otherwise we scan the QH as usual, and if none of its URBs have completed then we store the current periodic_stamp in the QH's stamp, preventing it from being scanned again. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-q.c1
-rw-r--r--drivers/usb/host/ehci-sched.c14
-rw-r--r--drivers/usb/host/ehci.h1
3 files changed, 12 insertions, 4 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index a46d6a1388c..5d6bc624c96 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -826,6 +826,7 @@ qh_make (
826 is_input, 0, 826 is_input, 0,
827 hb_mult(maxp) * max_packet(maxp))); 827 hb_mult(maxp) * max_packet(maxp)));
828 qh->start = NO_FRAME; 828 qh->start = NO_FRAME;
829 qh->stamp = ehci->periodic_stamp;
829 830
830 if (urb->dev->speed == USB_SPEED_HIGH) { 831 if (urb->dev->speed == USB_SPEED_HIGH) {
831 qh->c_usecs = 0; 832 qh->c_usecs = 0;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 1543c838b3d..a7408d88fda 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -2287,6 +2287,7 @@ scan_periodic (struct ehci_hcd *ehci)
2287 } 2287 }
2288 clock &= mod - 1; 2288 clock &= mod - 1;
2289 clock_frame = clock >> 3; 2289 clock_frame = clock >> 3;
2290 ++ehci->periodic_stamp;
2290 2291
2291 for (;;) { 2292 for (;;) {
2292 union ehci_shadow q, *q_p; 2293 union ehci_shadow q, *q_p;
@@ -2315,10 +2316,14 @@ restart:
2315 temp.qh = qh_get (q.qh); 2316 temp.qh = qh_get (q.qh);
2316 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); 2317 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
2317 q = q.qh->qh_next; 2318 q = q.qh->qh_next;
2318 modified = qh_completions (ehci, temp.qh); 2319 if (temp.qh->stamp != ehci->periodic_stamp) {
2319 if (unlikely(list_empty(&temp.qh->qtd_list) || 2320 modified = qh_completions(ehci, temp.qh);
2320 temp.qh->needs_rescan)) 2321 if (!modified)
2321 intr_deschedule (ehci, temp.qh); 2322 temp.qh->stamp = ehci->periodic_stamp;
2323 if (unlikely(list_empty(&temp.qh->qtd_list) ||
2324 temp.qh->needs_rescan))
2325 intr_deschedule(ehci, temp.qh);
2326 }
2322 qh_put (temp.qh); 2327 qh_put (temp.qh);
2323 break; 2328 break;
2324 case Q_TYPE_FSTN: 2329 case Q_TYPE_FSTN:
@@ -2460,6 +2465,7 @@ restart:
2460 if (ehci->clock_frame != clock_frame) { 2465 if (ehci->clock_frame != clock_frame) {
2461 free_cached_lists(ehci); 2466 free_cached_lists(ehci);
2462 ehci->clock_frame = clock_frame; 2467 ehci->clock_frame = clock_frame;
2468 ++ehci->periodic_stamp;
2463 } 2469 }
2464 } else { 2470 } else {
2465 now_uframe++; 2471 now_uframe++;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 829213423de..f68e419cae8 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -118,6 +118,7 @@ struct ehci_hcd { /* one per controller */
118 struct timer_list watchdog; 118 struct timer_list watchdog;
119 unsigned long actions; 119 unsigned long actions;
120 unsigned stamp; 120 unsigned stamp;
121 unsigned periodic_stamp;
121 unsigned random_frame; 122 unsigned random_frame;
122 unsigned long next_statechange; 123 unsigned long next_statechange;
123 ktime_t last_periodic_enable; 124 ktime_t last_periodic_enable;