* [v2,05/13] mtd: rawnand: marvell: remove the dmaengine compat need
From: Robert Jarzmik @ 2018-05-24 7:06 UTC (permalink / raw)
To: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Ezequiel Garcia,
Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
Richard Weinberger, Liam Girdwood, Mark Brown, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-ide, dmaengine, linux-media,
linux-mmc, linux-mtd, netdev, alsa-devel
As the pxa architecture switched towards the dmaengine slave map, the
old compatibility mechanism to acquire the dma requestor line number and
priority are not needed anymore.
This patch simplifies the dma resource acquisition, using the more
generic function dma_request_slave_channel().
Signed-off-by: Signed-off-by: Daniel Mack <daniel@zonque.org>
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
drivers/mtd/nand/raw/marvell_nand.c | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index 10e953218948..f9763be078ef 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2613,8 +2613,6 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
dev);
struct dma_slave_config config = {};
struct resource *r;
- dma_cap_mask_t mask;
- struct pxad_param param;
int ret;
if (!IS_ENABLED(CONFIG_PXA_DMA)) {
@@ -2627,20 +2625,7 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
if (ret)
return ret;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r) {
- dev_err(nfc->dev, "No resource defined for data DMA\n");
- return -ENXIO;
- }
-
- param.drcmr = r->start;
- param.prio = PXAD_PRIO_LOWEST;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- nfc->dma_chan =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶m, nfc->dev,
- "data");
+ nfc->dma_chan = dma_request_slave_channel(&nfc->dev, "data");
if (!nfc->dma_chan) {
dev_err(nfc->dev,
"Unable to request data DMA channel\n");
^ permalink raw reply related
* [v2,04/13] media: pxa_camera: remove the dmaengine compat need
From: Robert Jarzmik @ 2018-05-24 7:06 UTC (permalink / raw)
To: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Ezequiel Garcia,
Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
Richard Weinberger, Liam Girdwood, Mark Brown, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-ide, dmaengine, linux-media,
linux-mmc, linux-mtd, netdev, alsa-devel
As the pxa architecture switched towards the dmaengine slave map, the
old compatibility mechanism to acquire the dma requestor line number and
priority are not needed anymore.
This patch simplifies the dma resource acquisition, using the more
generic function dma_request_slave_channel().
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
drivers/media/platform/pxa_camera.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index c71a00736541..4c82d1880753 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -2357,8 +2357,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
.src_maxburst = 8,
.direction = DMA_DEV_TO_MEM,
};
- dma_cap_mask_t mask;
- struct pxad_param params;
char clk_name[V4L2_CLK_NAME_SIZE];
int irq;
int err = 0, i;
@@ -2432,34 +2430,20 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->base = base;
/* request dma */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- dma_cap_set(DMA_PRIVATE, mask);
-
- params.prio = 0;
- params.drcmr = 68;
- pcdev->dma_chans[0] =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶ms, &pdev->dev, "CI_Y");
+ pcdev->dma_chans[0] = dma_request_slave_channel(&pdev->dev, "CI_Y");
if (!pcdev->dma_chans[0]) {
dev_err(&pdev->dev, "Can't request DMA for Y\n");
return -ENODEV;
}
- params.drcmr = 69;
- pcdev->dma_chans[1] =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶ms, &pdev->dev, "CI_U");
+ pcdev->dma_chans[1] = dma_request_slave_channel(&pdev->dev, "CI_U");
if (!pcdev->dma_chans[1]) {
dev_err(&pdev->dev, "Can't request DMA for Y\n");
err = -ENODEV;
goto exit_free_dma_y;
}
- params.drcmr = 70;
- pcdev->dma_chans[2] =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶ms, &pdev->dev, "CI_V");
+ pcdev->dma_chans[2] = dma_request_slave_channel(&pdev->dev, "CI_V");
if (!pcdev->dma_chans[2]) {
dev_err(&pdev->dev, "Can't request DMA for V\n");
err = -ENODEV;
^ permalink raw reply related
* [v2,03/13] mmc: pxamci: remove the dmaengine compat need
From: Robert Jarzmik @ 2018-05-24 7:06 UTC (permalink / raw)
To: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Ezequiel Garcia,
Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
Richard Weinberger, Liam Girdwood, Mark Brown, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-ide, dmaengine, linux-media,
linux-mmc, linux-mtd, netdev, alsa-devel
As the pxa architecture switched towards the dmaengine slave map, the
old compatibility mechanism to acquire the dma requestor line number and
priority are not needed anymore.
This patch simplifies the dma resource acquisition, using the more
generic function dma_request_slave_channel().
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
drivers/mmc/host/pxamci.c | 29 +++--------------------------
1 file changed, 3 insertions(+), 26 deletions(-)
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index c763b404510f..6c94474e36f4 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mmc/host.h>
@@ -637,10 +636,8 @@ static int pxamci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct pxamci_host *host = NULL;
- struct resource *r, *dmarx, *dmatx;
- struct pxad_param param_rx, param_tx;
+ struct resource *r;
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
- dma_cap_mask_t mask;
ret = pxamci_of_init(pdev);
if (ret)
@@ -739,34 +736,14 @@ static int pxamci_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mmc);
- if (!pdev->dev.of_node) {
- dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmarx || !dmatx) {
- ret = -ENXIO;
- goto out;
- }
- param_rx.prio = PXAD_PRIO_LOWEST;
- param_rx.drcmr = dmarx->start;
- param_tx.prio = PXAD_PRIO_LOWEST;
- param_tx.drcmr = dmatx->start;
- }
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->dma_chan_rx =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶m_rx, &pdev->dev, "rx");
+ host->dma_chan_rx = dma_request_slave_channel(&pdev->dev, "rx");
if (host->dma_chan_rx == NULL) {
dev_err(&pdev->dev, "unable to request rx dma channel\n");
ret = -ENODEV;
goto out;
}
- host->dma_chan_tx =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶m_tx, &pdev->dev, "tx");
+ host->dma_chan_tx = dma_request_slave_channel(&pdev->dev, "tx");
if (host->dma_chan_tx == NULL) {
dev_err(&pdev->dev, "unable to request tx dma channel\n");
ret = -ENODEV;
^ permalink raw reply related
* [v2,02/13] ARM: pxa: add dma slave map
From: Robert Jarzmik @ 2018-05-24 7:06 UTC (permalink / raw)
To: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Ezequiel Garcia,
Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
Richard Weinberger, Liam Girdwood, Mark Brown, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-ide, dmaengine, linux-media,
linux-mmc, linux-mtd, netdev, alsa-devel
In order to remove the specific knowledge of the dma mapping from PXA
drivers, add a default slave map for pxa architectures.
This is the first step, and once all drivers are converted,
pxad_filter_fn() will be made static, and the DMA resources removed from
device.c.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Reported-by: Arnd Bergmann <arnd@arndb.de>
---
Since v1: revamped the SSP part, split into pxa25.c, pxa27x.c and
pxa3xx.c, and add pxa-i2s.
---
arch/arm/mach-pxa/devices.c | 12 +++---------
arch/arm/mach-pxa/devices.h | 6 +++++-
arch/arm/mach-pxa/pxa25x.c | 41 ++++++++++++++++++++++++++++++++++++++++-
arch/arm/mach-pxa/pxa27x.c | 42 +++++++++++++++++++++++++++++++++++++++++-
arch/arm/mach-pxa/pxa3xx.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 132 insertions(+), 13 deletions(-)
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index d7c9a8476d57..1e8915fc340d 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -4,6 +4,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/platform_data/i2c-pxa.h>
@@ -1202,11 +1203,6 @@ void __init pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info)
platform_device_add(pd);
}
-static struct mmp_dma_platdata pxa_dma_pdata = {
- .dma_channels = 0,
- .nb_requestors = 0,
-};
-
static struct resource pxa_dma_resource[] = {
[0] = {
.start = 0x40000000,
@@ -1233,9 +1229,7 @@ static struct platform_device pxa2xx_pxa_dma = {
.resource = pxa_dma_resource,
};
-void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors)
+void __init pxa2xx_set_dmac_info(struct mmp_dma_platdata *dma_pdata)
{
- pxa_dma_pdata.dma_channels = nb_channels;
- pxa_dma_pdata.nb_requestors = nb_requestors;
- pxa_register_device(&pxa2xx_pxa_dma, &pxa_dma_pdata);
+ pxa_register_device(&pxa2xx_pxa_dma, dma_pdata);
}
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
index 11263f7c455b..498b07bc6a3e 100644
--- a/arch/arm/mach-pxa/devices.h
+++ b/arch/arm/mach-pxa/devices.h
@@ -1,4 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#define PDMA_FILTER_PARAM(_prio, _requestor) (&(struct pxad_param) { \
+ .prio = PXAD_PRIO_##_prio, .drcmr = _requestor })
+struct mmp_dma_platdata;
+
extern struct platform_device pxa_device_pmu;
extern struct platform_device pxa_device_mci;
extern struct platform_device pxa3xx_device_mci2;
@@ -55,7 +59,7 @@ extern struct platform_device pxa3xx_device_gpio;
extern struct platform_device pxa93x_device_gpio;
void __init pxa_register_device(struct platform_device *dev, void *data);
-void __init pxa2xx_set_dmac_info(int nb_channels, int nb_requestors);
+void __init pxa2xx_set_dmac_info(struct mmp_dma_platdata *dma_pdata);
struct i2c_pxa_platform_data;
extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index ba431fad5c47..2d61de41a9d5 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -16,6 +16,8 @@
* initialization stuff for PXA machines which can be overridden later if
* need be.
*/
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/module.h>
@@ -26,6 +28,7 @@
#include <linux/syscore_ops.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
+#include <linux/platform_data/mmp_dma.h>
#include <asm/mach/map.h>
#include <asm/suspend.h>
@@ -201,6 +204,42 @@ static struct platform_device *pxa25x_devices[] __initdata = {
&pxa_device_asoc_platform,
};
+static const struct dma_slave_map pxa25x_slave_map[] = {
+ /* PXA25x, PXA27x and PXA3xx common entries */
+ { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
+ { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
+ { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
+ PDMA_FILTER_PARAM(LOWEST, 10) },
+ { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
+ { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
+ { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+ { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+ { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+ { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+ { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
+ { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
+ { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
+ { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
+ { "smc911x.0", "rx", PDMA_FILTER_PARAM(LOWEST, -1) },
+ { "smc911x.0", "tx", PDMA_FILTER_PARAM(LOWEST, -1) },
+ { "smc91x.0", "data", PDMA_FILTER_PARAM(LOWEST, -1) },
+
+ /* PXA25x specific map */
+ { "pxa25x-ssp.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+ { "pxa25x-ssp.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+ { "pxa25x-nssp.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+ { "pxa25x-nssp.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+ { "pxa25x-nssp.2", "rx", PDMA_FILTER_PARAM(LOWEST, 23) },
+ { "pxa25x-nssp.2", "tx", PDMA_FILTER_PARAM(LOWEST, 24) },
+};
+
+static struct mmp_dma_platdata pxa25x_dma_pdata = {
+ .dma_channels = 16,
+ .nb_requestors = 40,
+ .slave_map = pxa25x_slave_map,
+ .slave_map_cnt = ARRAY_SIZE(pxa25x_slave_map),
+};
+
static int __init pxa25x_init(void)
{
int ret = 0;
@@ -215,7 +254,7 @@ static int __init pxa25x_init(void)
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
if (!of_have_populated_dt()) {
- pxa2xx_set_dmac_info(16, 40);
+ pxa2xx_set_dmac_info(&pxa25x_dma_pdata);
pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
ret = platform_add_devices(pxa25x_devices,
ARRAY_SIZE(pxa25x_devices));
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 0c06f383ad52..b44e3c4f3013 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -11,6 +11,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/module.h>
@@ -23,6 +25,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/platform_data/i2c-pxa.h>
+#include <linux/platform_data/mmp_dma.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
@@ -297,6 +300,43 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_pwm1,
};
+static const struct dma_slave_map pxa27x_slave_map[] = {
+ /* PXA25x, PXA27x and PXA3xx common entries */
+ { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
+ { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
+ { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
+ PDMA_FILTER_PARAM(LOWEST, 10) },
+ { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
+ { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
+ { "pxa-ssp-dai.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+ { "pxa-ssp-dai.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+ { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+ { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+ { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
+ { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
+ { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
+ { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
+ { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 66) },
+ { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 67) },
+ { "smc911x.0", "rx", PDMA_FILTER_PARAM(LOWEST, -1) },
+ { "smc911x.0", "tx", PDMA_FILTER_PARAM(LOWEST, -1) },
+ { "smc91x.0", "data", PDMA_FILTER_PARAM(LOWEST, -1) },
+
+ /* PXA27x specific map */
+ { "pxa2xx-i2s", "rx", PDMA_FILTER_PARAM(LOWEST, 2) },
+ { "pxa2xx-i2s", "tx", PDMA_FILTER_PARAM(LOWEST, 3) },
+ { "pxa27x-camera.0", "CI_Y", PDMA_FILTER_PARAM(HIGHEST, 68) },
+ { "pxa27x-camera.0", "CI_U", PDMA_FILTER_PARAM(HIGHEST, 69) },
+ { "pxa27x-camera.0", "CI_V", PDMA_FILTER_PARAM(HIGHEST, 70) },
+};
+
+static struct mmp_dma_platdata pxa27x_dma_pdata = {
+ .dma_channels = 32,
+ .nb_requestors = 75,
+ .slave_map = pxa27x_slave_map,
+ .slave_map_cnt = ARRAY_SIZE(pxa27x_slave_map),
+};
+
static int __init pxa27x_init(void)
{
int ret = 0;
@@ -313,7 +353,7 @@ static int __init pxa27x_init(void)
if (!of_have_populated_dt()) {
pxa_register_device(&pxa27x_device_gpio,
&pxa27x_gpio_info);
- pxa2xx_set_dmac_info(32, 75);
+ pxa2xx_set_dmac_info(&pxa27x_dma_pdata);
ret = platform_add_devices(devices,
ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 4b8a0df8ea57..b5ca4be093ec 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -12,6 +12,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -24,6 +26,7 @@
#include <linux/of.h>
#include <linux/syscore_ops.h>
#include <linux/platform_data/i2c-pxa.h>
+#include <linux/platform_data/mmp_dma.h>
#include <asm/mach/map.h>
#include <asm/suspend.h>
@@ -421,6 +424,45 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_pwm1,
};
+static const struct dma_slave_map pxa3xx_slave_map[] = {
+ /* PXA25x, PXA27x and PXA3xx common entries */
+ { "pxa2xx-ac97", "pcm_pcm_mic_mono", PDMA_FILTER_PARAM(LOWEST, 8) },
+ { "pxa2xx-ac97", "pcm_pcm_aux_mono_in", PDMA_FILTER_PARAM(LOWEST, 9) },
+ { "pxa2xx-ac97", "pcm_pcm_aux_mono_out",
+ PDMA_FILTER_PARAM(LOWEST, 10) },
+ { "pxa2xx-ac97", "pcm_pcm_stereo_in", PDMA_FILTER_PARAM(LOWEST, 11) },
+ { "pxa2xx-ac97", "pcm_pcm_stereo_out", PDMA_FILTER_PARAM(LOWEST, 12) },
+ { "pxa-ssp-dai.0", "rx", PDMA_FILTER_PARAM(LOWEST, 13) },
+ { "pxa-ssp-dai.0", "tx", PDMA_FILTER_PARAM(LOWEST, 14) },
+ { "pxa-ssp-dai.1", "rx", PDMA_FILTER_PARAM(LOWEST, 15) },
+ { "pxa-ssp-dai.1", "tx", PDMA_FILTER_PARAM(LOWEST, 16) },
+ { "pxa2xx-ir", "rx", PDMA_FILTER_PARAM(LOWEST, 17) },
+ { "pxa2xx-ir", "tx", PDMA_FILTER_PARAM(LOWEST, 18) },
+ { "pxa2xx-mci.0", "rx", PDMA_FILTER_PARAM(LOWEST, 21) },
+ { "pxa2xx-mci.0", "tx", PDMA_FILTER_PARAM(LOWEST, 22) },
+ { "pxa-ssp-dai.2", "rx", PDMA_FILTER_PARAM(LOWEST, 66) },
+ { "pxa-ssp-dai.2", "tx", PDMA_FILTER_PARAM(LOWEST, 67) },
+ { "smc911x.0", "rx", PDMA_FILTER_PARAM(LOWEST, -1) },
+ { "smc911x.0", "tx", PDMA_FILTER_PARAM(LOWEST, -1) },
+ { "smc91x.0", "data", PDMA_FILTER_PARAM(LOWEST, -1) },
+
+ /* PXA3xx specific map */
+ { "pxa-ssp-dai.3", "rx", PDMA_FILTER_PARAM(LOWEST, 2) },
+ { "pxa-ssp-dai.3", "tx", PDMA_FILTER_PARAM(LOWEST, 3) },
+ { "pxa2xx-mci.1", "rx", PDMA_FILTER_PARAM(LOWEST, 93) },
+ { "pxa2xx-mci.1", "tx", PDMA_FILTER_PARAM(LOWEST, 94) },
+ { "pxa3xx-nand", "data", PDMA_FILTER_PARAM(LOWEST, 97) },
+ { "pxa2xx-mci.2", "rx", PDMA_FILTER_PARAM(LOWEST, 100) },
+ { "pxa2xx-mci.2", "tx", PDMA_FILTER_PARAM(LOWEST, 101) },
+};
+
+static struct mmp_dma_platdata pxa3xx_dma_pdata = {
+ .dma_channels = 32,
+ .nb_requestors = 100,
+ .slave_map = pxa3xx_slave_map,
+ .slave_map_cnt = ARRAY_SIZE(pxa3xx_slave_map),
+};
+
static int __init pxa3xx_init(void)
{
int ret = 0;
@@ -452,7 +494,7 @@ static int __init pxa3xx_init(void)
if (of_have_populated_dt())
return 0;
- pxa2xx_set_dmac_info(32, 100);
+ pxa2xx_set_dmac_info(&pxa3xx_dma_pdata);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
if (ret)
return ret;
^ permalink raw reply related
* [v2,01/13] dmaengine: pxa: use a dma slave map
From: Robert Jarzmik @ 2018-05-24 7:06 UTC (permalink / raw)
To: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Ezequiel Garcia,
Boris Brezillon, David Woodhouse, Brian Norris, Marek Vasut,
Richard Weinberger, Liam Girdwood, Mark Brown, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-ide, dmaengine, linux-media,
linux-mmc, linux-mtd, netdev, alsa-devel
In order to remove the specific knowledge of the dma mapping from PXA
drivers, add a default slave map for pxa architectures.
This won't impact MMP architecture, but is aimed only at all PXA boards.
This is the first step, and once all drivers are converted,
pxad_filter_fn() will be made static, and the DMA resources removed from
device.c.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Reported-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Vinod Koul <vkoul@kernel.org>
---
drivers/dma/pxa_dma.c | 10 +++++++++-
include/linux/platform_data/mmp_dma.h | 4 ++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index b53fb618bbf6..9505334f9c6e 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -179,6 +179,8 @@ static unsigned int pxad_drcmr(unsigned int line)
return 0x1000 + line * 4;
}
+bool pxad_filter_fn(struct dma_chan *chan, void *param);
+
/*
* Debug fs
*/
@@ -1396,9 +1398,10 @@ static int pxad_probe(struct platform_device *op)
{
struct pxad_device *pdev;
const struct of_device_id *of_id;
+ const struct dma_slave_map *slave_map = NULL;
struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
struct resource *iores;
- int ret, dma_channels = 0, nb_requestors = 0;
+ int ret, dma_channels = 0, nb_requestors = 0, slave_map_cnt = 0;
const enum dma_slave_buswidth widths =
DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES |
DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1429,6 +1432,8 @@ static int pxad_probe(struct platform_device *op)
} else if (pdata && pdata->dma_channels) {
dma_channels = pdata->dma_channels;
nb_requestors = pdata->nb_requestors;
+ slave_map = pdata->slave_map;
+ slave_map_cnt = pdata->slave_map_cnt;
} else {
dma_channels = 32; /* default 32 channel */
}
@@ -1440,6 +1445,9 @@ static int pxad_probe(struct platform_device *op)
pdev->slave.device_prep_dma_memcpy = pxad_prep_memcpy;
pdev->slave.device_prep_slave_sg = pxad_prep_slave_sg;
pdev->slave.device_prep_dma_cyclic = pxad_prep_dma_cyclic;
+ pdev->slave.filter.map = slave_map;
+ pdev->slave.filter.mapcnt = slave_map_cnt;
+ pdev->slave.filter.fn = pxad_filter_fn;
pdev->slave.copy_align = PDMA_ALIGNMENT;
pdev->slave.src_addr_widths = widths;
diff --git a/include/linux/platform_data/mmp_dma.h b/include/linux/platform_data/mmp_dma.h
index d1397c8ed94e..6397b9c8149a 100644
--- a/include/linux/platform_data/mmp_dma.h
+++ b/include/linux/platform_data/mmp_dma.h
@@ -12,9 +12,13 @@
#ifndef MMP_DMA_H
#define MMP_DMA_H
+struct dma_slave_map;
+
struct mmp_dma_platdata {
int dma_channels;
int nb_requestors;
+ int slave_map_cnt;
+ const struct dma_slave_map *slave_map;
};
#endif /* MMP_DMA_H */
^ permalink raw reply related
* [v1] dma: imx-sdma: add virt-dma support
From: Robin Gong @ 2018-05-24 1:42 UTC (permalink / raw)
To: s.hauer@pengutronix.de, vkoul@kernel.org
Cc: dan.j.williams@intel.com, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, vinod.koul@intel.com,
dl-linux-imx
Okay, I'll try to split it.
On 三, 2018-05-23 at 19:04 +0530, Vinod wrote:
> On 23-05-18, 12:56, s.hauer@pengutronix.de wrote:
>
> >
> > Well, it's somewhat related to virtual dma support, but that's not
> > my
> > point. My point is that this patch is quite big and thus hard to
> > review.
> > If we find ways to make it smaller and to split it up in multiple
> > patches then we should do so, because it makes it easier to review
> > and
> > in case you break something here we raise the chance that a "git
> > bisect"
> > lands on a smaller patch which is easier to understand.
> >
> > Please try and make that a separate change. I haven't really looked
> > into
> > it and it may not be possible due to reasons I haven't seen, but
> > please
> > at least give it a try.
> That is something would help me as well. I have reviewed the patch
> and am not
> sure I fully understand the changes, so breaking up stuff would
> definitely help
> in the review..
>
^ permalink raw reply
* [05/15] mtd: nand: pxa3xx: remove the dmaengine compat need
From: Daniel Mack @ 2018-05-23 21:54 UTC (permalink / raw)
To: Robert Jarzmik, Haojian Zhuang, Bartlomiej Zolnierkiewicz,
Tejun Heo, Vinod Koul, Mauro Carvalho Chehab, Ulf Hansson,
Ezequiel Garcia, Boris Brezillon, David Woodhouse, Brian Norris,
Marek Vasut, Richard Weinberger, Cyrille Pitchen, Nicolas Pitre,
Samuel Ortiz, Greg Kroah-Hartman, Jaroslav Kysela, Takashi Iwai,
Liam Girdwood, Mark Brown, Arnd Bergmann
Cc: linux-arm-kernel, linux-kernel, linux-ide, dmaengine, linux-media,
linux-mmc, linux-mtd, netdev, devel, alsa-devel, Robert Jarzmik
Hi Robert,
Please refer to the attached patch instead of the one I sent earlier. I
missed to also remove the platform_get_resource(IORESOURCE_DMA) call.
Thanks,
Daniel
On Friday, May 18, 2018 11:31 PM, Daniel Mack wrote:
> Hi Robert,
>
> Thanks for this series.
>
> On Monday, April 02, 2018 04:26 PM, Robert Jarzmik wrote:
>> From: Robert Jarzmik <robert.jarzmik@renault.com>
>>
>> As the pxa architecture switched towards the dmaengine slave map, the
>> old compatibility mechanism to acquire the dma requestor line number and
>> priority are not needed anymore.
>>
>> This patch simplifies the dma resource acquisition, using the more
>> generic function dma_request_slave_channel().
>>
>> Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
>> ---
>> drivers/mtd/nand/pxa3xx_nand.c | 10 +---------
>
> This driver was replaced by drivers/mtd/nand/raw/marvell_nand.c
> recently, so this patch can be dropped. I attached a version for the new
> driver which you can pick instead.
>
>
> Thanks,
> Daniel
>
From 72a306157dedb21f8c3289f0f7a288fc4542bd96 Mon Sep 17 00:00:00 2001
From: Daniel Mack <daniel@zonque.org>
Date: Sat, 12 May 2018 21:50:13 +0200
Subject: [PATCH] mtd: rawnand: marvell: remove dmaengine compat code
As the pxa architecture switched towards the dmaengine slave map, the
old compatibility mechanism to acquire the dma requestor line number and
priority are not needed anymore.
This patch simplifies the dma resource acquisition, using the more
generic function dma_request_slave_channel().
Signed-off-by: Daniel Mack <daniel@zonque.org>
---
drivers/mtd/nand/raw/marvell_nand.c | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index ebb1d141b900..319fea77daf1 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2612,8 +2612,6 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
dev);
struct dma_slave_config config = {};
struct resource *r;
- dma_cap_mask_t mask;
- struct pxad_param param;
int ret;
if (!IS_ENABLED(CONFIG_PXA_DMA)) {
@@ -2626,20 +2624,7 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
if (ret)
return ret;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r) {
- dev_err(nfc->dev, "No resource defined for data DMA\n");
- return -ENXIO;
- }
-
- param.drcmr = r->start;
- param.prio = PXAD_PRIO_LOWEST;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- nfc->dma_chan =
- dma_request_slave_channel_compat(mask, pxad_filter_fn,
- ¶m, nfc->dev,
- "data");
+ nfc->dma_chan = dma_request_slave_channel(nfc->dev, "data");
if (!nfc->dma_chan) {
dev_err(nfc->dev,
"Unable to request data DMA channel\n");
--
2.14.3
^ permalink raw reply related
* [v4,3/6] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Rob Herring @ 2018-05-23 19:59 UTC (permalink / raw)
To: Wen He
Cc: dmaengine@vger.kernel.org, devicetree@vger.kernel.org, Leo Li,
Jiafei Pan, Jiaheng Fan, Vinod
Updated Vinod's email...
On Mon, May 21, 2018 at 12:52 AM, Wen He <wen.he_1@nxp.com> wrote:
> Hi Rob,
>
> Please see my comments inline.
>
> Best Regards,
> Wen
>
>> -----Original Message-----
>> From: Rob Herring [mailto:robh@kernel.org]
>> Sent: 2018年5月19日 5:26
>> To: Wen He <wen.he_1@nxp.com>
>> Cc: vinod.koul@intel.com; dmaengine@vger.kernel.org;
>> devicetree@vger.kernel.org; Leo Li <leoyang.li@nxp.com>; Jiafei Pan
>> <jiafei.pan@nxp.com>; Jiaheng Fan <jiaheng.fan@nxp.com>
>> Subject: Re: [v4 3/6] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA
>> controller bindings
>>
>> On Mon, May 14, 2018 at 08:03:04PM +0800, Wen He wrote:
>> > Document the devicetree bindings for NXP Layerscape qDMA controller
>> > which could be found on NXP QorIQ Layerscape SoCs.
>> >
>> > Signed-off-by: Wen He <wen.he_1@nxp.com>
>> > ---
>> > change in v4:
>> > - Rewrite the bindings document that follows generic DMA bindings
>> > file
>> >
>> > change in v3:
>> > - no change
>> >
>> > change in v2:
>> > - Remove indentation
>> > - Add "Should be" before 'fsl,ls1021a-qdma'
>> > - Replace 'channels' by 'dma-channels'
>> > - Replace 'qdma@8390000' by 'dma-controller@8390000'
>> >
>> > Documentation/devicetree/bindings/dma/fsl-qdma.txt | 41
>> ++++++++++++++++++++
>> > 1 files changed, 41 insertions(+), 0 deletions(-) create mode 100644
>> > Documentation/devicetree/bindings/dma/fsl-qdma.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/dma/fsl-qdma.txt
>> > b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
>> > new file mode 100644
>> > index 0000000..368c4e7
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
>> > @@ -0,0 +1,41 @@
>> > +NXP Layerscape SoC qDMA Controller
>> > +==================================
>> > +
>> > +This device follows the generic DMA bindings defined in dma/dma.txt.
>> > +
>> > +Required properties:
>> > +
>> > +- compatible: Must be one of
>> > + "fsl,ls1021a-qdma": for LS1021A Board
>> > + "fsl,ls1043a-qdma": for ls1043A Board
>> > + "fsl,ls1046a-qdma": for ls1046A Board
>> > +- reg: Should contain the register's base address and length.
>> > +- interrupts: Should contain a reference to the interrupt used by
>> this
>> > + device.
>> > +- interrupt-names: Should contain interrupt names:
>> > + "qdma-error": the error interrupt
>> > + "qdma-queue": the queue interrupt
>> > +- queues: Should contain number of queues supported.
>>
>> Needs a vendor prefix.
>>
>
> Does means: The queues filed need a vendor prefix ?
> like 'fsl-queues' ? right?
No, vendor prefixes end with a comma: fsl,queues
Rob
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [v1] dma: imx-sdma: add virt-dma support
From: Vinod Koul @ 2018-05-23 13:34 UTC (permalink / raw)
To: s.hauer@pengutronix.de, Robin Gong
Cc: dan.j.williams@intel.com, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, vinod.koul@intel.com,
dl-linux-imx
On 23-05-18, 12:56, s.hauer@pengutronix.de wrote:
> Well, it's somewhat related to virtual dma support, but that's not my
> point. My point is that this patch is quite big and thus hard to review.
> If we find ways to make it smaller and to split it up in multiple
> patches then we should do so, because it makes it easier to review and
> in case you break something here we raise the chance that a "git bisect"
> lands on a smaller patch which is easier to understand.
>
> Please try and make that a separate change. I haven't really looked into
> it and it may not be possible due to reasons I haven't seen, but please
> at least give it a try.
That is something would help me as well. I have reviewed the patch and am not
sure I fully understand the changes, so breaking up stuff would definitely help
in the review..
^ permalink raw reply
* [v1] dmaengine: imx-sdma: add virt-dma support
From: Vinod Koul @ 2018-05-23 13:32 UTC (permalink / raw)
To: Robin Gong; +Cc: dan.j.williams, dmaengine, linux-kernel, linux-imx
On 22-05-18, 23:45, Robin Gong wrote:
> The legacy sdma driver has below limitations or drawbacks:
> 1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
> one page size for one channel regardless of only few BDs needed
> most time. But in few cases, the max PAGE_SIZE maybe not enough.
> 2. One SDMA channel can't stop immediatley once channel disabled which
typo immediatley
> means SDMA interrupt may come in after this channel terminated.There
> are some patches for this corner case such as commit "2746e2c389f9",
Please add patch title along with commit id in logs
> +struct sdma_desc {
> + struct virt_dma_desc vd;
> + struct list_head node;
> + unsigned int num_bd;
> + dma_addr_t bd_phys;
> + unsigned int buf_tail;
what are these two used for?
> static irqreturn_t sdma_int_handler(int irq, void *dev_id)
> @@ -785,13 +778,24 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
> while (stat) {
> int channel = fls(stat) - 1;
> struct sdma_channel *sdmac = &sdma->channel[channel];
> -
> - if (sdmac->flags & IMX_DMA_SG_LOOP)
> - sdma_update_channel_loop(sdmac);
> - else
> - tasklet_schedule(&sdmac->tasklet);
> + struct sdma_desc *desc;
> +
> + spin_lock(&sdmac->vc.lock);
> + desc = sdmac->desc;
> + if (desc) {
> + if (sdmac->flags & IMX_DMA_SG_LOOP) {
> + sdma_update_channel_loop(sdmac);
I guess loop is for cyclic case, are you not invoking vchan_cyclic_callback()
for that? I dont see this call in this patch although the driver supports
cyclic mode.
> +static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
> + enum dma_transfer_direction direction, u32 bds)
> +{
> + struct sdma_desc *desc;
> +
> + desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
this is called from _prep_ so we are in non slpeepy context and would need to
use GFP_NOWAIT flag..
> @@ -1432,26 +1497,74 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
> {
> struct sdma_channel *sdmac = to_sdma_chan(chan);
> u32 residue;
> + struct virt_dma_desc *vd;
> + struct sdma_desc *desc;
> + enum dma_status ret;
> + unsigned long flags;
>
> - if (sdmac->flags & IMX_DMA_SG_LOOP)
> - residue = (sdmac->num_bd - sdmac->buf_ptail) *
> + ret = dma_cookie_status(chan, cookie, txstate);
> + if (ret == DMA_COMPLETE && txstate) {
> + residue = sdmac->chn_count - sdmac->chn_real_count;
on DMA_COMPLETE reside is 0, so why this?
> + return ret;
> + }
> +
> + spin_lock_irqsave(&sdmac->vc.lock, flags);
> + vd = vchan_find_desc(&sdmac->vc, cookie);
> + desc = to_sdma_desc(&vd->tx);
> + if (vd) {
> + if (sdmac->flags & IMX_DMA_SG_LOOP)
> + residue = (desc->num_bd - desc->buf_ptail) *
> sdmac->period_len - sdmac->chn_real_count;
you need to check which descriptor is the query for, current or queued.
> +static void sdma_start_desc(struct sdma_channel *sdmac)
> +{
> + struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
> + struct sdma_desc *desc;
> + struct sdma_engine *sdma = sdmac->sdma;
> + int channel = sdmac->channel;
> +
> + if (!vd) {
> + sdmac->desc = NULL;
> + return;
> + }
> + sdmac->desc = desc = to_sdma_desc(&vd->tx);
> + /*
> + * Do not delete the node in desc_issued list in cyclic mode, otherwise
> + * the desc alloced will never be freed in vchan_dma_desc_free_list
alloced .. you mean allocated?
^ permalink raw reply
* [v1] dma: imx-sdma: add virt-dma support
From: Sascha Hauer @ 2018-05-23 10:56 UTC (permalink / raw)
To: Robin Gong
Cc: dan.j.williams@intel.com, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, vinod.koul@intel.com,
dl-linux-imx
On Wed, May 23, 2018 at 10:26:23AM +0000, Robin Gong wrote:
> >
> > >
> > > + u32 bd_size_sum;
> > This variable is never used for anything.
> Yes, it's not for significative use but debug to see how many current
> bds used.
I am not convinced this is useful. The variable could easily be added back
by someone who debugs this driver. The code has to be changed anyway to
make use of this variable.
> > > @@ -632,7 +635,7 @@ static int sdma_run_channel0(struct sdma_engine
> > > *sdma)
> > > static int sdma_load_script(struct sdma_engine *sdma, void *buf,
> > > int size,
> > > u32 address)
> > > {
> > > - struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
> > > + struct sdma_buffer_descriptor *bd0 = sdma->bd0;
> > This change seems to be an orthogonal change. Please make this a
> > separate patch.
> It's something related with virtual dma support, because in virtual
> dma framework, all bds should be allocated dynamically if they used.
> but bd0 is a specail case since it's must and basic for load sdma
> firmware and context for other channels. So here alloc 'bd0' for other
> channels.
Well, it's somewhat related to virtual dma support, but that's not my
point. My point is that this patch is quite big and thus hard to review.
If we find ways to make it smaller and to split it up in multiple
patches then we should do so, because it makes it easier to review and
in case you break something here we raise the chance that a "git bisect"
lands on a smaller patch which is easier to understand.
Please try and make that a separate change. I haven't really looked into
it and it may not be possible due to reasons I haven't seen, but please
at least give it a try.
> >
> > >
> > > +
> > > + if (sdmac->desc)
> > > + sdmac->desc = NULL;
> > The test is unnecesary.
> This 'NULL' is meaningful in case that dma done interrupt come after
> terminate as you know sdma will actually stop after current transfer
> done.
The setting of the variable to NULL is ok, but the test is useless.
if (sdmac->desc)
sdmac->desc = NULL;
is equivalent to:
sdmac->desc = NULL;
Sascha
^ permalink raw reply
* [v1] dma: imx-sdma: add virt-dma support
From: Robin Gong @ 2018-05-23 10:26 UTC (permalink / raw)
To: s.hauer@pengutronix.de
Cc: dan.j.williams@intel.com, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, vinod.koul@intel.com,
dl-linux-imx
On 二, 2018-05-22 at 12:09 +0200, Sascha Hauer wrote:
> Hi Robin,
>
> Several comments inside.
>
> Sascha
>
> On Fri, Mar 23, 2018 at 12:18:19AM +0800, Robin Gong wrote:
> >
> > The legacy sdma driver has below limitations or drawbacks:
> > 1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and
> > alloc
> > one page size for one channel regardless of only few BDs
> > needed
> > most time. But in few cases, the max PAGE_SIZE maybe not
> > enough.
> > 2. One SDMA channel can't stop immediatley once channel disabled
> > which
> > means SDMA interrupt may come in after this channel
> > terminated.There
> > are some patches for this corner case such as commit
> > "2746e2c389f9",
> > but not cover non-cyclic.
> >
> > The common virt-dma overcomes the above limitations. It can alloc
> > bd
> > dynamically and free bd once this tx transfer done. No memory
> > wasted or
> > maximum limititation here, only depends on how many memory can be
> > requested
> > from kernel. For No.2, such issue can be workaround by checking if
> > there
> > is available descript("sdmac->desc") now once the unwanted
> > interrupt
> > coming. At last the common virt-dma is easier for sdma driver
> > maintain.
> >
> > Signed-off-by: Robin Gong <yibin.gong@nxp.com>
> > ---
> > drivers/dma/Kconfig | 1 +
> > drivers/dma/imx-sdma.c | 395 +++++++++++++++++++++++++++++++----
> > --------------
> > 2 files changed, 253 insertions(+), 143 deletions(-)
> >
> > diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> > index 27df3e2..c4ce43c 100644
> > --- a/drivers/dma/Kconfig
> > +++ b/drivers/dma/Kconfig
> > @@ -247,6 +247,7 @@ config IMX_SDMA
> > tristate "i.MX SDMA support"
> > depends on ARCH_MXC
> > select DMA_ENGINE
> > + select DMA_VIRTUAL_CHANNELS
> > help
> > Support the i.MX SDMA engine. This engine is integrated
> > into
> > Freescale i.MX25/31/35/51/53/6 chips.
> > diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
> > index ccd03c3..df79e73 100644
> > --- a/drivers/dma/imx-sdma.c
> > +++ b/drivers/dma/imx-sdma.c
> > @@ -48,6 +48,7 @@
> > #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
> >
> > #include "dmaengine.h"
> > +#include "virt-dma.h"
> >
> > /* SDMA registers */
> > #define SDMA_H_C0PTR 0x000
> > @@ -291,10 +292,19 @@ struct sdma_context_data {
> > u32 scratch7;
> > } __attribute__ ((packed));
> >
> > -#define NUM_BD (int)(PAGE_SIZE / sizeof(struct
> > sdma_buffer_descriptor))
> > -
> > struct sdma_engine;
> >
> > +struct sdma_desc {
> > + struct virt_dma_desc vd;
> > + struct list_head node;
> > + unsigned int num_bd;
> > + dma_addr_t bd_phys;
> > + unsigned int buf_tail;
> > + unsigned int buf_ptail;
> > + struct sdma_channel *sdmac;
> > + struct sdma_buffer_descriptor *bd;
> > +};
> > +
> > /**
> > * struct sdma_channel - housekeeping for a SDMA channel
> > *
> > @@ -310,19 +320,17 @@ struct sdma_engine;
> > * @num_bd max NUM_BD. number of descriptors
> > currently handling
> > */
> > struct sdma_channel {
> > + struct virt_dma_chan vc;
> > + struct list_head pending;
> > struct sdma_engine *sdma;
> > + struct sdma_desc *desc;
> > unsigned int channel;
> > enum dma_transfer_direction direction;
> > enum sdma_peripheral_type peripheral_type;
> > unsigned int event_id0;
> > unsigned int event_id1;
> > enum dma_slave_buswidth word_size;
> > - unsigned int buf_tail;
> > - unsigned int buf_ptail;
> > - unsigned int num_bd;
> > unsigned int period_len;
> > - struct sdma_buffer_descriptor *bd;
> > - dma_addr_t bd_phys;
> > unsigned int pc_from_device,
> > pc_to_device;
> > unsigned int device_to_device;
> > unsigned long flags;
> > @@ -330,15 +338,12 @@ struct sdma_channel {
> > unsigned long event_mask[2];
> > unsigned long watermark_level;
> > u32 shp_addr, per_addr;
> > - struct dma_chan chan;
> > - spinlock_t lock;
> > - struct dma_async_tx_descriptor desc;
> > enum dma_status status;
> > unsigned int chn_count;
> > unsigned int chn_real_count;
> > - struct tasklet_struct tasklet;
> > struct imx_dma_data data;
> > bool enabled;
> Usage of this variable is removed in this patch, but not the variable
> itself.
Yes, will remove the usless 'enabled' in v2.
>
> >
> > + u32 bd_size_sum;
> This variable is never used for anything.
Yes, it's not for significative use but debug to see how many current
bds used.
>
> >
> > };
> >
> > #define IMX_DMA_SG_LOOP BIT(0)
> > @@ -398,6 +403,9 @@ struct sdma_engine {
> > u32 spba_start_addr;
> > u32 spba_end_addr;
> > unsigned int irq;
> > + /* channel0 bd */
> > + dma_addr_t bd0_phys;
> > + struct sdma_buffer_descriptor *bd0;
> > };
> >
> > static struct sdma_driver_data sdma_imx31 = {
> > @@ -553,6 +561,8 @@ MODULE_DEVICE_TABLE(of, sdma_dt_ids);
> > #define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq
> > /core freq = 2 or 1 */
> > #define SDMA_H_CONFIG_CSM (3) /* indicates which
> > context switch mode is selected*/
> >
> > +static void sdma_start_desc(struct sdma_channel *sdmac);
> > +
> > static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned
> > int event)
> > {
> > u32 chnenbl0 = sdma->drvdata->chnenbl0;
> > @@ -597,14 +607,7 @@ static int sdma_config_ownership(struct
> > sdma_channel *sdmac,
> >
> > static void sdma_enable_channel(struct sdma_engine *sdma, int
> > channel)
> > {
> > - unsigned long flags;
> > - struct sdma_channel *sdmac = &sdma->channel[channel];
> > -
> > writel(BIT(channel), sdma->regs + SDMA_H_START);
> > -
> > - spin_lock_irqsave(&sdmac->lock, flags);
> > - sdmac->enabled = true;
> > - spin_unlock_irqrestore(&sdmac->lock, flags);
> > }
> >
> > /*
> > @@ -632,7 +635,7 @@ static int sdma_run_channel0(struct sdma_engine
> > *sdma)
> > static int sdma_load_script(struct sdma_engine *sdma, void *buf,
> > int size,
> > u32 address)
> > {
> > - struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
> > + struct sdma_buffer_descriptor *bd0 = sdma->bd0;
> This change seems to be an orthogonal change. Please make this a
> separate patch.
It's something related with virtual dma support, because in virtual
dma framework, all bds should be allocated dynamically if they used.
but bd0 is a specail case since it's must and basic for load sdma
firmware and context for other channels. So here alloc 'bd0' for other
channels.
>
> >
> > void *buf_virt;
> > dma_addr_t buf_phys;
> > int ret;
> > @@ -691,23 +694,16 @@ static void sdma_event_disable(struct
> > sdma_channel *sdmac, unsigned int event)
> > static void sdma_update_channel_loop(struct sdma_channel *sdmac)
> > {
> > struct sdma_buffer_descriptor *bd;
> > + struct sdma_desc *desc = sdmac->desc;
> > int error = 0;
> > enum dma_status old_status = sdmac->status;
> > - unsigned long flags;
> > -
> > - spin_lock_irqsave(&sdmac->lock, flags);
> > - if (!sdmac->enabled) {
> > - spin_unlock_irqrestore(&sdmac->lock, flags);
> > - return;
> > - }
> > - spin_unlock_irqrestore(&sdmac->lock, flags);
> >
> > /*
> > * loop mode. Iterate over descriptors, re-setup them and
> > * call callback function.
> > */
> > - while (1) {
> > - bd = &sdmac->bd[sdmac->buf_tail];
> > + while (desc) {
> 'desc' seems to be used as a loop counter here, but this variable is
> never assigned another value, so I assume it's just another way to
> say
> "skip the loop if desc is NULL". When 'desc' NULL you won't get into
> this function at all though, so this check for desc seems rather
> pointless.
Good catch, should check 'sdmac->desc' here instead of 'desc' since in
the following 'sdmac->desc' may be set to NULL by sdma_terminate_all
during folllowing spin_unlock and spin_lock narrow window. Will improve
it in V2.
>
> >
> > + bd = &desc->bd[desc->buf_tail];
> >
> > if (bd->mode.status & BD_DONE)
> > break;
> > @@ -726,8 +722,8 @@ static void sdma_update_channel_loop(struct
> > sdma_channel *sdmac)
> > sdmac->chn_real_count = bd->mode.count;
> > bd->mode.status |= BD_DONE;
> > bd->mode.count = sdmac->period_len;
> > - sdmac->buf_ptail = sdmac->buf_tail;
> > - sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac-
> > >num_bd;
> > + desc->buf_ptail = desc->buf_tail;
> > + desc->buf_tail = (desc->buf_tail + 1) % desc-
> > >num_bd;
> >
> > /*
> > * The callback is called from the interrupt
> > context in order
> > @@ -735,15 +731,16 @@ static void sdma_update_channel_loop(struct
> > sdma_channel *sdmac)
> > * SDMA transaction status by the time the client
> > tasklet is
> > * executed.
> > */
> > -
> > - dmaengine_desc_get_callback_invoke(&sdmac->desc,
> > NULL);
> > + spin_unlock(&sdmac->vc.lock);
> > + dmaengine_desc_get_callback_invoke(&desc->vd.tx,
> > NULL);
> > + spin_lock(&sdmac->vc.lock);
> >
> > if (error)
> > sdmac->status = old_status;
> > }
> > }
> >
> > -static void mxc_sdma_handle_channel_normal(unsigned long data)
> > +static void mxc_sdma_handle_channel_normal(struct sdma_channel
> > *data)
> > {
> > struct sdma_channel *sdmac = (struct sdma_channel *) data;
> > struct sdma_buffer_descriptor *bd;
> > @@ -754,8 +751,8 @@ static void
> > mxc_sdma_handle_channel_normal(unsigned long data)
> > * non loop mode. Iterate over all descriptors, collect
> > * errors and call callback function
> > */
> > - for (i = 0; i < sdmac->num_bd; i++) {
> > - bd = &sdmac->bd[i];
> > + for (i = 0; i < sdmac->desc->num_bd; i++) {
> > + bd = &sdmac->desc->bd[i];
> >
> > if (bd->mode.status & (BD_DONE | BD_RROR))
> > error = -EIO;
> > @@ -766,10 +763,6 @@ static void
> > mxc_sdma_handle_channel_normal(unsigned long data)
> > sdmac->status = DMA_ERROR;
> > else
> > sdmac->status = DMA_COMPLETE;
> > -
> > - dma_cookie_complete(&sdmac->desc);
> > -
> > - dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
> > }
> >
> > static irqreturn_t sdma_int_handler(int irq, void *dev_id)
> > @@ -785,13 +778,24 @@ static irqreturn_t sdma_int_handler(int irq,
> > void *dev_id)
> > while (stat) {
> > int channel = fls(stat) - 1;
> > struct sdma_channel *sdmac = &sdma-
> > >channel[channel];
> > -
> > - if (sdmac->flags & IMX_DMA_SG_LOOP)
> > - sdma_update_channel_loop(sdmac);
> > - else
> > - tasklet_schedule(&sdmac->tasklet);
> > + struct sdma_desc *desc;
> > +
> > + spin_lock(&sdmac->vc.lock);
> > + desc = sdmac->desc;
> > + if (desc) {
> > + if (sdmac->flags & IMX_DMA_SG_LOOP) {
> > + sdma_update_channel_loop(sdmac);
> > + } else {
> > + mxc_sdma_handle_channel_normal(sdm
> > ac);
> > + vchan_cookie_complete(&desc->vd);
> > + if (!list_empty(&sdmac->pending))
> > + list_del(&desc->node);
> What does this list_empty check protect you from? It looks like when
> the
> list really is empty then it's a bug in your internal driver logic.
Yes, no need here check local sdmac->pending since I directly start
setup next desc flowing in isr instead of local tasklet and virt_dma
framework will handle all lists such as desc_issued/desc_completed etc.
Will remove sdmac->pending in V2.
>
> >
> > + sdma_start_desc(sdmac);
> Whitespace damage here.
Will fix in V2.
>
> >
> > + }
> > + }
> >
> > __clear_bit(channel, &stat);
> > + spin_unlock(&sdmac->vc.lock);
> > }
> >
> > return IRQ_HANDLED;
> > @@ -897,7 +901,7 @@ static int sdma_load_context(struct
> > sdma_channel *sdmac)
> > int channel = sdmac->channel;
> > int load_address;
> > struct sdma_context_data *context = sdma->context;
> > - struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
> > + struct sdma_buffer_descriptor *bd0 = sdma->bd0;
> > int ret;
> > unsigned long flags;
> >
> > @@ -946,7 +950,7 @@ static int sdma_load_context(struct
> > sdma_channel *sdmac)
> >
> > static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
> > {
> > - return container_of(chan, struct sdma_channel, chan);
> > + return container_of(chan, struct sdma_channel, vc.chan);
> > }
> >
> > static int sdma_disable_channel(struct dma_chan *chan)
> > @@ -954,15 +958,10 @@ static int sdma_disable_channel(struct
> > dma_chan *chan)
> > struct sdma_channel *sdmac = to_sdma_chan(chan);
> > struct sdma_engine *sdma = sdmac->sdma;
> > int channel = sdmac->channel;
> > - unsigned long flags;
> >
> > writel_relaxed(BIT(channel), sdma->regs +
> > SDMA_H_STATSTOP);
> > sdmac->status = DMA_ERROR;
> >
> > - spin_lock_irqsave(&sdmac->lock, flags);
> > - sdmac->enabled = false;
> > - spin_unlock_irqrestore(&sdmac->lock, flags);
> > -
> > return 0;
> > }
> >
> > @@ -1097,42 +1096,101 @@ static int
> > sdma_set_channel_priority(struct sdma_channel *sdmac,
> > return 0;
> > }
> >
> > -static int sdma_request_channel(struct sdma_channel *sdmac)
> > +static int sdma_alloc_bd(struct sdma_desc *desc)
> > {
> > - struct sdma_engine *sdma = sdmac->sdma;
> > - int channel = sdmac->channel;
> > - int ret = -EBUSY;
> > + u32 bd_size = desc->num_bd * sizeof(struct
> > sdma_buffer_descriptor);
> > + int ret = 0;
> > + unsigned long flags;
> >
> > - sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac-
> > >bd_phys,
> > + desc->bd = dma_zalloc_coherent(NULL, bd_size, &desc-
> > >bd_phys,
> > GFP_KERNEL);
> > - if (!sdmac->bd) {
> > + if (!desc->bd) {
> > ret = -ENOMEM;
> > goto out;
> > }
> >
> > - sdma->channel_control[channel].base_bd_ptr = sdmac-
> > >bd_phys;
> > - sdma->channel_control[channel].current_bd_ptr = sdmac-
> > >bd_phys;
> > + spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
> > + desc->sdmac->bd_size_sum += bd_size;
> > + spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
> >
> > - sdma_set_channel_priority(sdmac,
> > MXC_SDMA_DEFAULT_PRIORITY);
> > - return 0;
> > out:
> > -
> > return ret;
> > }
> >
> > -static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor
> > *tx)
> > +static void sdma_free_bd(struct sdma_desc *desc)
> > {
> > + u32 bd_size = desc->num_bd * sizeof(struct
> > sdma_buffer_descriptor);
> > unsigned long flags;
> > - struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
> > - dma_cookie_t cookie;
> >
> > - spin_lock_irqsave(&sdmac->lock, flags);
> > + if (desc->bd) {
> > + dma_free_coherent(NULL, bd_size, desc->bd, desc-
> > >bd_phys);
> > +
> > + spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
> > + desc->sdmac->bd_size_sum -= bd_size;
> > + spin_unlock_irqrestore(&desc->sdmac->vc.lock,
> > flags);
> > + }
> > +}
> > +
> > +static int sdma_request_channel0(struct sdma_engine *sdma)
> > +{
> > + int ret = 0;
> > +
> > + sdma->bd0 = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdma-
> > >bd0_phys,
> > + GFP_KERNEL);
> > + if (!sdma->bd0) {
> > + ret = -ENOMEM;
> > + goto out;
> > + }
> >
> > - cookie = dma_cookie_assign(tx);
> > + sdma->channel_control[0].base_bd_ptr = sdma->bd0_phys;
> > + sdma->channel_control[0].current_bd_ptr = sdma->bd0_phys;
> >
> > - spin_unlock_irqrestore(&sdmac->lock, flags);
> > + sdma_set_channel_priority(&sdma->channel[0],
> > MXC_SDMA_DEFAULT_PRIORITY);
> > +out:
> >
> > - return cookie;
> > + return ret;
> > +}
> > +
> > +static struct sdma_desc *to_sdma_desc(struct
> > dma_async_tx_descriptor *t)
> > +{
> > + return container_of(t, struct sdma_desc, vd.tx);
> > +}
> > +
> > +static void sdma_desc_free(struct virt_dma_desc *vd)
> > +{
> > + struct sdma_desc *desc = container_of(vd, struct
> > sdma_desc, vd);
> > +
> > + if (desc) {
> Depending on the position of 'vd' in struct sdma_desc 'desc' will
> always
> be non-NULL, even if 'vd' is NULL.
>
> I think this test is unnecessary since this function should never be
> called with an invalid pointer. If it is, then the caller really
> deserved the resulting crash.
Yes, will remove it.
>
> >
> > + sdma_free_bd(desc);
> > + kfree(desc);
> > + }
> > +}
> > +
> > +static int sdma_terminate_all(struct dma_chan *chan)
> > +{
> > + struct sdma_channel *sdmac = to_sdma_chan(chan);
> > + unsigned long flags;
> > + LIST_HEAD(head);
> > +
> > + spin_lock_irqsave(&sdmac->vc.lock, flags);
> > + vchan_get_all_descriptors(&sdmac->vc, &head);
> > + while (!list_empty(&sdmac->pending)) {
> > + struct sdma_desc *desc = list_first_entry(&sdmac-
> > >pending,
> > + struct sdma_desc, node);
> > +
> > + list_del(&desc->node);
> > + spin_unlock_irqrestore(&sdmac->vc.lock, flags);
> > + sdmac->vc.desc_free(&desc->vd);
> > + spin_lock_irqsave(&sdmac->vc.lock, flags);
> > + }
> list_for_each_entry_safe?
Will remove here all while(sdmac->pending) checking.No need here.
>
> >
> > +
> > + if (sdmac->desc)
> > + sdmac->desc = NULL;
> The test is unnecesary.
This 'NULL' is meaningful in case that dma done interrupt come after
terminate as you know sdma will actually stop after current transfer
done.
> >
> > + spin_unlock_irqrestore(&sdmac->vc.lock, flags);
> > + vchan_dma_desc_free_list(&sdmac->vc, &head);
> > + sdma_disable_channel_with_delay(chan);
> > +
> > + return 0;
> > }
> >
> > static int sdma_alloc_chan_resources(struct dma_chan *chan)
> > @@ -1168,18 +1226,11 @@ static int sdma_alloc_chan_resources(struct
> > dma_chan *chan)
> > if (ret)
> > goto disable_clk_ipg;
> >
> > - ret = sdma_request_channel(sdmac);
> > - if (ret)
> > - goto disable_clk_ahb;
> > -
> > ret = sdma_set_channel_priority(sdmac, prio);
> > if (ret)
> > goto disable_clk_ahb;
> >
> > - dma_async_tx_descriptor_init(&sdmac->desc, chan);
> > - sdmac->desc.tx_submit = sdma_tx_submit;
> > - /* txd.flags will be overwritten in prep funcs */
> > - sdmac->desc.flags = DMA_CTRL_ACK;
> > + sdmac->bd_size_sum = 0;
> >
> > return 0;
> >
> > @@ -1195,7 +1246,7 @@ static void sdma_free_chan_resources(struct
> > dma_chan *chan)
> > struct sdma_channel *sdmac = to_sdma_chan(chan);
> > struct sdma_engine *sdma = sdmac->sdma;
> >
> > - sdma_disable_channel(chan);
> > + sdma_terminate_all(chan);
> >
> > if (sdmac->event_id0)
> > sdma_event_disable(sdmac, sdmac->event_id0);
> > @@ -1207,12 +1258,43 @@ static void sdma_free_chan_resources(struct
> > dma_chan *chan)
> >
> > sdma_set_channel_priority(sdmac, 0);
> >
> > - dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac-
> > >bd_phys);
> > -
> > clk_disable(sdma->clk_ipg);
> > clk_disable(sdma->clk_ahb);
> > }
> >
> > +static struct sdma_desc *sdma_transfer_init(struct sdma_channel
> > *sdmac,
> > + enum dma_transfer_direction
> > direction, u32 bds)
> > +{
> > + struct sdma_desc *desc;
> > +
> > + desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
> > + if (!desc)
> > + goto err_out;
> > +
> > + sdmac->status = DMA_IN_PROGRESS;
> > + sdmac->direction = direction;
> > + sdmac->flags = 0;
> > + sdmac->chn_count = 0;
> > + sdmac->chn_real_count = 0;
> > +
> > + desc->sdmac = sdmac;
> > + desc->num_bd = bds;
> > + INIT_LIST_HEAD(&desc->node);
> > +
> > + if (sdma_alloc_bd(desc))
> > + goto err_desc_out;
> > +
> > + if (sdma_load_context(sdmac))
> > + goto err_desc_out;
> > +
> > + return desc;
> > +
> > +err_desc_out:
> > + kfree(desc);
> > +err_out:
> > + return NULL;
> > +}
> > +
> > static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
> > struct dma_chan *chan, struct scatterlist *sgl,
> > unsigned int sg_len, enum dma_transfer_direction
> > direction,
> > @@ -1223,35 +1305,24 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_slave_sg(
> > int ret, i, count;
> > int channel = sdmac->channel;
> > struct scatterlist *sg;
> > + struct sdma_desc *desc;
> >
> > - if (sdmac->status == DMA_IN_PROGRESS)
> > + if (!chan)
> > return NULL;
> > - sdmac->status = DMA_IN_PROGRESS;
> > -
> > - sdmac->flags = 0;
> >
> > - sdmac->buf_tail = 0;
> > - sdmac->buf_ptail = 0;
> > - sdmac->chn_real_count = 0;
> > + desc = sdma_transfer_init(sdmac, direction, sg_len);
> > + if (!desc)
> > + goto err_out;
> >
> > dev_dbg(sdma->dev, "setting up %d entries for channel
> > %d.\n",
> > sg_len, channel);
> >
> > - sdmac->direction = direction;
> > ret = sdma_load_context(sdmac);
> > if (ret)
> > goto err_out;
> >
> > - if (sg_len > NUM_BD) {
> > - dev_err(sdma->dev, "SDMA channel %d: maximum
> > number of sg exceeded: %d > %d\n",
> > - channel, sg_len, NUM_BD);
> > - ret = -EINVAL;
> > - goto err_out;
> > - }
> > -
> > - sdmac->chn_count = 0;
> > for_each_sg(sgl, sg, sg_len, i) {
> > - struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
> > + struct sdma_buffer_descriptor *bd = &desc->bd[i];
> > int param;
> >
> > bd->buffer_addr = sg->dma_address;
> > @@ -1262,7 +1333,7 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_slave_sg(
> > dev_err(sdma->dev, "SDMA channel %d:
> > maximum bytes for sg entry exceeded: %d > %d\n",
> > channel, count, 0xffff);
> > ret = -EINVAL;
> > - goto err_out;
> > + goto err_bd_out;
> > }
> >
> > bd->mode.count = count;
> > @@ -1307,10 +1378,11 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_slave_sg(
> > bd->mode.status = param;
> > }
> >
> > - sdmac->num_bd = sg_len;
> > - sdma->channel_control[channel].current_bd_ptr = sdmac-
> > >bd_phys;
> > + return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
> >
> > - return &sdmac->desc;
> > +err_bd_out:
> > + sdma_free_bd(desc);
> > + kfree(desc);
> > err_out:
> > sdmac->status = DMA_ERROR;
> > return NULL;
> > @@ -1326,39 +1398,32 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_dma_cyclic(
> > int num_periods = buf_len / period_len;
> > int channel = sdmac->channel;
> > int ret, i = 0, buf = 0;
> > + struct sdma_desc *desc;
> >
> > dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
> >
> > - if (sdmac->status == DMA_IN_PROGRESS)
> > - return NULL;
> > -
> > - sdmac->status = DMA_IN_PROGRESS;
> > + /* Now allocate and setup the descriptor. */
> > + desc = sdma_transfer_init(sdmac, direction, num_periods);
> > + if (!desc)
> > + goto err_out;
> >
> > - sdmac->buf_tail = 0;
> > - sdmac->buf_ptail = 0;
> > - sdmac->chn_real_count = 0;
> > + desc->buf_tail = 0;
> > + desc->buf_ptail = 0;
> > sdmac->period_len = period_len;
> > -
> > sdmac->flags |= IMX_DMA_SG_LOOP;
> > - sdmac->direction = direction;
> > +
> > ret = sdma_load_context(sdmac);
> > if (ret)
> > goto err_out;
> >
> > - if (num_periods > NUM_BD) {
> > - dev_err(sdma->dev, "SDMA channel %d: maximum
> > number of sg exceeded: %d > %d\n",
> > - channel, num_periods, NUM_BD);
> > - goto err_out;
> > - }
> > -
> > if (period_len > 0xffff) {
> > dev_err(sdma->dev, "SDMA channel %d: maximum
> > period size exceeded: %zu > %d\n",
> > channel, period_len, 0xffff);
> > - goto err_out;
> > + goto err_bd_out;
> > }
> >
> > while (buf < buf_len) {
> > - struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
> > + struct sdma_buffer_descriptor *bd = &desc->bd[i];
> > int param;
> >
> > bd->buffer_addr = dma_addr;
> > @@ -1366,7 +1431,7 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_dma_cyclic(
> > bd->mode.count = period_len;
> >
> > if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
> > - goto err_out;
> > + goto err_bd_out;
> > if (sdmac->word_size ==
> > DMA_SLAVE_BUSWIDTH_4_BYTES)
> > bd->mode.command = 0;
> > else
> > @@ -1389,10 +1454,10 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_dma_cyclic(
> > i++;
> > }
> >
> > - sdmac->num_bd = num_periods;
> > - sdma->channel_control[channel].current_bd_ptr = sdmac-
> > >bd_phys;
> > -
> > - return &sdmac->desc;
> > + return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
> > +err_bd_out:
> > + sdma_free_bd(desc);
> > + kfree(desc);
> > err_out:
> > sdmac->status = DMA_ERROR;
> > return NULL;
> > @@ -1432,26 +1497,74 @@ static enum dma_status
> > sdma_tx_status(struct dma_chan *chan,
> > {
> > struct sdma_channel *sdmac = to_sdma_chan(chan);
> > u32 residue;
> > + struct virt_dma_desc *vd;
> > + struct sdma_desc *desc;
> > + enum dma_status ret;
> > + unsigned long flags;
> >
> > - if (sdmac->flags & IMX_DMA_SG_LOOP)
> > - residue = (sdmac->num_bd - sdmac->buf_ptail) *
> > + ret = dma_cookie_status(chan, cookie, txstate);
> > + if (ret == DMA_COMPLETE && txstate) {
> > + residue = sdmac->chn_count - sdmac-
> > >chn_real_count;
> > + return ret;
> > + }
> > +
> > + spin_lock_irqsave(&sdmac->vc.lock, flags);
> > + vd = vchan_find_desc(&sdmac->vc, cookie);
> > + desc = to_sdma_desc(&vd->tx);
> You should use 'vd' only after you have made sure it is valid (though
> I
> see it causes no harm in this case, but let's be nice to the readers
> of
> this code)
Ok, will move desc = to_sdma_desc(&vd->tx) into the below if(vd)...
>
> >
> > + if (vd) {
> > + if (sdmac->flags & IMX_DMA_SG_LOOP)
> > + residue = (desc->num_bd - desc->buf_ptail)
> > *
> > sdmac->period_len - sdmac-
> > >chn_real_count;
> > - else
> > + else
> > + residue = sdmac->chn_count - sdmac-
> > >chn_real_count;
> > + } else if (sdmac->desc && sdmac->desc->vd.tx.cookie ==
> > cookie) {
> > residue = sdmac->chn_count - sdmac-
> > >chn_real_count;
> > + } else {
> > + residue = 0;
> > + }
> > + ret = sdmac->status;
> > + spin_unlock_irqrestore(&sdmac->vc.lock, flags);
> >
> > dma_set_tx_state(txstate, chan->completed_cookie, chan-
> > >cookie,
> > residue);
> >
> > - return sdmac->status;
> > + return ret;
> > +}
> > +
> > +static void sdma_start_desc(struct sdma_channel *sdmac)
> > +{
> > + struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
> > + struct sdma_desc *desc;
> > + struct sdma_engine *sdma = sdmac->sdma;
> > + int channel = sdmac->channel;
> > +
> > + if (!vd) {
> > + sdmac->desc = NULL;
> > + return;
> > + }
> > + sdmac->desc = desc = to_sdma_desc(&vd->tx);
> > + /*
> > + * Do not delete the node in desc_issued list in cyclic
> > mode, otherwise
> > + * the desc alloced will never be freed in
> > vchan_dma_desc_free_list
> > + */
> > + if (!(sdmac->flags & IMX_DMA_SG_LOOP)) {
> > + list_add_tail(&sdmac->desc->node, &sdmac-
> > >pending);
> > + list_del(&vd->node);
> > + }
> > + sdma->channel_control[channel].base_bd_ptr = desc-
> > >bd_phys;
> > + sdma->channel_control[channel].current_bd_ptr = desc-
> > >bd_phys;
> > + sdma_enable_channel(sdma, sdmac->channel);
> > }
> >
> > static void sdma_issue_pending(struct dma_chan *chan)
> > {
> > struct sdma_channel *sdmac = to_sdma_chan(chan);
> > - struct sdma_engine *sdma = sdmac->sdma;
> > + unsigned long flags;
> >
> > - if (sdmac->status == DMA_IN_PROGRESS)
> > - sdma_enable_channel(sdma, sdmac->channel);
> > + spin_lock_irqsave(&sdmac->vc.lock, flags);
> > + if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
> > + sdma_start_desc(sdmac);
> > + spin_unlock_irqrestore(&sdmac->vc.lock, flags);
> > }
> >
> > #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
> > @@ -1657,7 +1770,7 @@ static int sdma_init(struct sdma_engine
> > *sdma)
> > for (i = 0; i < MAX_DMA_CHANNELS; i++)
> > writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i *
> > 4);
> >
> > - ret = sdma_request_channel(&sdma->channel[0]);
> > + ret = sdma_request_channel0(sdma);
> > if (ret)
> > goto err_dma_alloc;
> >
> > @@ -1819,22 +1932,17 @@ static int sdma_probe(struct
> > platform_device *pdev)
> > struct sdma_channel *sdmac = &sdma->channel[i];
> >
> > sdmac->sdma = sdma;
> > - spin_lock_init(&sdmac->lock);
> > -
> > - sdmac->chan.device = &sdma->dma_device;
> > - dma_cookie_init(&sdmac->chan);
> > sdmac->channel = i;
> > -
> > - tasklet_init(&sdmac->tasklet,
> > mxc_sdma_handle_channel_normal,
> > - (unsigned long) sdmac);
> > + sdmac->status = DMA_IN_PROGRESS;
> > + sdmac->vc.desc_free = sdma_desc_free;
> > + INIT_LIST_HEAD(&sdmac->pending);
> > /*
> > * Add the channel to the DMAC list. Do not add
> > channel 0 though
> > * because we need it internally in the SDMA
> > driver. This also means
> > * that channel 0 in dmaengine counting matches
> > sdma channel 1.
> > */
> > if (i)
> > - list_add_tail(&sdmac->chan.device_node,
> > - &sdma-
> > >dma_device.channels);
> > + vchan_init(&sdmac->vc, &sdma->dma_device);
> > }
> >
> > ret = sdma_init(sdma);
> > @@ -1879,7 +1987,7 @@ static int sdma_probe(struct platform_device
> > *pdev)
> > sdma->dma_device.device_prep_slave_sg =
> > sdma_prep_slave_sg;
> > sdma->dma_device.device_prep_dma_cyclic =
> > sdma_prep_dma_cyclic;
> > sdma->dma_device.device_config = sdma_config;
> > - sdma->dma_device.device_terminate_all =
> > sdma_disable_channel_with_delay;
> > + sdma->dma_device.device_terminate_all =
> > sdma_terminate_all;
> > sdma->dma_device.src_addr_widths = SDMA_DMA_BUSWIDTHS;
> > sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
> > sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
> > @@ -1939,7 +2047,8 @@ static int sdma_remove(struct platform_device
> > *pdev)
> > for (i = 0; i < MAX_DMA_CHANNELS; i++) {
> > struct sdma_channel *sdmac = &sdma->channel[i];
> >
> > - tasklet_kill(&sdmac->tasklet);
> > + tasklet_kill(&sdmac->vc.task);
> > + sdma_free_chan_resources(&sdmac->vc.chan);
> > }
> >
> > platform_set_drvdata(pdev, NULL);
> > --
> > 2.7.4
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel@lists.infradead.org
> > https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fl
> > ists.infradead.org%2Fmailman%2Flistinfo%2Flinux-arm-
> > kernel&data=02%7C01%7Cyibin.gong%40nxp.com%7C3323f6aae75e45a3155f08
> > d5bfcc314f%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C63662580608
> > 2347660&sdata=5eDirTg4boJfw0zu320d9GZTeeDwnfCPfHFY8HXt1nI%3D&reserv
> > ed=0
> >
^ permalink raw reply
* [V4,2/2] dmaengine: sprd: Add Spreadtrum DMA configuration
From: Baolin Wang @ 2018-05-23 9:31 UTC (permalink / raw)
To: dan.j.williams, vkoul
Cc: eric.long, broonie, baolin.wang, dmaengine, linux-kernel
From: Eric Long <eric.long@spreadtrum.com>
This patch adds the 'device_config' and 'device_prep_slave_sg' interfaces
for users to configure DMA, as well as adding one 'struct sprd_dma_config'
structure to save Spreadtrum DMA configuration for each DMA channel.
Signed-off-by: Eric Long <eric.long@spreadtrum.com>
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
Changes since v3:
- Remove the 'struct sprd_dma_config'.
- Optimize the sprd_dma_fill_desc() function.
- Error out for default operation when checking datawidth.
- Add some comments to explain what we do.
- Remove some current unused configuration.
Changes since v2:
- Remove src/dst from struct sprd_dma_config.
- Simplify sprd_dma_get_datawidth()/sprd_dma_get_step().
- Change some logic to make code more readable.
- Other optimization.
Changes since v1:
- Fix the incorrect parameter type of sprd_dma_get_step().
---
drivers/dma/sprd-dma.c | 182 ++++++++++++++++++++++++++++++++++++++++++
include/linux/dma/sprd-dma.h | 4 +
2 files changed, 186 insertions(+)
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 924ada4..c3161c1 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -164,6 +164,7 @@ struct sprd_dma_desc {
struct sprd_dma_chn {
struct virt_dma_chan vc;
void __iomem *chn_base;
+ struct dma_slave_config slave_cfg;
u32 chn_num;
u32 dev_id;
struct sprd_dma_desc *cur_desc;
@@ -552,6 +553,129 @@ static void sprd_dma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&schan->vc.lock, flags);
}
+static int sprd_dma_get_datawidth(enum dma_slave_buswidth buswidth)
+{
+ switch (buswidth) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ case DMA_SLAVE_BUSWIDTH_8_BYTES:
+ return ffs(buswidth) - 1;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sprd_dma_get_step(enum dma_slave_buswidth buswidth)
+{
+ switch (buswidth) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ case DMA_SLAVE_BUSWIDTH_8_BYTES:
+ return buswidth;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sprd_dma_fill_desc(struct dma_chan *chan,
+ struct sprd_dma_desc *sdesc,
+ dma_addr_t src, dma_addr_t dst, u32 len,
+ enum dma_transfer_direction dir,
+ unsigned long flags,
+ struct dma_slave_config *slave_cfg)
+{
+ struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan);
+ struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
+ struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
+ u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK;
+ u32 int_mode = flags & SPRD_DMA_INT_MASK;
+ int src_datawidth, dst_datawidth, src_step, dst_step;
+ u32 temp, fix_mode = 0, fix_en = 0;
+
+ if (dir == DMA_MEM_TO_DEV) {
+ src_step = sprd_dma_get_step(slave_cfg->src_addr_width);
+ if (src_step < 0) {
+ dev_err(sdev->dma_dev.dev, "invalid source step\n");
+ return src_step;
+ }
+ dst_step = SPRD_DMA_NONE_STEP;
+ } else {
+ dst_step = sprd_dma_get_step(slave_cfg->dst_addr_width);
+ if (dst_step < 0) {
+ dev_err(sdev->dma_dev.dev, "invalid destination step\n");
+ return dst_step;
+ }
+ src_step = SPRD_DMA_NONE_STEP;
+ }
+
+ src_datawidth = sprd_dma_get_datawidth(slave_cfg->src_addr_width);
+ if (src_datawidth < 0) {
+ dev_err(sdev->dma_dev.dev, "invalid source datawidth\n");
+ return src_datawidth;
+ }
+
+ dst_datawidth = sprd_dma_get_datawidth(slave_cfg->dst_addr_width);
+ if (dst_datawidth < 0) {
+ dev_err(sdev->dma_dev.dev, "invalid destination datawidth\n");
+ return dst_datawidth;
+ }
+
+ if (slave_cfg->slave_id)
+ schan->dev_id = slave_cfg->slave_id;
+
+ hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;
+
+ /*
+ * wrap_ptr and wrap_to will save the high 4 bits source address and
+ * destination address.
+ */
+ hw->wrap_ptr = (src >> SPRD_DMA_HIGH_ADDR_OFFSET) & SPRD_DMA_HIGH_ADDR_MASK;
+ hw->wrap_to = (dst >> SPRD_DMA_HIGH_ADDR_OFFSET) & SPRD_DMA_HIGH_ADDR_MASK;
+ hw->src_addr = src & SPRD_DMA_LOW_ADDR_MASK;
+ hw->des_addr = dst & SPRD_DMA_LOW_ADDR_MASK;
+
+ /*
+ * If the src step and dst step both are 0 or both are not 0, that means
+ * we can not enable the fix mode. If one is 0 and another one is not,
+ * we can enable the fix mode.
+ */
+ if ((src_step != 0 && dst_step != 0) || (src_step | dst_step) == 0) {
+ fix_en = 0;
+ } else {
+ fix_en = 1;
+ if (src_step)
+ fix_mode = 1;
+ else
+ fix_mode = 0;
+ }
+
+ hw->intc = int_mode | SPRD_DMA_CFG_ERR_INT_EN;
+
+ temp = src_datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET;
+ temp |= dst_datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET;
+ temp |= req_mode << SPRD_DMA_REQ_MODE_OFFSET;
+ temp |= fix_mode << SPRD_DMA_FIX_SEL_OFFSET;
+ temp |= fix_en << SPRD_DMA_FIX_EN_OFFSET;
+ temp |= slave_cfg->src_maxburst & SPRD_DMA_FRG_LEN_MASK;
+ hw->frg_len = temp;
+
+ hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK;
+ hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK;
+
+ temp = (dst_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET;
+ temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
+ hw->trsf_step = temp;
+
+ hw->frg_step = 0;
+ hw->src_blk_step = 0;
+ hw->des_blk_step = 0;
+ return 0;
+}
+
static struct dma_async_tx_descriptor *
sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
@@ -607,6 +731,62 @@ static void sprd_dma_issue_pending(struct dma_chan *chan)
return vchan_tx_prep(&schan->vc, &sdesc->vd, flags);
}
+static struct dma_async_tx_descriptor *
+sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sglen, enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
+ struct dma_slave_config *slave_cfg = &schan->slave_cfg;
+ dma_addr_t src = 0, dst = 0;
+ struct sprd_dma_desc *sdesc;
+ struct scatterlist *sg;
+ u32 len = 0;
+ int ret, i;
+
+ /* TODO: now we only support one sg for each DMA configuration. */
+ if (!is_slave_direction(dir) || sglen > 1)
+ return NULL;
+
+ sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
+ if (!sdesc)
+ return NULL;
+
+ for_each_sg(sgl, sg, sglen, i) {
+ len = sg_dma_len(sg);
+
+ if (dir == DMA_MEM_TO_DEV) {
+ src = sg_dma_address(sg);
+ dst = slave_cfg->dst_addr;
+ } else {
+ src = slave_cfg->src_addr;
+ dst = sg_dma_address(sg);
+ }
+ }
+
+ ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags,
+ slave_cfg);
+ if (ret) {
+ kfree(sdesc);
+ return NULL;
+ }
+
+ return vchan_tx_prep(&schan->vc, &sdesc->vd, flags);
+}
+
+static int sprd_dma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
+ struct dma_slave_config *slave_cfg = &schan->slave_cfg;
+
+ if (!is_slave_direction(config->direction))
+ return -EINVAL;
+
+ memcpy(slave_cfg, config, sizeof(*config));
+ return 0;
+}
+
static int sprd_dma_pause(struct dma_chan *chan)
{
struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
@@ -733,6 +913,8 @@ static int sprd_dma_probe(struct platform_device *pdev)
sdev->dma_dev.device_tx_status = sprd_dma_tx_status;
sdev->dma_dev.device_issue_pending = sprd_dma_issue_pending;
sdev->dma_dev.device_prep_dma_memcpy = sprd_dma_prep_dma_memcpy;
+ sdev->dma_dev.device_prep_slave_sg = sprd_dma_prep_slave_sg;
+ sdev->dma_dev.device_config = sprd_dma_slave_config;
sdev->dma_dev.device_pause = sprd_dma_pause;
sdev->dma_dev.device_resume = sprd_dma_resume;
sdev->dma_dev.device_terminate_all = sprd_dma_terminate_all;
diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h
index c545162..b0115e3 100644
--- a/include/linux/dma/sprd-dma.h
+++ b/include/linux/dma/sprd-dma.h
@@ -3,6 +3,10 @@
#ifndef _SPRD_DMA_H_
#define _SPRD_DMA_H_
+#define SPRD_DMA_REQ_SHIFT 16
+#define SPRD_DMA_FLAGS(req_mode, int_type) \
+ ((req_mode) << SPRD_DMA_REQ_SHIFT | (int_type))
+
/*
* enum sprd_dma_req_mode: define the DMA request mode
* @SPRD_DMA_FRAG_REQ: fragment request mode
^ permalink raw reply related
* [V4,1/2] dmaengine: sprd: Optimize the sprd_dma_prep_dma_memcpy()
From: Baolin Wang @ 2018-05-23 9:31 UTC (permalink / raw)
To: dan.j.williams, vkoul
Cc: eric.long, broonie, baolin.wang, dmaengine, linux-kernel
From: Eric Long <eric.long@spreadtrum.com>
This is one preparation patch, we can use default DMA configuration to
implement the device_prep_dma_memcpy() interface instead of issuing
sprd_dma_config().
We will implement one new sprd_dma_config() function with introducing
device_prep_slave_sg() interface in following patch. So we can remove
the obsolete sprd_dma_config() firstly.
Signed-off-by: Eric Long <eric.long@spreadtrum.com>
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
Changes since v3:
- No updates.
Changes since v2:
- Change logic to make code more readable.
Changes since v1:
- No updates.
---
drivers/dma/sprd-dma.c | 167 +++++++++++-------------------------------------
1 file changed, 39 insertions(+), 128 deletions(-)
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index e715d07..924ada4 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -552,147 +552,58 @@ static void sprd_dma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&schan->vc.lock, flags);
}
-static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc,
- dma_addr_t dest, dma_addr_t src, size_t len)
-{
- struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan);
- struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
- u32 datawidth, src_step, des_step, fragment_len;
- u32 block_len, req_mode, irq_mode, transcation_len;
- u32 fix_mode = 0, fix_en = 0;
-
- if (IS_ALIGNED(len, 4)) {
- datawidth = SPRD_DMA_DATAWIDTH_4_BYTES;
- src_step = SPRD_DMA_WORD_STEP;
- des_step = SPRD_DMA_WORD_STEP;
- } else if (IS_ALIGNED(len, 2)) {
- datawidth = SPRD_DMA_DATAWIDTH_2_BYTES;
- src_step = SPRD_DMA_SHORT_STEP;
- des_step = SPRD_DMA_SHORT_STEP;
- } else {
- datawidth = SPRD_DMA_DATAWIDTH_1_BYTE;
- src_step = SPRD_DMA_BYTE_STEP;
- des_step = SPRD_DMA_BYTE_STEP;
- }
-
- fragment_len = SPRD_DMA_MEMCPY_MIN_SIZE;
- if (len <= SPRD_DMA_BLK_LEN_MASK) {
- block_len = len;
- transcation_len = 0;
- req_mode = SPRD_DMA_BLK_REQ;
- irq_mode = SPRD_DMA_BLK_INT;
- } else {
- block_len = SPRD_DMA_MEMCPY_MIN_SIZE;
- transcation_len = len;
- req_mode = SPRD_DMA_TRANS_REQ;
- irq_mode = SPRD_DMA_TRANS_INT;
- }
-
- hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;
- hw->wrap_ptr = (u32)((src >> SPRD_DMA_HIGH_ADDR_OFFSET) &
- SPRD_DMA_HIGH_ADDR_MASK);
- hw->wrap_to = (u32)((dest >> SPRD_DMA_HIGH_ADDR_OFFSET) &
- SPRD_DMA_HIGH_ADDR_MASK);
-
- hw->src_addr = (u32)(src & SPRD_DMA_LOW_ADDR_MASK);
- hw->des_addr = (u32)(dest & SPRD_DMA_LOW_ADDR_MASK);
-
- if ((src_step != 0 && des_step != 0) || (src_step | des_step) == 0) {
- fix_en = 0;
- } else {
- fix_en = 1;
- if (src_step)
- fix_mode = 1;
- else
- fix_mode = 0;
- }
-
- hw->frg_len = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET |
- datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET |
- req_mode << SPRD_DMA_REQ_MODE_OFFSET |
- fix_mode << SPRD_DMA_FIX_SEL_OFFSET |
- fix_en << SPRD_DMA_FIX_EN_OFFSET |
- (fragment_len & SPRD_DMA_FRG_LEN_MASK);
- hw->blk_len = block_len & SPRD_DMA_BLK_LEN_MASK;
-
- hw->intc = SPRD_DMA_CFG_ERR_INT_EN;
-
- switch (irq_mode) {
- case SPRD_DMA_NO_INT:
- break;
-
- case SPRD_DMA_FRAG_INT:
- hw->intc |= SPRD_DMA_FRAG_INT_EN;
- break;
-
- case SPRD_DMA_BLK_INT:
- hw->intc |= SPRD_DMA_BLK_INT_EN;
- break;
-
- case SPRD_DMA_BLK_FRAG_INT:
- hw->intc |= SPRD_DMA_BLK_INT_EN | SPRD_DMA_FRAG_INT_EN;
- break;
-
- case SPRD_DMA_TRANS_INT:
- hw->intc |= SPRD_DMA_TRANS_INT_EN;
- break;
-
- case SPRD_DMA_TRANS_FRAG_INT:
- hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_FRAG_INT_EN;
- break;
-
- case SPRD_DMA_TRANS_BLK_INT:
- hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_BLK_INT_EN;
- break;
-
- case SPRD_DMA_LIST_INT:
- hw->intc |= SPRD_DMA_LIST_INT_EN;
- break;
-
- case SPRD_DMA_CFGERR_INT:
- hw->intc |= SPRD_DMA_CFG_ERR_INT_EN;
- break;
-
- default:
- dev_err(sdev->dma_dev.dev, "invalid irq mode\n");
- return -EINVAL;
- }
-
- if (transcation_len == 0)
- hw->trsc_len = block_len & SPRD_DMA_TRSC_LEN_MASK;
- else
- hw->trsc_len = transcation_len & SPRD_DMA_TRSC_LEN_MASK;
-
- hw->trsf_step = (des_step & SPRD_DMA_TRSF_STEP_MASK) <<
- SPRD_DMA_DEST_TRSF_STEP_OFFSET |
- (src_step & SPRD_DMA_TRSF_STEP_MASK) <<
- SPRD_DMA_SRC_TRSF_STEP_OFFSET;
-
- hw->frg_step = 0;
- hw->src_blk_step = 0;
- hw->des_blk_step = 0;
- hw->src_blk_step = 0;
- return 0;
-}
-
static struct dma_async_tx_descriptor *
sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
{
struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
struct sprd_dma_desc *sdesc;
- int ret;
+ struct sprd_dma_chn_hw *hw;
+ enum sprd_dma_datawidth datawidth;
+ u32 step, temp;
sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
if (!sdesc)
return NULL;
- ret = sprd_dma_config(chan, sdesc, dest, src, len);
- if (ret) {
- kfree(sdesc);
- return NULL;
+ hw = &sdesc->chn_hw;
+
+ hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;
+ hw->intc = SPRD_DMA_TRANS_INT | SPRD_DMA_CFG_ERR_INT_EN;
+ hw->src_addr = src & SPRD_DMA_LOW_ADDR_MASK;
+ hw->des_addr = dest & SPRD_DMA_LOW_ADDR_MASK;
+ hw->wrap_ptr = (src >> SPRD_DMA_HIGH_ADDR_OFFSET) &
+ SPRD_DMA_HIGH_ADDR_MASK;
+ hw->wrap_to = (dest >> SPRD_DMA_HIGH_ADDR_OFFSET) &
+ SPRD_DMA_HIGH_ADDR_MASK;
+
+ if (IS_ALIGNED(len, 8)) {
+ datawidth = SPRD_DMA_DATAWIDTH_8_BYTES;
+ step = SPRD_DMA_DWORD_STEP;
+ } else if (IS_ALIGNED(len, 4)) {
+ datawidth = SPRD_DMA_DATAWIDTH_4_BYTES;
+ step = SPRD_DMA_WORD_STEP;
+ } else if (IS_ALIGNED(len, 2)) {
+ datawidth = SPRD_DMA_DATAWIDTH_2_BYTES;
+ step = SPRD_DMA_SHORT_STEP;
+ } else {
+ datawidth = SPRD_DMA_DATAWIDTH_1_BYTE;
+ step = SPRD_DMA_BYTE_STEP;
}
+ temp = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET;
+ temp |= datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET;
+ temp |= SPRD_DMA_TRANS_REQ << SPRD_DMA_REQ_MODE_OFFSET;
+ temp |= len & SPRD_DMA_FRG_LEN_MASK;
+ hw->frg_len = temp;
+
+ hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK;
+ hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK;
+
+ temp = (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET;
+ temp |= (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
+ hw->trsf_step = temp;
+
return vchan_tx_prep(&schan->vc, &sdesc->vd, flags);
}
^ permalink raw reply related
* [1/3] dmaengine: imx-sdma: Switch to SPDX identifier
From: Vinod Koul @ 2018-05-23 5:41 UTC (permalink / raw)
To: Fabio Estevam; +Cc: dmaengine, Fabio Estevam
On 21-05-18, 23:53, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@nxp.com>
>
> Adopt the SPDX license identifier headers to ease license compliance
> management.
Applied all, thanks
^ permalink raw reply
* Revert "dmaengine: pl330: add DMA_PAUSE feature"
From: Vinod Koul @ 2018-05-23 5:39 UTC (permalink / raw)
To: Frank Mori Hess
Cc: Marek Szyprowski, dmaengine, linux-kernel, Dan Williams,
r.baldyga, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
Linux Samsung SOC
On 22-05-18, 10:27, Frank Mori Hess wrote:
> On Mon, May 21, 2018 at 11:37 PM, Vinod Koul <vinod.koul@linaro.org> wrote:
> >
> > Well looks like even adding support for sync_pause doesn't solve your issue on
> > pl330. Do you want to move this to PIO mode then..?
The issue for which you requested the revert of pl330 pause
> I'm not sure what you think my issue is with the pl330, are you
> confusing me with Marek? My position is that pause is unsupported by
> the pl330 at the hardware level. Nothing the pl330.c driver or
> dmaengine api or 8250 serial driver does will change that. That is
> why I sent a patch to remove pause support from pl330.c. The rest is
> just trying to fix some bugs in mainline Linux I hit when I was a
> naive youngster who thought Linux support for the computer world's
> canonical serial uart could be counted on to move data from point A to
> point B. In truth though, I've already concluded it's not worth it to
> slog though the linux kernel development process just to clean up
> other people's messes. I've already fixed my issues out-of-tree. I
> don't mind answering questions if anyone else cares about the issue
> though. Other than that, I think I'll just be ghosting out now.
~Vinod
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* dmaengine: mcf-edma: add ColdFire mcf5441x eDMA support
From: Vinod Koul @ 2018-05-23 5:37 UTC (permalink / raw)
To: Angelo Dureghello; +Cc: Vinod Koul, dmaengine, gerg, linux-m68k
On 22-05-18, 23:28, Angelo Dureghello wrote:
> Hi Vinod,
>
> On Mon, May 07, 2018 at 07:45:35PM +0530, Vinod Koul wrote:
> > On Fri, May 04, 2018 at 09:18:19PM +0200, Angelo Dureghello wrote:
> > > Hi Vinod,
> > >
> > > thanks for the review,
> > >
> > > On Thu, May 03, 2018 at 10:18:30PM +0530, Vinod Koul wrote:
> > > > On Wed, Apr 25, 2018 at 10:08:17PM +0200, Angelo Dureghello wrote:
> > > > > This patch adds dma support for NXP mcf5441x (ColdFire) family.
> > > > >
> > > > > ColdFire mcf5441x implements an edma hw module similar to the
> > > >
> > > > Is it similar to to edma ?
> > > >
> > >
> > > It is similar to Freescale "edma" but with a different number of
> > > channels, a bit different register set, different interrupt
> > > structure, no channel multiplexer.
> >
> > ok
> >
> > > > > one implemented in Vybrid VFxxx controllers, but with a slightly
> > > > > different register set, more dma channels (64 instead of 32),
> > > > > a different interrupt mechanism and some other minor differences.
> > > > >
> > > > > For the above reasons, modfying fsl-edma.c was too complex and
> > > > > likely too ugly. From here, the decision to create a different
> > > > > driver, but starting from fsl-edma.
> > > >
> > > > can the common stuff be made into a lib and shared between then two rather
> > > > than having a same driver or different drivers?
> > >
> > > It should be possible to collect some common code in a kind of
> > > mcf_edma_core.c common module, but in this case i cannot then test
> > > the Vybrid edma after the changes since i miss that hardware.
> >
> > Sure you should send the patches and folks who care about fsl driver
> > would look it up and test
> >
> > > Would be maybe possible for you to diff fsl-edma and this mcf-edma,
> > > just to confirm if i can still stay this way, or if moving to a
> > > library becomes mandatory ?
> >
> > well since you know the IP you would make a better guess on that, best is
> > to check register sets in drivers
> >
> I fixed all the discussed points.
>
> Actaully mcf-edma (ColdFire) has a slightly different register set (due to 64
> channels in place of 16 of fsl-edma) and, for the same reason, a different
> DMA interrupt structure.
> Also, i simplified some parts of the driver considering ColdFire (mcf)
> big endian architecture.
>
> So i would send a rev 2 patch with all the fixes, than eventually in a second
> phase i may try to create some common code, but at least we have the ColdFire
> DMA. What do you think ?
wouldn't it be easier to just make common parts and then add edma specific code.
If I was doing this it would be my apprach and that way code edma specific will
be lesser and faster review
^ permalink raw reply
* [1/3] dmaengine: imx-sdma: Switch to SPDX identifier
From: Vinod Koul @ 2018-05-23 5:20 UTC (permalink / raw)
To: Fabio Estevam; +Cc: dmaengine, Fabio Estevam
On 22-05-18, 08:22, Fabio Estevam wrote:
> Hi Vinod,
>
> On Tue, May 22, 2018 at 12:36 AM, Vinod Koul <vinod.koul@linaro.org> wrote:
>
> > Are you sure putting everything thru c99 style is apt. I have been told that we
> > should:
> >
> > // SPDX-License-Identifier: GPL-2.0+
> > // Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
> >
> > /*
> > * rest of the comments you would like
> > */
> >
> > essentially SPDX tag and copyright should be c99 so that tools can parse, rest
> > information can be in regular linux comment style
>
> Putting everything as // is Linus' preferred style:
> https://lkml.org/lkml/2017/11/25/133
Sadly it is not documented, only SPDX tags are in
Documentation/process/license-rules.rst
^ permalink raw reply
* [-next] dmaengine: sprd: Fix return value check in sprd_dma_probe()
From: Baolin Wang @ 2018-05-23 1:57 UTC (permalink / raw)
To: Wei Yongjun
Cc: Dan Williams, Vinod Koul, Orson Zhai, Chunyan Zhang, dmaengine,
kernel-janitors
Hi,
On 22 May 2018 at 19:48, Wei Yongjun <weiyongjun1@huawei.com> wrote:
> In case of error, the function devm_ioremap_resource() returns ERR_PTR()
> and never returns NULL. The NULL test in the return value check should
> be replaced with IS_ERR().
>
> Fixes: e7f063ae1a31 ("dmaengine: sprd: Use devm_ioremap_resource() to map memory")
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Thanks, but we already had a fix for this issue:
https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/slave-dma.git/commit/?h=topic/sprd&id=fd8d26adc9a909c0c099265cb62d5e5ec2a87e7e
^ permalink raw reply
* [2/2] dmaengine: rcar-dmac: Document R8A77990 bindings
From: Rob Herring @ 2018-05-22 22:58 UTC (permalink / raw)
To: Ulrich Hecht
Cc: linux-renesas-soc, horms, dmaengine, devicetree,
Hiroyuki Yokoyama
On Wed, May 16, 2018 at 03:06:19PM +0200, Ulrich Hecht wrote:
> From: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
>
> Renesas R-Car E3 (R8A77990) SoC also has the R-Car gen2/3 compatible DMA
> controllers, so document the SoC specific binding.
>
> Signed-off-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
> Signed-off-by: Ulrich Hecht <ulrich.hecht+renesas@gmail.com>
> ---
> Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt | 1 +
> 1 file changed, 1 insertion(+)
Acked-by: Rob Herring <robh@kernel.org>
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* dmaengine: mcf-edma: add ColdFire mcf5441x eDMA support
From: Angelo Dureghello @ 2018-05-22 21:28 UTC (permalink / raw)
To: Vinod Koul; +Cc: Vinod Koul, dmaengine, gerg, linux-m68k, vkoul
Hi Vinod,
On Mon, May 07, 2018 at 07:45:35PM +0530, Vinod Koul wrote:
> On Fri, May 04, 2018 at 09:18:19PM +0200, Angelo Dureghello wrote:
> > Hi Vinod,
> >
> > thanks for the review,
> >
> > On Thu, May 03, 2018 at 10:18:30PM +0530, Vinod Koul wrote:
> > > On Wed, Apr 25, 2018 at 10:08:17PM +0200, Angelo Dureghello wrote:
> > > > This patch adds dma support for NXP mcf5441x (ColdFire) family.
> > > >
> > > > ColdFire mcf5441x implements an edma hw module similar to the
> > >
> > > Is it similar to to edma ?
> > >
> >
> > It is similar to Freescale "edma" but with a different number of
> > channels, a bit different register set, different interrupt
> > structure, no channel multiplexer.
>
> ok
>
> > > > one implemented in Vybrid VFxxx controllers, but with a slightly
> > > > different register set, more dma channels (64 instead of 32),
> > > > a different interrupt mechanism and some other minor differences.
> > > >
> > > > For the above reasons, modfying fsl-edma.c was too complex and
> > > > likely too ugly. From here, the decision to create a different
> > > > driver, but starting from fsl-edma.
> > >
> > > can the common stuff be made into a lib and shared between then two rather
> > > than having a same driver or different drivers?
> >
> > It should be possible to collect some common code in a kind of
> > mcf_edma_core.c common module, but in this case i cannot then test
> > the Vybrid edma after the changes since i miss that hardware.
>
> Sure you should send the patches and folks who care about fsl driver
> would look it up and test
>
> > Would be maybe possible for you to diff fsl-edma and this mcf-edma,
> > just to confirm if i can still stay this way, or if moving to a
> > library becomes mandatory ?
>
> well since you know the IP you would make a better guess on that, best is
> to check register sets in drivers
>
I fixed all the discussed points.
Actaully mcf-edma (ColdFire) has a slightly different register set (due to 64
channels in place of 16 of fsl-edma) and, for the same reason, a different
DMA interrupt structure.
Also, i simplified some parts of the driver considering ColdFire (mcf)
big endian architecture.
So i would send a rev 2 patch with all the fixes, than eventually in a second
phase i may try to create some common code, but at least we have the ColdFire
DMA. What do you think ?
> > > > +// SPDX-License-Identifier: GPL-2.0
> > >
> > > Copyright info should be here in c99 style comments
> > >
> >
> > Seems checkpatch.pl, for C files, does not like the C style
> > initial line comment:
> >
> > WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
> > #87: FILE: drivers/dma/mcf-edma.c:1:
> > +/* SPDX-License-Identifier: GPL-2.0 */
> >
> > While c++ type is accepted.
> >
> > In contrary, in .h files it wants cpp // style and not C style.
>
> SC99 comments style is
> // SPDX-License-Identifier: GPL-2.0
>
> Point is the copyright should be added is same formar i.e.,
>
> // Copyright 20018 - foo bar
>
> this line should follow the spdx line
>
> > > > +
> > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > >
> > > why do you need this, why not use dev_xxx
> > >
> >
> > Well, pr_ style seems to simplify the call a bit, should be allowed
> > but if you prefer i can move all to dev_ format.
>
> in hindsight dev_ makes better sense, been there done that :)
>
> --
> ~Vinod
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Regards,
Angelo
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [v1] dmaengine: imx-sdma: add virt-dma support
From: Robin Gong @ 2018-05-22 15:45 UTC (permalink / raw)
To: dan.j.williams, vkoul, dmaengine, linux-kernel; +Cc: linux-imx
The legacy sdma driver has below limitations or drawbacks:
1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
one page size for one channel regardless of only few BDs needed
most time. But in few cases, the max PAGE_SIZE maybe not enough.
2. One SDMA channel can't stop immediatley once channel disabled which
means SDMA interrupt may come in after this channel terminated.There
are some patches for this corner case such as commit "2746e2c389f9",
but not cover non-cyclic.
The common virt-dma overcomes the above limitations. It can alloc bd
dynamically and free bd once this tx transfer done. No memory wasted or
maximum limititation here, only depends on how many memory can be requested
from kernel. For No.2, such issue can be workaround by checking if there
is available descript("sdmac->desc") now once the unwanted interrupt
coming. At last the common virt-dma is easier for sdma driver maintain.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
drivers/dma/Kconfig | 1 +
drivers/dma/imx-sdma.c | 395 +++++++++++++++++++++++++++++++------------------
2 files changed, 253 insertions(+), 143 deletions(-)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ca1680a..d4a4230 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -250,6 +250,7 @@ config IMX_SDMA
tristate "i.MX SDMA support"
depends on ARCH_MXC
select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
help
Support the i.MX SDMA engine. This engine is integrated into
Freescale i.MX25/31/35/51/53/6 chips.
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index ccd03c3..df79e73 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -48,6 +48,7 @@
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include "dmaengine.h"
+#include "virt-dma.h"
/* SDMA registers */
#define SDMA_H_C0PTR 0x000
@@ -291,10 +292,19 @@ struct sdma_context_data {
u32 scratch7;
} __attribute__ ((packed));
-#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
-
struct sdma_engine;
+struct sdma_desc {
+ struct virt_dma_desc vd;
+ struct list_head node;
+ unsigned int num_bd;
+ dma_addr_t bd_phys;
+ unsigned int buf_tail;
+ unsigned int buf_ptail;
+ struct sdma_channel *sdmac;
+ struct sdma_buffer_descriptor *bd;
+};
+
/**
* struct sdma_channel - housekeeping for a SDMA channel
*
@@ -310,19 +320,17 @@ struct sdma_engine;
* @num_bd max NUM_BD. number of descriptors currently handling
*/
struct sdma_channel {
+ struct virt_dma_chan vc;
+ struct list_head pending;
struct sdma_engine *sdma;
+ struct sdma_desc *desc;
unsigned int channel;
enum dma_transfer_direction direction;
enum sdma_peripheral_type peripheral_type;
unsigned int event_id0;
unsigned int event_id1;
enum dma_slave_buswidth word_size;
- unsigned int buf_tail;
- unsigned int buf_ptail;
- unsigned int num_bd;
unsigned int period_len;
- struct sdma_buffer_descriptor *bd;
- dma_addr_t bd_phys;
unsigned int pc_from_device, pc_to_device;
unsigned int device_to_device;
unsigned long flags;
@@ -330,15 +338,12 @@ struct sdma_channel {
unsigned long event_mask[2];
unsigned long watermark_level;
u32 shp_addr, per_addr;
- struct dma_chan chan;
- spinlock_t lock;
- struct dma_async_tx_descriptor desc;
enum dma_status status;
unsigned int chn_count;
unsigned int chn_real_count;
- struct tasklet_struct tasklet;
struct imx_dma_data data;
bool enabled;
+ u32 bd_size_sum;
};
#define IMX_DMA_SG_LOOP BIT(0)
@@ -398,6 +403,9 @@ struct sdma_engine {
u32 spba_start_addr;
u32 spba_end_addr;
unsigned int irq;
+ /* channel0 bd */
+ dma_addr_t bd0_phys;
+ struct sdma_buffer_descriptor *bd0;
};
static struct sdma_driver_data sdma_imx31 = {
@@ -553,6 +561,8 @@ MODULE_DEVICE_TABLE(of, sdma_dt_ids);
#define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq /core freq = 2 or 1 */
#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
+static void sdma_start_desc(struct sdma_channel *sdmac);
+
static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
{
u32 chnenbl0 = sdma->drvdata->chnenbl0;
@@ -597,14 +607,7 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
{
- unsigned long flags;
- struct sdma_channel *sdmac = &sdma->channel[channel];
-
writel(BIT(channel), sdma->regs + SDMA_H_START);
-
- spin_lock_irqsave(&sdmac->lock, flags);
- sdmac->enabled = true;
- spin_unlock_irqrestore(&sdmac->lock, flags);
}
/*
@@ -632,7 +635,7 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
u32 address)
{
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
void *buf_virt;
dma_addr_t buf_phys;
int ret;
@@ -691,23 +694,16 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
static void sdma_update_channel_loop(struct sdma_channel *sdmac)
{
struct sdma_buffer_descriptor *bd;
+ struct sdma_desc *desc = sdmac->desc;
int error = 0;
enum dma_status old_status = sdmac->status;
- unsigned long flags;
-
- spin_lock_irqsave(&sdmac->lock, flags);
- if (!sdmac->enabled) {
- spin_unlock_irqrestore(&sdmac->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&sdmac->lock, flags);
/*
* loop mode. Iterate over descriptors, re-setup them and
* call callback function.
*/
- while (1) {
- bd = &sdmac->bd[sdmac->buf_tail];
+ while (desc) {
+ bd = &desc->bd[desc->buf_tail];
if (bd->mode.status & BD_DONE)
break;
@@ -726,8 +722,8 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
sdmac->chn_real_count = bd->mode.count;
bd->mode.status |= BD_DONE;
bd->mode.count = sdmac->period_len;
- sdmac->buf_ptail = sdmac->buf_tail;
- sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd;
+ desc->buf_ptail = desc->buf_tail;
+ desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
/*
* The callback is called from the interrupt context in order
@@ -735,15 +731,16 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* SDMA transaction status by the time the client tasklet is
* executed.
*/
-
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
+ spin_unlock(&sdmac->vc.lock);
+ dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
+ spin_lock(&sdmac->vc.lock);
if (error)
sdmac->status = old_status;
}
}
-static void mxc_sdma_handle_channel_normal(unsigned long data)
+static void mxc_sdma_handle_channel_normal(struct sdma_channel *data)
{
struct sdma_channel *sdmac = (struct sdma_channel *) data;
struct sdma_buffer_descriptor *bd;
@@ -754,8 +751,8 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
* non loop mode. Iterate over all descriptors, collect
* errors and call callback function
*/
- for (i = 0; i < sdmac->num_bd; i++) {
- bd = &sdmac->bd[i];
+ for (i = 0; i < sdmac->desc->num_bd; i++) {
+ bd = &sdmac->desc->bd[i];
if (bd->mode.status & (BD_DONE | BD_RROR))
error = -EIO;
@@ -766,10 +763,6 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
sdmac->status = DMA_ERROR;
else
sdmac->status = DMA_COMPLETE;
-
- dma_cookie_complete(&sdmac->desc);
-
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
}
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -785,13 +778,24 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
while (stat) {
int channel = fls(stat) - 1;
struct sdma_channel *sdmac = &sdma->channel[channel];
-
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- sdma_update_channel_loop(sdmac);
- else
- tasklet_schedule(&sdmac->tasklet);
+ struct sdma_desc *desc;
+
+ spin_lock(&sdmac->vc.lock);
+ desc = sdmac->desc;
+ if (desc) {
+ if (sdmac->flags & IMX_DMA_SG_LOOP) {
+ sdma_update_channel_loop(sdmac);
+ } else {
+ mxc_sdma_handle_channel_normal(sdmac);
+ vchan_cookie_complete(&desc->vd);
+ if (!list_empty(&sdmac->pending))
+ list_del(&desc->node);
+ sdma_start_desc(sdmac);
+ }
+ }
__clear_bit(channel, &stat);
+ spin_unlock(&sdmac->vc.lock);
}
return IRQ_HANDLED;
@@ -897,7 +901,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
int channel = sdmac->channel;
int load_address;
struct sdma_context_data *context = sdma->context;
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
int ret;
unsigned long flags;
@@ -946,7 +950,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
{
- return container_of(chan, struct sdma_channel, chan);
+ return container_of(chan, struct sdma_channel, vc.chan);
}
static int sdma_disable_channel(struct dma_chan *chan)
@@ -954,15 +958,10 @@ static int sdma_disable_channel(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
- unsigned long flags;
writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
sdmac->status = DMA_ERROR;
- spin_lock_irqsave(&sdmac->lock, flags);
- sdmac->enabled = false;
- spin_unlock_irqrestore(&sdmac->lock, flags);
-
return 0;
}
@@ -1097,42 +1096,101 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
return 0;
}
-static int sdma_request_channel(struct sdma_channel *sdmac)
+static int sdma_alloc_bd(struct sdma_desc *desc)
{
- struct sdma_engine *sdma = sdmac->sdma;
- int channel = sdmac->channel;
- int ret = -EBUSY;
+ u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+ int ret = 0;
+ unsigned long flags;
- sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys,
+ desc->bd = dma_zalloc_coherent(NULL, bd_size, &desc->bd_phys,
GFP_KERNEL);
- if (!sdmac->bd) {
+ if (!desc->bd) {
ret = -ENOMEM;
goto out;
}
- sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
+ desc->sdmac->bd_size_sum += bd_size;
+ spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
- sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
- return 0;
out:
-
return ret;
}
-static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
+static void sdma_free_bd(struct sdma_desc *desc)
{
+ u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
unsigned long flags;
- struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
- dma_cookie_t cookie;
- spin_lock_irqsave(&sdmac->lock, flags);
+ if (desc->bd) {
+ dma_free_coherent(NULL, bd_size, desc->bd, desc->bd_phys);
+
+ spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
+ desc->sdmac->bd_size_sum -= bd_size;
+ spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
+ }
+}
+
+static int sdma_request_channel0(struct sdma_engine *sdma)
+{
+ int ret = 0;
+
+ sdma->bd0 = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdma->bd0_phys,
+ GFP_KERNEL);
+ if (!sdma->bd0) {
+ ret = -ENOMEM;
+ goto out;
+ }
- cookie = dma_cookie_assign(tx);
+ sdma->channel_control[0].base_bd_ptr = sdma->bd0_phys;
+ sdma->channel_control[0].current_bd_ptr = sdma->bd0_phys;
- spin_unlock_irqrestore(&sdmac->lock, flags);
+ sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY);
+out:
- return cookie;
+ return ret;
+}
+
+static struct sdma_desc *to_sdma_desc(struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct sdma_desc, vd.tx);
+}
+
+static void sdma_desc_free(struct virt_dma_desc *vd)
+{
+ struct sdma_desc *desc = container_of(vd, struct sdma_desc, vd);
+
+ if (desc) {
+ sdma_free_bd(desc);
+ kfree(desc);
+ }
+}
+
+static int sdma_terminate_all(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ vchan_get_all_descriptors(&sdmac->vc, &head);
+ while (!list_empty(&sdmac->pending)) {
+ struct sdma_desc *desc = list_first_entry(&sdmac->pending,
+ struct sdma_desc, node);
+
+ list_del(&desc->node);
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+ sdmac->vc.desc_free(&desc->vd);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ }
+
+ if (sdmac->desc)
+ sdmac->desc = NULL;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+ vchan_dma_desc_free_list(&sdmac->vc, &head);
+ sdma_disable_channel_with_delay(chan);
+
+ return 0;
}
static int sdma_alloc_chan_resources(struct dma_chan *chan)
@@ -1168,18 +1226,11 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
if (ret)
goto disable_clk_ipg;
- ret = sdma_request_channel(sdmac);
- if (ret)
- goto disable_clk_ahb;
-
ret = sdma_set_channel_priority(sdmac, prio);
if (ret)
goto disable_clk_ahb;
- dma_async_tx_descriptor_init(&sdmac->desc, chan);
- sdmac->desc.tx_submit = sdma_tx_submit;
- /* txd.flags will be overwritten in prep funcs */
- sdmac->desc.flags = DMA_CTRL_ACK;
+ sdmac->bd_size_sum = 0;
return 0;
@@ -1195,7 +1246,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- sdma_disable_channel(chan);
+ sdma_terminate_all(chan);
if (sdmac->event_id0)
sdma_event_disable(sdmac, sdmac->event_id0);
@@ -1207,12 +1258,43 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
- dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
-
clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb);
}
+static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
+ enum dma_transfer_direction direction, u32 bds)
+{
+ struct sdma_desc *desc;
+
+ desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+ if (!desc)
+ goto err_out;
+
+ sdmac->status = DMA_IN_PROGRESS;
+ sdmac->direction = direction;
+ sdmac->flags = 0;
+ sdmac->chn_count = 0;
+ sdmac->chn_real_count = 0;
+
+ desc->sdmac = sdmac;
+ desc->num_bd = bds;
+ INIT_LIST_HEAD(&desc->node);
+
+ if (sdma_alloc_bd(desc))
+ goto err_desc_out;
+
+ if (sdma_load_context(sdmac))
+ goto err_desc_out;
+
+ return desc;
+
+err_desc_out:
+ kfree(desc);
+err_out:
+ return NULL;
+}
+
static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@@ -1223,35 +1305,24 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
int ret, i, count;
int channel = sdmac->channel;
struct scatterlist *sg;
+ struct sdma_desc *desc;
- if (sdmac->status == DMA_IN_PROGRESS)
+ if (!chan)
return NULL;
- sdmac->status = DMA_IN_PROGRESS;
-
- sdmac->flags = 0;
- sdmac->buf_tail = 0;
- sdmac->buf_ptail = 0;
- sdmac->chn_real_count = 0;
+ desc = sdma_transfer_init(sdmac, direction, sg_len);
+ if (!desc)
+ goto err_out;
dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
sg_len, channel);
- sdmac->direction = direction;
ret = sdma_load_context(sdmac);
if (ret)
goto err_out;
- if (sg_len > NUM_BD) {
- dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- channel, sg_len, NUM_BD);
- ret = -EINVAL;
- goto err_out;
- }
-
- sdmac->chn_count = 0;
for_each_sg(sgl, sg, sg_len, i) {
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
bd->buffer_addr = sg->dma_address;
@@ -1262,7 +1333,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
channel, count, 0xffff);
ret = -EINVAL;
- goto err_out;
+ goto err_bd_out;
}
bd->mode.count = count;
@@ -1307,10 +1378,11 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
bd->mode.status = param;
}
- sdmac->num_bd = sg_len;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
- return &sdmac->desc;
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
err_out:
sdmac->status = DMA_ERROR;
return NULL;
@@ -1326,39 +1398,32 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
int num_periods = buf_len / period_len;
int channel = sdmac->channel;
int ret, i = 0, buf = 0;
+ struct sdma_desc *desc;
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
- if (sdmac->status == DMA_IN_PROGRESS)
- return NULL;
-
- sdmac->status = DMA_IN_PROGRESS;
+ /* Now allocate and setup the descriptor. */
+ desc = sdma_transfer_init(sdmac, direction, num_periods);
+ if (!desc)
+ goto err_out;
- sdmac->buf_tail = 0;
- sdmac->buf_ptail = 0;
- sdmac->chn_real_count = 0;
+ desc->buf_tail = 0;
+ desc->buf_ptail = 0;
sdmac->period_len = period_len;
-
sdmac->flags |= IMX_DMA_SG_LOOP;
- sdmac->direction = direction;
+
ret = sdma_load_context(sdmac);
if (ret)
goto err_out;
- if (num_periods > NUM_BD) {
- dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- channel, num_periods, NUM_BD);
- goto err_out;
- }
-
if (period_len > 0xffff) {
dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
channel, period_len, 0xffff);
- goto err_out;
+ goto err_bd_out;
}
while (buf < buf_len) {
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
bd->buffer_addr = dma_addr;
@@ -1366,7 +1431,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
bd->mode.count = period_len;
if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
- goto err_out;
+ goto err_bd_out;
if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
bd->mode.command = 0;
else
@@ -1389,10 +1454,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
i++;
}
- sdmac->num_bd = num_periods;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
-
- return &sdmac->desc;
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
err_out:
sdmac->status = DMA_ERROR;
return NULL;
@@ -1432,26 +1497,74 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
u32 residue;
+ struct virt_dma_desc *vd;
+ struct sdma_desc *desc;
+ enum dma_status ret;
+ unsigned long flags;
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- residue = (sdmac->num_bd - sdmac->buf_ptail) *
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_COMPLETE && txstate) {
+ residue = sdmac->chn_count - sdmac->chn_real_count;
+ return ret;
+ }
+
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ vd = vchan_find_desc(&sdmac->vc, cookie);
+ desc = to_sdma_desc(&vd->tx);
+ if (vd) {
+ if (sdmac->flags & IMX_DMA_SG_LOOP)
+ residue = (desc->num_bd - desc->buf_ptail) *
sdmac->period_len - sdmac->chn_real_count;
- else
+ else
+ residue = sdmac->chn_count - sdmac->chn_real_count;
+ } else if (sdmac->desc && sdmac->desc->vd.tx.cookie == cookie) {
residue = sdmac->chn_count - sdmac->chn_real_count;
+ } else {
+ residue = 0;
+ }
+ ret = sdmac->status;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
residue);
- return sdmac->status;
+ return ret;
+}
+
+static void sdma_start_desc(struct sdma_channel *sdmac)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
+ struct sdma_desc *desc;
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
+
+ if (!vd) {
+ sdmac->desc = NULL;
+ return;
+ }
+ sdmac->desc = desc = to_sdma_desc(&vd->tx);
+ /*
+ * Do not delete the node in desc_issued list in cyclic mode, otherwise
+ * the desc alloced will never be freed in vchan_dma_desc_free_list
+ */
+ if (!(sdmac->flags & IMX_DMA_SG_LOOP)) {
+ list_add_tail(&sdmac->desc->node, &sdmac->pending);
+ list_del(&vd->node);
+ }
+ sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
+ sdma_enable_channel(sdma, sdmac->channel);
}
static void sdma_issue_pending(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
- struct sdma_engine *sdma = sdmac->sdma;
+ unsigned long flags;
- if (sdmac->status == DMA_IN_PROGRESS)
- sdma_enable_channel(sdma, sdmac->channel);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
+ sdma_start_desc(sdmac);
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
}
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
@@ -1657,7 +1770,7 @@ static int sdma_init(struct sdma_engine *sdma)
for (i = 0; i < MAX_DMA_CHANNELS; i++)
writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
- ret = sdma_request_channel(&sdma->channel[0]);
+ ret = sdma_request_channel0(sdma);
if (ret)
goto err_dma_alloc;
@@ -1819,22 +1932,17 @@ static int sdma_probe(struct platform_device *pdev)
struct sdma_channel *sdmac = &sdma->channel[i];
sdmac->sdma = sdma;
- spin_lock_init(&sdmac->lock);
-
- sdmac->chan.device = &sdma->dma_device;
- dma_cookie_init(&sdmac->chan);
sdmac->channel = i;
-
- tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
- (unsigned long) sdmac);
+ sdmac->status = DMA_IN_PROGRESS;
+ sdmac->vc.desc_free = sdma_desc_free;
+ INIT_LIST_HEAD(&sdmac->pending);
/*
* Add the channel to the DMAC list. Do not add channel 0 though
* because we need it internally in the SDMA driver. This also means
* that channel 0 in dmaengine counting matches sdma channel 1.
*/
if (i)
- list_add_tail(&sdmac->chan.device_node,
- &sdma->dma_device.channels);
+ vchan_init(&sdmac->vc, &sdma->dma_device);
}
ret = sdma_init(sdma);
@@ -1879,7 +1987,7 @@ static int sdma_probe(struct platform_device *pdev)
sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
sdma->dma_device.device_config = sdma_config;
- sdma->dma_device.device_terminate_all = sdma_disable_channel_with_delay;
+ sdma->dma_device.device_terminate_all = sdma_terminate_all;
sdma->dma_device.src_addr_widths = SDMA_DMA_BUSWIDTHS;
sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
@@ -1939,7 +2047,8 @@ static int sdma_remove(struct platform_device *pdev)
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
- tasklet_kill(&sdmac->tasklet);
+ tasklet_kill(&sdmac->vc.task);
+ sdma_free_chan_resources(&sdmac->vc.chan);
}
platform_set_drvdata(pdev, NULL);
^ permalink raw reply related
* Revert "dmaengine: pl330: add DMA_PAUSE feature"
From: Frank Mori Hess @ 2018-05-22 14:27 UTC (permalink / raw)
To: Vinod Koul
Cc: Marek Szyprowski, dmaengine, linux-kernel, Dan Williams,
r.baldyga, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
Linux Samsung SOC
On Mon, May 21, 2018 at 11:37 PM, Vinod Koul <vinod.koul@linaro.org> wrote:
>
> Well looks like even adding support for sync_pause doesn't solve your issue on
> pl330. Do you want to move this to PIO mode then..?
>
I'm not sure what you think my issue is with the pl330, are you
confusing me with Marek? My position is that pause is unsupported by
the pl330 at the hardware level. Nothing the pl330.c driver or
dmaengine api or 8250 serial driver does will change that. That is
why I sent a patch to remove pause support from pl330.c. The rest is
just trying to fix some bugs in mainline Linux I hit when I was a
naive youngster who thought Linux support for the computer world's
canonical serial uart could be counted on to move data from point A to
point B. In truth though, I've already concluded it's not worth it to
slog though the linux kernel development process just to clean up
other people's messes. I've already fixed my issues out-of-tree. I
don't mind answering questions if anyone else cares about the issue
though. Other than that, I think I'll just be ghosting out now.
^ permalink raw reply
* [-next] dmaengine: sprd: Fix return value check in sprd_dma_probe()
From: weiyongjun (A) @ 2018-05-22 11:48 UTC (permalink / raw)
To: Dan Williams, Vinod Koul, Orson Zhai, Baolin Wang, Chunyan Zhang
Cc: Wei Yongjun, dmaengine, kernel-janitors
In case of error, the function devm_ioremap_resource() returns ERR_PTR()
and never returns NULL. The NULL test in the return value check should
be replaced with IS_ERR().
Fixes: e7f063ae1a31 ("dmaengine: sprd: Use devm_ioremap_resource() to map memory")
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/dma/sprd-dma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index e715d07..36df3b0 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -808,8 +808,8 @@ static int sprd_dma_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sdev->glb_base = devm_ioremap_resource(&pdev->dev, res);
- if (!sdev->glb_base)
- return -ENOMEM;
+ if (IS_ERR(sdev->glb_base))
+ return PTR_ERR(sdev->glb_base);
dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask);
sdev->total_chns = chn_count;
^ permalink raw reply related
* [1/3] dmaengine: imx-sdma: Switch to SPDX identifier
From: Fabio Estevam @ 2018-05-22 11:22 UTC (permalink / raw)
To: Vinod Koul; +Cc: dmaengine, Fabio Estevam
Hi Vinod,
On Tue, May 22, 2018 at 12:36 AM, Vinod Koul <vinod.koul@linaro.org> wrote:
> Are you sure putting everything thru c99 style is apt. I have been told that we
> should:
>
> // SPDX-License-Identifier: GPL-2.0+
> // Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
>
> /*
> * rest of the comments you would like
> */
>
> essentially SPDX tag and copyright should be c99 so that tools can parse, rest
> information can be in regular linux comment style
Putting everything as // is Linus' preferred style:
https://lkml.org/lkml/2017/11/25/133
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox