mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 09:50:04 +00:00
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>
This commit is contained in:
parent
2b7aaf503d
commit
1e12c910ee
3 changed files with 12 additions and 4 deletions
|
@ -826,6 +826,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;
|
||||
|
|
|
@ -2287,6 +2287,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
}
|
||||
clock &= mod - 1;
|
||||
clock_frame = clock >> 3;
|
||||
++ehci->periodic_stamp;
|
||||
|
||||
for (;;) {
|
||||
union ehci_shadow q, *q_p;
|
||||
|
@ -2315,10 +2316,14 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
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:
|
||||
|
@ -2460,6 +2465,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
if (ehci->clock_frame != clock_frame) {
|
||||
free_cached_lists(ehci);
|
||||
ehci->clock_frame = clock_frame;
|
||||
++ehci->periodic_stamp;
|
||||
}
|
||||
} else {
|
||||
now_uframe++;
|
||||
|
|
|
@ -118,6 +118,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;
|
||||
|
|
Loading…
Reference in a new issue