summaryrefslogtreecommitdiff
path: root/drivers/dma/fsl-edma-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/fsl-edma-common.c')
-rw-r--r--drivers/dma/fsl-edma-common.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 65f466ab9d4d..c8acff09308f 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -351,7 +351,7 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
{
struct fsl_edma_desc *edesc = fsl_chan->edesc;
enum dma_transfer_direction dir = edesc->dirn;
- dma_addr_t cur_addr, dma_addr;
+ dma_addr_t cur_addr, dma_addr, old_addr;
size_t len, size;
u32 nbytes = 0;
int i;
@@ -367,10 +367,16 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
if (!in_progress)
return len;
- if (dir == DMA_MEM_TO_DEV)
- cur_addr = edma_read_tcdreg(fsl_chan, saddr);
- else
- cur_addr = edma_read_tcdreg(fsl_chan, daddr);
+ /* 64bit read is not atomic, need read retry when high 32bit changed */
+ do {
+ if (dir == DMA_MEM_TO_DEV) {
+ old_addr = edma_read_tcdreg(fsl_chan, saddr);
+ cur_addr = edma_read_tcdreg(fsl_chan, saddr);
+ } else {
+ old_addr = edma_read_tcdreg(fsl_chan, daddr);
+ cur_addr = edma_read_tcdreg(fsl_chan, daddr);
+ }
+ } while (upper_32_bits(cur_addr) != upper_32_bits(old_addr));
/* figure out the finished and calculate the residue */
for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
@@ -426,8 +432,7 @@ enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
return fsl_chan->status;
}
-static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
- struct fsl_edma_hw_tcd *tcd)
+static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, void *tcd)
{
u16 csr = 0;
@@ -478,9 +483,9 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
static inline
void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
- struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
- u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
- u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+ struct fsl_edma_hw_tcd *tcd, dma_addr_t src, dma_addr_t dst,
+ u16 attr, u16 soff, u32 nbytes, dma_addr_t slast, u16 citer,
+ u16 biter, u16 doff, dma_addr_t dlast_sga, bool major_int,
bool disable_req, bool enable_sg)
{
struct dma_slave_config *cfg = &fsl_chan->cfg;
@@ -581,8 +586,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
dma_addr_t dma_buf_next;
bool major_int = true;
int sg_len, i;
- u32 src_addr, dst_addr, last_sg, nbytes;
+ dma_addr_t src_addr, dst_addr, last_sg;
u16 soff, doff, iter;
+ u32 nbytes;
if (!is_slave_direction(direction))
return NULL;
@@ -654,8 +660,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
struct fsl_edma_desc *fsl_desc;
struct scatterlist *sg;
- u32 src_addr, dst_addr, last_sg, nbytes;
+ dma_addr_t src_addr, dst_addr, last_sg;
u16 soff, doff, iter;
+ u32 nbytes;
int i;
if (!is_slave_direction(direction))
@@ -804,7 +811,8 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
- sizeof(struct fsl_edma_hw_tcd),
+ fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
+ sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd),
32, 0);
return 0;
}