From 9c71b9eb3cb25856e29f0486eae9ee1ba864ba51 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Jul 2019 10:16:44 +0200 Subject: dmaengine: omap-dma: make omap_dma_filter_fn private With the audio driver no longer referring to this function, it can be made private to the dmaengine driver itself, and the header file removed. Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/lkml/20190307151646.1016966-1-arnd@arndb.de/ Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20190722081705.2084961-1-arnd@arndb.de Signed-off-by: Vinod Koul --- drivers/dma/ti/omap-dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index ba2489d4ea24..49da402a1927 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -202,6 +202,7 @@ static const unsigned es_bytes[] = { [CSDP_DATA_TYPE_32] = 4, }; +static bool omap_dma_filter_fn(struct dma_chan *chan, void *param); static struct of_dma_filter_info omap_dma_info = { .filter_fn = omap_dma_filter_fn, }; @@ -1637,7 +1638,7 @@ static struct platform_driver omap_dma_driver = { }, }; -bool omap_dma_filter_fn(struct dma_chan *chan, void *param) +static bool omap_dma_filter_fn(struct dma_chan *chan, void *param) { if (chan->device->dev->driver == &omap_dma_driver.driver) { struct omap_dmadev *od = to_omap_dma_dev(chan->device); -- cgit v1.2.3 From d2bfe7b5d182dad54aedb9dcdb736e8816ead1c3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Jul 2019 10:16:45 +0200 Subject: dmaengine: edma: make edma_filter_fn private With the audio driver no longer referring to this function, it can be made private to the dmaengine driver itself, and the header file removed. Acked-by: Peter Ujfalusi Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20190722081705.2084961-2-arnd@arndb.de Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index ceabdea40ae0..f2549ee3fb49 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -2185,6 +2184,8 @@ static struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec, } #endif +static bool edma_filter_fn(struct dma_chan *chan, void *param); + static int edma_probe(struct platform_device *pdev) { struct edma_soc_info *info = pdev->dev.platform_data; @@ -2524,7 +2525,7 @@ static struct platform_driver edma_tptc_driver = { }, }; -bool edma_filter_fn(struct dma_chan *chan, void *param) +static bool edma_filter_fn(struct dma_chan *chan, void *param) { bool match = false; -- cgit v1.2.3 From aac8670369dc017609b8e8870975641ad3143448 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:24:58 +0300 Subject: dmaengine: ti: omap-dma: Readability cleanup in omap_dma_tx_status() The tx_status is most likely going to be asked for the current transfer, so check that first then try to fall back to lookup of non started transfers. In this way the code is a bit more readable and in most cases we will avoid to run vchan_find_desc() all the time. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190716082459.1222-2-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/omap-dma.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 49da402a1927..80fd2667b2c8 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -833,10 +833,8 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, return ret; spin_lock_irqsave(&c->vc.lock, flags); - vd = vchan_find_desc(&c->vc, cookie); - if (vd) { - txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx)); - } else if (c->desc && c->desc->vd.tx.cookie == cookie) { + + if (c->desc && c->desc->vd.tx.cookie == cookie) { struct omap_desc *d = c->desc; dma_addr_t pos; @@ -848,11 +846,15 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, pos = 0; txstate->residue = omap_dma_desc_size_pos(d, pos); + } else if ((vd = vchan_find_desc(&c->vc, cookie))) { + txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx)); } else { txstate->residue = 0; } + if (ret == DMA_IN_PROGRESS && c->paused) ret = DMA_PAUSED; + spin_unlock_irqrestore(&c->vc.lock, flags); return ret; -- cgit v1.2.3 From 4689d35c765c696bdf0535486a990038b242a26b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:24:59 +0300 Subject: dmaengine: ti: omap-dma: Improved memcpy polling support When a DMA client driver does not set the DMA_PREP_INTERRUPT because it does not want to use interrupts for DMA completion or because it can not rely on DMA interrupts due to executing the memcpy when interrupts are disabled it will poll the status of the transfer. If the interrupts are enabled then the cookie will be set completed in the interrupt handler so only check in HW completion when the polling is really needed. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190716082459.1222-3-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/omap-dma.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 80fd2667b2c8..a4a63425dc0b 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -91,6 +91,7 @@ struct omap_desc { bool using_ll; enum dma_transfer_direction dir; dma_addr_t dev_addr; + bool polled; int32_t fi; /* for OMAP_DMA_SYNC_PACKET / double indexing */ int16_t ei; /* for double indexing */ @@ -816,26 +817,20 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, struct virt_dma_desc *vd; enum dma_status ret; unsigned long flags; + struct omap_desc *d = NULL; ret = dma_cookie_status(chan, cookie, txstate); - - if (!c->paused && c->running) { - uint32_t ccr = omap_dma_chan_read(c, CCR); - /* - * The channel is no longer active, set the return value - * accordingly - */ - if (!(ccr & CCR_ENABLE)) - ret = DMA_COMPLETE; - } - - if (ret == DMA_COMPLETE || !txstate) + if (ret == DMA_COMPLETE) return ret; spin_lock_irqsave(&c->vc.lock, flags); + if (c->desc && c->desc->vd.tx.cookie == cookie) + d = c->desc; + + if (!txstate) + goto out; - if (c->desc && c->desc->vd.tx.cookie == cookie) { - struct omap_desc *d = c->desc; + if (d) { dma_addr_t pos; if (d->dir == DMA_MEM_TO_DEV) @@ -852,8 +847,22 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, txstate->residue = 0; } - if (ret == DMA_IN_PROGRESS && c->paused) +out: + if (ret == DMA_IN_PROGRESS && c->paused) { ret = DMA_PAUSED; + } else if (d && d->polled && c->running) { + uint32_t ccr = omap_dma_chan_read(c, CCR); + /* + * The channel is no longer active, set the return value + * accordingly and mark it as completed + */ + if (!(ccr & CCR_ENABLE)) { + struct omap_desc *d = c->desc; + ret = DMA_COMPLETE; + omap_dma_start_desc(c); + vchan_cookie_complete(&d->vd); + } + } spin_unlock_irqrestore(&c->vc.lock, flags); @@ -1181,7 +1190,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy( d->ccr = c->ccr; d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_POSTINC; - d->cicr = CICR_DROP_IE | CICR_FRAME_IE; + if (tx_flags & DMA_PREP_INTERRUPT) + d->cicr |= CICR_FRAME_IE; + else + d->polled = true; d->csdp = data_type; -- cgit v1.2.3 From e96b1f64ee2885acb8fb26325eb9743ad6c64696 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:26:53 +0300 Subject: dmaengine: ti: edma: Clean up the 2x32bit array register accesses Introduce defines for getting the array index and the bit number within the 64bit array register pairs. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190716082655.1620-2-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 106 +++++++++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 45 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index f2549ee3fb49..6d0e0bcc0379 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -132,6 +132,17 @@ #define EDMA_CONT_PARAMS_FIXED_EXACT 1002 #define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003 +/* + * 64bit array registers are split into two 32bit registers: + * reg0: channel/event 0-31 + * reg1: channel/event 32-63 + * + * bit 5 in the channel number tells the array index (0/1) + * bit 0-4 (0x1f) is the bit offset within the register + */ +#define EDMA_REG_ARRAY_INDEX(channel) ((channel) >> 5) +#define EDMA_CHANNEL_BIT(channel) (BIT((channel) & 0x1f)) + /* PaRAM slots are laid out like this */ struct edmacc_param { u32 opt; @@ -440,15 +451,14 @@ static void edma_setup_interrupt(struct edma_chan *echan, bool enable) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); if (enable) { - edma_shadow0_write_array(ecc, SH_ICR, channel >> 5, - BIT(channel & 0x1f)); - edma_shadow0_write_array(ecc, SH_IESR, channel >> 5, - BIT(channel & 0x1f)); + edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_IESR, idx, ch_bit); } else { - edma_shadow0_write_array(ecc, SH_IECR, channel >> 5, - BIT(channel & 0x1f)); + edma_shadow0_write_array(ecc, SH_IECR, idx, ch_bit); } } @@ -586,26 +596,26 @@ static void edma_start(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - int j = (channel >> 5); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); if (!echan->hw_triggered) { /* EDMA channels without event association */ - dev_dbg(ecc->dev, "ESR%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_ESR, j)); - edma_shadow0_write_array(ecc, SH_ESR, j, mask); + dev_dbg(ecc->dev, "ESR%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_ESR, idx)); + edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit); } else { /* EDMA channel with event association */ - dev_dbg(ecc->dev, "ER%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_ER, j)); + dev_dbg(ecc->dev, "ER%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_ER, idx)); /* Clear any pending event or error */ - edma_write_array(ecc, EDMA_ECR, j, mask); - edma_write_array(ecc, EDMA_EMCR, j, mask); + edma_write_array(ecc, EDMA_ECR, idx, ch_bit); + edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); /* Clear any SER */ - edma_shadow0_write_array(ecc, SH_SECR, j, mask); - edma_shadow0_write_array(ecc, SH_EESR, j, mask); - dev_dbg(ecc->dev, "EER%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_EER, j)); + edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_EESR, idx, ch_bit); + dev_dbg(ecc->dev, "EER%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_EER, idx)); } } @@ -613,19 +623,19 @@ static void edma_stop(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - int j = (channel >> 5); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); - edma_shadow0_write_array(ecc, SH_EECR, j, mask); - edma_shadow0_write_array(ecc, SH_ECR, j, mask); - edma_shadow0_write_array(ecc, SH_SECR, j, mask); - edma_write_array(ecc, EDMA_EMCR, j, mask); + edma_shadow0_write_array(ecc, SH_EECR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit); + edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); + edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); /* clear possibly pending completion interrupt */ - edma_shadow0_write_array(ecc, SH_ICR, j, mask); + edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit); - dev_dbg(ecc->dev, "EER%d %08x\n", j, - edma_shadow0_read_array(ecc, SH_EER, j)); + dev_dbg(ecc->dev, "EER%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_EER, idx)); /* REVISIT: consider guarding against inappropriate event * chaining by overwriting with dummy_paramset. @@ -639,45 +649,49 @@ static void edma_stop(struct edma_chan *echan) static void edma_pause(struct edma_chan *echan) { int channel = EDMA_CHAN_SLOT(echan->ch_num); - unsigned int mask = BIT(channel & 0x1f); - edma_shadow0_write_array(echan->ecc, SH_EECR, channel >> 5, mask); + edma_shadow0_write_array(echan->ecc, SH_EECR, + EDMA_REG_ARRAY_INDEX(channel), + EDMA_CHANNEL_BIT(channel)); } /* Re-enable EDMA hardware events on the specified channel. */ static void edma_resume(struct edma_chan *echan) { int channel = EDMA_CHAN_SLOT(echan->ch_num); - unsigned int mask = BIT(channel & 0x1f); - edma_shadow0_write_array(echan->ecc, SH_EESR, channel >> 5, mask); + edma_shadow0_write_array(echan->ecc, SH_EESR, + EDMA_REG_ARRAY_INDEX(channel), + EDMA_CHANNEL_BIT(channel)); } static void edma_trigger_channel(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); - edma_shadow0_write_array(ecc, SH_ESR, (channel >> 5), mask); + edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit); - dev_dbg(ecc->dev, "ESR%d %08x\n", (channel >> 5), - edma_shadow0_read_array(ecc, SH_ESR, (channel >> 5))); + dev_dbg(ecc->dev, "ESR%d %08x\n", idx, + edma_shadow0_read_array(ecc, SH_ESR, idx)); } static void edma_clean_channel(struct edma_chan *echan) { struct edma_cc *ecc = echan->ecc; int channel = EDMA_CHAN_SLOT(echan->ch_num); - int j = (channel >> 5); - unsigned int mask = BIT(channel & 0x1f); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); - dev_dbg(ecc->dev, "EMR%d %08x\n", j, edma_read_array(ecc, EDMA_EMR, j)); - edma_shadow0_write_array(ecc, SH_ECR, j, mask); + dev_dbg(ecc->dev, "EMR%d %08x\n", idx, + edma_read_array(ecc, EDMA_EMR, idx)); + edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit); /* Clear the corresponding EMR bits */ - edma_write_array(ecc, EDMA_EMCR, j, mask); + edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); /* Clear any SER */ - edma_shadow0_write_array(ecc, SH_SECR, j, mask); + edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); edma_write(ecc, EDMA_CCERRCLR, BIT(16) | BIT(1) | BIT(0)); } @@ -707,7 +721,8 @@ static int edma_alloc_channel(struct edma_chan *echan, int channel = EDMA_CHAN_SLOT(echan->ch_num); /* ensure access through shadow region 0 */ - edma_or_array2(ecc, EDMA_DRAE, 0, channel >> 5, BIT(channel & 0x1f)); + edma_or_array2(ecc, EDMA_DRAE, 0, EDMA_REG_ARRAY_INDEX(channel), + EDMA_CHANNEL_BIT(channel)); /* ensure no events are pending */ edma_stop(echan); @@ -2483,8 +2498,9 @@ static int edma_pm_resume(struct device *dev) for (i = 0; i < ecc->num_channels; i++) { if (echan[i].alloced) { /* ensure access through shadow region 0 */ - edma_or_array2(ecc, EDMA_DRAE, 0, i >> 5, - BIT(i & 0x1f)); + edma_or_array2(ecc, EDMA_DRAE, 0, + EDMA_REG_ARRAY_INDEX(i), + EDMA_CHANNEL_BIT(i)); edma_setup_interrupt(&echan[i], true); -- cgit v1.2.3 From 097ffdc75259139ba157b7f924cfeb0d6b00559e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:26:54 +0300 Subject: dmaengine: ti: edma: Correct the residue calculation (fix for memcpy) For memcpy we never stored the start address of the transfer for the pset which rendered the memcpy residue calculation completely broken. In the edma_residue() function we also need to to some correction for the calculations: Instead waiting for all EDMA channels to be idle (in a busy system it can take few iteration to hit a point when all queues are idle) wait for the event pending on the given channel (SH_ER for hw synchronized channels, SH_ESR for manually triggered channels). If the position returned by EMDA is 0 it implies that the last paRAM set has been consumed and we are at the closing dummy set, thus we can conclude that the transfer is completed and we can return 0 as residue. Signed-off-by: Peter Ujfalusi [vkoul: fixed typo in commit log] Link: https://lore.kernel.org/r/20190716082655.1620-3-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 6d0e0bcc0379..201b838ec808 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -1025,6 +1025,7 @@ static int edma_config_pset(struct dma_chan *chan, struct edma_pset *epset, src_cidx = cidx; dst_bidx = acnt; dst_cidx = cidx; + epset->addr = src_addr; } else { dev_err(dev, "%s: direction not implemented yet\n", __func__); return -EINVAL; @@ -1735,7 +1736,11 @@ static u32 edma_residue(struct edma_desc *edesc) 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; + dma_addr_t done, pos, pos_old; + int channel = EDMA_CHAN_SLOT(echan->ch_num); + int idx = EDMA_REG_ARRAY_INDEX(channel); + int ch_bit = EDMA_CHANNEL_BIT(channel); + int event_reg; int i; /* @@ -1748,16 +1753,20 @@ static u32 edma_residue(struct edma_desc *edesc) * "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 + * 1. while and event is pending for the channel + * 2. a position updated * 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) { + if (is_slave_direction(edesc->direction)) + event_reg = SH_ER; + else + event_reg = SH_ESR; + + pos_old = pos; + while (edma_shadow0_read_array(echan->ecc, event_reg, idx) & ch_bit) { + pos = edma_get_position(echan->ecc, echan->slot[0], dst); + if (pos != pos_old) break; - } if (!--loop_count) { dev_dbg_ratelimited(echan->vchan.chan.device->dev, @@ -1782,6 +1791,12 @@ static u32 edma_residue(struct edma_desc *edesc) return edesc->residue_stat; } + /* + * If the position is 0, then EDMA loaded the closing dummy slot, the + * transfer is completed + */ + if (!pos) + return 0; /* * For SG operation we catch up with the last processed * status. -- cgit v1.2.3 From aa3c6ce4eab8fb0e967954be1ba1cad3b715f63b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:26:55 +0300 Subject: dmaengine: ti: edma: Support for polled (memcpy) completion When a DMA client driver does not set the DMA_PREP_INTERRUPT because it does not want to use interrupts for DMA completion or because it can not rely on DMA interrupts due to executing the memcpy when interrupts are disabled it will poll the status of the transfer. Since we can not tell from any EDMA register that the transfer is completed, we can only know that the paRAM set has been sent to TPTC for processing we need to check the residue of the transfer, if it is 0 then the transfer is completed. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190716082655.1620-4-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 201b838ec808..fe468e2f7e67 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -179,6 +179,7 @@ struct edma_desc { struct list_head node; enum dma_transfer_direction direction; int cyclic; + bool polled; int absync; int pset_nr; struct edma_chan *echan; @@ -1226,8 +1227,9 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( edesc->pset[0].param.opt |= ITCCHEN; if (nslots == 1) { - /* Enable transfer complete interrupt */ - edesc->pset[0].param.opt |= TCINTEN; + /* Enable transfer complete interrupt if requested */ + if (tx_flags & DMA_PREP_INTERRUPT) + edesc->pset[0].param.opt |= TCINTEN; } else { /* Enable transfer complete chaining for the first slot */ edesc->pset[0].param.opt |= TCCHEN; @@ -1254,9 +1256,14 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( } edesc->pset[1].param.opt |= ITCCHEN; - edesc->pset[1].param.opt |= TCINTEN; + /* Enable transfer complete interrupt if requested */ + if (tx_flags & DMA_PREP_INTERRUPT) + edesc->pset[1].param.opt |= TCINTEN; } + if (!(tx_flags & DMA_PREP_INTERRUPT)) + edesc->polled = true; + return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); } @@ -1826,18 +1833,40 @@ static enum dma_status edma_tx_status(struct dma_chan *chan, { struct edma_chan *echan = to_edma_chan(chan); struct virt_dma_desc *vdesc; + struct dma_tx_state txstate_tmp; enum dma_status ret; unsigned long flags; ret = dma_cookie_status(chan, cookie, txstate); - if (ret == DMA_COMPLETE || !txstate) + + if (ret == DMA_COMPLETE) return ret; + /* Provide a dummy dma_tx_state for completion checking */ + if (!txstate) + txstate = &txstate_tmp; + + txstate->residue = 0; spin_lock_irqsave(&echan->vchan.lock, flags); if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) txstate->residue = edma_residue(echan->edesc); else if ((vdesc = vchan_find_desc(&echan->vchan, cookie))) txstate->residue = to_edma_desc(&vdesc->tx)->residue; + + /* + * Mark the cookie completed if the residue is 0 for non cyclic + * transfers + */ + if (ret != DMA_COMPLETE && !txstate->residue && + echan->edesc && echan->edesc->polled && + echan->edesc->vdesc.tx.cookie == cookie) { + edma_stop(echan); + vchan_cookie_complete(&echan->edesc->vdesc); + echan->edesc = NULL; + edma_execute(echan); + ret = DMA_COMPLETE; + } + spin_unlock_irqrestore(&echan->vchan.lock, flags); return ret; -- cgit v1.2.3 From 069e4a19f44d82c43d6a3866499f3d4da6ab3dec Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Aug 2019 12:11:43 +0200 Subject: dmaengine: ti: unexport filter functions The two filter functions are now marked static, but still exported, which triggers a coming build-time check: WARNING: "omap_dma_filter_fn" [vmlinux] is a static EXPORT_SYMBOL_GPL WARNING: "edma_filter_fn" [vmlinux] is a static EXPORT_SYMBOL Remove the unneeded exports as well, as originally intended. Fixes: 9c71b9eb3cb2 ("dmaengine: omap-dma: make omap_dma_filter_fn private") Fixes: d2bfe7b5d182 ("dmaengine: edma: make edma_filter_fn private") Reported-by: Stephen Rothwell Acked-by: Peter Ujfalusi Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20190812101155.997721-1-arnd@arndb.de Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 1 - drivers/dma/ti/omap-dma.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index fe468e2f7e67..f7555d78ff9e 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -2600,7 +2600,6 @@ static bool edma_filter_fn(struct dma_chan *chan, void *param) } return match; } -EXPORT_SYMBOL(edma_filter_fn); static int edma_init(void) { diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index a4a63425dc0b..d27779be5b17 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1666,7 +1666,6 @@ static bool omap_dma_filter_fn(struct dma_chan *chan, void *param) } return false; } -EXPORT_SYMBOL_GPL(omap_dma_filter_fn); static int omap_dma_init(void) { -- cgit v1.2.3 From e3b9fef8ddf8a5a31a16c4959202f5d88e07e080 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Jul 2019 16:20:06 +0300 Subject: dmaengine: ti: edma: Remove 'Assignment in if condition' While the compiler does not have problem with how it is implemented, checkpatch does give en ERROR for this arrangement. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190730132006.2790-1-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index f7555d78ff9e..54895112ba59 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -1832,7 +1832,6 @@ static enum dma_status edma_tx_status(struct dma_chan *chan, struct dma_tx_state *txstate) { struct edma_chan *echan = to_edma_chan(chan); - struct virt_dma_desc *vdesc; struct dma_tx_state txstate_tmp; enum dma_status ret; unsigned long flags; @@ -1846,12 +1845,18 @@ static enum dma_status edma_tx_status(struct dma_chan *chan, if (!txstate) txstate = &txstate_tmp; - txstate->residue = 0; spin_lock_irqsave(&echan->vchan.lock, flags); - if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) + if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) { txstate->residue = edma_residue(echan->edesc); - else if ((vdesc = vchan_find_desc(&echan->vchan, cookie))) - txstate->residue = to_edma_desc(&vdesc->tx)->residue; + } else { + struct virt_dma_desc *vdesc = vchan_find_desc(&echan->vchan, + cookie); + + if (vdesc) + txstate->residue = to_edma_desc(&vdesc->tx)->residue; + else + txstate->residue = 0; + } /* * Mark the cookie completed if the residue is 0 for non cyclic -- cgit v1.2.3 From 7a09c09c300761f2a0f34cfecebe327883de5864 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Jul 2019 16:20:15 +0300 Subject: dmaengine: ti: omap-dma: Remove 'Assignment in if condition' While the compiler does not have problem with how it is implemented, checkpatch does give en ERROR for this arrangement. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190730132015.2863-1-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/omap-dma.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index d27779be5b17..23da592594fa 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -814,7 +814,6 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) { struct omap_chan *c = to_omap_dma_chan(chan); - struct virt_dma_desc *vd; enum dma_status ret; unsigned long flags; struct omap_desc *d = NULL; @@ -841,10 +840,14 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, pos = 0; txstate->residue = omap_dma_desc_size_pos(d, pos); - } else if ((vd = vchan_find_desc(&c->vc, cookie))) { - txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx)); } else { - txstate->residue = 0; + struct virt_dma_desc *vd = vchan_find_desc(&c->vc, cookie); + + if (vd) + txstate->residue = omap_dma_desc_size( + to_omap_dma_desc(&vd->tx)); + else + txstate->residue = 0; } out: -- cgit v1.2.3 From 9fa2df6eafa024e9f10ff60518ab62abe1c6cfb6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Jul 2019 16:20:29 +0300 Subject: dmaengine: ti: omap-dma: Remove variable override in omap_dma_tx_status() There is no need to fetch local omap_desc since the desc we have is the correct one already when we need to check the channel status. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190730132029.2971-1-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/omap-dma.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 23da592594fa..7b5d485289ab 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -860,7 +860,6 @@ out: * accordingly and mark it as completed */ if (!(ccr & CCR_ENABLE)) { - struct omap_desc *d = c->desc; ret = DMA_COMPLETE; omap_dma_start_desc(c); vchan_cookie_complete(&d->vd); -- cgit v1.2.3 From c5dbe60664b3660f5ac5854e21273ea2e7ff698f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:14 +0300 Subject: dmaengine: ti: edma: Do not reset reserved paRAM slots Skip resetting paRAM slots marked as reserved as they might be used by other cores. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190823125618.8133-2-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 54895112ba59..1aae95cc0d4b 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -2338,9 +2338,6 @@ static int edma_probe(struct platform_device *pdev) ecc->default_queue = info->default_queue; - for (i = 0; i < ecc->num_slots; i++) - edma_write_slot(ecc, i, &dummy_paramset); - if (info->rsv) { /* Set the reserved slots in inuse list */ rsv_slots = info->rsv->rsv_slots; @@ -2353,6 +2350,12 @@ static int edma_probe(struct platform_device *pdev) } } + for (i = 0; i < ecc->num_slots; i++) { + /* Reset only unused - not reserved - paRAM slots */ + if (!test_bit(i, ecc->slot_inuse)) + edma_write_slot(ecc, i, &dummy_paramset); + } + /* Clear the xbar mapped channels in unused list */ xbar_chans = info->xbar_chans; if (xbar_chans) { -- cgit v1.2.3 From b2003f61a554ff402509c6061aa5e3f6ef92f12a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:15 +0300 Subject: dmaengine: ti: edma: Only reset region0 access registers Region0 is used by Linux, do not reset other registers controlling access for other shadow regions. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190823125618.8133-3-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 1aae95cc0d4b..87450431f336 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -2434,11 +2434,10 @@ static int edma_probe(struct platform_device *pdev) edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0], queue_priority_mapping[i][1]); - for (i = 0; i < ecc->num_region; i++) { - edma_write_array2(ecc, EDMA_DRAE, i, 0, 0x0); - edma_write_array2(ecc, EDMA_DRAE, i, 1, 0x0); - edma_write_array(ecc, EDMA_QRAE, i, 0x0); - } + edma_write_array2(ecc, EDMA_DRAE, 0, 0, 0x0); + edma_write_array2(ecc, EDMA_DRAE, 0, 1, 0x0); + edma_write_array(ecc, EDMA_QRAE, 0, 0x0); + ecc->info = info; /* Init the dma device and channels */ -- cgit v1.2.3 From c5c6faaee6e0c374c7dfaf053aa23750f5a68e20 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:16 +0300 Subject: dmaengine: ti: edma: Use bitmap_set() instead of open coded edma_set_bits() bitmap_set() is the standard way of setting an area in the bitfield. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190823125618.8133-4-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/edma.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/dma/ti') diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 87450431f336..ba7c4f07fcd6 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -423,12 +424,6 @@ static inline void edma_param_or(struct edma_cc *ecc, int offset, int param_no, edma_or(ecc, EDMA_PARM + offset + (param_no << 5), or); } -static inline void edma_set_bits(int offset, int len, unsigned long *p) -{ - for (; len > 0; len--) - set_bit(offset + (len - 1), p); -} - static void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no, int priority) { @@ -2254,7 +2249,7 @@ static int edma_probe(struct platform_device *pdev) { struct edma_soc_info *info = pdev->dev.platform_data; s8 (*queue_priority_mapping)[2]; - int i, off, ln; + int i, off; const s16 (*rsv_slots)[2]; const s16 (*xbar_chans)[2]; int irq; @@ -2342,11 +2337,9 @@ static int edma_probe(struct platform_device *pdev) /* Set the reserved slots in inuse list */ rsv_slots = info->rsv->rsv_slots; if (rsv_slots) { - for (i = 0; rsv_slots[i][0] != -1; i++) { - off = rsv_slots[i][0]; - ln = rsv_slots[i][1]; - edma_set_bits(off, ln, ecc->slot_inuse); - } + for (i = 0; rsv_slots[i][0] != -1; i++) + bitmap_set(ecc->slot_inuse, rsv_slots[i][0], + rsv_slots[i][1]); } } -- cgit v1.2.3