On Sat, 8 Dec 2007, Dr. Peer Griebel wrote:

> Dear USB developers
> 
> some time ago (3/4 year) I already reported my problem with the EHCI
> driver.  There was no response to it.  I would like to tell you that my
> problem still persists.  I just tried it today using the current Gentoo
> kernel 2.6.23-gentoo-r3.
> 
> There don't seem to be many people with this problem and it is not very
> urgent for me to get it resolved.  But I do think that this problem
> should be resolved.  It is not very easy to find out that there are
> "lost IAA" messages since only the debug version of the driver shows the
> message.  The average user doesn't know about the debug version.  The
> everage user only sees that his web cam does not work.
> 
> I'm a software developer myself.  But I don't know very much about USB.
>  I would be very glad if I can help you in any way to resolve my problem.

On Sat, 8 Dec 2007, Christian Hoffmann wrote:

> Hi,
> I am running into a similar crash with a dvb t receiver in end_async_unlink as
> reported some month ago on this ML.
> 
> PID: 0      TASK: ffffffff804b7870  CPU: 0   COMMAND: "swapper"
>  #0 [ffffffff80624b10] machine_kexec at ffffffff8021c00d
>  #1 [ffffffff80624bc0] crash_kexec at ffffffff80255dbe
>  #2 [ffffffff80624c80] do_page_fault at ffffffff803fde21
>  #3 [ffffffff80624d90] error_exit at ffffffff803fc0fd
>     [exception RIP: end_unlink_async+34]
>     RIP: ffffffff8811d20a  RSP: ffffffff80624e48  RFLAGS: 00010202
>     RAX: 0000000000010029  RBX: ffff81007e098178  RCX: 0000000000000000
>     RDX: 0000000000008028  RSI: ffffffff8811fe7e  RDI: 0000000000000080
>     RBP: 0000000000000000   R8: 0000000000000000   R9: ffffffff8047dc64
>     R10: ffff8100022ffc48  R11: 0000000000000246  R12: 0000000000000000
>     R13: ffff81007e098178  R14: ffff81007e098000  R15: 0000000000000000
>     ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
>  #4 [ffffffff80624e60] ehci_work at ffffffff8811d78b
>  #5 [ffffffff80624ed0] ehci_irq at ffffffff88120d0f
>  #6 [ffffffff80624f20] usb_hcd_irq at ffffffff880ded82
>  #7 [ffffffff80624f30] handle_IRQ_event at ffffffff802603e8
>  #8 [ffffffff80624f60] handle_fasteoi_irq at ffffffff802618b6
>  #9 [ffffffff80624f90] do_IRQ at ffffffff8020c136
> --- <IRQ stack> ---
> #10 [ffffffff805c7e88] ret_from_intr at ffffffff8020a141
>     [exception RIP: acpi_safe_halt+40]
>     RIP: ffffffff88003dc6  RSP: ffffffff805c7f30  RFLAGS: 00000246
>     RAX: 0000000000000000  RBX: ffff81007e6760a8  RCX: ffffffff8047dde4
>     RDX: 0000000000000007  RSI: 00000000000001c6  RDI: 0000000004000000
>     RBP: 0000000000000000   R8: 0000000000000002   R9: ffffffff8047dc64
>     R10: ffff8100022ffc48  R11: 0000000000000246  R12: ffffffff805c7f14
>     R13: 0000000000001001  R14: ffffffff80332334  R15: 0000000000000000
>     ORIG_RAX: ffffffffffffff86  CS: 0010  SS: 0018
> #11 [ffffffff805c7f30] acpi_processor_idle at ffffffff88003ff9
> #12 [ffffffff805c7f70] cpu_idle at ffffffff80208daf
> crash>

> I use 2.6.22.13-0.3-default on an Acer Laptop. ATI chipset. Anything
> else I can provide?

For both of you, here is a somewhat experimental patch you can try.  It 
probably won't fix the problem, but it might make the problem easier to 
diagnose.

Along with this patch you should enable CONFIG_USB_DEBUG.  If a problem 
occurs, the contents of the files in /sys/class/usb_host/usb_hostN 
(where N is the bus number of the EHCI controller in question) will be 
of interest, especially the "async" and "registers" files.

This patch is for 2.6.24-rc4, but it ought to apply with little 
difficulty to all recent kernels.

Alan Stern



Index: 2.6.24-rc4/drivers/usb/host/ehci-dbg.c
===================================================================
--- 2.6.24-rc4.orig/drivers/usb/host/ehci-dbg.c
+++ 2.6.24-rc4/drivers/usb/host/ehci-dbg.c
@@ -763,9 +763,7 @@ show_registers (struct class_device *cla
        }
 
        if (ehci->reclaim) {
-               temp = scnprintf (next, size, "reclaim qh %p%s\n",
-                               ehci->reclaim,
-                               ehci->reclaim_ready ? " ready" : "");
+               temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
                size -= temp;
                next += temp;
        }
Index: 2.6.24-rc4/drivers/usb/host/ehci-hcd.c
===================================================================
--- 2.6.24-rc4.orig/drivers/usb/host/ehci-hcd.c
+++ 2.6.24-rc4/drivers/usb/host/ehci-hcd.c
@@ -109,7 +109,7 @@ static const char   hcd_name [] = "ehci_hc
 #define        EHCI_TUNE_MULT_TT       1
 #define        EHCI_TUNE_FLS           2       /* (small) 256 frame schedule */
 
-#define EHCI_IAA_JIFFIES       (HZ/100)        /* arbitrary; ~10 msec */
+#define EHCI_IAA_MSECS         10              /* arbitrary */
 #define EHCI_IO_JIFFIES                (HZ/10)         /* io watchdog > 
irq_thresh */
 #define EHCI_ASYNC_JIFFIES     (HZ/20)         /* async idle timeout */
 #define EHCI_SHRINK_JIFFIES    (HZ/200)        /* async qh unlink delay */
