Patch "dmaengine: dw: fix cyclic transfer callbacks" has been added to the 4.4-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
dmaengine: dw: fix cyclic transfer callbacks
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
dmaengine-dw-fix-cyclic-transfer-callbacks.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
2895b2cad6e7a95104cf396e5330054453382ae1Mon Sep 17 00:00:00 2001
From: Mans Rullgard <[email protected]>
Date: Mon, 11 Jan 2016 13:04:29 +0000
Subject: dmaengine: dw: fix cyclic transfer callbacks
From: Mans Rullgard <[email protected]>
commit 2895b2cad6e7a95104cf396e5330054453382ae1 upstream.
Cyclic transfer callbacks rely on block completion interrupts which were disabled in commit ff7b05f29fd4 ("dmaengine/dw_dmac: Don't handle block interrupts"). This re-enables block interrupts so the cyclic callbacks can work. Other transfer types are not affected as they set the INT_EN bit only on the last block.
--- drivers/dma/dw/core.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
drivers/dma/dw/core.c +15 -6
@@ -156,6 +156,7 @@ static void dwc_initialize(struct dw_dma/* Enable interrupts */ channel_set_bit (dw,MASK .XFER, dwc->mask); +channel_set_bit (dw,MASK .BLOCK, dwc->mask);channel_set_bit (dw,MASK .ERROR, dwc->mask); dwc->initialized = true;
@@ -536,16 +537,17 @@ EXPORT_SYMBOL(dw_dma_get_dst_addr);/* Called with dwc->lock held and all DMAC interrupts disabled */ static void dwc_handle_cyclic (struct dw_dma *dw,struct dw_dma_chan *dwc, -u32 status_err,u32 status_xfer) +u32 status_block,u32 status_err,u32 status_xfer) {unsigned long flags; -if (dwc->mask) { +if (status_block & dwc->mask) {void (*callback)(void *param);void *callback_param;dev_vdbg (chan2dev (&dwc->chan),"new cyclic period llp 0x%08x\n" ,channel_readl (dwc,LLP )); +dma_writel (dw,CLEAR .BLOCK, dwc->mask); callback = dwc->cdesc->period_callback; callback_param = dwc->cdesc->period_callback_param;
@@ -577,6 +579,7 @@ static void dwc_handle_cyclic(struct dw_channel_writel (dwc,CTL_LO ,0 );channel_writel (dwc,CTL_HI ,0 ); +dma_writel (dw,CLEAR .BLOCK, dwc->mask);dma_writel (dw,CLEAR .ERROR, dwc->mask);dma_writel (dw,CLEAR .XFER, dwc->mask);
@@ -593,10 +596,12 @@ static void dw_dma_tasklet(unsigned long {struct dw_dma *dw = (struct dw_dma *)data;struct dw_dma_chan *dwc; +u32 status_block;u32 status_xfer;u32 status_err;int i; + status_block =dma_readl (dw,RAW .BLOCK); status_xfer =dma_readl (dw,RAW .XFER); status_err =dma_readl (dw,RAW .ERROR);
@@ -605,7 +610,8 @@ static void dw_dma_tasklet(unsigned longfor (i =0 ; i < dw->dma.chancnt; i++) { dwc = &dw->chan[i];if (test_bit (DW_DMA_IS_CYCLIC , &dwc->flags)) -dwc_handle_cyclic (dw, dwc, status_err, status_xfer); +dwc_handle_cyclic (dw, dwc, status_block, status_err, + status_xfer);else if (status_err & (1 << i))dwc_handle_error (dw, dwc);else if (status_xfer & (1 << i))
@@ -616,6 +622,7 @@ static void dw_dma_tasklet(unsigned long* Re-enable interrupts. */ channel_set_bit (dw,MASK .XFER, dw->all_chan_mask); +channel_set_bit (dw,MASK .BLOCK, dw->all_chan_mask);channel_set_bit (dw,MASK .ERROR, dw->all_chan_mask); }
@@ -635,6 +642,7 @@ static irqreturn_t dw_dma_interrupt(int* softirq handler. */ channel_clear_bit (dw,MASK .XFER, dw->all_chan_mask); +channel_clear_bit (dw,MASK .BLOCK, dw->all_chan_mask);channel_clear_bit (dw,MASK .ERROR, dw->all_chan_mask); status =dma_readl (dw,STATUS_INT );
@@ -645,6 +653,7 @@ static irqreturn_t dw_dma_interrupt(int/* Try to recover */ channel_clear_bit (dw,MASK .XFER, (1 <<8 ) -1 ); +channel_clear_bit (dw,MASK .BLOCK, (1 <<8 ) -1 );channel_clear_bit (dw,MASK .SRC_TRAN, (1 <<8 ) -1 );channel_clear_bit (dw,MASK .DST_TRAN, (1 <<8 ) -1 );channel_clear_bit (dw,MASK .ERROR, (1 <<8 ) -1 );
@@ -1111,6 +1120,7 @@ static void dw_dma_off(struct dw_dma *dwdma_writel (dw,CFG ,0 );channel_clear_bit (dw,MASK .XFER, dw->all_chan_mask); +channel_clear_bit (dw,MASK .BLOCK, dw->all_chan_mask);channel_clear_bit (dw,MASK .SRC_TRAN, dw->all_chan_mask);channel_clear_bit (dw,MASK .DST_TRAN, dw->all_chan_mask);channel_clear_bit (dw,MASK .ERROR, dw->all_chan_mask);
@@ -1216,6 +1226,7 @@ static void dwc_free_chan_resources(stru/* Disable interrupts */ channel_clear_bit (dw,MASK .XFER, dwc->mask); +channel_clear_bit (dw,MASK .BLOCK, dwc->mask);channel_clear_bit (dw,MASK .ERROR, dwc->mask);spin_unlock_irqrestore (&dwc->lock, flags);
@@ -1458,6 +1469,7 @@ void dw_dma_cyclic_free(struct dma_chandwc_chan_disable (dw, dwc); +dma_writel (dw,CLEAR .BLOCK, dwc->mask);dma_writel (dw,CLEAR .ERROR, dwc->mask);dma_writel (dw,CLEAR .XFER, dwc->mask);
@@ -1546,9 +1558,6 @@ int dw_dma_probe(struct dw_dma_chip *chi/* Force dma off, just in case */ dw_dma_off (dw); -/* Disable BLOCK interrupts as well */ -channel_clear_bit (dw,MASK .BLOCK, dw->all_chan_mask); -/* Create a pool of consistent memory blocks for hardware descriptors */ dw->desc_pool =dmam_pool_create ("dw_dmac_desc_pool" , chip->dev,sizeof (struct dw_desc ),4 ,0 );
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/dmaengine-dw-fix-cyclic-transfer-callbacks.patch queue-4.4/dmaengine-dw-fix-cyclic-transfer-setup.patch queue-4.4/dmaengine-dw-disable-block-irqs-for-non-cyclic-xfer.patch