[PATCH 2/2 v2] Workaround MUSB DMA_INTR sometimes reads zero

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxx>
Cc: Ajay Kumar Gupta <ajay.gupta@xxxxxx>
Cc: Felipe Balbi <felipe.balbi@xxxxxxxxx>
Cc: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx>
Cc: Sergei Shtylyov <sshtylyov@xxxxxxxxxxxxx>
Cc: Vikram Pandita <vikram.pandita@xxxxxx>
---
This is a fix for buggy hardware (OMAP3630, OMAP4430).
Please queue this up for the -rc series if possible.

v2: Fix a bug in v1 pointed out by Vikram.
DMA_COUNT is a 32 bit register, while csr is a 16 bit variable

Also, use the wrapper API to read the register.

 drivers/usb/musb/musbhsdma.c |   25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

Index: linux-2.6/drivers/usb/musb/musbhsdma.c
===================================================================
--- linux-2.6.orig/drivers/usb/musb/musbhsdma.c	2009-12-18 19:53:39.000000000 +0530
+++ linux-2.6/drivers/usb/musb/musbhsdma.c	2009-12-18 19:55:17.000000000 +0530
@@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(in
 	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 *)
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux