ChangeSet 1.883.3.1, 2002/12/16 10:31:05-08:00, [EMAIL PROTECTED]
[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;
}
}
-------------------------------------------------------
This sf.net email is sponsored by:
With Great Power, Comes Great Responsibility
Learn to use your power at OSDN's High Performance Computing Channel
http://hpc.devchannel.org/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel