usb: musb: workaround MUSB DMA_INTR sometimes reads zero
authorAnand Gadiyar <gadiyar@ti.com>
Mon, 28 Dec 2009 11:40:36 +0000 (13:40 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 2 Mar 2010 22:53:42 +0000 (14:53 -0800)
MUSB DMA_INTR register may sometimes read zero when infact there
was a pending interrupt. Workaround this by reading the DMA_COUNT
values for all enabled channels when this condition occurs.
Flag these channels as the ones needing to be serviced.

Additionally, the absence of a debug print meant we would never
catch a spurious DMA interrupt in MUSB. So this patch adds a
debug print in the IRQ handler.

Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
Cc: Ajay Kumar Gupta <ajay.gupta@ti.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Vikram Pandita <vikram.pandita@ti.com>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/musb/musbhsdma.c

index a237550..2fa7d5c 100644 (file)
@@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
        u8 bchannel;
        u8 int_hsdma;
 
-       u32 addr;
+       u32 addr, count;
        u16 csr;
 
        spin_lock_irqsave(&musb->lock, flags);
 
        int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
-       if (!int_hsdma)
-               goto done;
 
 #ifdef CONFIG_BLACKFIN
        /* Clear DMA interrupt flags */
        musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
 #endif
 
+       if (!int_hsdma) {
+               DBG(2, "spurious DMA irq\n");
+
+               for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+                       musb_channel = (struct musb_dma_channel *)
+                                       &(controller->channel[bchannel]);
+                       channel = &musb_channel->channel;
+                       if (channel->status == MUSB_DMA_STATUS_BUSY) {
+                               count = musb_read_hsdma_count(mbase, bchannel);
+
+                               if (count == 0)
+                                       int_hsdma |= (1 << bchannel);
+                       }
+               }
+
+               DBG(2, "int_hsdma = 0x%x\n", int_hsdma);
+
+               if (!int_hsdma)
+                       goto done;
+       }
+
        for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
                if (int_hsdma & (1 << bchannel)) {
                        musb_channel = (struct musb_dma_channel *)