ChangeSet 1.883.3.1, 2002/12/16 10:31:05-08:00, david-b@pacbell.net [PATCH] ehci-hcd (1/2): portability (2.4), tasklet, This should be innocuous; I expect most folk won't notice anything better (or worse) from this patch unless they're using Intel EHCI. removing tasklet - parts of davem's patch (passing pt_regs down) - remove 'max_completions' - update cleanup after hc died - fix an urb unlink oops (null ptr) that happens more often this way talking to hardware - fixes for some short read issues (may still be others) * use qtd->hw_alt_next to stop qh processing after short reads * detect/report short reads differently - longer reset timeout (it was excessively short, broke Intel) other - simpler diagnostics portability to 2.4: wrap dev_err() etc - urb unlink wait and non-wait unlink codepaths share most code - don't try ehci_stop() in interrupt context (bug from hcd layer) - minor stuff, including * some "after hc died" paths were wrong * verbose debug messages compile again * don't break error irq count diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c Wed Dec 18 00:35:29 2002 +++ b/drivers/usb/host/ehci-dbg.c Wed Dec 18 00:35:29 2002 @@ -18,21 +18,45 @@ /* this file is part of ehci-hcd.c */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,50) + #define ehci_dbg(ehci, fmt, args...) \ dev_dbg (*(ehci)->hcd.controller, fmt, ## args ) +#define ehci_err(ehci, fmt, args...) \ + dev_err (*(ehci)->hcd.controller, fmt, ## args ) +#define ehci_info(ehci, fmt, args...) \ + dev_info (*(ehci)->hcd.controller, fmt, ## args ) +#define ehci_warn(ehci, fmt, args...) \ + dev_warn (*(ehci)->hcd.controller, fmt, ## args ) -#ifdef EHCI_VERBOSE_DEBUG -#define ehci_vdbg(ehci, fmt, args...) \ - dev_dbg (*(ehci)->hcd.controller, fmt, ## args ) #else -#define ehci_vdbg(ehci, fmt, args...) do { } while (0) + +#ifdef DEBUG +#define ehci_dbg(ehci, fmt, args...) \ + printk(KERN_DEBUG "%s %s: " fmt, hcd_name, \ + (ehci)->hcd.pdev->slot_name, ## args ) +#else +#define ehci_dbg(ehci, fmt, args...) do { } while (0) +#endif + +#define ehci_err(ehci, fmt, args...) \ + printk(KERN_ERR "%s %s: " fmt, hcd_name, \ + (ehci)->hcd.pdev->slot_name, ## args ) +#define ehci_info(ehci, fmt, args...) \ + printk(KERN_INFO "%s %s: " fmt, hcd_name, \ + (ehci)->hcd.pdev->slot_name, ## args ) +#define ehci_warn(ehci, fmt, args...) \ + printk(KERN_WARNING "%s %s: " fmt, hcd_name, \ + (ehci)->hcd.pdev->slot_name, ## args ) #endif #ifdef EHCI_VERBOSE_DEBUG # define vdbg dbg +# define ehci_vdbg ehci_dbg #else - static inline void vdbg (char *fmt, ...) { } +# define vdbg(fmt,args...) do { } while (0) +# define ehci_vdbg(ehci, fmt, args...) do { } while (0) #endif #ifdef DEBUG @@ -289,7 +313,8 @@ scratch = cpu_to_le32p (&qh->hw_info1); hw_curr = cpu_to_le32p (&qh->hw_current); - temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x (%08x %08x)", + temp = snprintf (next, size, + "qh/%p dev%d %cs ep%d %08x %08x (%08x %08x)", qh, scratch & 0x007f, speed_char (scratch), (scratch >> 8) & 0x000f, diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Wed Dec 18 00:35:29 2002 +++ b/drivers/usb/host/ehci-hcd.c Wed Dec 18 00:35:29 2002 @@ -123,12 +123,6 @@ MODULE_PARM (log2_irq_thresh, "i"); MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); -/* allow irqs at least every N URB completions */ -static int max_completions = 16; -MODULE_PARM (max_completions, "i"); -MODULE_PARM_DESC (max_completions, - "limit for urb completions called with irqs disenabled"); - #define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT) /*-------------------------------------------------------------------------*/ @@ -202,7 +196,7 @@ dbg_cmd (ehci, "reset", command); writel (command, &ehci->regs->command); ehci->hcd.state = USB_STATE_HALT; - return handshake (&ehci->regs->command, CMD_RESET, 0, 250); + return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); } /* idle the controller (from running) */ @@ -289,8 +283,7 @@ pci_read_config_dword (ehci->hcd.pdev, where, &cap); } while ((cap & (1 << 16)) && msec); if (cap & (1 << 16)) { - dev_info (*ehci->hcd.controller, - "BIOS handoff failed (%d, %04x)\n", + ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); return 1; } @@ -333,8 +326,7 @@ return -EOPNOTSUPP; break; case 0: /* illegal reserved capability */ - dev_warn (*ehci->hcd.controller, - "illegal capability!\n"); + ehci_warn (ehci, "illegal capability!\n"); cap = 0; /* FALLTHROUGH */ default: /* unknown */ @@ -381,6 +373,8 @@ * dedicate a qh for the async ring head, since we couldn't unlink * a 'real' qh without stopping the async schedule [4.8]. use it * as the 'reclamation list head' too. + * its dummy is used in hw_alt_next of many tds, to prevent the qh + * from automatically advancing to the next td after short reads. */ ehci->async->qh_next.qh = 0; ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma); @@ -388,8 +382,7 @@ ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT); ehci->async->hw_qtd_next = EHCI_LIST_END; ehci->async->qh_state = QH_STATE_LINKED; - ehci_qtd_free (ehci, ehci->async->dummy); - ehci->async->dummy = 0; + ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma); writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); /* @@ -406,8 +399,7 @@ if (HCC_64BIT_ADDR (hcc_params)) { writel (0, &ehci->regs->segment); if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL)) - dev_info (*ehci->hcd.controller, - "enabled 64bit PCI DMA (DAC)\n"); + ehci_info (ehci, "enabled 64bit PCI DMA\n"); } /* clear interrupt enables, set irq latency */ @@ -454,7 +446,7 @@ /* PCI Serial Bus Release Number is at 0x60 offset */ pci_read_config_byte (hcd->pdev, 0x60, &tempbyte); temp = readw (&ehci->caps->hci_version); - dev_info (*hcd->controller, + ehci_info (ehci, "USB %x.%x enabled, EHCI %x.%02x, driver %s\n", ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f), temp >> 8, temp & 0xff, DRIVER_VERSION); @@ -494,10 +486,11 @@ /* no more interrupts ... */ if (hcd->state == USB_STATE_RUNNING) ehci_ready (ehci); - if (in_interrupt ()) /* should not happen!! */ - dev_err (*hcd->controller, "stopped %s!\n", RUN_CONTEXT); - else - del_timer_sync (&ehci->watchdog); + if (in_interrupt ()) { /* must not happen!! */ + ehci_err (ehci, "stopped in_interrupt!\n"); + return; + } + del_timer_sync (&ehci->watchdog); ehci_reset (ehci); /* let companion controllers work when we aren't */ @@ -621,14 +614,15 @@ static void ehci_tasklet (unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; + struct pt_regs *regs = NULL; spin_lock_irq (&ehci->lock); if (ehci->reclaim_ready) - end_unlink_async (ehci); - scan_async (ehci); + end_unlink_async (ehci, regs); + scan_async (ehci, regs); if (ehci->next_uframe != -1) - scan_periodic (ehci); + scan_periodic (ehci, regs); spin_unlock_irq (&ehci->lock); } @@ -643,7 +637,7 @@ /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { - dbg ("%s: device removed!", hcd_to_bus (hcd)->bus_name); + ehci_dbg (ehci, "device removed\n"); goto dead; } @@ -681,8 +675,7 @@ /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { - err ("%s: fatal error, state %x", - hcd_to_bus (hcd)->bus_name, hcd->state); + ehci_err (ehci, "fatal error\n"); dead: ehci_reset (ehci); /* generic layer kills/unlinks all urbs, then @@ -754,52 +747,52 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; + struct ehci_qh *qh; unsigned long flags; + int maybe_irq = 1; - ehci_vdbg (ehci, "urb_dequeue %p qh %p state %d\n", - urb, qh, qh->qh_state); - + spin_lock_irqsave (&ehci->lock, flags); switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: default: - spin_lock_irqsave (&ehci->lock, flags); - if (ehci->reclaim) { - vdbg ("dq %p: reclaim = %p, %s", - qh, ehci->reclaim, RUN_CONTEXT); - if (qh == ehci->reclaim) { - /* unlinking qh for another queued urb? */ - spin_unlock_irqrestore (&ehci->lock, flags); - return 0; - } - if (in_interrupt ()) { - spin_unlock_irqrestore (&ehci->lock, flags); - return -EAGAIN; - } - while (qh->qh_state == QH_STATE_LINKED - && ehci->reclaim - && ehci->hcd.state != USB_STATE_HALT - ) { - spin_unlock_irqrestore (&ehci->lock, flags); - /* let pending unlinks complete */ - wait_ms (1); - spin_lock_irqsave (&ehci->lock, flags); + qh = (struct ehci_qh *) urb->hcpriv; + if (!qh) + break; + while (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && HCD_IS_RUNNING (ehci->hcd.state) + ) { + spin_unlock_irqrestore (&ehci->lock, flags); + + if (maybe_irq) { + if (in_interrupt ()) + return -EAGAIN; + maybe_irq = 0; } + /* let pending unlinks complete, so this can start */ + wait_ms (1); + + spin_lock_irqsave (&ehci->lock, flags); } + if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim) + end_unlink_async (ehci, NULL); + + /* something else might have unlinked the qh by now */ if (qh->qh_state == QH_STATE_LINKED) start_unlink_async (ehci, qh); - spin_unlock_irqrestore (&ehci->lock, flags); break; case PIPE_INTERRUPT: - spin_lock_irqsave (&ehci->lock, flags); + qh = (struct ehci_qh *) urb->hcpriv; + if (!qh) + break; if (qh->qh_state == QH_STATE_LINKED) { /* messy, can spin or block a microframe ... */ intr_deschedule (ehci, qh, 1); /* qh_state == IDLE */ } - qh_completions (ehci, qh); + qh_completions (ehci, qh, NULL); /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) @@ -817,7 +810,6 @@ } return status; } - spin_unlock_irqrestore (&ehci->lock, flags); break; case PIPE_ISOCHRONOUS: @@ -828,6 +820,7 @@ urb->transfer_flags |= EHCI_STATE_UNLINK; break; } + spin_unlock_irqrestore (&ehci->lock, flags); return 0; } diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c --- a/drivers/usb/host/ehci-hub.c Wed Dec 18 00:35:29 2002 +++ b/drivers/usb/host/ehci-hub.c Wed Dec 18 00:35:29 2002 @@ -315,7 +315,7 @@ wIndex + 1); temp |= PORT_OWNER; } else { - ehci_vdbg (ehci, "port %d reset", wIndex + 1); + ehci_vdbg (ehci, "port %d reset\n", wIndex + 1); temp |= PORT_RESET; temp &= ~PORT_PE; diff -Nru a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c --- a/drivers/usb/host/ehci-mem.c Wed Dec 18 00:35:29 2002 +++ b/drivers/usb/host/ehci-mem.c Wed Dec 18 00:35:29 2002 @@ -73,8 +73,11 @@ dma_addr_t dma; qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); - if (qtd != 0) + if (qtd != 0) { ehci_qtd_init (qtd, dma); + if (ehci->async) + qtd->hw_alt_next = ehci->async->hw_alt_next; + } return qtd; } diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c Wed Dec 18 00:35:29 2002 +++ b/drivers/usb/host/ehci-q.c Wed Dec 18 00:35:29 2002 @@ -85,11 +85,12 @@ /* update halted (but potentially linked) qh */ -static void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd) +static void +qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) { qh->hw_current = 0; qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); - qh->hw_alt_next = EHCI_LIST_END; + qh->hw_alt_next = ehci->async->hw_alt_next; /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); @@ -98,7 +99,12 @@ /*-------------------------------------------------------------------------*/ -static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token) +static inline void qtd_copy_status ( + struct ehci_hcd *ehci, + struct urb *urb, + size_t length, + u32 token +) { /* count IN/OUT bytes, not SETUP (even short packets) */ if (likely (QTD_PID (token) != 2)) @@ -132,7 +138,7 @@ ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", - usb_pipedev (urb->pipe), + usb_pipedevice (urb->pipe), usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", token, urb->status); @@ -157,9 +163,17 @@ } } } + + /* force cleanup after short read; not necessarily an error */ + if (unlikely (urb->status == -EINPROGRESS + && QTD_LENGTH (token) != 0 + && QTD_PID (token) == 1)) { + urb->status = -EREMOTEIO; + } } -static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +static void +ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs) { if (likely (urb->hcpriv != 0)) { struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; @@ -174,24 +188,26 @@ urb->hcpriv = 0; } - if (likely (urb->status == -EINPROGRESS)) { - if (urb->actual_length != urb->transfer_buffer_length - && (urb->transfer_flags & URB_SHORT_NOT_OK)) - urb->status = -EREMOTEIO; - else + switch (urb->status) { + case -EINPROGRESS: /* success */ + urb->status = 0; + default: /* fault */ + COUNT (ehci->stats.complete); + break; + case -EREMOTEIO: /* fault or normal */ + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) urb->status = 0; - } - - if (likely (urb->status == 0)) COUNT (ehci->stats.complete); - else if (urb->status == -ECONNRESET || urb->status == -ENOENT) + break; + case -ECONNRESET: /* canceled */ + case -ENOENT: COUNT (ehci->stats.unlink); - else - COUNT (ehci->stats.error); + break; + } /* complete() can reenter this HCD */ spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (&ehci->hcd, urb, NULL); + usb_hcd_giveback_urb (&ehci->hcd, urb, regs); spin_lock (&ehci->lock); } @@ -203,14 +219,14 @@ * indicating how much "real" work we did. */ static unsigned -qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) +qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) { struct ehci_qtd *qtd, *last; struct list_head *next, *qtd_list = &qh->qtd_list; - int unlink = 0, halted = 0; + int unlink = 0, stopped = 0; unsigned count = 0; - if (unlikely (list_empty (qtd_list))) + if (unlikely (list_empty (&qh->qtd_list))) return count; /* scan QTDs till end of list, or we reach an active one */ @@ -225,7 +241,7 @@ /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done (ehci, last->urb, regs); count++; } ehci_qtd_free (ehci, last); @@ -236,12 +252,14 @@ /* QTDs at tail may be active if QH+HC are running, * or when unlinking some urbs queued to this QH */ + rmb (); token = le32_to_cpu (qtd->hw_token); - halted = halted + stopped = stopped + || (qh->qh_state == QH_STATE_IDLE) || (__constant_cpu_to_le32 (QTD_STS_HALT) & qh->hw_token) != 0 || (ehci->hcd.state == USB_STATE_HALT) - || (qh->qh_state == QH_STATE_IDLE); + || (qh->hw_current == ehci->async->hw_alt_next); // FIXME Remove the automagic unlink mode. // Drivers can now clean up safely; it's their job. @@ -257,7 +275,7 @@ /* status copied below */ /* QH halts only because of fault (above) or unlink (here). */ - } else if (unlikely (halted != 0)) { + } else if (unlikely (stopped != 0)) { /* unlinking everything because of HC shutdown? */ if (ehci->hcd.state == USB_STATE_HALT) { @@ -293,7 +311,7 @@ } spin_lock (&urb->lock); - qtd_copy_status (urb, qtd->length, token); + qtd_copy_status (ehci, urb, qtd->length, token); spin_unlock (&urb->lock); list_del (&qtd->qtd_list); @@ -311,14 +329,14 @@ /* last urb's completion might still need calling */ if (likely (last != 0)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done (ehci, last->urb, regs); count++; ehci_qtd_free (ehci, last); } /* reactivate queue after error and driver's cleanup */ - if (unlikely (halted && !list_empty (qtd_list))) { - qh_update (qh, list_entry (qtd_list->next, + if (unlikely (stopped && !list_empty (&qh->qtd_list))) { + qh_update (ehci, qh, list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list)); } @@ -420,7 +438,6 @@ for (;;) { int this_qtd_len; - qtd->urb = urb; this_qtd_len = qtd_fill (qtd, buf, len, token); len -= this_qtd_len; buf += this_qtd_len; @@ -658,7 +675,7 @@ list_splice (qtd_list, &qh->qtd_list); qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); - qh_update (qh, qtd); + qh_update (ehci, qh, qtd); } else { qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END; } @@ -784,6 +801,7 @@ list_add (&dummy->qtd_list, qtd_list); ehci_qtd_init (qtd, qtd->qtd_dma); + qtd->hw_alt_next = ehci->async->hw_alt_next; qh->dummy = qtd; /* hc must see the new dummy at list end */ @@ -797,15 +815,6 @@ /* no URB queued */ } else { - struct ehci_qtd *last_qtd; - - /* make sure hc sees current dummy at the end */ - last_qtd = list_entry (qtd_list->prev, - struct ehci_qtd, qtd_list); - last_qtd->hw_next = QTD_NEXT (qh->dummy->qtd_dma); - - // dbg_qh ("empty qh", ehci, qh); - /* usb_clear_halt() means qh data toggle gets reset */ if (unlikely (!usb_gettoggle (urb->dev, (epnum & 0x0f), @@ -813,8 +822,17 @@ clear_toggle (urb->dev, epnum & 0x0f, !(epnum & 0x10), qh); } - if (qtd) - qh_update (qh, qtd); + + /* make sure hc sees current dummy at the end */ + if (qtd) { + struct ehci_qtd *last_qtd; + + last_qtd = list_entry (qtd_list->prev, + struct ehci_qtd, qtd_list); + last_qtd->hw_next = QTD_NEXT ( + qh->dummy->qtd_dma); + qh_update (ehci, qh, qtd); + } } list_splice (qtd_list, qh->qtd_list.prev); @@ -877,34 +895,38 @@ /*-------------------------------------------------------------------------*/ /* the async qh for the qtds being reclaimed are now unlinked from the HC */ -/* caller must not own ehci->lock */ -static void end_unlink_async (struct ehci_hcd *ehci) +static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) { struct ehci_qh *qh = ehci->reclaim; del_timer (&ehci->watchdog); + qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; qh->qh_next.qh = 0; qh_put (ehci, qh); // refcount from reclaim ehci->reclaim = 0; ehci->reclaim_ready = 0; - qh_completions (ehci, qh); + qh_completions (ehci, qh, regs); if (!list_empty (&qh->qtd_list) && HCD_IS_RUNNING (ehci->hcd.state)) qh_link_async (ehci, qh); - else + else { qh_put (ehci, qh); // refcount from async list - /* it's not free to turn the async schedule on/off, so we leave it - * active but idle for a while once it empties. - */ - if (!ehci->async->qh_next.qh && !timer_pending (&ehci->watchdog)) { - ehci->async_idle = 1; - mod_timer (&ehci->watchdog, jiffies + EHCI_ASYNC_JIFFIES); + /* it's not free to turn the async schedule on/off; leave it + * active but idle for a while once it empties. + */ + if (HCD_IS_RUNNING (ehci->hcd.state) + && ehci->async->qh_next.qh == 0 + && !timer_pending (&ehci->watchdog)) { + ehci->async_idle = 1; + mod_timer (&ehci->watchdog, + jiffies + EHCI_ASYNC_JIFFIES); + } } } @@ -941,12 +963,6 @@ qh->qh_state = QH_STATE_UNLINK; ehci->reclaim = qh = qh_get (qh); - if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { - ehci->reclaim_ready = 1; - tasklet_schedule (&ehci->tasklet); - return; - } - prev = ehci->async; while (prev->qh_next.qh != qh) prev = prev->qh_next.qh; @@ -955,6 +971,11 @@ prev->qh_next = qh->qh_next; wmb (); + if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { + end_unlink_async (ehci, NULL); + return; + } + ehci->reclaim_ready = 0; cmd |= CMD_IAAD; writel (cmd, &ehci->regs->command); @@ -966,7 +987,7 @@ /*-------------------------------------------------------------------------*/ static void -scan_async (struct ehci_hcd *ehci) +scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) { struct ehci_qh *qh; unsigned count; @@ -984,7 +1005,7 @@ * reporting drops the lock. */ qh = qh_get (qh); - temp = qh_completions (ehci, qh); + temp = qh_completions (ehci, qh, regs); qh_put (ehci, qh); if (temp != 0) { count += temp; @@ -1000,14 +1021,6 @@ */ if (list_empty (&qh->qtd_list) && !ehci->reclaim) { start_unlink_async (ehci, qh); - } - - /* keep latencies down: let any irqs in */ - if (count > max_completions) { - spin_unlock_irq (&ehci->lock); - cpu_relax (); - spin_lock_irq (&ehci->lock); - goto rescan; } qh = qh->qh_next.qh; diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c Wed Dec 18 00:35:29 2002 +++ b/drivers/usb/host/ehci-sched.c Wed Dec 18 00:35:29 2002 @@ -495,7 +495,8 @@ intr_complete ( struct ehci_hcd *ehci, unsigned frame, - struct ehci_qh *qh + struct ehci_qh *qh, + struct pt_regs *regs ) { unsigned count; @@ -509,7 +510,7 @@ } /* handle any completions */ - count = qh_completions (ehci, qh); + count = qh_completions (ehci, qh, regs); if (unlikely (list_empty (&qh->qtd_list))) intr_deschedule (ehci, qh, 0); @@ -867,7 +868,8 @@ itd_complete ( struct ehci_hcd *ehci, struct ehci_itd *itd, - unsigned uframe + unsigned uframe, + struct pt_regs *regs ) { struct urb *urb = itd->urb; struct usb_iso_packet_descriptor *desc; @@ -922,7 +924,7 @@ /* complete() can reenter this HCD */ spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (&ehci->hcd, urb, NULL); + usb_hcd_giveback_urb (&ehci->hcd, urb, regs); spin_lock (&ehci->lock); /* defer stopping schedule; completion can submit */ @@ -973,7 +975,7 @@ /*-------------------------------------------------------------------------*/ static void -scan_periodic (struct ehci_hcd *ehci) +scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) { unsigned frame, clock, now_uframe, mod; unsigned count = 0; @@ -999,14 +1001,6 @@ u32 type, *hw_p; unsigned uframes; - /* keep latencies down: let any irqs in */ - if (count > max_completions) { - spin_unlock_irq (&ehci->lock); - cpu_relax (); - count = 0; - spin_lock_irq (&ehci->lock); - } - restart: /* scan schedule to _before_ current frame index */ if (frame == clock) @@ -1031,7 +1025,7 @@ temp = q.qh->qh_next; type = Q_NEXT_TYPE (q.qh->hw_next); count += intr_complete (ehci, frame, - qh_get (q.qh)); + qh_get (q.qh), regs); qh_put (ehci, q.qh); q = temp; break; @@ -1064,7 +1058,7 @@ /* might free q.itd ... */ count += itd_complete (ehci, - temp.itd, uf); + temp.itd, uf, regs); break; } }