[<prev] [next>] [day] [month] [year] [list]
Message-ID: <201203221453.23796.hartleys@visionengravers.com>
Date: Thu, 22 Mar 2012 14:53:23 -0700
From: H Hartley Sweeten <hartleys@...ionengravers.com>
To: Linux Kernel <linux-kernel@...r.kernel.org>
CC: <mika.westerberg@....fi>, <dan.j.williams@...el.com>,
<vinod.koul@...el.com>
Subject: dma: ep93xx: check for spurious interrupts
The ep93xx dma controller generates spurious interrupts on dmachan1
when used with the mmc_spi driver. These are causing random debug
noise like:
dma dma1chan1: got interrupt while active list is empty
Catch these early by making sure there is an interrupt to actually
process.
This was exposed when ep93xx was changed to MULTI_IRQ_HANDLER with
the new handle_one_vic function that does a single read of the vic
status register and then handles all pending interrupts in order
from LSB first.
Note, we still will get the spurious interrupts due to the handle_one_vic.
But now they will not cause any unnecessary noise. To see the spurious
interrupt count check /proc/irq/*/spurious.
Signed-off-by: H Hartley Sweeten <hsweeten@...ionengravers.com>
Tested-by: Mika Westerberg <mika.westerberg@....fi>
Cc: Dan Williams <dan.j.williams@...el.com>
Cc: Vinod Koul <vinod.koul@...el.com>
---
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index e6f133b..001e089 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -38,7 +38,7 @@
#define M2P_CONTROL_ENABLE BIT(4)
#define M2P_CONTROL_ICE BIT(6)
-#define M2P_INTERRUPT 0x0004
+#define M2X_INTERRUPT 0x0004 /* M2P and M2M */
#define M2P_INTERRUPT_STALL BIT(0)
#define M2P_INTERRUPT_NFB BIT(1)
#define M2P_INTERRUPT_ERROR BIT(3)
@@ -78,7 +78,6 @@
#define M2M_CONTROL_NO_HDSK BIT(24)
#define M2M_CONTROL_PWSC_SHIFT 25
-#define M2M_INTERRUPT 0x0004
#define M2M_INTERRUPT_DONEINT BIT(1)
#define M2M_BCR0 0x0010
@@ -187,7 +186,8 @@ struct ep93xx_dma_engine {
int (*hw_setup)(struct ep93xx_dma_chan *);
void (*hw_shutdown)(struct ep93xx_dma_chan *);
void (*hw_submit)(struct ep93xx_dma_chan *);
- int (*hw_interrupt)(struct ep93xx_dma_chan *);
+ int (*hw_interrupt)(struct ep93xx_dma_chan *,
+ u32 irq_status);
#define INTERRUPT_UNKNOWN 0
#define INTERRUPT_DONE 1
#define INTERRUPT_NEXT_BUFFER 2
@@ -376,16 +376,15 @@ static void m2p_hw_submit(struct ep93xx_dma_chan *edmac)
m2p_set_control(edmac, control);
}
-static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac)
+static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac, u32 irq_status)
{
- u32 irq_status = readl(edmac->regs + M2P_INTERRUPT);
u32 control;
if (irq_status & M2P_INTERRUPT_ERROR) {
struct ep93xx_dma_desc *desc = ep93xx_dma_get_active(edmac);
/* Clear the error interrupt */
- writel(1, edmac->regs + M2P_INTERRUPT);
+ writel(1, edmac->regs + M2X_INTERRUPT);
/*
* It seems that there is no easy way of reporting errors back
@@ -560,15 +559,15 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac)
}
}
-static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac)
+static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac, u32 irq_status)
{
u32 control;
- if (!(readl(edmac->regs + M2M_INTERRUPT) & M2M_INTERRUPT_DONEINT))
+ if (!(irq_status & M2M_INTERRUPT_DONEINT))
return INTERRUPT_UNKNOWN;
/* Clear the DONE bit */
- writel(0, edmac->regs + M2M_INTERRUPT);
+ writel(0, edmac->regs + M2X_INTERRUPT);
/* Disable interrupts and the channel */
control = readl(edmac->regs + M2M_CONTROL);
@@ -735,6 +734,12 @@ static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
struct ep93xx_dma_chan *edmac = dev_id;
struct ep93xx_dma_desc *desc;
irqreturn_t ret = IRQ_HANDLED;
+ u32 irq_status;
+
+ /* Make sure we actually have an interrupt to process */
+ irq_status = readl(edmac->regs + M2X_INTERRUPT);
+ if (!irq_status)
+ return IRQ_NONE;
spin_lock(&edmac->lock);
@@ -746,7 +751,7 @@ static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
return IRQ_NONE;
}
- switch (edmac->edma->hw_interrupt(edmac)) {
+ switch (edmac->edma->hw_interrupt(edmac, irq_status)) {
case INTERRUPT_DONE:
desc->complete = true;
tasklet_schedule(&edmac->tasklet);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists