[lkml]   [2012]   [Mar]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    SubjectRE: [PATCH] ep93xx: Implement double buffering for M2M DMA channels
    On Thursday, March 22, 2012 12:38 AM, Mika Westerberg wrote:
    > On Wed, Mar 21, 2012 at 07:47:52PM -0500, H Hartley Sweeten wrote:
    >> Without this patch I get the "got interrupt while active list is empty" messages
    >> but only occasionally. Other than the messages the mmc_spi driver seems to
    >> be working ok with dma.
    >> I hacked in a dump of the DMA Global Interrupt register when I get the
    >> "got interrupt while active list is empty" messages and get this:
    >> dma dma1chan1: got interrupt while active list is empty (00000000)


    I hacked this back to the handle_one_vic function. It looks like every time
    I get the message above the stat read in that function shows an active
    interrupt for DMAM2M0 (the dma rx channel) and DMAM2M1 (the dma
    tx channel). Because of the way handle_one_vic processes the irq's, the
    DMAM2M0 interrupt gets handled first. When it's done it must be clearing
    the DMAM2M1 interrupt automatically for some reason. So, when it's
    handled there is no interrupt pending so we get the message.

    The "cleanest" fix I can think of is the following patch. This is against


    From: H Hartley Sweeten <>

    dma: ep93xx: check for spurious interrupts

    The ep93xx dma controller generates spurious interrupts on dma1chan1 when
    used with the mmc_spi driver. Catch these early by making sure there is an
    interrupt to actually process.

    Signed-off-by: H Hartley Sweeten <>


    diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
    index e6f133b..3cfabe6 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_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_DONE 1
    @@ -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))

    /* 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;


     \ /
      Last update: 2012-03-22 19:55    [W:0.027 / U:19.128 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site