diff options
| author | Linus Walleij <[email protected]> | 2016-03-10 09:29:25 +0700 |
|---|---|---|
| committer | Linus Walleij <[email protected]> | 2016-03-10 09:29:25 +0700 |
| commit | cc998d8bc74341f6bbbcd63ab4449a6acfc45ee9 (patch) | |
| tree | 2f4e23fa1ceb83b3e720afd52d9a5ef2be26c77e /drivers/dma/edma.c | |
| parent | d2d13ed01362ecddc3f76f9cca31b0cd5d663a7e (diff) | |
| parent | 81f70ba233d5f660e1ea5fe23260ee323af5d53a (diff) | |
Merge tag 'v4.5-rc5' into devel
Linux 4.5-rc5
Diffstat (limited to 'drivers/dma/edma.c')
| -rw-r--r-- | drivers/dma/edma.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index d92d65549406..e3d7fcb69b4c 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -113,6 +113,9 @@ #define GET_NUM_REGN(x) ((x & 0x300000) >> 20) /* bits 20-21 */ #define CHMAP_EXIST BIT(24) +/* CCSTAT register */ +#define EDMA_CCSTAT_ACTV BIT(4) + /* * Max of 20 segments per channel to conserve PaRAM slots * Also note that MAX_NR_SG should be atleast the no.of periods @@ -1680,9 +1683,20 @@ static void edma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&echan->vchan.lock, flags); } +/* + * This limit exists to avoid a possible infinite loop when waiting for proof + * that a particular transfer is completed. This limit can be hit if there + * are large bursts to/from slow devices or the CPU is never able to catch + * the DMA hardware idle. On an AM335x transfering 48 bytes from the UART + * RX-FIFO, as many as 55 loops have been seen. + */ +#define EDMA_MAX_TR_WAIT_LOOPS 1000 + static u32 edma_residue(struct edma_desc *edesc) { bool dst = edesc->direction == DMA_DEV_TO_MEM; + int loop_count = EDMA_MAX_TR_WAIT_LOOPS; + struct edma_chan *echan = edesc->echan; struct edma_pset *pset = edesc->pset; dma_addr_t done, pos; int i; @@ -1691,7 +1705,32 @@ static u32 edma_residue(struct edma_desc *edesc) * We always read the dst/src position from the first RamPar * pset. That's the one which is active now. */ - pos = edma_get_position(edesc->echan->ecc, edesc->echan->slot[0], dst); + pos = edma_get_position(echan->ecc, echan->slot[0], dst); + + /* + * "pos" may represent a transfer request that is still being + * processed by the EDMACC or EDMATC. We will busy wait until + * any one of the situations occurs: + * 1. the DMA hardware is idle + * 2. a new transfer request is setup + * 3. we hit the loop limit + */ + while (edma_read(echan->ecc, EDMA_CCSTAT) & EDMA_CCSTAT_ACTV) { + /* check if a new transfer request is setup */ + if (edma_get_position(echan->ecc, + echan->slot[0], dst) != pos) { + break; + } + + if (!--loop_count) { + dev_dbg_ratelimited(echan->vchan.chan.device->dev, + "%s: timeout waiting for PaRAM update\n", + __func__); + break; + } + + cpu_relax(); + } /* * Cyclic is simple. Just subtract pset[0].addr from pos. |