Commit aba85312 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: SMP ehci-q.c 1010 BUG()

Stefano Barbato wrote:
> Dual PIII
> kernel 2.4.21-rc2 (w/ SMP)  (2.5.69 below)
> ...
>
> I put a few printk before the BUG() and I found that the offending if() is
> this:
>         if(qh->qh_state != QH_STATE_LINKED
>                                 && qh->qh_state != QH_STATE_UNLINK_WAIT)
>
> because qh_state were QH_STATE_COMPLETING.

I got a similar SMP report recently, but without info about
which clause was failing -- which is a key clue, thanks!!

The COMPLETING state is used only while a QH is being
scanned for completed TDs.  (Think CPU-0 irq handler.)
Looking at the handful of places that call the routine
reporting the BUG(), a couple seem like they could make
trouble with multiple CPUs in the driver.
parent 6d58d234
...@@ -918,11 +918,11 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -918,11 +918,11 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = 0; qh->qh_next.qh = 0;
qh_put (ehci, qh); // refcount from reclaim qh_put (ehci, qh); // refcount from reclaim
ehci->reclaim = 0;
ehci->reclaim_ready = 0;
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim; next = qh->reclaim;
ehci->reclaim = next;
ehci->reclaim_ready = 0;
qh->reclaim = 0; qh->reclaim = 0;
qh_completions (ehci, qh, regs); qh_completions (ehci, qh, regs);
...@@ -941,8 +941,10 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -941,8 +941,10 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
timer_action (ehci, TIMER_ASYNC_OFF); timer_action (ehci, TIMER_ASYNC_OFF);
} }
if (next) if (next) {
ehci->reclaim = 0;
start_unlink_async (ehci, next); start_unlink_async (ehci, next);
}
} }
/* makes sure the async qh will become idle */ /* makes sure the async qh will become idle */
...@@ -1046,7 +1048,8 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1046,7 +1048,8 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
if (list_empty (&qh->qtd_list)) { if (list_empty (&qh->qtd_list)) {
if (qh->stamp == ehci->stamp) if (qh->stamp == ehci->stamp)
action = TIMER_ASYNC_SHRINK; action = TIMER_ASYNC_SHRINK;
else if (!ehci->reclaim) else if (!ehci->reclaim
&& qh->qh_state == QH_STATE_LINKED)
start_unlink_async (ehci, qh); start_unlink_async (ehci, qh);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment