From 9c71b9eb3cb25856e29f0486eae9ee1ba864ba51 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Jul 2019 10:16:44 +0200 Subject: [PATCH 01/55] 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 ++- include/linux/omap-dma.h | 2 -- include/linux/omap-dmaengine.h | 18 ------------------ 3 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 include/linux/omap-dmaengine.h 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); diff --git a/include/linux/omap-dma.h b/include/linux/omap-dma.h index 840ce551e773..ba3cfbb52312 100644 --- a/include/linux/omap-dma.h +++ b/include/linux/omap-dma.h @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LINUX_OMAP_DMA_H #define __LINUX_OMAP_DMA_H -#include - /* * Legacy OMAP DMA handling defines and functions * diff --git a/include/linux/omap-dmaengine.h b/include/linux/omap-dmaengine.h deleted file mode 100644 index b6e42f933c40..000000000000 --- a/include/linux/omap-dmaengine.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * OMAP DMA Engine support - */ -#ifndef __LINUX_OMAP_DMAENGINE_H -#define __LINUX_OMAP_DMAENGINE_H - -struct dma_chan; - -#if defined(CONFIG_DMA_OMAP) || (defined(CONFIG_DMA_OMAP_MODULE) && defined(MODULE)) -bool omap_dma_filter_fn(struct dma_chan *, void *); -#else -static inline bool omap_dma_filter_fn(struct dma_chan *c, void *d) -{ - return false; -} -#endif -#endif /* __LINUX_OMAP_DMAENGINE_H */ From d2bfe7b5d182dad54aedb9dcdb736e8816ead1c3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Jul 2019 10:16:45 +0200 Subject: [PATCH 02/55] 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 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 From 72503b25ee363827aafffc3e8d872e6a92a7e422 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 16 Jul 2019 19:15:18 +0200 Subject: [PATCH 03/55] 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(-) 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) From 156a599b0716ab3ee3869ff26119e3b5d46d91c8 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 5 Jul 2019 18:05:19 +0300 Subject: [PATCH 04/55] 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(-) 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; From f4c255f1a747497a21748619d909cadabcfa060e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 14 Jul 2019 17:55:04 -0400 Subject: [PATCH 05/55] 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(-) 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 = { From aac8670369dc017609b8e8870975641ad3143448 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:24:58 +0300 Subject: [PATCH 06/55] 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(-) 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; From 4689d35c765c696bdf0535486a990038b242a26b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:24:59 +0300 Subject: [PATCH 07/55] 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(-) 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 (c->desc && c->desc->vd.tx.cookie == cookie) { - struct omap_desc *d = c->desc; + if (!txstate) + goto out; + + 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; From e96b1f64ee2885acb8fb26325eb9743ad6c64696 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:26:53 +0300 Subject: [PATCH 08/55] 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(-) 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); From 097ffdc75259139ba157b7f924cfeb0d6b00559e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:26:54 +0300 Subject: [PATCH 09/55] 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(-) 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. From aa3c6ce4eab8fb0e967954be1ba1cad3b715f63b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 16 Jul 2019 11:26:55 +0300 Subject: [PATCH 10/55] 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(-) 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; From b37e3534ac4275c1f0d0e08d1b6f672f6cc740c3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 20 Jul 2019 11:26:05 +0200 Subject: [PATCH 11/55] dt-bindings: dmaengine: Add YAML schemas for the generic DMA bindings The DMA controllers and consumers have a bunch of generic properties that are needed in a device tree. Add a YAML schemas for those. Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20190720092607.31095-1-maxime.ripard@bootlin.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/dma-common.yaml | 45 +++++++ .../bindings/dma/dma-controller.yaml | 35 ++++++ .../devicetree/bindings/dma/dma-router.yaml | 50 ++++++++ Documentation/devicetree/bindings/dma/dma.txt | 114 +----------------- 4 files changed, 131 insertions(+), 113 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/dma-common.yaml create mode 100644 Documentation/devicetree/bindings/dma/dma-controller.yaml create mode 100644 Documentation/devicetree/bindings/dma/dma-router.yaml diff --git a/Documentation/devicetree/bindings/dma/dma-common.yaml b/Documentation/devicetree/bindings/dma/dma-common.yaml new file mode 100644 index 000000000000..0141af047820 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma-common.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/dma-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA Engine Generic Binding + +maintainers: + - Vinod Koul + +description: + Generic binding to provide a way for a driver using DMA Engine to + retrieve the DMA request or channel information that goes from a + hardware device to a DMA controller. + +select: false + +properties: + "#dma-cells": + minimum: 1 + # Should be enough + maximum: 255 + description: + Used to provide DMA controller specific information. + + dma-channel-masks: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Bitmask of available DMA channels in ascending order that are + not reserved by firmware and are available to the + kernel. i.e. first channel corresponds to LSB. + + dma-channels: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Number of DMA channels supported by the controller. + + dma-requests: + $ref: /schemas/types.yaml#definitions/uint32 + description: + Number of DMA request signals supported by the controller. + +required: + - "#dma-cells" diff --git a/Documentation/devicetree/bindings/dma/dma-controller.yaml b/Documentation/devicetree/bindings/dma/dma-controller.yaml new file mode 100644 index 000000000000..c39f6de76670 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma-controller.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/dma-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA Controller Generic Binding + +maintainers: + - Vinod Koul + +allOf: + - $ref: "dma-common.yaml#" + +# Everything else is described in the common file +properties: + $nodename: + pattern: "^dma-controller(@.*)?$" + +examples: + - | + dma: dma-controller@48000000 { + compatible = "ti,omap-sdma"; + reg = <0x48000000 0x1000>; + interrupts = <0 12 0x4 + 0 13 0x4 + 0 14 0x4 + 0 15 0x4>; + #dma-cells = <1>; + dma-channels = <32>; + dma-requests = <127>; + dma-channel-mask = <0xfffe>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/dma-router.yaml b/Documentation/devicetree/bindings/dma/dma-router.yaml new file mode 100644 index 000000000000..5b5f07393135 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/dma-router.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/dma-router.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA Router Generic Binding + +maintainers: + - Vinod Koul + +allOf: + - $ref: "dma-common.yaml#" + +description: + DMA routers are transparent IP blocks used to route DMA request + lines from devices to the DMA controller. Some SoCs (like TI DRA7x) + have more peripherals integrated with DMA requests than what the DMA + controller can handle directly. + +properties: + $nodename: + pattern: "^dma-router(@.*)?$" + + dma-masters: + $ref: /schemas/types.yaml#definitions/phandle-array + description: + Array of phandles to the DMA controllers the router can direct + the signal to. + + dma-requests: + description: + Number of incoming request lines the router can handle. + +required: + - "#dma-cells" + - dma-masters + +examples: + - | + sdma_xbar: dma-router@4a002b78 { + compatible = "ti,dra7-dma-crossbar"; + reg = <0x4a002b78 0xfc>; + #dma-cells = <1>; + dma-requests = <205>; + ti,dma-safe-map = <0>; + dma-masters = <&sdma>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/dma.txt b/Documentation/devicetree/bindings/dma/dma.txt index eeb4e4d1771e..90a67a016a48 100644 --- a/Documentation/devicetree/bindings/dma/dma.txt +++ b/Documentation/devicetree/bindings/dma/dma.txt @@ -1,113 +1 @@ -* Generic DMA Controller and DMA request bindings - -Generic binding to provide a way for a driver using DMA Engine to retrieve the -DMA request or channel information that goes from a hardware device to a DMA -controller. - - -* DMA controller - -Required property: -- #dma-cells: Must be at least 1. Used to provide DMA controller - specific information. See DMA client binding below for - more details. - -Optional properties: -- dma-channels: Number of DMA channels supported by the controller. -- dma-requests: Number of DMA request signals supported by the - controller. -- dma-channel-mask: Bitmask of available DMA channels in ascending order - that are not reserved by firmware and are available to - the kernel. i.e. first channel corresponds to LSB. - -Example: - - dma: dma@48000000 { - compatible = "ti,omap-sdma"; - reg = <0x48000000 0x1000>; - interrupts = <0 12 0x4 - 0 13 0x4 - 0 14 0x4 - 0 15 0x4>; - #dma-cells = <1>; - dma-channels = <32>; - dma-requests = <127>; - dma-channel-mask = <0xfffe> - }; - -* DMA router - -DMA routers are transparent IP blocks used to route DMA request lines from -devices to the DMA controller. Some SoCs (like TI DRA7x) have more peripherals -integrated with DMA requests than what the DMA controller can handle directly. - -Required property: -- dma-masters: phandle of the DMA controller or list of phandles for - the DMA controllers the router can direct the signal to. -- #dma-cells: Must be at least 1. Used to provide DMA router specific - information. See DMA client binding below for more - details. - -Optional properties: -- dma-requests: Number of incoming request lines the router can handle. -- In the node pointed by the dma-masters: - - dma-requests: The router driver might need to look for this in order - to configure the routing. - -Example: - sdma_xbar: dma-router@4a002b78 { - compatible = "ti,dra7-dma-crossbar"; - reg = <0x4a002b78 0xfc>; - #dma-cells = <1>; - dma-requests = <205>; - ti,dma-safe-map = <0>; - dma-masters = <&sdma>; - }; - -* DMA client - -Client drivers should specify the DMA property using a phandle to the controller -followed by DMA controller specific data. - -Required property: -- dmas: List of one or more DMA specifiers, each consisting of - - A phandle pointing to DMA controller node - - A number of integer cells, as determined by the - #dma-cells property in the node referenced by phandle - containing DMA controller specific information. This - typically contains a DMA request line number or a - channel number, but can contain any data that is - required for configuring a channel. -- dma-names: Contains one identifier string for each DMA specifier in - the dmas property. The specific strings that can be used - are defined in the binding of the DMA client device. - Multiple DMA specifiers can be used to represent - alternatives and in this case the dma-names for those - DMA specifiers must be identical (see examples). - -Examples: - -1. A device with one DMA read channel, one DMA write channel: - - i2c1: i2c@1 { - ... - dmas = <&dma 2 /* read channel */ - &dma 3>; /* write channel */ - dma-names = "rx", "tx"; - ... - }; - -2. A single read-write channel with three alternative DMA controllers: - - dmas = <&dma1 5 - &dma2 7 - &dma3 2>; - dma-names = "rx-tx", "rx-tx", "rx-tx"; - -3. A device with three channels, one of which has two alternatives: - - dmas = <&dma1 2 /* read channel */ - &dma1 3 /* write channel */ - &dma2 0 /* error read */ - &dma3 0>; /* alternative error read */ - dma-names = "rx", "tx", "error", "error"; +This file has been moved to dma-controller.yaml. From 545a29c811f6a07433c2725a94243f56ae28a81f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 20 Jul 2019 11:26:06 +0200 Subject: [PATCH 12/55] dt-bindings: dmaengine: Convert Allwinner A10 DMA to a schema The older Allwinner SoCs have a DMA controller supported in Linux, with a matching Device Tree binding. Now that we have the DT validation in place, let's convert the device tree bindings for that controller over to a YAML schemas. Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20190720092607.31095-2-maxime.ripard@bootlin.com Signed-off-by: Vinod Koul --- .../bindings/dma/allwinner,sun4i-a10-dma.yaml | 55 +++++++++++++++++++ .../devicetree/bindings/dma/sun4i-dma.txt | 45 --------------- 2 files changed, 55 insertions(+), 45 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml delete mode 100644 Documentation/devicetree/bindings/dma/sun4i-dma.txt diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml new file mode 100644 index 000000000000..15abc0f9429f --- /dev/null +++ b/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/allwinner,sun4i-a10-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A10 DMA Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + "#dma-cells": + const: 2 + description: + The first cell is either 0 or 1, the former to use the normal + DMA, 1 for dedicated DMA. The second cell is the request line + number. + + compatible: + const: allwinner,sun4i-a10-dma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - "#dma-cells" + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + dma: dma-controller@1c02000 { + compatible = "allwinner,sun4i-a10-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <27>; + clocks = <&ahb_gates 6>; + #dma-cells = <2>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/sun4i-dma.txt b/Documentation/devicetree/bindings/dma/sun4i-dma.txt deleted file mode 100644 index 8ad556aca70b..000000000000 --- a/Documentation/devicetree/bindings/dma/sun4i-dma.txt +++ /dev/null @@ -1,45 +0,0 @@ -Allwinner A10 DMA Controller - -This driver follows the generic DMA bindings defined in dma.txt. - -Required properties: - -- compatible: Must be "allwinner,sun4i-a10-dma" -- reg: Should contain the registers base address and length -- interrupts: Should contain a reference to the interrupt used by this device -- clocks: Should contain a reference to the parent AHB clock -- #dma-cells : Should be 2, first cell denoting normal or dedicated dma, - second cell holding the request line number. - -Example: - dma: dma-controller@1c02000 { - compatible = "allwinner,sun4i-a10-dma"; - reg = <0x01c02000 0x1000>; - interrupts = <27>; - clocks = <&ahb_gates 6>; - #dma-cells = <2>; - }; - -Clients: - -DMA clients connected to the Allwinner A10 DMA controller must use the -format described in the dma.txt file, using a three-cell specifier for -each channel: a phandle plus two integer cells. -The three cells in order are: - -1. A phandle pointing to the DMA controller. -2. Whether it is using normal (0) or dedicated (1) channels -3. The port ID as specified in the datasheet - -Example: - spi2: spi@1c17000 { - compatible = "allwinner,sun4i-a10-spi"; - reg = <0x01c17000 0x1000>; - interrupts = <0 12 4>; - clocks = <&ahb_gates 22>, <&spi2_clk>; - clock-names = "ahb", "mod"; - dmas = <&dma 1 29>, <&dma 1 28>; - dma-names = "rx", "tx"; - #address-cells = <1>; - #size-cells = <0>; - }; From edd14218bd663e4dd2f1c8f4eed84f92ada93c9d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 20 Jul 2019 11:26:07 +0200 Subject: [PATCH 13/55] dt-bindings: dmaengine: Convert Allwinner A31 and A64 DMA to a schema The newer Allwinner SoCs have a DMA controller supported in Linux, with a matching Device Tree binding. Now that we have the DT validation in place, let's convert the device tree bindings for that controller over to a YAML schemas. Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20190720092607.31095-3-maxime.ripard@bootlin.com Signed-off-by: Vinod Koul --- .../dma/allwinner,sun50i-a64-dma.yaml | 88 +++++++++++++++++++ .../bindings/dma/allwinner,sun6i-a31-dma.yaml | 62 +++++++++++++ .../devicetree/bindings/dma/sun6i-dma.txt | 81 ----------------- 3 files changed, 150 insertions(+), 81 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml create mode 100644 Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml delete mode 100644 Documentation/devicetree/bindings/dma/sun6i-dma.txt diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml new file mode 100644 index 000000000000..4cb9d6b93138 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/allwinner,sun50i-a64-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A64 DMA Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + "#dma-cells": + const: 1 + description: The cell is the request line number. + + compatible: + enum: + - allwinner,sun50i-a64-dma + - allwinner,sun50i-h6-dma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: bus + - const: mbus + + resets: + maxItems: 1 + +required: + - "#dma-cells" + - compatible + - reg + - interrupts + - clocks + - resets + - dma-channels + +if: + properties: + compatible: + const: allwinner,sun50i-h6-dma + +then: + properties: + clocks: + maxItems: 2 + + required: + - clock-names + +else: + properties: + clocks: + maxItems: 1 + +# FIXME: We should set it, but it would report all the generic +# properties as additional properties. +# additionalProperties: false + +examples: + - | + dma: dma-controller@1c02000 { + compatible = "allwinner,sun50i-a64-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <0 50 4>; + clocks = <&ccu 30>; + dma-channels = <8>; + dma-requests = <27>; + resets = <&ccu 7>; + #dma-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml new file mode 100644 index 000000000000..740b7f9b535b --- /dev/null +++ b/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/allwinner,sun6i-a31-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A31 DMA Controller Device Tree Bindings + +maintainers: + - Chen-Yu Tsai + - Maxime Ripard + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + "#dma-cells": + const: 1 + description: The cell is the request line number. + + compatible: + oneOf: + - const: allwinner,sun6i-a31-dma + - const: allwinner,sun8i-a23-dma + - const: allwinner,sun8i-a83t-dma + - const: allwinner,sun8i-h3-dma + - const: allwinner,sun8i-v3s-dma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - "#dma-cells" + - compatible + - reg + - interrupts + - clocks + - resets + +additionalProperties: false + +examples: + - | + dma: dma-controller@1c02000 { + compatible = "allwinner,sun6i-a31-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <0 50 4>; + clocks = <&ahb1_gates 6>; + resets = <&ahb1_rst 6>; + #dma-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/sun6i-dma.txt b/Documentation/devicetree/bindings/dma/sun6i-dma.txt deleted file mode 100644 index cae31f4e77ba..000000000000 --- a/Documentation/devicetree/bindings/dma/sun6i-dma.txt +++ /dev/null @@ -1,81 +0,0 @@ -Allwinner A31 DMA Controller - -This driver follows the generic DMA bindings defined in dma.txt. - -Required properties: - -- compatible: Must be one of - "allwinner,sun6i-a31-dma" - "allwinner,sun8i-a23-dma" - "allwinner,sun8i-a83t-dma" - "allwinner,sun8i-h3-dma" - "allwinner,sun8i-v3s-dma" -- reg: Should contain the registers base address and length -- interrupts: Should contain a reference to the interrupt used by this device -- clocks: Should contain a reference to the parent AHB clock -- resets: Should contain a reference to the reset controller asserting - this device in reset -- #dma-cells : Should be 1, a single cell holding a line request number - -Example: - dma: dma-controller@1c02000 { - compatible = "allwinner,sun6i-a31-dma"; - reg = <0x01c02000 0x1000>; - interrupts = <0 50 4>; - clocks = <&ahb1_gates 6>; - resets = <&ahb1_rst 6>; - #dma-cells = <1>; - }; - ------------------------------------------------------------------------------- -For A64 and H6 DMA controller: - -Required properties: -- compatible: Must be one of - "allwinner,sun50i-a64-dma" - "allwinner,sun50i-h6-dma" -- dma-channels: Number of DMA channels supported by the controller. - Refer to Documentation/devicetree/bindings/dma/dma.txt -- clocks: In addition to parent AHB clock, it should also contain mbus - clock (H6 only) -- clock-names: Should contain "bus" and "mbus" (H6 only) -- all properties above, i.e. reg, interrupts, clocks, resets and #dma-cells - -Optional properties: -- dma-requests: Number of DMA request signals supported by the controller. - Refer to Documentation/devicetree/bindings/dma/dma.txt - -Example: - dma: dma-controller@1c02000 { - compatible = "allwinner,sun50i-a64-dma"; - reg = <0x01c02000 0x1000>; - interrupts = ; - clocks = <&ccu CLK_BUS_DMA>; - dma-channels = <8>; - dma-requests = <27>; - resets = <&ccu RST_BUS_DMA>; - #dma-cells = <1>; - }; ------------------------------------------------------------------------------- - -Clients: - -DMA clients connected to the A31 DMA controller must use the format -described in the dma.txt file, using a two-cell specifier for each -channel: a phandle plus one integer cells. -The two cells in order are: - -1. A phandle pointing to the DMA controller. -2. The port ID as specified in the datasheet - -Example: -spi2: spi@1c6a000 { - compatible = "allwinner,sun6i-a31-spi"; - reg = <0x01c6a000 0x1000>; - interrupts = <0 67 4>; - clocks = <&ahb1_gates 22>, <&spi2_clk>; - clock-names = "ahb", "mod"; - dmas = <&dma 25>, <&dma 25>; - dma-names = "rx", "tx"; - resets = <&ahb1_rst 22>; -}; From ffbb569b9cee1fa0277a48d7925dbed1356dbb32 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 24 Jul 2019 13:49:46 +0200 Subject: [PATCH 14/55] dt-bindings: dmaengine: shdma: Rename bindings documentation file Rename the bindings documentation file for shdma from shdma.txt to renesas,shdma.txt. This is part of an ongoing effort to name bindings documentation files for Renesas IP blocks consistently, in line with the compat strings they document. Signed-off-by: Simon Horman Link: https://lore.kernel.org/r/20190724114946.14021-1-horms+renesas@verge.net.au [vkoul: add subsystem name] Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/{shdma.txt => renesas,shdma.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/dma/{shdma.txt => renesas,shdma.txt} (100%) diff --git a/Documentation/devicetree/bindings/dma/shdma.txt b/Documentation/devicetree/bindings/dma/renesas,shdma.txt similarity index 100% rename from Documentation/devicetree/bindings/dma/shdma.txt rename to Documentation/devicetree/bindings/dma/renesas,shdma.txt From 2cb114c4fac7a9c3e8fd8c39ceac1e6ca030b412 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2019 22:07:56 +0300 Subject: [PATCH 15/55] 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(-) 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; From 57dbd0e4b97d3bc9f257159a8853badff2dfb0d1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2019 22:07:57 +0300 Subject: [PATCH 16/55] 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(-) 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; From a9afc9ea93995021f29025e62d83415a45c5f58b Mon Sep 17 00:00:00 2001 From: Jonathan Hunter Date: Wed, 31 Jul 2019 11:16:39 +0100 Subject: [PATCH 17/55] 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(-) 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) From 7f5d7425748d1cc2dadb6966ec84363d3342b5a1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 29 Jul 2019 17:52:21 -0500 Subject: [PATCH 18/55] 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(+) 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)); From e17be6e1b713f188728a23ebfba15546a025c109 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Jul 2019 11:15:10 -0700 Subject: [PATCH 19/55] 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(-) 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; } From 9603a7ab60989f586786f082a8b1e3bf6fbcc749 Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 15 Jul 2019 11:17:16 +0800 Subject: [PATCH 20/55] 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(-) 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)); From 719e25dba4430a7f2b1e77fa962f0527ebc9371d Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 15 Jul 2019 11:17:23 +0800 Subject: [PATCH 21/55] 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(-) 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 */ From 232a7f18cf8ecbd92a8cc6ca7feee4f6aab668fe Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Wed, 24 Jul 2019 15:20:34 +0800 Subject: [PATCH 22/55] 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(-) 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]; From 057b05d5ac4745e7999656223bc6426c0129ba86 Mon Sep 17 00:00:00 2001 From: Nishka Dasgupta Date: Wed, 24 Jul 2019 13:46:09 +0530 Subject: [PATCH 23/55] 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(-) 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; From d1b622f68daf6c9f1abed360428e5a8f22063f99 Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Fri, 26 Jul 2019 18:59:47 +0800 Subject: [PATCH 24/55] 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(-) 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 */ From ba1cab79cfc629f7238a26e040545ca394cd695f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 31 Jul 2019 10:36:59 -0700 Subject: [PATCH 25/55] 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(+) 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; From 069e4a19f44d82c43d6a3866499f3d4da6ab3dec Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Aug 2019 12:11:43 +0200 Subject: [PATCH 26/55] 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(-) 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) { From 7607a121f4617840fe645c65f090af6403738031 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 11 Aug 2019 19:22:00 -0500 Subject: [PATCH 27/55] 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(+) 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; From 14c2a7b934e43527e38adc40cb9466811baaf8a9 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 19 Aug 2019 15:52:44 +0200 Subject: [PATCH 28/55] dt-bindings: dmaengine: nbpfaxi: Rename bindings documentation file Rename the device tree bindings for renesas "Type-AXI" NBPFAXI* DMA controllers from nbpfaxi.txt to renesas,nbpfaxi.txt. This is part of an ongoing effort to name bindings documentation files for Renesas IP blocks consistently, in line with the compat strings they document. Signed-off-by: Simon Horman Link: https://lore.kernel.org/r/20190819135244.18183-1-horms+renesas@verge.net.au Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/{nbpfaxi.txt => renesas,nbpfaxi.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/dma/{nbpfaxi.txt => renesas,nbpfaxi.txt} (100%) diff --git a/Documentation/devicetree/bindings/dma/nbpfaxi.txt b/Documentation/devicetree/bindings/dma/renesas,nbpfaxi.txt similarity index 100% rename from Documentation/devicetree/bindings/dma/nbpfaxi.txt rename to Documentation/devicetree/bindings/dma/renesas,nbpfaxi.txt From b48b8bc45a8fe4bc1d1369f0e2eb98b15a4b6c56 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 13 Aug 2019 11:06:02 +0300 Subject: [PATCH 29/55] 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(-) 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 }, From 3a1144f83c531dea36bad013b04888fd6e69aa0b Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Tue, 13 Aug 2019 09:00:04 +0300 Subject: [PATCH 30/55] MAINTAINERS: dmaengine: dw axi dmac: Fix typo in a path Fix typo (s/dwi-/dw-/) in the directory path. Fixes: 1fe20f1b8454 ("dmaengine: Introduce DW AXI DMAC driver") Signed-off-by: Denis Efremov Link: https://lore.kernel.org/r/20190813060004.10594-1-efremov@linux.com Signed-off-by: Vinod Koul --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 783569e3c4b4..ddb88afc2fdb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15488,7 +15488,7 @@ F: Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt SYNOPSYS DESIGNWARE AXI DMAC DRIVER M: Eugeniy Paltsev S: Maintained -F: drivers/dma/dwi-axi-dmac/ +F: drivers/dma/dw-axi-dmac/ F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt SYNOPSYS DESIGNWARE DMAC DRIVER From 698f7a9be9b2389384c69750d87a0c68202c0621 Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Tue, 13 Aug 2019 10:34:48 -0700 Subject: [PATCH 31/55] 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(-) 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); } From 4f48e29f7673726a8c1a18b10906ccd58a031b95 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 14 Aug 2019 15:21:04 +0800 Subject: [PATCH 32/55] 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(-) 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; From d071fd294f2474118629f4021a6a3dedef28e09f Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 14 Aug 2019 15:21:05 +0800 Subject: [PATCH 33/55] 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(-) 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; From a6bc332373e5176c2d085657bc643a28950b20b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:37 +0300 Subject: [PATCH 34/55] 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(+) 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; From 4b8584bac0407367f8157244c8952ed80bdb12fb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:38 +0300 Subject: [PATCH 35/55] 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(-) 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 From ae923c91aa3b4f7e20b764744188c0d859243d81 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:39 +0300 Subject: [PATCH 36/55] 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(-) 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 }, { } }; From b3757413b91ecf4a227c5f075446afe8126d882f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:40 +0300 Subject: [PATCH 37/55] 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(-) 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); From f8d9ddbc28518a0f7d39d2ce51f778759b49f73e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:41 +0300 Subject: [PATCH 38/55] 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(-) 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); From a9c56721d6ae99b22e983d0722e6b1b53a11dd59 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:42 +0300 Subject: [PATCH 39/55] 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(-) 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); From e7b8514e4d68bec21fc6385fa0a66797ddc34ac9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:43 +0300 Subject: [PATCH 40/55] 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(-) 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); From 84da042e702347c186b84d9cc2e766f83e1814d6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:44 +0300 Subject: [PATCH 41/55] 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(-) 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); From b685fe26e9af7318d73bf50af659a282d188a3e5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:45 +0300 Subject: [PATCH 42/55] 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 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) From f5e84eae7956c694d27ddaba7113fe7d1174eff7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:46 +0300 Subject: [PATCH 43/55] 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 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) From e3b9fef8ddf8a5a31a16c4959202f5d88e07e080 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Jul 2019 16:20:06 +0300 Subject: [PATCH 44/55] 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(-) 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 From 7a09c09c300761f2a0f34cfecebe327883de5864 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Jul 2019 16:20:15 +0300 Subject: [PATCH 45/55] 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(-) 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: From 9fa2df6eafa024e9f10ff60518ab62abe1c6cfb6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 30 Jul 2019 16:20:29 +0300 Subject: [PATCH 46/55] 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(-) 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); From fb9816f9d05f01330b27ddf5dfa93d0f848e3405 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Jul 2019 10:14:38 +0300 Subject: [PATCH 47/55] 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(-) 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); - status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); + wait_event_freezable_timeout(thread->done_wait, + done->done, + msecs_to_jiffies(params->timeout)); + + 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); From 09104bb1b5d4680444687839b1d155ed69e89248 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 21 Aug 2019 20:19:08 +0800 Subject: [PATCH 48/55] 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(-) 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); From 25af5afe77a8b4278103c4c4fe23fe8d6f095490 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 28 Aug 2019 13:40:15 -0500 Subject: [PATCH 49/55] 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(-) 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; From 37256335bd065e200c7e42cfd27b26b688606466 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 28 Aug 2019 19:30:23 +0900 Subject: [PATCH 50/55] dt-bindings: dmaengine: dma-common: Fix the dma-channel-mask property The commit b37e3534ac42 ("dt-bindings: dmaengine: Add YAML schemas for the generic DMA bindings") changed the property from dma-channel-mask to dma-channel-masks. So, this patch fixes it. Fixes: b37e3534ac42 ("dt-bindings: dmaengine: Add YAML schemas for the generic DMA bindings") Signed-off-by: Yoshihiro Shimoda Reviewed-by: Geert Uytterhoeven Acked-by: Rob Herring Link: https://lore.kernel.org/r/1566988223-14657-1-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/dma-common.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/dma-common.yaml b/Documentation/devicetree/bindings/dma/dma-common.yaml index 0141af047820..ed0a49a6f020 100644 --- a/Documentation/devicetree/bindings/dma/dma-common.yaml +++ b/Documentation/devicetree/bindings/dma/dma-common.yaml @@ -24,7 +24,7 @@ properties: description: Used to provide DMA controller specific information. - dma-channel-masks: + dma-channel-mask: $ref: /schemas/types.yaml#definitions/uint32 description: Bitmask of available DMA channels in ascending order that are From 402096cb5b7d9ae9c69b851f5ec6289d249a9ed5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Aug 2019 11:14:23 -0500 Subject: [PATCH 51/55] 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(-) 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; From d17d9ea9572796f13f4aa2fed6cfb9e7fdf44406 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 3 Sep 2019 22:06:57 -0700 Subject: [PATCH 52/55] 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(-) 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); From c5dbe60664b3660f5ac5854e21273ea2e7ff698f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:14 +0300 Subject: [PATCH 53/55] 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(-) 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) { From b2003f61a554ff402509c6061aa5e3f6ef92f12a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:15 +0300 Subject: [PATCH 54/55] 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(-) 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 */ From c5c6faaee6e0c374c7dfaf053aa23750f5a68e20 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:16 +0300 Subject: [PATCH 55/55] 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(-) 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]); } }