Commit f79abb62 authored by Zhang Wei's avatar Zhang Wei Committed by Dan Williams

fsldma: Fix the DMA halt when using DMA_INTERRUPT async_tx transfer.

The DMA_INTERRUPT async_tx is a NULL transfer, thus the BCR(count register)
is 0. When the transfer started with a byte count of zero, the DMA
controller will triger a PE(programming error) event and halt, not a normal
interrupt. I add special codes for PE event and DMA_INTERRUPT
async_tx testing.
Signed-off-by: default avatarZhang Wei <wei.zhang@freescale.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent f920bb6f
...@@ -123,6 +123,11 @@ static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan) ...@@ -123,6 +123,11 @@ static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan)
return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64); return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64);
} }
static u32 get_bcr(struct fsl_dma_chan *fsl_chan)
{
return DMA_IN(fsl_chan, &fsl_chan->reg_base->bcr, 32);
}
static int dma_is_idle(struct fsl_dma_chan *fsl_chan) static int dma_is_idle(struct fsl_dma_chan *fsl_chan)
{ {
u32 sr = get_sr(fsl_chan); u32 sr = get_sr(fsl_chan);
...@@ -426,6 +431,9 @@ fsl_dma_prep_interrupt(struct dma_chan *chan) ...@@ -426,6 +431,9 @@ fsl_dma_prep_interrupt(struct dma_chan *chan)
new->async_tx.cookie = -EBUSY; new->async_tx.cookie = -EBUSY;
new->async_tx.ack = 0; new->async_tx.ack = 0;
/* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &new->async_tx.tx_list);
/* Set End-of-link to the last link descriptor of new list*/ /* Set End-of-link to the last link descriptor of new list*/
set_ld_eol(fsl_chan, new); set_ld_eol(fsl_chan, new);
...@@ -701,6 +709,23 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) ...@@ -701,6 +709,23 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
if (stat & FSL_DMA_SR_TE) if (stat & FSL_DMA_SR_TE)
dev_err(fsl_chan->dev, "Transfer Error!\n"); dev_err(fsl_chan->dev, "Transfer Error!\n");
/* Programming Error
* The DMA_INTERRUPT async_tx is a NULL transfer, which will
* triger a PE interrupt.
*/
if (stat & FSL_DMA_SR_PE) {
dev_dbg(fsl_chan->dev, "event: Programming Error INT\n");
if (get_bcr(fsl_chan) == 0) {
/* BCR register is 0, this is a DMA_INTERRUPT async_tx.
* Now, update the completed cookie, and continue the
* next uncompleted transfer.
*/
fsl_dma_update_completed_cookie(fsl_chan);
fsl_chan_xfer_ld_queue(fsl_chan);
}
stat &= ~FSL_DMA_SR_PE;
}
/* If the link descriptor segment transfer finishes, /* If the link descriptor segment transfer finishes,
* we will recycle the used descriptor. * we will recycle the used descriptor.
*/ */
...@@ -841,6 +866,11 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) ...@@ -841,6 +866,11 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan)
tx3 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0); tx3 = fsl_dma_prep_memcpy(chan, dma_dest, dma_src, test_size / 4, 0);
async_tx_ack(tx3); async_tx_ack(tx3);
/* Interrupt tx test */
tx1 = fsl_dma_prep_interrupt(chan);
async_tx_ack(tx1);
cookie = fsl_dma_tx_submit(tx1);
/* Test exchanging the prepared tx sort */ /* Test exchanging the prepared tx sort */
cookie = fsl_dma_tx_submit(tx3); cookie = fsl_dma_tx_submit(tx3);
cookie = fsl_dma_tx_submit(tx2); cookie = fsl_dma_tx_submit(tx2);
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define FSL_DMA_MR_EOTIE 0x00000080 #define FSL_DMA_MR_EOTIE 0x00000080
#define FSL_DMA_SR_CH 0x00000020 #define FSL_DMA_SR_CH 0x00000020
#define FSL_DMA_SR_PE 0x00000010
#define FSL_DMA_SR_CB 0x00000004 #define FSL_DMA_SR_CB 0x00000004
#define FSL_DMA_SR_TE 0x00000080 #define FSL_DMA_SR_TE 0x00000080
#define FSL_DMA_SR_EOSI 0x00000002 #define FSL_DMA_SR_EOSI 0x00000002
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment