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 <[email protected]>
Tested-by Mika Westerberg <[email protected]>
Cc Dan Williams <[email protected]>
Cc Vinod Koul <[email protected]>
---
drivers/dma/ep93xx_dma.c +15 -10
@@ -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);