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') 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-59-g8ed1b 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 +++-- include/linux/edma.h | 29 ----------------------------- 2 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 include/linux/edma.h (limited to 'drivers/dma') 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; diff --git a/include/linux/edma.h b/include/linux/edma.h deleted file mode 100644 index a1307e7827e8..000000000000 --- a/include/linux/edma.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * TI EDMA DMA engine driver - * - * Copyright 2012 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef __LINUX_EDMA_H -#define __LINUX_EDMA_H - -struct dma_chan; - -#if defined(CONFIG_TI_EDMA) || defined(CONFIG_TI_EDMA_MODULE) -bool edma_filter_fn(struct dma_chan *, void *); -#else -static inline bool edma_filter_fn(struct dma_chan *chan, void *param) -{ - return false; -} -#endif - -#endif -- cgit v1.2.3-59-g8ed1b From 72503b25ee363827aafffc3e8d872e6a92a7e422 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 16 Jul 2019 19:15:18 +0200 Subject: dmaengine: bcm2835: Print error in case setting DMA mask fails During enabling of the RPi 4, we found out that the driver doesn't provide a helpful error message in case setting DMA mask fails. So add one. Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/1563297318-4900-1-git-send-email-wahrenst@gmx.net Signed-off-by: Vinod Koul --- drivers/dma/bcm2835-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/dma') diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 8101ff2f05c1..970f654611bd 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -871,8 +871,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) + if (rc) { + dev_err(&pdev->dev, "Unable to set DMA mask\n"); return rc; + } od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); if (!od) -- cgit v1.2.3-59-g8ed1b From 156a599b0716ab3ee3869ff26119e3b5d46d91c8 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 5 Jul 2019 18:05:19 +0300 Subject: dmaengine: tegra-apb: Support per-burst residue granularity Tegra's APB DMA engine updates words counter after each transferred burst of data, hence it can report transfer's residual with more fidelity which may be required in cases like audio playback. In particular this fixes audio stuttering during playback in a chromium web browser. The patch is based on the original work that was made by Ben Dooks and a patch from downstream kernel. It was tested on Tegra20 and Tegra30 devices. Link: https://lore.kernel.org/lkml/20190424162348.23692-1-ben.dooks@codethink.co.uk/ Link: https://nv-tegra.nvidia.com/gitweb/?p=linux-4.4.git;a=commit;h=c7bba40c6846fbf3eaad35c4472dcc7d8bbc02e5 Inspired-by: Ben Dooks Reviewed-by: Jon Hunter Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20190705150519.18171-1-digetx@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 75 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 7 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 79e9593815f1..3a45079d11ec 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -152,6 +152,7 @@ struct tegra_dma_sg_req { bool last_sg; struct list_head node; struct tegra_dma_desc *dma_desc; + unsigned int words_xferred; }; /* @@ -496,6 +497,7 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc, tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB); nsg_req->configured = true; + nsg_req->words_xferred = 0; tegra_dma_resume(tdc); } @@ -511,6 +513,7 @@ static void tdc_start_head_req(struct tegra_dma_channel *tdc) typeof(*sg_req), node); tegra_dma_start(tdc, sg_req); sg_req->configured = true; + sg_req->words_xferred = 0; tdc->busy = true; } @@ -638,6 +641,8 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc, list_add_tail(&dma_desc->cb_node, &tdc->cb_desc); dma_desc->cb_count++; + sgreq->words_xferred = 0; + /* If not last req then put at end of pending list */ if (!list_is_last(&sgreq->node, &tdc->pending_sg_req)) { list_move_tail(&sgreq->node, &tdc->pending_sg_req); @@ -797,6 +802,65 @@ skip_dma_stop: return 0; } +static unsigned int tegra_dma_sg_bytes_xferred(struct tegra_dma_channel *tdc, + struct tegra_dma_sg_req *sg_req) +{ + unsigned long status, wcount = 0; + + if (!list_is_first(&sg_req->node, &tdc->pending_sg_req)) + return 0; + + if (tdc->tdma->chip_data->support_separate_wcount_reg) + wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER); + + status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS); + + if (!tdc->tdma->chip_data->support_separate_wcount_reg) + wcount = status; + + if (status & TEGRA_APBDMA_STATUS_ISE_EOC) + return sg_req->req_len; + + wcount = get_current_xferred_count(tdc, sg_req, wcount); + + if (!wcount) { + /* + * If wcount wasn't ever polled for this SG before, then + * simply assume that transfer hasn't started yet. + * + * Otherwise it's the end of the transfer. + * + * The alternative would be to poll the status register + * until EOC bit is set or wcount goes UP. That's so + * because EOC bit is getting set only after the last + * burst's completion and counter is less than the actual + * transfer size by 4 bytes. The counter value wraps around + * in a cyclic mode before EOC is set(!), so we can't easily + * distinguish start of transfer from its end. + */ + if (sg_req->words_xferred) + wcount = sg_req->req_len - 4; + + } else if (wcount < sg_req->words_xferred) { + /* + * This case will never happen for a non-cyclic transfer. + * + * For a cyclic transfer, although it is possible for the + * next transfer to have already started (resetting the word + * count), this case should still not happen because we should + * have detected that the EOC bit is set and hence the transfer + * was completed. + */ + WARN_ON_ONCE(1); + + wcount = sg_req->req_len - 4; + } else { + sg_req->words_xferred = wcount; + } + + return wcount; +} + static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, dma_cookie_t cookie, struct dma_tx_state *txstate) { @@ -806,6 +870,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, enum dma_status ret; unsigned long flags; unsigned int residual; + unsigned int bytes = 0; ret = dma_cookie_status(dc, cookie, txstate); if (ret == DMA_COMPLETE) @@ -825,6 +890,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, list_for_each_entry(sg_req, &tdc->pending_sg_req, node) { dma_desc = sg_req->dma_desc; if (dma_desc->txd.cookie == cookie) { + bytes = tegra_dma_sg_bytes_xferred(tdc, sg_req); ret = dma_desc->dma_status; goto found; } @@ -836,7 +902,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc, found: if (dma_desc && txstate) { residual = dma_desc->bytes_requested - - (dma_desc->bytes_transferred % + ((dma_desc->bytes_transferred + bytes) % dma_desc->bytes_requested); dma_set_residue(txstate, residual); } @@ -1441,12 +1507,7 @@ static int tegra_dma_probe(struct platform_device *pdev) BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_8_BYTES); tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - /* - * XXX The hardware appears to support - * DMA_RESIDUE_GRANULARITY_BURST-level reporting, but it's - * only used by this driver during tegra_dma_terminate_all() - */ - tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; tdma->dma_dev.device_config = tegra_dma_slave_config; tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all; tdma->dma_dev.device_tx_status = tegra_dma_tx_status; -- cgit v1.2.3-59-g8ed1b From f4c255f1a747497a21748619d909cadabcfa060e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 14 Jul 2019 17:55:04 -0400 Subject: dmaengine: dma-jz4780: Break descriptor chains on JZ4740 The current driver works perfectly fine on every generation of the JZ47xx SoCs, except on the JZ4740. There, when hardware descriptors are chained together (with the LINK bit set), the next descriptor isn't automatically fetched as it should - instead, an interrupt is raised, even if the TIE bit (Transfer Interrupt Enable) bit is cleared. When it happens, the DMA transfer seems to be stopped (it doesn't chain), and it's uncertain how many bytes have actually been transferred. Until somebody smarter than me can figure out how to make chained descriptors work on the JZ4740, we now disable chained descriptors on that particular SoC. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20190714215504.10877-1-paul@crapouillou.net Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 7fe9309a876b..9a985a9710aa 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -92,6 +92,7 @@ #define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) #define JZ_SOC_DATA_PER_CHAN_PM BIT(2) #define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3) +#define JZ_SOC_DATA_BREAK_LINKS BIT(4) /** * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. @@ -355,6 +356,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg( void *context) { struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); struct jz4780_dma_desc *desc; unsigned int i; int err; @@ -375,7 +377,8 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg( desc->desc[i].dcm |= JZ_DMA_DCM_TIE; - if (i != (sg_len - 1)) { + if (i != (sg_len - 1) && + !(jzdma->soc_data->flags & JZ_SOC_DATA_BREAK_LINKS)) { /* Automatically proceeed to the next descriptor. */ desc->desc[i].dcm |= JZ_DMA_DCM_LINK; @@ -664,6 +667,8 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, struct jz4780_dma_chan *jzchan) { + const unsigned int soc_flags = jzdma->soc_data->flags; + struct jz4780_dma_desc *desc = jzchan->desc; uint32_t dcs; bool ack = true; @@ -691,8 +696,11 @@ static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, jz4780_dma_begin(jzchan); } else if (dcs & JZ_DMA_DCS_TT) { - vchan_cookie_complete(&jzchan->desc->vdesc); - jzchan->desc = NULL; + if (!(soc_flags & JZ_SOC_DATA_BREAK_LINKS) || + (jzchan->curr_hwdesc + 1 == desc->count)) { + vchan_cookie_complete(&desc->vdesc); + jzchan->desc = NULL; + } jz4780_dma_begin(jzchan); } else { @@ -992,6 +1000,7 @@ static int jz4780_dma_remove(struct platform_device *pdev) static const struct jz4780_dma_soc_data jz4740_dma_soc_data = { .nb_channels = 6, .transfer_ord_max = 5, + .flags = JZ_SOC_DATA_BREAK_LINKS, }; static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = { -- cgit v1.2.3-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b From 2cb114c4fac7a9c3e8fd8c39ceac1e6ca030b412 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2019 22:07:56 +0300 Subject: dmaengine: stm32-dmamux: Switch to use device_property_count_u32() Use use device_property_count_u32() directly, that makes code neater. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190723190757.67351-1-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/stm32-dmamux.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index b552949da14b..3c89bd39e096 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -185,8 +185,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev) if (!node) return -ENODEV; - count = device_property_read_u32_array(&pdev->dev, "dma-masters", - NULL, 0); + count = device_property_count_u32(&pdev->dev, "dma-masters"); if (count < 0) { dev_err(&pdev->dev, "Can't get DMA master(s) node\n"); return -ENODEV; -- cgit v1.2.3-59-g8ed1b From 57dbd0e4b97d3bc9f257159a8853badff2dfb0d1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2019 22:07:57 +0300 Subject: dmaengine: stm32-mdma: Switch to use device_property_count_u32() Use use device_property_count_u32() directly, that makes code neater. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190723190757.67351-2-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index d6e919d3936a..0d56fde78c1f 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1555,8 +1555,7 @@ static int stm32_mdma_probe(struct platform_device *pdev) nr_requests); } - count = device_property_read_u32_array(&pdev->dev, "st,ahb-addr-masks", - NULL, 0); + count = device_property_count_u32(&pdev->dev, "st,ahb-addr-masks"); if (count < 0) count = 0; -- cgit v1.2.3-59-g8ed1b From a9afc9ea93995021f29025e62d83415a45c5f58b Mon Sep 17 00:00:00 2001 From: Jonathan Hunter Date: Wed, 31 Jul 2019 11:16:39 +0100 Subject: dmaengine: tegra210-adma: Don't program FIFO threshold The Tegra210 ADMA supports two modes for transferring data to a FIFO which are ... 1. Transfer data to/from the FIFO as soon as a single burst can be transferred. 2. Transfer data to/from the FIFO based upon FIFO thresholds, where the FIFO threshold is specified in terms on multiple bursts. Currently, the ADMA driver programs the FIFO threshold values in the FIFO_CTRL register, but never enables the transfer mode that uses these threshold values. Given that these have never been used so far, simplify the ADMA driver by removing the programming of these threshold values. Signed-off-by: Jonathan Hunter Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20190731101639.22755-1-jonathanh@nvidia.com Signed-off-by: Vinod Koul --- drivers/dma/tegra210-adma.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 2805853e963f..d8646a49ba5b 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -42,12 +42,8 @@ #define ADMA_CH_CONFIG_MAX_BUFS 8 #define ADMA_CH_FIFO_CTRL 0x2c -#define TEGRA210_ADMA_CH_FIFO_CTRL_OFLWTHRES(val) (((val) & 0xf) << 24) -#define TEGRA210_ADMA_CH_FIFO_CTRL_STRVTHRES(val) (((val) & 0xf) << 16) #define TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(val) (((val) & 0xf) << 8) #define TEGRA210_ADMA_CH_FIFO_CTRL_RXSIZE(val) ((val) & 0xf) -#define TEGRA186_ADMA_CH_FIFO_CTRL_OFLWTHRES(val) (((val) & 0x1f) << 24) -#define TEGRA186_ADMA_CH_FIFO_CTRL_STRVTHRES(val) (((val) & 0x1f) << 16) #define TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(val) (((val) & 0x1f) << 8) #define TEGRA186_ADMA_CH_FIFO_CTRL_RXSIZE(val) ((val) & 0x1f) @@ -64,14 +60,10 @@ #define TEGRA_ADMA_BURST_COMPLETE_TIME 20 -#define TEGRA210_FIFO_CTRL_DEFAULT (TEGRA210_ADMA_CH_FIFO_CTRL_OFLWTHRES(1) | \ - TEGRA210_ADMA_CH_FIFO_CTRL_STRVTHRES(1) | \ - TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ +#define TEGRA210_FIFO_CTRL_DEFAULT (TEGRA210_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ TEGRA210_ADMA_CH_FIFO_CTRL_RXSIZE(3)) -#define TEGRA186_FIFO_CTRL_DEFAULT (TEGRA186_ADMA_CH_FIFO_CTRL_OFLWTHRES(1) | \ - TEGRA186_ADMA_CH_FIFO_CTRL_STRVTHRES(1) | \ - TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ +#define TEGRA186_FIFO_CTRL_DEFAULT (TEGRA186_ADMA_CH_FIFO_CTRL_TXSIZE(3) | \ TEGRA186_ADMA_CH_FIFO_CTRL_RXSIZE(3)) #define ADMA_CH_REG_FIELD_VAL(val, mask, shift) (((val) & mask) << shift) -- cgit v1.2.3-59-g8ed1b From 7f5d7425748d1cc2dadb6966ec84363d3342b5a1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 17:52:21 -0500 Subject: dmaengine: imx-dma: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: arm): drivers/dma/imx-dma.c: In function ‘imxdma_xfer_desc’: drivers/dma/imx-dma.c:542:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (slot == IMX_DMA_2D_SLOT_A) { ^ drivers/dma/imx-dma.c:559:2: note: here case IMXDMA_DESC_MEMCPY: ^~~~ Notice that, in this particular case, the code comment is modified in accordance with what GCC is expecting to find. Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20190729225221.GA24269@embeddedor Reviewed-by: Kees Cook Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/dma') diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 00a089e24150..5c0fb3134825 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -556,6 +556,7 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) * We fall-through here intentionally, since a 2D transfer is * similar to MEMCPY just adding the 2D slot configuration. */ + /* Fall through */ case IMXDMA_DESC_MEMCPY: imx_dmav1_writel(imxdma, d->src, DMA_SAR(imxdmac->channel)); imx_dmav1_writel(imxdma, d->dest, DMA_DAR(imxdmac->channel)); -- cgit v1.2.3-59-g8ed1b From e17be6e1b713f188728a23ebfba15546a025c109 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Jul 2019 11:15:10 -0700 Subject: dmaengine: Remove dev_err() usage after platform_get_irq() We don't need dev_err() messages when platform_get_irq() fails now that platform_get_irq() prints an error message itself when something goes wrong. Let's remove these prints with a simple semantic patch. // @@ expression ret; struct platform_device *E; @@ ret = ( platform_get_irq(E, ...) | platform_get_irq_byname(E, ...) ); if ( \( ret < 0 \| ret <= 0 \) ) { ( -if (ret != -EPROBE_DEFER) -{ ... -dev_err(...); -... } | ... -dev_err(...); ) ... } // While we're here, remove braces on if statements that only have one statement (manually). Cc: Vinod Koul Cc: Dan Williams Cc: dmaengine@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20190730181557.90391-11-swboyd@chromium.org Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4780.c | 4 +--- drivers/dma/fsl-edma.c | 8 ++------ drivers/dma/fsl-qdma.c | 9 ++------- drivers/dma/mediatek/mtk-uart-apdma.c | 4 +--- drivers/dma/qcom/hidma_mgmt.c | 1 - drivers/dma/s3c24xx-dma.c | 5 +---- drivers/dma/sh/rcar-dmac.c | 4 +--- drivers/dma/sh/usb-dmac.c | 4 +--- drivers/dma/st_fdma.c | 4 +--- drivers/dma/stm32-dma.c | 6 +----- drivers/dma/stm32-mdma.c | 4 +--- drivers/dma/sun4i-dma.c | 4 +--- drivers/dma/sun6i-dma.c | 4 +--- drivers/dma/uniphier-mdmac.c | 5 +---- drivers/dma/xgene-dma.c | 8 ++------ 15 files changed, 17 insertions(+), 57 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 9a985a9710aa..cafb1cc065bb 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -886,10 +886,8 @@ static int jz4780_dma_probe(struct platform_device *pdev) } ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "failed to get IRQ: %d\n", ret); + if (ret < 0) return ret; - } jzdma->irq = ret; diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index fcbad6ae954a..71650fa01f18 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -125,16 +125,12 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma int ret; fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx"); - if (fsl_edma->txirq < 0) { - dev_err(&pdev->dev, "Can't get edma-tx irq.\n"); + if (fsl_edma->txirq < 0) return fsl_edma->txirq; - } fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err"); - if (fsl_edma->errirq < 0) { - dev_err(&pdev->dev, "Can't get edma-err irq.\n"); + if (fsl_edma->errirq < 0) return fsl_edma->errirq; - } if (fsl_edma->txirq == fsl_edma->errirq) { ret = devm_request_irq(&pdev->dev, fsl_edma->txirq, diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index 8e341c0c13bc..06664fbd2d91 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -758,10 +758,8 @@ fsl_qdma_irq_init(struct platform_device *pdev, fsl_qdma->error_irq = platform_get_irq_byname(pdev, "qdma-error"); - if (fsl_qdma->error_irq < 0) { - dev_err(&pdev->dev, "Can't get qdma controller irq.\n"); + if (fsl_qdma->error_irq < 0) return fsl_qdma->error_irq; - } ret = devm_request_irq(&pdev->dev, fsl_qdma->error_irq, fsl_qdma_error_handler, 0, @@ -776,11 +774,8 @@ fsl_qdma_irq_init(struct platform_device *pdev, fsl_qdma->queue_irq[i] = platform_get_irq_byname(pdev, irq_name); - if (fsl_qdma->queue_irq[i] < 0) { - dev_err(&pdev->dev, - "Can't get qdma queue %d irq.\n", i); + if (fsl_qdma->queue_irq[i] < 0) return fsl_qdma->queue_irq[i]; - } ret = devm_request_irq(&pdev->dev, fsl_qdma->queue_irq[i], diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c index 546995c20876..f40051d6aecb 100644 --- a/drivers/dma/mediatek/mtk-uart-apdma.c +++ b/drivers/dma/mediatek/mtk-uart-apdma.c @@ -547,10 +547,8 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev) vchan_init(&c->vc, &mtkd->ddev); rc = platform_get_irq(pdev, i); - if (rc < 0) { - dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i); + if (rc < 0) goto err_no_dma; - } c->irq = rc; } diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 3022d66e7a33..7cb81a50f3f3 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -183,7 +183,6 @@ static int hidma_mgmt_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "irq resources not found\n"); rc = irq; goto out; } diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index ad30f3d2c7f6..43da8eeb18ef 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -1237,11 +1237,8 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) phy->host = s3cdma; phy->irq = platform_get_irq(pdev, i); - if (phy->irq < 0) { - dev_err(&pdev->dev, "failed to get irq %d, err %d\n", - i, phy->irq); + if (phy->irq < 0) continue; - } ret = devm_request_irq(&pdev->dev, phy->irq, s3c24xx_dma_irq, 0, pdev->name, phy); diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 9c41a4e42575..eb6f2312a6a2 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1744,10 +1744,8 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac, /* Request the channel interrupt. */ sprintf(pdev_irqname, "ch%u", index); rchan->irq = platform_get_irq_byname(pdev, pdev_irqname); - if (rchan->irq < 0) { - dev_err(dmac->dev, "no IRQ specified for channel %u\n", index); + if (rchan->irq < 0) return -ENODEV; - } irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", dev_name(dmac->dev), index); diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 17063aaf51bc..b218a013c260 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -717,10 +717,8 @@ static int usb_dmac_chan_probe(struct usb_dmac *dmac, /* Request the channel interrupt. */ sprintf(pdev_irqname, "ch%u", index); uchan->irq = platform_get_irq_byname(pdev, pdev_irqname); - if (uchan->irq < 0) { - dev_err(dmac->dev, "no IRQ specified for channel %u\n", index); + if (uchan->irq < 0) return -ENODEV; - } irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", dev_name(dmac->dev), index); diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index a3ee0f6bb664..67087dbe2f9f 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -771,10 +771,8 @@ static int st_fdma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fdev); fdev->irq = platform_get_irq(pdev, 0); - if (fdev->irq < 0) { - dev_err(&pdev->dev, "Failed to get irq resource\n"); + if (fdev->irq < 0) return -EINVAL; - } ret = devm_request_irq(&pdev->dev, fdev->irq, st_fdma_irq_handler, 0, dev_name(&pdev->dev), fdev); diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index ef4d109e7189..e4cbe38d1b83 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -1366,12 +1366,8 @@ static int stm32_dma_probe(struct platform_device *pdev) for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; ret = platform_get_irq(pdev, i); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "No irq resource for chan %d\n", i); + if (ret < 0) goto err_unregister; - } chan->irq = ret; ret = devm_request_irq(&pdev->dev, chan->irq, diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 0d56fde78c1f..057811a7149c 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1637,10 +1637,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) } dmadev->irq = platform_get_irq(pdev, 0); - if (dmadev->irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ\n"); + if (dmadev->irq < 0) return dmadev->irq; - } ret = devm_request_irq(&pdev->dev, dmadev->irq, stm32_mdma_irq_handler, 0, dev_name(&pdev->dev), dmadev); diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c index 1f80568b2613..e397a50058c8 100644 --- a/drivers/dma/sun4i-dma.c +++ b/drivers/dma/sun4i-dma.c @@ -1132,10 +1132,8 @@ static int sun4i_dma_probe(struct platform_device *pdev) return PTR_ERR(priv->base); priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); + if (priv->irq < 0) return priv->irq; - } priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index ed5b68dcfe50..06cd7f867f7c 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -1251,10 +1251,8 @@ static int sun6i_dma_probe(struct platform_device *pdev) return PTR_ERR(sdc->base); sdc->irq = platform_get_irq(pdev, 0); - if (sdc->irq < 0) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); + if (sdc->irq < 0) return sdc->irq; - } sdc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sdc->clk)) { diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c index ec65a7430dc4..fde54687856b 100644 --- a/drivers/dma/uniphier-mdmac.c +++ b/drivers/dma/uniphier-mdmac.c @@ -354,11 +354,8 @@ static int uniphier_mdmac_chan_init(struct platform_device *pdev, int irq, ret; irq = platform_get_irq(pdev, chan_id); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ number for ch%d\n", - chan_id); + if (irq < 0) return irq; - } irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d", chan_id); diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index 957c269ce1fd..cd60fa6d6750 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -1678,20 +1678,16 @@ static int xgene_dma_get_resources(struct platform_device *pdev, /* Get DMA error interrupt */ irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "Failed to get Error IRQ\n"); + if (irq <= 0) return -ENXIO; - } pdma->err_irq = irq; /* Get DMA Rx ring descriptor interrupts for all DMA channels */ for (i = 1; i <= XGENE_DMA_MAX_CHANNEL; i++) { irq = platform_get_irq(pdev, i); - if (irq <= 0) { - dev_err(&pdev->dev, "Failed to get Rx IRQ\n"); + if (irq <= 0) return -ENXIO; - } pdma->chan[i - 1].rx_irq = irq; } -- cgit v1.2.3-59-g8ed1b From 9603a7ab60989f586786f082a8b1e3bf6fbcc749 Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 15 Jul 2019 11:17:16 +0800 Subject: dmaengine: imx-sdma: Remove call to memset after dma_alloc_coherent In commit 518a2f1925c3 ("dma-mapping: zero memory returned from dma_alloc_*"), dma_alloc_coherent has already zeroed the memory. So memset is not needed. Signed-off-by: Fuqian Huang Link: https://lore.kernel.org/r/20190715031716.6328-1-huangfq.daxian@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a01f4b5d793c..9ba74ab7e912 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1886,10 +1886,6 @@ static int sdma_init(struct sdma_engine *sdma) sdma->context_phys = ccb_phys + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); - /* Zero-out the CCB structures array just allocated */ - memset(sdma->channel_control, 0, - MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control)); - /* disable all channels */ for (i = 0; i < sdma->drvdata->num_events; i++) writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i)); -- cgit v1.2.3-59-g8ed1b From 719e25dba4430a7f2b1e77fa962f0527ebc9371d Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 15 Jul 2019 11:17:23 +0800 Subject: dmaengine: qcom_hidma: Remove call to memset after dmam_alloc_coherent In commit 518a2f1925c3 ("dma-mapping: zero memory returned from dma_alloc_*"), dma_alloc_coherent has already zeroed the memory. So memset is not needed. Signed-off-by: Fuqian Huang Acked-by: Sinan Kaya Link: https://lore.kernel.org/r/20190715031723.6375-1-huangfq.daxian@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_ll.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 5bf8b145c427..bb4471e84e48 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -749,7 +749,6 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres, if (!lldev->tre_ring) return NULL; - memset(lldev->tre_ring, 0, (HIDMA_TRE_SIZE + 1) * nr_tres); lldev->tre_ring_size = HIDMA_TRE_SIZE * nr_tres; lldev->nr_tres = nr_tres; @@ -769,7 +768,6 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres, if (!lldev->evre_ring) return NULL; - memset(lldev->evre_ring, 0, (HIDMA_EVRE_SIZE + 1) * nr_tres); lldev->evre_ring_size = HIDMA_EVRE_SIZE * nr_tres; /* the EVRE ring has to be EVRE_SIZE aligned */ -- cgit v1.2.3-59-g8ed1b From 232a7f18cf8ecbd92a8cc6ca7feee4f6aab668fe Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Wed, 24 Jul 2019 15:20:34 +0800 Subject: dmaengine: fsl-edma: add i.mx7ulp edma2 version support Add edma2 for i.mx7ulp by version v3, since v2 has already been used by mcf-edma. The big changes based on v1 are belows: 1. only one dmamux. 2. another clock dma_clk except dmamux clk. 3. 16 independent interrupts instead of only one interrupt for all channels. Signed-off-by: Robin Gong Link: https://lore.kernel.org/r/1563952834-7731-1-git-send-email-yibin.gong@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 18 +++++++++++- drivers/dma/fsl-edma-common.h | 4 +++ drivers/dma/fsl-edma.c | 65 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) (limited to 'drivers/dma') diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 44d92c34dec3..6d6d8a4e8e38 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -90,6 +90,19 @@ static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr, iowrite8(val8, addr + off); } +void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, + u32 off, u32 slot, bool enable) +{ + u32 val; + + if (enable) + val = EDMAMUX_CHCFG_ENBL << 24 | slot; + else + val = EDMAMUX_CHCFG_DIS; + + iowrite32(val, addr + off * 4); +} + void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, unsigned int slot, bool enable) { @@ -103,7 +116,10 @@ void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; slot = EDMAMUX_CHCFG_SOURCE(slot); - mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); + if (fsl_chan->edma->drvdata->version == v3) + mux_configure32(fsl_chan, muxaddr, ch_off, slot, enable); + else + mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); } EXPORT_SYMBOL_GPL(fsl_edma_chan_mux); diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 4e175560292c..5eaa2902ed39 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -125,6 +125,7 @@ struct fsl_edma_chan { dma_addr_t dma_dev_addr; u32 dma_dev_size; enum dma_data_direction dma_dir; + char chan_name[16]; }; struct fsl_edma_desc { @@ -139,11 +140,13 @@ struct fsl_edma_desc { enum edma_version { v1, /* 32ch, Vybrid, mpc57x, etc */ v2, /* 64ch Coldfire */ + v3, /* 32ch, i.mx7ulp */ }; struct fsl_edma_drvdata { enum edma_version version; u32 dmamuxs; + bool has_dmaclk; int (*setup_irq)(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma); }; @@ -153,6 +156,7 @@ struct fsl_edma_engine { void __iomem *membase; void __iomem *muxbase[DMAMUX_NR]; struct clk *muxclk[DMAMUX_NR]; + struct clk *dmaclk; struct mutex fsl_edma_mutex; const struct fsl_edma_drvdata *drvdata; u32 n_chans; diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 71650fa01f18..dfce75c2991b 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -158,6 +158,49 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma return 0; } +static int +fsl_edma2_irq_init(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma) +{ + int i, ret, irq; + int count; + + count = platform_irq_count(pdev); + dev_dbg(&pdev->dev, "%s Found %d interrupts\r\n", __func__, count); + if (count <= 2) { + dev_err(&pdev->dev, "Interrupts in DTS not correct.\n"); + return -EINVAL; + } + /* + * 16 channel independent interrupts + 1 error interrupt on i.mx7ulp. + * 2 channel share one interrupt, for example, ch0/ch16, ch1/ch17... + * For now, just simply request irq without IRQF_SHARED flag, since 16 + * channels are enough on i.mx7ulp whose M4 domain own some peripherals. + */ + for (i = 0; i < count; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + return -ENXIO; + + sprintf(fsl_edma->chans[i].chan_name, "eDMA2-CH%02d", i); + + /* The last IRQ is for eDMA err */ + if (i == count - 1) + ret = devm_request_irq(&pdev->dev, irq, + fsl_edma_err_handler, + 0, "eDMA2-ERR", fsl_edma); + else + ret = devm_request_irq(&pdev->dev, irq, + fsl_edma_tx_handler, 0, + fsl_edma->chans[i].chan_name, + fsl_edma); + if (ret) + return ret; + } + + return 0; +} + static void fsl_edma_irq_exit( struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) { @@ -183,8 +226,16 @@ static struct fsl_edma_drvdata vf610_data = { .setup_irq = fsl_edma_irq_init, }; +static struct fsl_edma_drvdata imx7ulp_data = { + .version = v3, + .dmamuxs = 1, + .has_dmaclk = true, + .setup_irq = fsl_edma2_irq_init, +}; + static const struct of_device_id fsl_edma_dt_ids[] = { { .compatible = "fsl,vf610-edma", .data = &vf610_data}, + { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); @@ -232,6 +283,20 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_edma_setup_regs(fsl_edma); regs = &fsl_edma->regs; + if (drvdata->has_dmaclk) { + fsl_edma->dmaclk = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(fsl_edma->dmaclk)) { + dev_err(&pdev->dev, "Missing DMA block clock.\n"); + return PTR_ERR(fsl_edma->dmaclk); + } + + ret = clk_prepare_enable(fsl_edma->dmaclk); + if (ret) { + dev_err(&pdev->dev, "DMA clk block failed.\n"); + return ret; + } + } + for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) { char clkname[32]; -- cgit v1.2.3-59-g8ed1b From 057b05d5ac4745e7999656223bc6426c0129ba86 Mon Sep 17 00:00:00 2001 From: Nishka Dasgupta Date: Wed, 24 Jul 2019 13:46:09 +0530 Subject: dmaengine: qcom: hidma_mgmt: Add of_node_put() before goto Each iteration of for_each_available_child_of_node puts the previous node, but in the case of a goto from the middle of the loop, there is no put, thus causing a memory leak. Hence add an of_node_put under the label that the gotos point to. In order to avoid decrementing an already-decremented refcount, copy the original contents of the label (including the return statement) to just above the label, so that the code under the label is executed only when a goto exit from the loop occurs. Additionally, remove an unnecessary get/put pair from the loop, as the loop itself already keeps track of refcount. Issue found with Coccinelle. Signed-off-by: Nishka Dasgupta Acked-by: Sinan Kaya Link: https://lore.kernel.org/r/20190724081609.9724-1-nishkadg.linux@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_mgmt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 7cb81a50f3f3..806ca02c52d7 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -387,7 +387,6 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) ret = PTR_ERR(new_pdev); goto out; } - of_node_get(child); new_pdev->dev.of_node = child; of_dma_configure(&new_pdev->dev, child, true); /* @@ -395,9 +394,14 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) * platforms with or without MSI support. */ of_msi_configure(&new_pdev->dev, child); - of_node_put(child); } + + kfree(res); + + return ret; + out: + of_node_put(child); kfree(res); return ret; -- cgit v1.2.3-59-g8ed1b From d1b622f68daf6c9f1abed360428e5a8f22063f99 Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Fri, 26 Jul 2019 18:59:47 +0800 Subject: dmaengine: pl330: use the same attributes when freeing pl330->mcode_cpu In function dmac_alloc_resources(), pl330->mcode_cpu is allocated using dma_alloc_attrs() but freed with dma_free_coherent(). Use the correct dma_free_attrs() function to free pl330->mcode_cpu. Signed-off-by: Fuqian Huang Link: https://lore.kernel.org/r/20190726105947.25342-1-huangfq.daxian@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 1163af2ba4a3..6cce9ef61b29 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1922,9 +1922,10 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) if (ret) { dev_err(pl330->ddma.dev, "%s:%d Can't to create channels for DMAC!\n", __func__, __LINE__); - dma_free_coherent(pl330->ddma.dev, + dma_free_attrs(pl330->ddma.dev, chans * pl330->mcbufsz, - pl330->mcode_cpu, pl330->mcode_bus); + pl330->mcode_cpu, pl330->mcode_bus, + DMA_ATTR_PRIVILEGED); return ret; } @@ -2003,9 +2004,9 @@ static void pl330_del(struct pl330_dmac *pl330) /* Free DMAC resources */ dmac_free_threads(pl330); - dma_free_coherent(pl330->ddma.dev, + dma_free_attrs(pl330->ddma.dev, pl330->pcfg.num_chan * pl330->mcbufsz, pl330->mcode_cpu, - pl330->mcode_bus); + pl330->mcode_bus, DMA_ATTR_PRIVILEGED); } /* forward declaration */ -- cgit v1.2.3-59-g8ed1b From ba1cab79cfc629f7238a26e040545ca394cd695f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 31 Jul 2019 10:36:59 -0700 Subject: dmaengine: fsl-edma: implement .device_synchronize callback Implement .device_synchronize callback in order to be able to use dmaengine_terminate_sync() and other primitives relying on said callback. Signed-off-by: Andrey Smirnov Cc: Stefan Agner Cc: Chris Healy Cc: Vinod Koul Cc: linux-imx@nxp.com Cc: dmaengine@vger.kernel.org Cc: linux-kernel@vger.kernel.org Link: https://lore.kernel.org/r/20190731173659.14778-1-andrew.smirnov@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/dma') diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index dfce75c2991b..b626c06ac2e0 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -20,6 +20,13 @@ #include "fsl-edma-common.h" +static void fsl_edma_synchronize(struct dma_chan *chan) +{ + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + + vchan_synchronize(&fsl_chan->vchan); +} + static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id) { struct fsl_edma_engine *fsl_edma = dev_id; @@ -363,6 +370,7 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_edma->dma_dev.device_pause = fsl_edma_pause; fsl_edma->dma_dev.device_resume = fsl_edma_resume; fsl_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all; + fsl_edma->dma_dev.device_synchronize = fsl_edma_synchronize; fsl_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending; fsl_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS; -- cgit v1.2.3-59-g8ed1b 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') 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-59-g8ed1b From 7607a121f4617840fe645c65f090af6403738031 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 11 Aug 2019 19:22:00 -0500 Subject: dmaengine: fsldma: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark switch cases where we are expecting to fall through. Fix the following warning (Building: powerpc-ppa8548_defconfig powerpc): drivers/dma/fsldma.c: In function ‘fsl_dma_chan_probe’: drivers/dma/fsldma.c:1165:26: warning: this statement may fall through [-Wimplicit-fallthrough=] chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/dma/fsldma.c:1166:2: note: here case FSL_DMA_IP_83XX: ^~~~ Reported-by: kbuild test robot Signed-off-by: Gustavo A. R. Silva Acked-by: Li Yang Link: https://lore.kernel.org/r/20190812002159.GA26899@embeddedor Signed-off-by: Vinod Koul --- drivers/dma/fsldma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/dma') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 23e0a356f167..ad72b3f42ffa 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1163,6 +1163,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev, switch (chan->feature & FSL_DMA_IP_MASK) { case FSL_DMA_IP_85XX: chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; + /* Fall through */ case FSL_DMA_IP_83XX: chan->toggle_ext_start = fsl_chan_toggle_ext_start; chan->set_src_loop_size = fsl_chan_set_src_loop_size; -- cgit v1.2.3-59-g8ed1b From b48b8bc45a8fe4bc1d1369f0e2eb98b15a4b6c56 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 13 Aug 2019 11:06:02 +0300 Subject: dmaengine: dw: Update Intel Elkhart Lake Service Engine acronym Intel Elkhart Lake Offload Service Engine (OSE) will be called as Intel(R) Programmable Services Engine (Intel(R) PSE) in documentation. Update the comment here accordingly. Signed-off-by: Jarkko Nikula Acked-by: Andy Shevchenko Acked-by: Viresh Kumar Link: https://lore.kernel.org/r/20190813080602.15376-1-jarkko.nikula@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 8de87b15a988..ad6db1cc287e 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -143,7 +143,7 @@ static const struct pci_device_id dw_pci_id_table[] = { { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data }, { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data }, - /* Elkhart Lake iDMA 32-bit (OSE DMA) */ + /* Elkhart Lake iDMA 32-bit (PSE DMA) */ { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_pci_data }, { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_pci_data }, { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_pci_data }, -- cgit v1.2.3-59-g8ed1b From 698f7a9be9b2389384c69750d87a0c68202c0621 Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Tue, 13 Aug 2019 10:34:48 -0700 Subject: dmaengine: mv_xor_v2: Fix -Wshift-negative-value Clang produces the following warning drivers/dma/mv_xor_v2.c:264:40: warning: shifting a negative signed value is undefined [-Wshift-negative-value] reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ drivers/dma/mv_xor_v2.c:271:46: warning: shifting a negative signed value is undefined [-Wshift-negative-value] reg &= (~MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK << ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ Upon further investigation MV_XOR_V2_DMA_IMSG_THRD_SHIFT and MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT are both 0. Since shifting by 0 does nothing, these variables can be removed. Cc: clang-built-linux@googlegroups.com Link: https://github.com/ClangBuiltLinux/linux/issues/521 Signed-off-by: Nathan Huckleberry Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20190813173448.109859-1-nhuck@google.com Signed-off-by: Vinod Koul --- drivers/dma/mv_xor_v2.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index fa5dab481203..e3850f04f676 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -33,7 +33,6 @@ #define MV_XOR_V2_DMA_IMSG_CDAT_OFF 0x014 #define MV_XOR_V2_DMA_IMSG_THRD_OFF 0x018 #define MV_XOR_V2_DMA_IMSG_THRD_MASK 0x7FFF -#define MV_XOR_V2_DMA_IMSG_THRD_SHIFT 0x0 #define MV_XOR_V2_DMA_IMSG_TIMER_EN BIT(18) #define MV_XOR_V2_DMA_DESQ_AWATTR_OFF 0x01C /* Same flags as MV_XOR_V2_DMA_DESQ_ARATTR_OFF */ @@ -50,7 +49,6 @@ #define MV_XOR_V2_DMA_DESQ_ADD_OFF 0x808 #define MV_XOR_V2_DMA_IMSG_TMOT 0x810 #define MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK 0x1FFF -#define MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT 0 /* XOR Global registers */ #define MV_XOR_V2_GLOB_BW_CTRL 0x4 @@ -261,16 +259,15 @@ void mv_xor_v2_enable_imsg_thrd(struct mv_xor_v2_device *xor_dev) /* Configure threshold of number of descriptors, and enable timer */ reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF); - reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); - reg |= (MV_XOR_V2_DONE_IMSG_THRD << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); + reg &= ~MV_XOR_V2_DMA_IMSG_THRD_MASK; + reg |= MV_XOR_V2_DONE_IMSG_THRD; reg |= MV_XOR_V2_DMA_IMSG_TIMER_EN; writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF); /* Configure Timer Threshold */ reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_TMOT); - reg &= (~MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK << - MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT); - reg |= (MV_XOR_V2_TIMER_THRD << MV_XOR_V2_DMA_IMSG_TIMER_THRD_SHIFT); + reg &= ~MV_XOR_V2_DMA_IMSG_TIMER_THRD_MASK; + reg |= MV_XOR_V2_TIMER_THRD; writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_TMOT); } -- cgit v1.2.3-59-g8ed1b From 4f48e29f7673726a8c1a18b10906ccd58a031b95 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 14 Aug 2019 15:21:04 +0800 Subject: dmaengine: make mux_configure32 static There is one sparse warning in drivers/dma/fsl-edma-common.c: drivers/dma/fsl-edma-common.c:93:6: warning: symbol 'mux_configure32' was not declared. Should it be static? Fix it by setting mux_configure32() as static. Fixes: 232a7f18cf8ec ("dmaengine: fsl-edma: add i.mx7ulp edma2 version support") Signed-off-by: Mao Wenan Link: https://lore.kernel.org/r/20190814072105.144107-2-maowenan@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/dma') diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 6d6d8a4e8e38..264c448de409 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -90,7 +90,7 @@ static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr, iowrite8(val8, addr + off); } -void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, +static void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, u32 off, u32 slot, bool enable) { u32 val; -- cgit v1.2.3-59-g8ed1b From d071fd294f2474118629f4021a6a3dedef28e09f Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 14 Aug 2019 15:21:05 +0800 Subject: dmaengine: change alignment of mux_configure32 and fsl_edma_chan_mux The alignment of mux_configure32() and fsl_edma_chan_mux() need to be adjusted, it must start precisely at the first column after the openning parenthesis of the first line. Fixes: 9d831528a656 ("dmaengine: fsl-edma: extract common fsl-edma code (no changes in behavior intended)") Signed-off-by: Mao Wenan Link: https://lore.kernel.org/r/20190814072105.144107-3-maowenan@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 264c448de409..b1a7ca91701a 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -91,7 +91,7 @@ static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr, } static void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, - u32 off, u32 slot, bool enable) + u32 off, u32 slot, bool enable) { u32 val; @@ -104,7 +104,7 @@ static void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, } void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, - unsigned int slot, bool enable) + unsigned int slot, bool enable) { u32 ch = fsl_chan->vchan.chan.chan_id; void __iomem *muxaddr; -- cgit v1.2.3-59-g8ed1b From a6bc332373e5176c2d085657bc643a28950b20b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:37 +0300 Subject: dmaengine: acpi: Set up DMA mask based on CSRT CSRT has an information about address width, which is supported by the certain DMA controller. Use information from CSRT to set up DMA mask for shared controller. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-2-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/acpi-dma.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/dma') diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index 30243f5c0710..4d66ee059808 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -82,6 +83,12 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, if (si->base_request_line == 0 && si->num_handshake_signals == 0) return 0; + /* Set up DMA mask based on value from CSRT */ + ret = dma_coerce_mask_and_coherent(&adev->dev, + DMA_BIT_MASK(si->dma_address_width)); + if (ret) + return 0; + adma->base_request_line = si->base_request_line; adma->end_request_line = si->base_request_line + si->num_handshake_signals - 1; -- cgit v1.2.3-59-g8ed1b From 4b8584bac0407367f8157244c8952ed80bdb12fb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:38 +0300 Subject: dmaengine: acpi: Add kernel doc parameter descriptions Kernel documentation script is not happy about absence of function parameter descriptions: drivers/dma/acpi-dma.c:163: warning: Function parameter or member 'data' not described in 'acpi_dma_controller_register' drivers/dma/acpi-dma.c:247: warning: Function parameter or member 'data' not described in 'devm_acpi_dma_controller_register' drivers/dma/acpi-dma.c:274: warning: Function parameter or member 'dev' not described in 'devm_acpi_dma_controller_free' Append the descriptions of above mentioned function parameters. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-3-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/acpi-dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index 4d66ee059808..8a05db3343d3 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -147,7 +147,7 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma) * @dev: struct device of DMA controller * @acpi_dma_xlate: translation function which converts a dma specifier * into a dma_chan structure - * @data pointer to controller specific data to be used by + * @data: pointer to controller specific data to be used by * translation function * * Allocated memory should be freed with appropriate acpi_dma_controller_free() @@ -231,7 +231,7 @@ static void devm_acpi_dma_release(struct device *dev, void *res) * devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register() * @dev: device that is registering this DMA controller * @acpi_dma_xlate: translation function - * @data pointer to controller specific data + * @data: pointer to controller specific data * * Managed acpi_dma_controller_register(). DMA controller registered by this * function are automatically freed on driver detach. See @@ -264,6 +264,7 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register); /** * devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free() + * @dev: device that is unregistering as DMA controller * * Unregister a DMA controller registered with * devm_acpi_dma_controller_register(). Normally this function will not need to -- cgit v1.2.3-59-g8ed1b From ae923c91aa3b4f7e20b764744188c0d859243d81 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:39 +0300 Subject: dmaengine: dw: Export struct dw_dma_chip_pdata for wider use We are expecting some devices can be enumerated either as PCI or ACPI. Nevertheless, they will share same information, thus, provide a generic struct dw_dma_chip_pdata for all glue drivers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-4-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/internal.h | 28 ++++++++++++++++++++++ drivers/dma/dw/pci.c | 60 +++++++++++++---------------------------------- 2 files changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 1dd7a4e6dd23..df5c84e2a4fd 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -23,4 +23,32 @@ int do_dw_dma_enable(struct dw_dma_chip *chip); extern bool dw_dma_filter(struct dma_chan *chan, void *param); +struct dw_dma_chip_pdata { + const struct dw_dma_platform_data *pdata; + int (*probe)(struct dw_dma_chip *chip); + int (*remove)(struct dw_dma_chip *chip); + struct dw_dma_chip *chip; +}; + +static __maybe_unused const struct dw_dma_chip_pdata dw_dma_chip_pdata = { + .probe = dw_dma_probe, + .remove = dw_dma_remove, +}; + +static const struct dw_dma_platform_data idma32_pdata = { + .nr_channels = 8, + .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, + .chan_priority = CHAN_PRIORITY_ASCENDING, + .block_size = 131071, + .nr_masters = 1, + .data_width = {4}, + .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, +}; + +static __maybe_unused const struct dw_dma_chip_pdata idma32_chip_pdata = { + .pdata = &idma32_pdata, + .probe = idma32_dma_probe, + .remove = idma32_dma_remove, +}; + #endif /* _DMA_DW_INTERNAL_H */ diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index ad6db1cc287e..cf6e8ec4c0ff 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -12,38 +12,10 @@ #include "internal.h" -struct dw_dma_pci_data { - const struct dw_dma_platform_data *pdata; - int (*probe)(struct dw_dma_chip *chip); - int (*remove)(struct dw_dma_chip *chip); - struct dw_dma_chip *chip; -}; - -static const struct dw_dma_pci_data dw_pci_data = { - .probe = dw_dma_probe, - .remove = dw_dma_remove, -}; - -static const struct dw_dma_platform_data idma32_pdata = { - .nr_channels = 8, - .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, - .chan_priority = CHAN_PRIORITY_ASCENDING, - .block_size = 131071, - .nr_masters = 1, - .data_width = {4}, - .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, -}; - -static const struct dw_dma_pci_data idma32_pci_data = { - .pdata = &idma32_pdata, - .probe = idma32_dma_probe, - .remove = idma32_dma_remove, -}; - static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) { - const struct dw_dma_pci_data *drv_data = (void *)pid->driver_data; - struct dw_dma_pci_data *data; + const struct dw_dma_chip_pdata *drv_data = (void *)pid->driver_data; + struct dw_dma_chip_pdata *data; struct dw_dma_chip *chip; int ret; @@ -95,7 +67,7 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) static void dw_pci_remove(struct pci_dev *pdev) { - struct dw_dma_pci_data *data = pci_get_drvdata(pdev); + struct dw_dma_chip_pdata *data = pci_get_drvdata(pdev); struct dw_dma_chip *chip = data->chip; int ret; @@ -108,7 +80,7 @@ static void dw_pci_remove(struct pci_dev *pdev) static int dw_pci_suspend_late(struct device *dev) { - struct dw_dma_pci_data *data = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); struct dw_dma_chip *chip = data->chip; return do_dw_dma_disable(chip); @@ -116,7 +88,7 @@ static int dw_pci_suspend_late(struct device *dev) static int dw_pci_resume_early(struct device *dev) { - struct dw_dma_pci_data *data = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); struct dw_dma_chip *chip = data->chip; return do_dw_dma_enable(chip); @@ -130,29 +102,29 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = { static const struct pci_device_id dw_pci_id_table[] = { /* Medfield (GPDMA) */ - { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_dma_chip_pdata }, /* BayTrail */ - { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data }, - { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_dma_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_dma_chip_pdata }, /* Merrifield */ - { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data }, + { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_chip_pdata }, /* Braswell */ - { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data }, - { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_dma_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_dma_chip_pdata }, /* Elkhart Lake iDMA 32-bit (PSE DMA) */ - { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_pci_data }, - { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_pci_data }, - { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_pci_data }, + { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_chip_pdata }, /* Haswell */ - { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_dma_chip_pdata }, /* Broadwell */ - { PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data }, + { PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_dma_chip_pdata }, { } }; -- cgit v1.2.3-59-g8ed1b From b3757413b91ecf4a227c5f075446afe8126d882f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:40 +0300 Subject: dmaengine: dw: platform: Use struct dw_dma_chip_pdata Now, when we have a generic structure for the chip and platform data, use it in the platform glue driver. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-5-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 382dfd9e9600..234abbd6359a 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -168,12 +168,22 @@ dw_dma_parse_dt(struct platform_device *pdev) static int dw_probe(struct platform_device *pdev) { + const struct dw_dma_chip_pdata *match; + struct dw_dma_chip_pdata *data; struct dw_dma_chip *chip; struct device *dev = &pdev->dev; struct resource *mem; const struct dw_dma_platform_data *pdata; int err; + match = device_get_match_data(dev); + if (!match) + return -ENODEV; + + data = devm_kmemdup(&pdev->dev, match, sizeof(*match), GFP_KERNEL); + if (!data) + return -ENOMEM; + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -199,6 +209,8 @@ static int dw_probe(struct platform_device *pdev) chip->id = pdev->id; chip->pdata = pdata; + data->chip = chip; + chip->clk = devm_clk_get(chip->dev, "hclk"); if (IS_ERR(chip->clk)) return PTR_ERR(chip->clk); @@ -208,11 +220,11 @@ static int dw_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - err = dw_dma_probe(chip); + err = data->probe(chip); if (err) goto err_dw_dma_probe; - platform_set_drvdata(pdev, chip); + platform_set_drvdata(pdev, data); if (pdev->dev.of_node) { err = of_dma_controller_register(pdev->dev.of_node, @@ -235,12 +247,17 @@ err_dw_dma_probe: static int dw_remove(struct platform_device *pdev) { - struct dw_dma_chip *chip = platform_get_drvdata(pdev); + struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev); + struct dw_dma_chip *chip = data->chip; + int ret; if (pdev->dev.of_node) of_dma_controller_free(pdev->dev.of_node); - dw_dma_remove(chip); + ret = data->remove(chip); + if (ret) + dev_warn(chip->dev, "can't remove device properly: %d\n", ret); + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(chip->clk); @@ -249,7 +266,8 @@ static int dw_remove(struct platform_device *pdev) static void dw_shutdown(struct platform_device *pdev) { - struct dw_dma_chip *chip = platform_get_drvdata(pdev); + struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev); + struct dw_dma_chip *chip = data->chip; /* * We have to call do_dw_dma_disable() to stop any ongoing transfer. On @@ -269,7 +287,7 @@ static void dw_shutdown(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id dw_dma_of_id_table[] = { - { .compatible = "snps,dma-spear1340" }, + { .compatible = "snps,dma-spear1340", .data = &dw_dma_chip_pdata }, {} }; MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); @@ -277,9 +295,9 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); #ifdef CONFIG_ACPI static const struct acpi_device_id dw_dma_acpi_id_table[] = { - { "INTL9C60", 0 }, - { "80862286", 0 }, - { "808622C0", 0 }, + { "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata }, + { "80862286", (kernel_ulong_t)&dw_dma_chip_pdata }, + { "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata }, { } }; MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); @@ -289,7 +307,8 @@ MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); static int dw_suspend_late(struct device *dev) { - struct dw_dma_chip *chip = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); + struct dw_dma_chip *chip = data->chip; do_dw_dma_disable(chip); clk_disable_unprepare(chip->clk); @@ -299,7 +318,8 @@ static int dw_suspend_late(struct device *dev) static int dw_resume_early(struct device *dev) { - struct dw_dma_chip *chip = dev_get_drvdata(dev); + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); + struct dw_dma_chip *chip = data->chip; int ret; ret = clk_prepare_enable(chip->clk); -- cgit v1.2.3-59-g8ed1b From f8d9ddbc28518a0f7d39d2ce51f778759b49f73e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:41 +0300 Subject: dmaengine: dw: platform: Enable iDMA 32-bit on Intel Elkhart Lake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intel® PSE (Programmable Services Engine) provides few DMA controllers to the host on Intel Elkhart Lake. Enable them in the ACPI glue driver. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-6-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 234abbd6359a..63465fd0e286 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -173,7 +173,6 @@ static int dw_probe(struct platform_device *pdev) struct dw_dma_chip *chip; struct device *dev = &pdev->dev; struct resource *mem; - const struct dw_dma_platform_data *pdata; int err; match = device_get_match_data(dev); @@ -201,13 +200,14 @@ static int dw_probe(struct platform_device *pdev) if (err) return err; - pdata = dev_get_platdata(dev); - if (!pdata) - pdata = dw_dma_parse_dt(pdev); + if (!data->pdata) + data->pdata = dev_get_platdata(dev); + if (!data->pdata) + data->pdata = dw_dma_parse_dt(pdev); chip->dev = dev; chip->id = pdev->id; - chip->pdata = pdata; + chip->pdata = data->pdata; data->chip = chip; @@ -298,6 +298,12 @@ static const struct acpi_device_id dw_dma_acpi_id_table[] = { { "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata }, { "80862286", (kernel_ulong_t)&dw_dma_chip_pdata }, { "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata }, + + /* Elkhart Lake iDMA 32-bit (PSE DMA) */ + { "80864BB4", (kernel_ulong_t)&idma32_chip_pdata }, + { "80864BB5", (kernel_ulong_t)&idma32_chip_pdata }, + { "80864BB6", (kernel_ulong_t)&idma32_chip_pdata }, + { } }; MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); -- cgit v1.2.3-59-g8ed1b From a9c56721d6ae99b22e983d0722e6b1b53a11dd59 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:42 +0300 Subject: dmaengine: dw: platform: Use devm_platform_ioremap_resource() Use the new helper that wraps the calls to platform_get_resource() and devm_ioremap_resource() together. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-7-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 63465fd0e286..8576439d0035 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -172,7 +172,6 @@ static int dw_probe(struct platform_device *pdev) struct dw_dma_chip_pdata *data; struct dw_dma_chip *chip; struct device *dev = &pdev->dev; - struct resource *mem; int err; match = device_get_match_data(dev); @@ -191,8 +190,7 @@ static int dw_probe(struct platform_device *pdev) if (chip->irq < 0) return chip->irq; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->regs = devm_ioremap_resource(dev, mem); + chip->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->regs)) return PTR_ERR(chip->regs); -- cgit v1.2.3-59-g8ed1b From e7b8514e4d68bec21fc6385fa0a66797ddc34ac9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:43 +0300 Subject: dmaengine: dw: platform: Switch to acpi_dma_controller_register() There is a possibility to have registered ACPI DMA controller while it has been gone already. To avoid the potential crash, move to non-managed acpi_dma_controller_register(). Fixes: 42c91ee71d6d ("dw_dmac: add ACPI support") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-8-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 8576439d0035..44fec1eabccd 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -84,13 +84,20 @@ static void dw_dma_acpi_controller_register(struct dw_dma *dw) dma_cap_set(DMA_SLAVE, info->dma_cap); info->filter_fn = dw_dma_acpi_filter; - ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate, - info); + ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); if (ret) dev_err(dev, "could not register acpi_dma_controller\n"); } + +static void dw_dma_acpi_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + acpi_dma_controller_free(dev); +} #else /* !CONFIG_ACPI */ static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} #endif /* !CONFIG_ACPI */ #ifdef CONFIG_OF @@ -249,6 +256,9 @@ static int dw_remove(struct platform_device *pdev) struct dw_dma_chip *chip = data->chip; int ret; + if (ACPI_HANDLE(&pdev->dev)) + dw_dma_acpi_controller_free(chip->dw); + if (pdev->dev.of_node) of_dma_controller_free(pdev->dev.of_node); -- cgit v1.2.3-59-g8ed1b From 84da042e702347c186b84d9cc2e766f83e1814d6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:44 +0300 Subject: dmaengine: dw: platform: Move handle check to dw_dma_acpi_controller_register() Move ACPI handle check to the dw_dma_acpi_controller_register(). While here, convert it to has_acpi_companion() which is recommended way. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-9-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 44fec1eabccd..b8514d7895d1 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -76,6 +76,9 @@ static void dw_dma_acpi_controller_register(struct dw_dma *dw) struct acpi_dma_filter_info *info; int ret; + if (!has_acpi_companion(dev)) + return; + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) return; @@ -93,6 +96,9 @@ static void dw_dma_acpi_controller_free(struct dw_dma *dw) { struct device *dev = dw->dma.dev; + if (!has_acpi_companion(dev)) + return; + acpi_dma_controller_free(dev); } #else /* !CONFIG_ACPI */ @@ -239,8 +245,7 @@ static int dw_probe(struct platform_device *pdev) "could not register of_dma_controller\n"); } - if (ACPI_HANDLE(&pdev->dev)) - dw_dma_acpi_controller_register(chip->dw); + dw_dma_acpi_controller_register(chip->dw); return 0; @@ -256,8 +261,7 @@ static int dw_remove(struct platform_device *pdev) struct dw_dma_chip *chip = data->chip; int ret; - if (ACPI_HANDLE(&pdev->dev)) - dw_dma_acpi_controller_free(chip->dw); + dw_dma_acpi_controller_free(chip->dw); if (pdev->dev.of_node) of_dma_controller_free(pdev->dev.of_node); -- cgit v1.2.3-59-g8ed1b From b685fe26e9af7318d73bf50af659a282d188a3e5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:45 +0300 Subject: dmaengine: dw: platform: Split ACPI helpers to separate module For better maintenance split ACPI helpers to the separate module. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-10-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/Makefile | 3 ++- drivers/dma/dw/acpi.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/dma/dw/internal.h | 8 +++++++ drivers/dma/dw/platform.c | 52 ---------------------------------------------- 4 files changed, 63 insertions(+), 53 deletions(-) create mode 100644 drivers/dma/dw/acpi.c (limited to 'drivers/dma') diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile index 63ed895c09aa..5e69815f3cf1 100644 --- a/drivers/dma/dw/Makefile +++ b/drivers/dma/dw/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o dw_dmac_core-objs := core.o dw.o idma32.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o -dw_dmac-objs := platform.o +dw_dmac-y := platform.o +dw_dmac-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o dw_dmac_pci-objs := pci.o diff --git a/drivers/dma/dw/acpi.c b/drivers/dma/dw/acpi.c new file mode 100644 index 000000000000..f6e8d55b4f6e --- /dev/null +++ b/drivers/dma/dw/acpi.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2013,2019 Intel Corporation + +#include +#include + +#include "internal.h" + +static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) +{ + struct acpi_dma_spec *dma_spec = param; + struct dw_dma_slave slave = { + .dma_dev = dma_spec->dev, + .src_id = dma_spec->slave_id, + .dst_id = dma_spec->slave_id, + .m_master = 0, + .p_master = 1, + }; + + return dw_dma_filter(chan, &slave); +} + +void dw_dma_acpi_controller_register(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + struct acpi_dma_filter_info *info; + int ret; + + if (!has_acpi_companion(dev)) + return; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return; + + dma_cap_zero(info->dma_cap); + dma_cap_set(DMA_SLAVE, info->dma_cap); + info->filter_fn = dw_dma_acpi_filter; + + ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); + if (ret) + dev_err(dev, "could not register acpi_dma_controller\n"); +} + +void dw_dma_acpi_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + if (!has_acpi_companion(dev)) + return; + + acpi_dma_controller_free(dev); +} diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index df5c84e2a4fd..acada530aa96 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -23,6 +23,14 @@ int do_dw_dma_enable(struct dw_dma_chip *chip); extern bool dw_dma_filter(struct dma_chan *chan, void *param); +#ifdef CONFIG_ACPI +void dw_dma_acpi_controller_register(struct dw_dma *dw); +void dw_dma_acpi_controller_free(struct dw_dma *dw); +#else /* !CONFIG_ACPI */ +static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} +#endif /* !CONFIG_ACPI */ + struct dw_dma_chip_pdata { const struct dw_dma_platform_data *pdata; int (*probe)(struct dw_dma_chip *chip); diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index b8514d7895d1..d50e038acb1e 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "internal.h" @@ -55,57 +54,6 @@ static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, return dma_request_channel(cap, dw_dma_filter, &slave); } -#ifdef CONFIG_ACPI -static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) -{ - struct acpi_dma_spec *dma_spec = param; - struct dw_dma_slave slave = { - .dma_dev = dma_spec->dev, - .src_id = dma_spec->slave_id, - .dst_id = dma_spec->slave_id, - .m_master = 0, - .p_master = 1, - }; - - return dw_dma_filter(chan, &slave); -} - -static void dw_dma_acpi_controller_register(struct dw_dma *dw) -{ - struct device *dev = dw->dma.dev; - struct acpi_dma_filter_info *info; - int ret; - - if (!has_acpi_companion(dev)) - return; - - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); - if (!info) - return; - - dma_cap_zero(info->dma_cap); - dma_cap_set(DMA_SLAVE, info->dma_cap); - info->filter_fn = dw_dma_acpi_filter; - - ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); - if (ret) - dev_err(dev, "could not register acpi_dma_controller\n"); -} - -static void dw_dma_acpi_controller_free(struct dw_dma *dw) -{ - struct device *dev = dw->dma.dev; - - if (!has_acpi_companion(dev)) - return; - - acpi_dma_controller_free(dev); -} -#else /* !CONFIG_ACPI */ -static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} -static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} -#endif /* !CONFIG_ACPI */ - #ifdef CONFIG_OF static struct dw_dma_platform_data * dw_dma_parse_dt(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From f5e84eae7956c694d27ddaba7113fe7d1174eff7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:46 +0300 Subject: dmaengine: dw: platform: Split OF helpers to separate module For better maintenance split OF helpers to the separate module. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-11-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/Makefile | 1 + drivers/dma/dw/internal.h | 15 ++++++ drivers/dma/dw/of.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/dma/dw/platform.c | 115 +--------------------------------------- 4 files changed, 149 insertions(+), 113 deletions(-) create mode 100644 drivers/dma/dw/of.c (limited to 'drivers/dma') diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile index 5e69815f3cf1..b6f06699e91a 100644 --- a/drivers/dma/dw/Makefile +++ b/drivers/dma/dw/Makefile @@ -5,6 +5,7 @@ dw_dmac_core-objs := core.o dw.o idma32.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o dw_dmac-y := platform.o dw_dmac-$(CONFIG_ACPI) += acpi.o +dw_dmac-$(CONFIG_OF) += of.o obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o dw_dmac_pci-objs := pci.o diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index acada530aa96..2e1c52eefdeb 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -31,6 +31,21 @@ static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} #endif /* !CONFIG_ACPI */ +struct platform_device; + +#ifdef CONFIG_OF +struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev); +void dw_dma_of_controller_register(struct dw_dma *dw); +void dw_dma_of_controller_free(struct dw_dma *dw); +#else +static inline struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +static inline void dw_dma_of_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_of_controller_free(struct dw_dma *dw) {} +#endif + struct dw_dma_chip_pdata { const struct dw_dma_platform_data *pdata; int (*probe)(struct dw_dma_chip *chip); diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c new file mode 100644 index 000000000000..9e27831dee32 --- /dev/null +++ b/drivers/dma/dw/of.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Platform driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2007-2008 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * Copyright (C) 2013 Intel Corporation + */ + +#include +#include +#include + +#include "internal.h" + +static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct dw_dma *dw = ofdma->of_dma_data; + struct dw_dma_slave slave = { + .dma_dev = dw->dma.dev, + }; + dma_cap_mask_t cap; + + if (dma_spec->args_count != 3) + return NULL; + + slave.src_id = dma_spec->args[0]; + slave.dst_id = dma_spec->args[0]; + slave.m_master = dma_spec->args[1]; + slave.p_master = dma_spec->args[2]; + + if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || + slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || + slave.m_master >= dw->pdata->nr_masters || + slave.p_master >= dw->pdata->nr_masters)) + return NULL; + + dma_cap_zero(cap); + dma_cap_set(DMA_SLAVE, cap); + + /* TODO: there should be a simpler way to do this */ + return dma_request_channel(cap, dw_dma_filter, &slave); +} + +struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct dw_dma_platform_data *pdata; + u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; + u32 nr_masters; + u32 nr_channels; + + if (!np) { + dev_err(&pdev->dev, "Missing DT data\n"); + return NULL; + } + + if (of_property_read_u32(np, "dma-masters", &nr_masters)) + return NULL; + if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) + return NULL; + + if (of_property_read_u32(np, "dma-channels", &nr_channels)) + return NULL; + if (nr_channels > DW_DMA_MAX_NR_CHANNELS) + return NULL; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->nr_masters = nr_masters; + pdata->nr_channels = nr_channels; + + if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) + pdata->chan_allocation_order = (unsigned char)tmp; + + if (!of_property_read_u32(np, "chan_priority", &tmp)) + pdata->chan_priority = tmp; + + if (!of_property_read_u32(np, "block_size", &tmp)) + pdata->block_size = tmp; + + if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { + for (tmp = 0; tmp < nr_masters; tmp++) + pdata->data_width[tmp] = arr[tmp]; + } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { + for (tmp = 0; tmp < nr_masters; tmp++) + pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); + } + + if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { + for (tmp = 0; tmp < nr_channels; tmp++) + pdata->multi_block[tmp] = mb[tmp]; + } else { + for (tmp = 0; tmp < nr_channels; tmp++) + pdata->multi_block[tmp] = 1; + } + + if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { + if (tmp > CHAN_PROTCTL_MASK) + return NULL; + pdata->protctl = tmp; + } + + return pdata; +} + +void dw_dma_of_controller_register(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + int ret; + + if (!dev->of_node) + return; + + ret = of_dma_controller_register(dev->of_node, dw_dma_of_xlate, dw); + if (ret) + dev_err(dev, "could not register of_dma_controller\n"); +} + +void dw_dma_of_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + if (!dev->of_node) + return; + + of_dma_controller_free(dev->of_node); +} diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index d50e038acb1e..c90c798e5ec3 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -17,116 +17,12 @@ #include #include #include -#include #include #include "internal.h" #define DRV_NAME "dw_dmac" -static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, - struct of_dma *ofdma) -{ - struct dw_dma *dw = ofdma->of_dma_data; - struct dw_dma_slave slave = { - .dma_dev = dw->dma.dev, - }; - dma_cap_mask_t cap; - - if (dma_spec->args_count != 3) - return NULL; - - slave.src_id = dma_spec->args[0]; - slave.dst_id = dma_spec->args[0]; - slave.m_master = dma_spec->args[1]; - slave.p_master = dma_spec->args[2]; - - if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || - slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || - slave.m_master >= dw->pdata->nr_masters || - slave.p_master >= dw->pdata->nr_masters)) - return NULL; - - dma_cap_zero(cap); - dma_cap_set(DMA_SLAVE, cap); - - /* TODO: there should be a simpler way to do this */ - return dma_request_channel(cap, dw_dma_filter, &slave); -} - -#ifdef CONFIG_OF -static struct dw_dma_platform_data * -dw_dma_parse_dt(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct dw_dma_platform_data *pdata; - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; - u32 nr_masters; - u32 nr_channels; - - if (!np) { - dev_err(&pdev->dev, "Missing DT data\n"); - return NULL; - } - - if (of_property_read_u32(np, "dma-masters", &nr_masters)) - return NULL; - if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) - return NULL; - - if (of_property_read_u32(np, "dma-channels", &nr_channels)) - return NULL; - if (nr_channels > DW_DMA_MAX_NR_CHANNELS) - return NULL; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - pdata->nr_masters = nr_masters; - pdata->nr_channels = nr_channels; - - if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) - pdata->chan_allocation_order = (unsigned char)tmp; - - if (!of_property_read_u32(np, "chan_priority", &tmp)) - pdata->chan_priority = tmp; - - if (!of_property_read_u32(np, "block_size", &tmp)) - pdata->block_size = tmp; - - if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { - for (tmp = 0; tmp < nr_masters; tmp++) - pdata->data_width[tmp] = arr[tmp]; - } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { - for (tmp = 0; tmp < nr_masters; tmp++) - pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); - } - - if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { - for (tmp = 0; tmp < nr_channels; tmp++) - pdata->multi_block[tmp] = mb[tmp]; - } else { - for (tmp = 0; tmp < nr_channels; tmp++) - pdata->multi_block[tmp] = 1; - } - - if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { - if (tmp > CHAN_PROTCTL_MASK) - return NULL; - pdata->protctl = tmp; - } - - return pdata; -} -#else -static inline struct dw_dma_platform_data * -dw_dma_parse_dt(struct platform_device *pdev) -{ - return NULL; -} -#endif - static int dw_probe(struct platform_device *pdev) { const struct dw_dma_chip_pdata *match; @@ -185,13 +81,7 @@ static int dw_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - if (pdev->dev.of_node) { - err = of_dma_controller_register(pdev->dev.of_node, - dw_dma_of_xlate, chip->dw); - if (err) - dev_err(&pdev->dev, - "could not register of_dma_controller\n"); - } + dw_dma_of_controller_register(chip->dw); dw_dma_acpi_controller_register(chip->dw); @@ -211,8 +101,7 @@ static int dw_remove(struct platform_device *pdev) dw_dma_acpi_controller_free(chip->dw); - if (pdev->dev.of_node) - of_dma_controller_free(pdev->dev.of_node); + dw_dma_of_controller_free(chip->dw); ret = data->remove(chip); if (ret) -- cgit v1.2.3-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b From fb9816f9d05f01330b27ddf5dfa93d0f848e3405 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Jul 2019 10:14:38 +0300 Subject: dmaengine: dmatest: Add support for completion polling With the polled parameter the DMA drivers can be tested if they can work correctly when no completion is requested (no DMA_PREP_INTERRUPT and no callback is provided). If polled mode is selected then use dma_sync_wait() to execute the test iteration instead of relying on the completion callback. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190731071438.24075-1-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul --- drivers/dma/dmatest.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 3d22ae8dca72..a2cadfa2e6d7 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -72,6 +72,10 @@ static bool norandom; module_param(norandom, bool, 0644); MODULE_PARM_DESC(norandom, "Disable random offset setup (default: random)"); +static bool polled; +module_param(polled, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts"); + static bool verbose; module_param(verbose, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)"); @@ -110,6 +114,7 @@ struct dmatest_params { bool norandom; int alignment; unsigned int transfer_size; + bool polled; }; /** @@ -651,7 +656,10 @@ static int dmatest_func(void *data) /* * src and dst buffers are freed by ourselves below */ - flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + if (params->polled) + flags = DMA_CTRL_ACK; + else + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; ktime = ktime_get(); while (!kthread_should_stop() @@ -780,8 +788,10 @@ static int dmatest_func(void *data) } done->done = false; - tx->callback = dmatest_callback; - tx->callback_param = done; + if (!params->polled) { + tx->callback = dmatest_callback; + tx->callback_param = done; + } cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { @@ -790,12 +800,22 @@ static int dmatest_func(void *data) msleep(100); goto error_unmap_continue; } - dma_async_issue_pending(chan); - wait_event_freezable_timeout(thread->done_wait, done->done, - msecs_to_jiffies(params->timeout)); + if (params->polled) { + status = dma_sync_wait(chan, cookie); + dmaengine_terminate_sync(chan); + if (status == DMA_COMPLETE) + done->done = true; + } else { + dma_async_issue_pending(chan); + + wait_event_freezable_timeout(thread->done_wait, + done->done, + msecs_to_jiffies(params->timeout)); - status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); + status = dma_async_is_tx_complete(chan, cookie, NULL, + NULL); + } if (!done->done) { result("test timed out", total_tests, src->off, dst->off, @@ -1065,6 +1085,7 @@ static void add_threaded_test(struct dmatest_info *info) params->norandom = norandom; params->alignment = alignment; params->transfer_size = transfer_size; + params->polled = polled; request_channels(info, DMA_MEMCPY); request_channels(info, DMA_MEMSET); -- cgit v1.2.3-59-g8ed1b From 09104bb1b5d4680444687839b1d155ed69e89248 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 21 Aug 2019 20:19:08 +0800 Subject: dmaengine: iop-adma: remove set but not used variable 'slots_per_op' Fixes gcc '-Wunused-but-set-variable' warning: drivers/dma/iop-adma.c: In function iop_adma_tx_submit: drivers/dma/iop-adma.c:367:6: warning: variable slots_per_op set but not used [-Wunused-but-set-variable] It is never used, so can be removed. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190821121908.7468-1-yuehaibing@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/iop-adma.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index c6c0143670d9..64a6e262d38f 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -364,13 +364,11 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx) struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan); struct iop_adma_desc_slot *grp_start, *old_chain_tail; int slot_cnt; - int slots_per_op; dma_cookie_t cookie; dma_addr_t next_dma; grp_start = sw_desc->group_head; slot_cnt = grp_start->slot_cnt; - slots_per_op = grp_start->slots_per_op; spin_lock_bh(&iop_chan->lock); cookie = dma_cookie_assign(tx); -- cgit v1.2.3-59-g8ed1b From 25af5afe77a8b4278103c4c4fe23fe8d6f095490 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 28 Aug 2019 13:40:15 -0500 Subject: dmanegine: ioat/dca: Use struct_size() helper One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct ioat_dca_priv { ... struct ioat_dca_slot req_slots[0]; }; Make use of the struct_size() helper instead of an open-coded version in order to avoid any potential type mistakes. So, replace the following form: sizeof(*ioatdca) + (sizeof(struct ioat_dca_slot) * slots) with: struct_size(ioatdca, req_slots, slots) This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Acked-by: Dave Jiang Link: https://lore.kernel.org/r/20190828184015.GA4273@embeddedor Signed-off-by: Vinod Koul --- drivers/dma/ioat/dca.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c index 70fd8454d002..be61c32a876f 100644 --- a/drivers/dma/ioat/dca.c +++ b/drivers/dma/ioat/dca.c @@ -286,8 +286,7 @@ struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) return NULL; dca = alloc_dca_provider(&ioat_dca_ops, - sizeof(*ioatdca) - + (sizeof(struct ioat_dca_slot) * slots)); + struct_size(ioatdca, req_slots, slots)); if (!dca) return NULL; -- cgit v1.2.3-59-g8ed1b From 402096cb5b7d9ae9c69b851f5ec6289d249a9ed5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Aug 2019 11:14:23 -0500 Subject: dmaengine: stm32-dma: Use struct_size() helper One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct stm32_dma_desc { ... struct stm32_dma_sg_req sg_req[]; }; Make use of the struct_size() helper instead of an open-coded version in order to avoid any potential type mistakes. So, replace the following function: static struct stm32_dma_desc *stm32_dma_alloc_desc(u32 num_sgs) { return kzalloc(sizeof(struct stm32_dma_desc) + sizeof(struct stm32_dma_sg_req) * num_sgs, GFP_NOWAIT); } with: kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT) This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20190830161423.GA3483@embeddedor Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index e4cbe38d1b83..5989b0893521 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -243,12 +243,6 @@ static void stm32_dma_write(struct stm32_dma_device *dmadev, u32 reg, u32 val) writel_relaxed(val, dmadev->base + reg); } -static struct stm32_dma_desc *stm32_dma_alloc_desc(u32 num_sgs) -{ - return kzalloc(sizeof(struct stm32_dma_desc) + - sizeof(struct stm32_dma_sg_req) * num_sgs, GFP_NOWAIT); -} - static int stm32_dma_get_width(struct stm32_dma_chan *chan, enum dma_slave_buswidth width) { @@ -853,7 +847,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( return NULL; } - desc = stm32_dma_alloc_desc(sg_len); + desc = kzalloc(struct_size(desc, sg_req, sg_len), GFP_NOWAIT); if (!desc) return NULL; @@ -954,7 +948,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( num_periods = buf_len / period_len; - desc = stm32_dma_alloc_desc(num_periods); + desc = kzalloc(struct_size(desc, sg_req, num_periods), GFP_NOWAIT); if (!desc) return NULL; @@ -989,7 +983,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( int i; num_sgs = DIV_ROUND_UP(len, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); - desc = stm32_dma_alloc_desc(num_sgs); + desc = kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT); if (!desc) return NULL; -- cgit v1.2.3-59-g8ed1b From d17d9ea9572796f13f4aa2fed6cfb9e7fdf44406 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 3 Sep 2019 22:06:57 -0700 Subject: dmaengine: iop-adma.c: fix printk format warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix printk format warning in iop-adma.c (seen on x86_64) by using %pad: ../drivers/dma/iop-adma.c:118:12: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 6 has type ‘dma_addr_t {aka long long unsigned int}’ [-Wformat=] Fixes: c211092313b9 ("dmaengine: driver for the iop32x, iop33x, and iop13xx raid engines") Signed-off-by: Randy Dunlap Acked-by: Dan Williams Link: https://lore.kernel.org/r/1803541f-98a6-7cce-b050-ff1e9a333ab2@infradead.org Signed-off-by: Vinod Koul --- drivers/dma/iop-adma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 64a6e262d38f..003b753e4604 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -116,9 +116,9 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) list_for_each_entry_safe(iter, _iter, &iop_chan->chain, chain_node) { pr_debug("\tcookie: %d slot: %d busy: %d " - "this_desc: %#x next_desc: %#x ack: %d\n", + "this_desc: %pad next_desc: %#x ack: %d\n", iter->async_tx.cookie, iter->idx, busy, - iter->async_tx.phys, iop_desc_get_next_desc(iter), + &iter->async_tx.phys, iop_desc_get_next_desc(iter), async_tx_test_ack(&iter->async_tx)); prefetch(_iter); prefetch(&_iter->async_tx); -- cgit v1.2.3-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b 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') 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-59-g8ed1b