@@ -266,6 +266,7 @@ static void ehci_quiesce (struct ehci_hc
 
 /*-------------------------------------------------------------------------*/
 
+static void end_unlink_async(struct ehci_hcd *ehci);
 static void ehci_work(struct ehci_hcd *ehci);
 
 #include "ehci-hub.c"
@@ -275,25 +276,41 @@ static void ehci_work(struct ehci_hcd *e
 
 /*-------------------------------------------------------------------------*/
 
-static void ehci_watchdog (unsigned long param)
+static void ehci_iaa_watchdog(unsigned long param)
 {
        struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
        unsigned long           flags;
+       u32                     status, cmd;
 
        spin_lock_irqsave (&ehci->lock, flags);
+       WARN_ON(!ehci->reclaim);
 
-       /* lost IAA irqs wedge things badly; seen with a vt8235 */
+       status = ehci_readl(ehci, &ehci->regs->status);
+       cmd = ehci_readl(ehci, &ehci->regs->command);
+       ehci_info(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+
+       /* lost IAA irqs wedge things badly; seen first with a vt8235 */
        if (ehci->reclaim) {
-               u32             status = ehci_readl(ehci, &ehci->regs->status);
                if (status & STS_IAA) {
                        ehci_vdbg (ehci, "lost IAA\n");
                        COUNT (ehci->stats.lost_iaa);
                        ehci_writel(ehci, STS_IAA, &ehci->regs->status);
-                       ehci->reclaim_ready = 1;
                }
+               ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command);
+               end_unlink_async(ehci);
        }
 
-       /* stop async processing after it's idled a bit */
+       spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_watchdog(unsigned long param)
+{
+       struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&ehci->lock, flags);
+
+       /* stop async processing after it's idled a bit */
        if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
                start_unlink_async (ehci, ehci->async);
 
@@ -363,8 +380,6 @@ static void ehci_port_power (struct ehci
 static void ehci_work (struct ehci_hcd *ehci)
 {
        timer_action_done (ehci, TIMER_IO_WATCHDOG);
-       if (ehci->reclaim_ready)
-               end_unlink_async (ehci);
 
        /* another CPU may drop ehci->lock during a schedule scan while
         * it reports urb completions.  this flag guards against bogus
@@ -399,6 +414,7 @@ static void ehci_stop (struct usb_hcd *h
 
        /* no more interrupts ... */
        del_timer_sync (&ehci->watchdog);
+       del_timer_sync(&ehci->iaa_watchdog);
 
        spin_lock_irq(&ehci->lock);
        if (HC_IS_RUNNING (hcd->state))
@@ -447,6 +463,10 @@ static int ehci_init(struct usb_hcd *hcd
        ehci->watchdog.function = ehci_watchdog;
        ehci->watchdog.data = (unsigned long) ehci;
 
+       init_timer(&ehci->iaa_watchdog);
+       ehci->iaa_watchdog.function = ehci_iaa_watchdog;
+       ehci->iaa_watchdog.data = (unsigned long) ehci;
+
        /*
         * hw default: 1K periodic list heads, one per frame.
         * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -463,7 +483,6 @@ static int ehci_init(struct usb_hcd *hcd
                ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 
        ehci->reclaim = NULL;
-       ehci->reclaim_ready = 0;
        ehci->next_uframe = -1;
 
        /*
@@ -654,8 +673,7 @@ static irqreturn_t ehci_irq (struct usb_
        /* complete the unlinking of some qh [4.15.2.3] */
        if (status & STS_IAA) {
                COUNT (ehci->stats.reclaim);
-               ehci->reclaim_ready = 1;
-               bh = 1;
+               end_unlink_async(ehci);
        }
 
        /* remote wakeup [4.3.1] */
@@ -761,10 +779,16 @@ static int ehci_urb_enqueue (
 
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       /* if we need to use IAA and it's busy, defer */
-       if (qh->qh_state == QH_STATE_LINKED
-                       && ehci->reclaim
-                       && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+       /* failfast */
+       if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+               end_unlink_async(ehci);
+
+       /* if it's not linked then there's nothing to do */
+       if (qh->qh_state != QH_STATE_LINKED)
+               ;
+
+       /* defer till later if busy */
+       else if (ehci->reclaim) {
                struct ehci_qh          *last;
 
                for (last = ehci->reclaim;
@@ -774,12 +798,8 @@ static void unlink_async (struct ehci_hc
                qh->qh_state = QH_STATE_UNLINK_WAIT;
                last->reclaim = qh;
 
-       /* bypass IAA if the hc can't care */
-       } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
-               end_unlink_async (ehci);
-
-       /* something else might have unlinked the qh by now */
-       if (qh->qh_state == QH_STATE_LINKED)
+       /* start IAA cycle */
+       } else
                start_unlink_async (ehci, qh);
 }
 
@@ -806,7 +826,19 @@ static int ehci_urb_dequeue(struct usb_h
                qh = (struct ehci_qh *) urb->hcpriv;
                if (!qh)
                        break;
-               unlink_async (ehci, qh);
+               switch (qh->qh_state) {
+               case QH_STATE_LINKED:
+               case QH_STATE_COMPLETING:
+                       unlink_async(ehci, qh);
+                       break;
+               case QH_STATE_UNLINK:
+               case QH_STATE_UNLINK_WAIT:
+                       /* already started */
+                       break;
+               case QH_STATE_IDLE:
+                       WARN_ON(1);
+                       break;
+               }
                break;
 
        case PIPE_INTERRUPT:
@@ -898,6 +930,7 @@ rescan:
                unlink_async (ehci, qh);
                /* FALL THROUGH */
        case QH_STATE_UNLINK:           /* wait for hw to finish? */
+       case QH_STATE_UNLINK_WAIT:
 idle_timeout:
                spin_unlock_irqrestore (&ehci->lock, flags);
                schedule_timeout_uninterruptible(1);
Index: 2.6.24-rc4/drivers/usb/host/ehci-hub.c
===================================================================
--- 2.6.24-rc4.orig/drivers/usb/host/ehci-hub.c
+++ 2.6.24-rc4/drivers/usb/host/ehci-hub.c
@@ -134,7 +134,7 @@ static int ehci_bus_suspend (struct usb_
        }
        ehci->command = ehci_readl(ehci, &ehci->regs->command);
        if (ehci->reclaim)
-               ehci->reclaim_ready = 1;
+               end_unlink_async(ehci);
        ehci_work(ehci);
 
        /* Unlike other USB host controller types, EHCI doesn't have
Index: 2.6.24-rc4/drivers/usb/host/ehci-pci.c
===================================================================
--- 2.6.24-rc4.orig/drivers/usb/host/ehci-pci.c
+++ 2.6.24-rc4/drivers/usb/host/ehci-pci.c
@@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hc
        /* emptying the schedule aborts any urbs */
        spin_lock_irq(&ehci->lock);
        if (ehci->reclaim)
-               ehci->reclaim_ready = 1;
+               end_unlink_async(ehci);
        ehci_work(ehci);
        spin_unlock_irq(&ehci->lock);
 
Index: 2.6.24-rc4/drivers/usb/host/ehci-q.c
===================================================================
--- 2.6.24-rc4.orig/drivers/usb/host/ehci-q.c
+++ 2.6.24-rc4/drivers/usb/host/ehci-q.c
@@ -973,7 +973,7 @@ static void end_unlink_async (struct ehc
        struct ehci_qh          *qh = ehci->reclaim;
        struct ehci_qh          *next;
 
-       timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+       iaa_watchdog_done(ehci);
 
        // qh->hw_next = cpu_to_hc32(qh->qh_dma);
        qh->qh_state = QH_STATE_IDLE;
@@ -983,7 +983,6 @@ static void end_unlink_async (struct ehc
        /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
        next = qh->reclaim;
        ehci->reclaim = next;
-       ehci->reclaim_ready = 0;
        qh->reclaim = NULL;
 
        qh_completions (ehci, qh);
@@ -1059,11 +1058,10 @@ static void start_unlink_async (struct e
                return;
        }
 
-       ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
        ehci_writel(ehci, cmd, &ehci->regs->command);
        (void)ehci_readl(ehci, &ehci->regs->command);
-       timer_action (ehci, TIMER_IAA_WATCHDOG);
+       iaa_watchdog_start(ehci);
 }
 
 /*-------------------------------------------------------------------------*/
Index: 2.6.24-rc4/drivers/usb/host/ehci.h
===================================================================
--- 2.6.24-rc4.orig/drivers/usb/host/ehci.h
+++ 2.6.24-rc4/drivers/usb/host/ehci.h
@@ -74,7 +74,6 @@ struct ehci_hcd {                     /* one per controlle
        /* async schedule support */
        struct ehci_qh          *async;
        struct ehci_qh          *reclaim;
-       unsigned                reclaim_ready : 1;
        unsigned                scanning : 1;
 
        /* periodic schedule support */
@@ -105,6 +104,7 @@ struct ehci_hcd {                   /* one per controlle
        struct dma_pool         *itd_pool;      /* itd per iso urb */
        struct dma_pool         *sitd_pool;     /* sitd per split iso urb */
 
+       struct timer_list       iaa_watchdog;
        struct timer_list       watchdog;
        unsigned long           actions;
        unsigned                stamp;
@@ -140,9 +140,21 @@ static inline struct usb_hcd *ehci_to_hc
 }
 
 
+static inline void
+iaa_watchdog_start(struct ehci_hcd *ehci)
+{
+       WARN_ON(timer_pending(&ehci->iaa_watchdog));
+       mod_timer(&ehci->iaa_watchdog,
+                       jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
+}
+
+static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
+{
+       del_timer(&ehci->iaa_watchdog);
+}
+
 enum ehci_timer_action {
        TIMER_IO_WATCHDOG,
-       TIMER_IAA_WATCHDOG,
        TIMER_ASYNC_SHRINK,
        TIMER_ASYNC_OFF,
 };
@@ -160,9 +172,6 @@ timer_action (struct ehci_hcd *ehci, enu
                unsigned long t;
 
                switch (action) {
-               case TIMER_IAA_WATCHDOG:
-                       t = EHCI_IAA_JIFFIES;
-                       break;
                case TIMER_IO_WATCHDOG:
                        t = EHCI_IO_JIFFIES;
                        break;
@@ -179,8 +188,7 @@ timer_action (struct ehci_hcd *ehci, enu
                // async queue SHRINK often precedes IAA.  while it's ready
                // to go OFF neither can matter, and afterwards the IO
                // watchdog stops unless there's still periodic traffic.
-               if (action != TIMER_IAA_WATCHDOG
-                               && t > ehci->watchdog.expires
+               if (time_before_eq(t, ehci->watchdog.expires)
                                && timer_pending (&ehci->watchdog))
                        return;
                mod_timer (&ehci->watchdog, t);

-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to