* [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature
@ 2017-10-17 13:43 Pierre-Yves MORDRET
2017-10-17 14:26 ` Benjamin Gaignard
2017-11-08 5:20 ` Vinod Koul
0 siblings, 2 replies; 4+ messages in thread
From: Pierre-Yves MORDRET @ 2017-10-17 13:43 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Mark Rutland, Maxime Coquelin,
Alexandre Torgue, Russell King, Dan Williams,
M'boumba Cedric Madianga, Fabrice GASNIER, Herbert Xu,
Fabien DESSENNE, Amelie Delaunay, Pierre-Yves MORDRET, dmaengine,
devicetree, linux-arm-kernel, linux-kernel
If source and destination bus width differs pack/unpack MDMA
feature has to be activated for alignment.
This pack/unpack feature implies to have both source/destination address
and buffer length aligned on bus width.
Fixes: a4ffb13c8946 ("dmaengine: Add STM32 MDMA driver")
Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
---
drivers/dma/stm32-mdma.c | 84 ++++++++++++++++++++++++++++--------------------
1 file changed, 50 insertions(+), 34 deletions(-)
diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
index d3be6bf..daa1602 100644
--- a/drivers/dma/stm32-mdma.c
+++ b/drivers/dma/stm32-mdma.c
@@ -387,14 +387,20 @@ static int stm32_mdma_get_width(struct stm32_mdma_chan *chan,
}
}
-static enum dma_slave_buswidth stm32_mdma_get_max_width(u32 buf_len, u32 tlen)
+static enum dma_slave_buswidth stm32_mdma_get_max_width(dma_addr_t addr,
+ u32 buf_len, u32 tlen)
{
enum dma_slave_buswidth max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
for (max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
max_width > DMA_SLAVE_BUSWIDTH_1_BYTE;
max_width >>= 1) {
- if (((buf_len % max_width) == 0) && (tlen >= max_width))
+ /*
+ * Address and buffer length both have to be aligned on
+ * bus width
+ */
+ if ((((buf_len | addr) & (max_width - 1)) == 0) &&
+ tlen >= max_width)
break;
}
@@ -486,7 +492,8 @@ static void stm32_mdma_set_bus(struct stm32_mdma_device *dmadev, u32 *ctbr,
static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
enum dma_transfer_direction direction,
u32 *mdma_ccr, u32 *mdma_ctcr,
- u32 *mdma_ctbr, u32 buf_len)
+ u32 *mdma_ctbr, dma_addr_t addr,
+ u32 buf_len)
{
struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
@@ -520,6 +527,9 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
ctcr &= ~STM32_MDMA_CTCR_LEN2_MSK;
ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
+ /* Disable Pack Enable */
+ ctcr &= ~STM32_MDMA_CTCR_PKE;
+
/* Check burst size constraints */
if (src_maxburst * src_addr_width > STM32_MDMA_MAX_BURST ||
dst_maxburst * dst_addr_width > STM32_MDMA_MAX_BURST) {
@@ -551,6 +561,8 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
switch (direction) {
case DMA_MEM_TO_DEV:
+ dst_addr = chan->dma_config.dst_addr;
+
/* Set device data size */
dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
if (dst_bus_width < 0)
@@ -567,7 +579,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
/* Set memory data size */
- src_addr_width = stm32_mdma_get_max_width(buf_len, tlen);
+ src_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
chan->mem_width = src_addr_width;
src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
if (src_bus_width < 0)
@@ -587,15 +599,19 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
/* Select bus */
- dst_addr = chan->dma_config.dst_addr;
stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
dst_addr);
+ if (dst_bus_width != src_bus_width)
+ ctcr |= STM32_MDMA_CTCR_PKE;
+
/* Set destination address */
stm32_mdma_write(dmadev, STM32_MDMA_CDAR(chan->id), dst_addr);
break;
case DMA_DEV_TO_MEM:
+ src_addr = chan->dma_config.src_addr;
+
/* Set device data size */
src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
if (src_bus_width < 0)
@@ -611,7 +627,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
/* Set memory data size */
- dst_addr_width = stm32_mdma_get_max_width(buf_len, tlen);
+ dst_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
chan->mem_width = dst_addr_width;
dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
if (dst_bus_width < 0)
@@ -630,10 +646,12 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
/* Select bus */
- src_addr = chan->dma_config.src_addr;
stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
src_addr);
+ if (dst_bus_width != src_bus_width)
+ ctcr |= STM32_MDMA_CTCR_PKE;
+
/* Set source address */
stm32_mdma_write(dmadev, STM32_MDMA_CSAR(chan->id), src_addr);
break;
@@ -719,23 +737,27 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
return -EINVAL;
}
- ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
- &ctbr, sg_dma_len(sg));
- if (ret < 0)
- return ret;
-
if (direction == DMA_MEM_TO_DEV) {
src_addr = sg_dma_address(sg);
dst_addr = dma_config->dst_addr;
+ ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
+ &ctcr, &ctbr, src_addr,
+ sg_dma_len(sg));
stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
src_addr);
} else {
src_addr = dma_config->src_addr;
dst_addr = sg_dma_address(sg);
+ ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
+ &ctcr, &ctbr, dst_addr,
+ sg_dma_len(sg));
stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
dst_addr);
}
+ if (ret < 0)
+ return ret;
+
stm32_mdma_setup_hwdesc(chan, desc, direction, i, src_addr,
dst_addr, sg_dma_len(sg), ctcr, ctbr,
i == sg_len - 1, i == 0, false);
@@ -830,27 +852,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr,
if (!desc)
return NULL;
- ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr,
- period_len);
- if (ret < 0)
- goto xfer_setup_err;
-
- /* Enable interrupts */
- ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
- ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
- desc->ccr = ccr;
-
/* Select bus */
if (direction == DMA_MEM_TO_DEV) {
src_addr = buf_addr;
+ ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
+ &ctbr, src_addr, period_len);
stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
src_addr);
} else {
dst_addr = buf_addr;
+ ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
+ &ctbr, dst_addr, period_len);
stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
dst_addr);
}
+ if (ret < 0)
+ goto xfer_setup_err;
+
+ /* Enable interrupts */
+ ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
+ ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
+ desc->ccr = ccr;
+
/* Configure hwdesc list */
for (i = 0; i < count; i++) {
if (direction == DMA_MEM_TO_DEV) {
@@ -956,9 +980,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
/* Set source best burst size */
- max_width = stm32_mdma_get_max_width(len, tlen);
- if (src % max_width)
- max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ max_width = stm32_mdma_get_max_width(src, len, tlen);
src_bus_width = stm32_mdma_get_width(chan, max_width);
max_burst = tlen / max_width;
@@ -971,9 +993,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
STM32_MDMA_CTCR_SINCOS(src_bus_width);
/* Set destination best burst size */
- max_width = stm32_mdma_get_max_width(len, tlen);
- if (dest % max_width)
- max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ max_width = stm32_mdma_get_max_width(dest, len, tlen);
dst_bus_width = stm32_mdma_get_width(chan, max_width);
max_burst = tlen / max_width;
@@ -1014,9 +1034,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
STM32_MDMA_MAX_BLOCK_LEN);
/* Set source best burst size */
- max_width = stm32_mdma_get_max_width(len, tlen);
- if (src % max_width)
- max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ max_width = stm32_mdma_get_max_width(src, len, tlen);
src_bus_width = stm32_mdma_get_width(chan, max_width);
max_burst = tlen / max_width;
@@ -1030,9 +1048,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
STM32_MDMA_CTCR_SINCOS(src_bus_width);
/* Set destination best burst size */
- max_width = stm32_mdma_get_max_width(len, tlen);
- if (dest % max_width)
- max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ max_width = stm32_mdma_get_max_width(dest, len, tlen);
dst_bus_width = stm32_mdma_get_width(chan, max_width);
max_burst = tlen / max_width;
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature
2017-10-17 13:43 [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature Pierre-Yves MORDRET
@ 2017-10-17 14:26 ` Benjamin Gaignard
[not found] ` <CA+M3ks4EymJ2aR5Fm1G1mTgyiOaGUcQgWMvDp0K4Hvue+M7rbA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-11-08 5:20 ` Vinod Koul
1 sibling, 1 reply; 4+ messages in thread
From: Benjamin Gaignard @ 2017-10-17 14:26 UTC (permalink / raw)
To: Pierre-Yves MORDRET
Cc: Vinod Koul, Rob Herring, Mark Rutland, Maxime Coquelin,
Alexandre Torgue, Russell King, Dan Williams,
M'boumba Cedric Madianga, Fabrice GASNIER, Herbert Xu,
Fabien DESSENNE, Amelie Delaunay, dmaengine, devicetree,
Linux ARM, Linux Kernel Mailing List, Arnd Bergmann
+Arnd since it should also fix 64 bits division issue
2017-10-17 15:43 GMT+02:00 Pierre-Yves MORDRET <pierre-yves.mordret@st.com>:
> If source and destination bus width differs pack/unpack MDMA
> feature has to be activated for alignment.
> This pack/unpack feature implies to have both source/destination address
> and buffer length aligned on bus width.
>
> Fixes: a4ffb13c8946 ("dmaengine: Add STM32 MDMA driver")
> Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
> ---
> drivers/dma/stm32-mdma.c | 84 ++++++++++++++++++++++++++++--------------------
> 1 file changed, 50 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
> index d3be6bf..daa1602 100644
> --- a/drivers/dma/stm32-mdma.c
> +++ b/drivers/dma/stm32-mdma.c
> @@ -387,14 +387,20 @@ static int stm32_mdma_get_width(struct stm32_mdma_chan *chan,
> }
> }
>
> -static enum dma_slave_buswidth stm32_mdma_get_max_width(u32 buf_len, u32 tlen)
> +static enum dma_slave_buswidth stm32_mdma_get_max_width(dma_addr_t addr,
> + u32 buf_len, u32 tlen)
> {
> enum dma_slave_buswidth max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
>
> for (max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
> max_width > DMA_SLAVE_BUSWIDTH_1_BYTE;
> max_width >>= 1) {
> - if (((buf_len % max_width) == 0) && (tlen >= max_width))
> + /*
> + * Address and buffer length both have to be aligned on
> + * bus width
> + */
> + if ((((buf_len | addr) & (max_width - 1)) == 0) &&
> + tlen >= max_width)
> break;
> }
>
> @@ -486,7 +492,8 @@ static void stm32_mdma_set_bus(struct stm32_mdma_device *dmadev, u32 *ctbr,
> static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> enum dma_transfer_direction direction,
> u32 *mdma_ccr, u32 *mdma_ctcr,
> - u32 *mdma_ctbr, u32 buf_len)
> + u32 *mdma_ctbr, dma_addr_t addr,
> + u32 buf_len)
> {
> struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
> struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
> @@ -520,6 +527,9 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> ctcr &= ~STM32_MDMA_CTCR_LEN2_MSK;
> ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
>
> + /* Disable Pack Enable */
> + ctcr &= ~STM32_MDMA_CTCR_PKE;
> +
> /* Check burst size constraints */
> if (src_maxburst * src_addr_width > STM32_MDMA_MAX_BURST ||
> dst_maxburst * dst_addr_width > STM32_MDMA_MAX_BURST) {
> @@ -551,6 +561,8 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
>
> switch (direction) {
> case DMA_MEM_TO_DEV:
> + dst_addr = chan->dma_config.dst_addr;
> +
> /* Set device data size */
> dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
> if (dst_bus_width < 0)
> @@ -567,7 +579,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
>
> /* Set memory data size */
> - src_addr_width = stm32_mdma_get_max_width(buf_len, tlen);
> + src_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
> chan->mem_width = src_addr_width;
> src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
> if (src_bus_width < 0)
> @@ -587,15 +599,19 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
>
> /* Select bus */
> - dst_addr = chan->dma_config.dst_addr;
> stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
> dst_addr);
>
> + if (dst_bus_width != src_bus_width)
> + ctcr |= STM32_MDMA_CTCR_PKE;
> +
> /* Set destination address */
> stm32_mdma_write(dmadev, STM32_MDMA_CDAR(chan->id), dst_addr);
> break;
>
> case DMA_DEV_TO_MEM:
> + src_addr = chan->dma_config.src_addr;
> +
> /* Set device data size */
> src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
> if (src_bus_width < 0)
> @@ -611,7 +627,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
>
> /* Set memory data size */
> - dst_addr_width = stm32_mdma_get_max_width(buf_len, tlen);
> + dst_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
> chan->mem_width = dst_addr_width;
> dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
> if (dst_bus_width < 0)
> @@ -630,10 +646,12 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
>
> /* Select bus */
> - src_addr = chan->dma_config.src_addr;
> stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
> src_addr);
>
> + if (dst_bus_width != src_bus_width)
> + ctcr |= STM32_MDMA_CTCR_PKE;
> +
> /* Set source address */
> stm32_mdma_write(dmadev, STM32_MDMA_CSAR(chan->id), src_addr);
> break;
> @@ -719,23 +737,27 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
> return -EINVAL;
> }
>
> - ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
> - &ctbr, sg_dma_len(sg));
> - if (ret < 0)
> - return ret;
> -
> if (direction == DMA_MEM_TO_DEV) {
> src_addr = sg_dma_address(sg);
> dst_addr = dma_config->dst_addr;
> + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
> + &ctcr, &ctbr, src_addr,
> + sg_dma_len(sg));
> stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
> src_addr);
> } else {
> src_addr = dma_config->src_addr;
> dst_addr = sg_dma_address(sg);
> + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
> + &ctcr, &ctbr, dst_addr,
> + sg_dma_len(sg));
> stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
> dst_addr);
> }
>
> + if (ret < 0)
> + return ret;
> +
> stm32_mdma_setup_hwdesc(chan, desc, direction, i, src_addr,
> dst_addr, sg_dma_len(sg), ctcr, ctbr,
> i == sg_len - 1, i == 0, false);
> @@ -830,27 +852,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr,
> if (!desc)
> return NULL;
>
> - ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr,
> - period_len);
> - if (ret < 0)
> - goto xfer_setup_err;
> -
> - /* Enable interrupts */
> - ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
> - ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
> - desc->ccr = ccr;
> -
> /* Select bus */
> if (direction == DMA_MEM_TO_DEV) {
> src_addr = buf_addr;
> + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
> + &ctbr, src_addr, period_len);
> stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
> src_addr);
> } else {
> dst_addr = buf_addr;
> + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
> + &ctbr, dst_addr, period_len);
> stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
> dst_addr);
> }
>
> + if (ret < 0)
> + goto xfer_setup_err;
> +
> + /* Enable interrupts */
> + ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
> + ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
> + desc->ccr = ccr;
> +
> /* Configure hwdesc list */
> for (i = 0; i < count; i++) {
> if (direction == DMA_MEM_TO_DEV) {
> @@ -956,9 +980,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
>
> /* Set source best burst size */
> - max_width = stm32_mdma_get_max_width(len, tlen);
> - if (src % max_width)
> - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> + max_width = stm32_mdma_get_max_width(src, len, tlen);
> src_bus_width = stm32_mdma_get_width(chan, max_width);
>
> max_burst = tlen / max_width;
> @@ -971,9 +993,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> STM32_MDMA_CTCR_SINCOS(src_bus_width);
>
> /* Set destination best burst size */
> - max_width = stm32_mdma_get_max_width(len, tlen);
> - if (dest % max_width)
> - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> + max_width = stm32_mdma_get_max_width(dest, len, tlen);
> dst_bus_width = stm32_mdma_get_width(chan, max_width);
>
> max_burst = tlen / max_width;
> @@ -1014,9 +1034,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> STM32_MDMA_MAX_BLOCK_LEN);
>
> /* Set source best burst size */
> - max_width = stm32_mdma_get_max_width(len, tlen);
> - if (src % max_width)
> - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> + max_width = stm32_mdma_get_max_width(src, len, tlen);
> src_bus_width = stm32_mdma_get_width(chan, max_width);
>
> max_burst = tlen / max_width;
> @@ -1030,9 +1048,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> STM32_MDMA_CTCR_SINCOS(src_bus_width);
>
> /* Set destination best burst size */
> - max_width = stm32_mdma_get_max_width(len, tlen);
> - if (dest % max_width)
> - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> + max_width = stm32_mdma_get_max_width(dest, len, tlen);
> dst_bus_width = stm32_mdma_get_width(chan, max_width);
>
> max_burst = tlen / max_width;
> --
> 2.7.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
Benjamin Gaignard
Graphic Study Group
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature
[not found] ` <CA+M3ks4EymJ2aR5Fm1G1mTgyiOaGUcQgWMvDp0K4Hvue+M7rbA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2017-10-31 11:29 ` Vinod Koul
0 siblings, 0 replies; 4+ messages in thread
From: Vinod Koul @ 2017-10-31 11:29 UTC (permalink / raw)
To: Benjamin Gaignard, Arnd Bergmann
Cc: Pierre-Yves MORDRET, Rob Herring, Mark Rutland, Maxime Coquelin,
Alexandre Torgue, Russell King, Dan Williams,
M'boumba Cedric Madianga, Fabrice GASNIER, Herbert Xu,
Fabien DESSENNE, Amelie Delaunay,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Linux ARM,
Linux Kernel Mailing List
On Tue, Oct 17, 2017 at 04:26:50PM +0200, Benjamin Gaignard wrote:
> +Arnd since it should also fix 64 bits division issue
Arnd would be back from Prague, so would like to get an ack before I
apply...
>
> 2017-10-17 15:43 GMT+02:00 Pierre-Yves MORDRET <pierre-yves.mordret-qxv4g6HH51o@public.gmane.org>:
> > If source and destination bus width differs pack/unpack MDMA
> > feature has to be activated for alignment.
> > This pack/unpack feature implies to have both source/destination address
> > and buffer length aligned on bus width.
> >
> > Fixes: a4ffb13c8946 ("dmaengine: Add STM32 MDMA driver")
> > Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret-qxv4g6HH51o@public.gmane.org>
> > ---
> > drivers/dma/stm32-mdma.c | 84 ++++++++++++++++++++++++++++--------------------
> > 1 file changed, 50 insertions(+), 34 deletions(-)
> >
> > diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
> > index d3be6bf..daa1602 100644
> > --- a/drivers/dma/stm32-mdma.c
> > +++ b/drivers/dma/stm32-mdma.c
> > @@ -387,14 +387,20 @@ static int stm32_mdma_get_width(struct stm32_mdma_chan *chan,
> > }
> > }
> >
> > -static enum dma_slave_buswidth stm32_mdma_get_max_width(u32 buf_len, u32 tlen)
> > +static enum dma_slave_buswidth stm32_mdma_get_max_width(dma_addr_t addr,
> > + u32 buf_len, u32 tlen)
> > {
> > enum dma_slave_buswidth max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
> >
> > for (max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
> > max_width > DMA_SLAVE_BUSWIDTH_1_BYTE;
> > max_width >>= 1) {
> > - if (((buf_len % max_width) == 0) && (tlen >= max_width))
> > + /*
> > + * Address and buffer length both have to be aligned on
> > + * bus width
> > + */
> > + if ((((buf_len | addr) & (max_width - 1)) == 0) &&
> > + tlen >= max_width)
> > break;
> > }
> >
> > @@ -486,7 +492,8 @@ static void stm32_mdma_set_bus(struct stm32_mdma_device *dmadev, u32 *ctbr,
> > static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> > enum dma_transfer_direction direction,
> > u32 *mdma_ccr, u32 *mdma_ctcr,
> > - u32 *mdma_ctbr, u32 buf_len)
> > + u32 *mdma_ctbr, dma_addr_t addr,
> > + u32 buf_len)
> > {
> > struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
> > struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
> > @@ -520,6 +527,9 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> > ctcr &= ~STM32_MDMA_CTCR_LEN2_MSK;
> > ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
> >
> > + /* Disable Pack Enable */
> > + ctcr &= ~STM32_MDMA_CTCR_PKE;
> > +
> > /* Check burst size constraints */
> > if (src_maxburst * src_addr_width > STM32_MDMA_MAX_BURST ||
> > dst_maxburst * dst_addr_width > STM32_MDMA_MAX_BURST) {
> > @@ -551,6 +561,8 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> >
> > switch (direction) {
> > case DMA_MEM_TO_DEV:
> > + dst_addr = chan->dma_config.dst_addr;
> > +
> > /* Set device data size */
> > dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
> > if (dst_bus_width < 0)
> > @@ -567,7 +579,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> > ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
> >
> > /* Set memory data size */
> > - src_addr_width = stm32_mdma_get_max_width(buf_len, tlen);
> > + src_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
> > chan->mem_width = src_addr_width;
> > src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
> > if (src_bus_width < 0)
> > @@ -587,15 +599,19 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> > ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
> >
> > /* Select bus */
> > - dst_addr = chan->dma_config.dst_addr;
> > stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
> > dst_addr);
> >
> > + if (dst_bus_width != src_bus_width)
> > + ctcr |= STM32_MDMA_CTCR_PKE;
> > +
> > /* Set destination address */
> > stm32_mdma_write(dmadev, STM32_MDMA_CDAR(chan->id), dst_addr);
> > break;
> >
> > case DMA_DEV_TO_MEM:
> > + src_addr = chan->dma_config.src_addr;
> > +
> > /* Set device data size */
> > src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
> > if (src_bus_width < 0)
> > @@ -611,7 +627,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> > ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
> >
> > /* Set memory data size */
> > - dst_addr_width = stm32_mdma_get_max_width(buf_len, tlen);
> > + dst_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
> > chan->mem_width = dst_addr_width;
> > dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
> > if (dst_bus_width < 0)
> > @@ -630,10 +646,12 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
> > ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
> >
> > /* Select bus */
> > - src_addr = chan->dma_config.src_addr;
> > stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
> > src_addr);
> >
> > + if (dst_bus_width != src_bus_width)
> > + ctcr |= STM32_MDMA_CTCR_PKE;
> > +
> > /* Set source address */
> > stm32_mdma_write(dmadev, STM32_MDMA_CSAR(chan->id), src_addr);
> > break;
> > @@ -719,23 +737,27 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
> > return -EINVAL;
> > }
> >
> > - ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
> > - &ctbr, sg_dma_len(sg));
> > - if (ret < 0)
> > - return ret;
> > -
> > if (direction == DMA_MEM_TO_DEV) {
> > src_addr = sg_dma_address(sg);
> > dst_addr = dma_config->dst_addr;
> > + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
> > + &ctcr, &ctbr, src_addr,
> > + sg_dma_len(sg));
> > stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
> > src_addr);
> > } else {
> > src_addr = dma_config->src_addr;
> > dst_addr = sg_dma_address(sg);
> > + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
> > + &ctcr, &ctbr, dst_addr,
> > + sg_dma_len(sg));
> > stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
> > dst_addr);
> > }
> >
> > + if (ret < 0)
> > + return ret;
> > +
> > stm32_mdma_setup_hwdesc(chan, desc, direction, i, src_addr,
> > dst_addr, sg_dma_len(sg), ctcr, ctbr,
> > i == sg_len - 1, i == 0, false);
> > @@ -830,27 +852,29 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr,
> > if (!desc)
> > return NULL;
> >
> > - ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr,
> > - period_len);
> > - if (ret < 0)
> > - goto xfer_setup_err;
> > -
> > - /* Enable interrupts */
> > - ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
> > - ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
> > - desc->ccr = ccr;
> > -
> > /* Select bus */
> > if (direction == DMA_MEM_TO_DEV) {
> > src_addr = buf_addr;
> > + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
> > + &ctbr, src_addr, period_len);
> > stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
> > src_addr);
> > } else {
> > dst_addr = buf_addr;
> > + ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
> > + &ctbr, dst_addr, period_len);
> > stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
> > dst_addr);
> > }
> >
> > + if (ret < 0)
> > + goto xfer_setup_err;
> > +
> > + /* Enable interrupts */
> > + ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
> > + ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
> > + desc->ccr = ccr;
> > +
> > /* Configure hwdesc list */
> > for (i = 0; i < count; i++) {
> > if (direction == DMA_MEM_TO_DEV) {
> > @@ -956,9 +980,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> > ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
> >
> > /* Set source best burst size */
> > - max_width = stm32_mdma_get_max_width(len, tlen);
> > - if (src % max_width)
> > - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> > + max_width = stm32_mdma_get_max_width(src, len, tlen);
> > src_bus_width = stm32_mdma_get_width(chan, max_width);
> >
> > max_burst = tlen / max_width;
> > @@ -971,9 +993,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> > STM32_MDMA_CTCR_SINCOS(src_bus_width);
> >
> > /* Set destination best burst size */
> > - max_width = stm32_mdma_get_max_width(len, tlen);
> > - if (dest % max_width)
> > - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> > + max_width = stm32_mdma_get_max_width(dest, len, tlen);
> > dst_bus_width = stm32_mdma_get_width(chan, max_width);
> >
> > max_burst = tlen / max_width;
> > @@ -1014,9 +1034,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> > STM32_MDMA_MAX_BLOCK_LEN);
> >
> > /* Set source best burst size */
> > - max_width = stm32_mdma_get_max_width(len, tlen);
> > - if (src % max_width)
> > - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> > + max_width = stm32_mdma_get_max_width(src, len, tlen);
> > src_bus_width = stm32_mdma_get_width(chan, max_width);
> >
> > max_burst = tlen / max_width;
> > @@ -1030,9 +1048,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
> > STM32_MDMA_CTCR_SINCOS(src_bus_width);
> >
> > /* Set destination best burst size */
> > - max_width = stm32_mdma_get_max_width(len, tlen);
> > - if (dest % max_width)
> > - max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> > + max_width = stm32_mdma_get_max_width(dest, len, tlen);
> > dst_bus_width = stm32_mdma_get_width(chan, max_width);
> >
> > max_burst = tlen / max_width;
> > --
> > 2.7.4
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
>
> --
> Benjamin Gaignard
>
> Graphic Study Group
>
> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro: Facebook | Twitter | Blog
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
~Vinod
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature
2017-10-17 13:43 [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature Pierre-Yves MORDRET
2017-10-17 14:26 ` Benjamin Gaignard
@ 2017-11-08 5:20 ` Vinod Koul
1 sibling, 0 replies; 4+ messages in thread
From: Vinod Koul @ 2017-11-08 5:20 UTC (permalink / raw)
To: Pierre-Yves MORDRET
Cc: Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre Torgue,
Russell King, Dan Williams, M'boumba Cedric Madianga,
Fabrice GASNIER, Herbert Xu, Fabien DESSENNE, Amelie Delaunay,
dmaengine, devicetree, linux-arm-kernel, linux-kernel
On Tue, Oct 17, 2017 at 03:43:47PM +0200, Pierre-Yves MORDRET wrote:
> If source and destination bus width differs pack/unpack MDMA
> feature has to be activated for alignment.
> This pack/unpack feature implies to have both source/destination address
> and buffer length aligned on bus width.
Applied, thanks
--
~Vinod
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2017-11-08 5:20 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-17 13:43 [PATCH v1] dmaengine: stm32_mdma: activate pack/unpack feature Pierre-Yves MORDRET
2017-10-17 14:26 ` Benjamin Gaignard
[not found] ` <CA+M3ks4EymJ2aR5Fm1G1mTgyiOaGUcQgWMvDp0K4Hvue+M7rbA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-10-31 11:29 ` Vinod Koul
2017-11-08 5:20 ` Vinod Koul
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).