diff mbox

[v1,1/4] dmaengine: imx-sdma: add memcpy interface

Message ID 1531239793-11781-2-git-send-email-yibin.gong@nxp.com (mailing list archive)
State New, archived
Headers show

Commit Message

Robin Gong July 10, 2018, 4:23 p.m. UTC
Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead
of '0xffff'.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/dma/imx-sdma.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 98 insertions(+), 6 deletions(-)

Comments

Vinod Koul July 10, 2018, 3:29 p.m. UTC | #1
Hi Robin,

On 11-07-18, 00:23, Robin Gong wrote:
> Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead
> of '0xffff'.

latter part should be its own patch. Never mix things

> +static struct dma_async_tx_descriptor *sdma_prep_memcpy(
> +		struct dma_chan *chan, dma_addr_t dma_dst,
> +		dma_addr_t dma_src, size_t len, unsigned long flags)
> +{
> +	struct sdma_channel *sdmac = to_sdma_chan(chan);
> +	struct sdma_engine *sdma = sdmac->sdma;
> +	int channel = sdmac->channel;
> +	size_t count;
> +	int i = 0, param;
> +	struct sdma_buffer_descriptor *bd;
> +	struct sdma_desc *desc;
> +
> +	if (!chan || !len)
> +		return NULL;
> +
> +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
> +		&dma_src, &dma_dst, len, channel);
> +
> +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len / SDMA_BD_MAX_CNT
> +					+ 1);

this looks quite odd to read consider:

        esc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM,
                                 len / SDMA_BD_MAX_CNT + 1);

> +	if (!desc)
> +		goto err_out;
> +
> +	do {
> +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
> +		bd = &desc->bd[i];
> +		bd->buffer_addr = dma_src;
> +		bd->ext_buffer_addr = dma_dst;
> +		bd->mode.count = count;
> +		desc->chn_count += count;
> +
> +		switch (sdmac->word_size) {
> +		case DMA_SLAVE_BUSWIDTH_4_BYTES:

This looks wrong, we are in memcpy, there is no SLAVE so no SLAVE
widths..

>  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,
> @@ -1344,9 +1431,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
>  
>  		count = sg_dma_len(sg);
>  
> -		if (count > 0xffff) {
> +		if (count > SDMA_BD_MAX_CNT) {
>  			dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
> -					channel, count, 0xffff);
> +					channel, count, SDMA_BD_MAX_CNT);

these changes dont belong to this patch

> @@ -1486,6 +1573,8 @@ static int sdma_config(struct dma_chan *chan,
>  		sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) &
>  			SDMA_WATERMARK_LEVEL_HWML;
>  		sdmac->word_size = dmaengine_cfg->dst_addr_width;
> +	} else if (dmaengine_cfg->direction == DMA_MEM_TO_MEM) {
> +		sdmac->word_size = dmaengine_cfg->dst_addr_width;

same here too, we are in .device_config which deals with slave. Not
memcpy!

>  	} else {
>  		sdmac->per_address = dmaengine_cfg->dst_addr;
>  		sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
> @@ -1902,6 +1991,7 @@ static int sdma_probe(struct platform_device *pdev)
>  
>  	dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
>  	dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
> +	dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask);
>  
>  	INIT_LIST_HEAD(&sdma->dma_device.channels);
>  	/* Initialize channel parameters */
> @@ -1968,9 +2058,11 @@ static int sdma_probe(struct platform_device *pdev)
>  	sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
>  	sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
>  	sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
> +	sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy;
>  	sdma->dma_device.device_issue_pending = sdma_issue_pending;
>  	sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
> -	dma_set_max_seg_size(sdma->dma_device.dev, 65535);
> +	sdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES;
> +	dma_set_max_seg_size(sdma->dma_device.dev, SDMA_BD_MAX_CNT);

this line should not be part of this patch
Robin Gong July 11, 2018, 5:34 a.m. UTC | #2
> Hi Robin,
> 
> On 11-07-18, 00:23, Robin Gong wrote:
> > Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead of
> > '0xffff'.
> 
> latter part should be its own patch. Never mix things
Okay, I will split it even for this minor change.
> 
> > +static struct dma_async_tx_descriptor *sdma_prep_memcpy(
> > +		struct dma_chan *chan, dma_addr_t dma_dst,
> > +		dma_addr_t dma_src, size_t len, unsigned long flags) {
> > +	struct sdma_channel *sdmac = to_sdma_chan(chan);
> > +	struct sdma_engine *sdma = sdmac->sdma;
> > +	int channel = sdmac->channel;
> > +	size_t count;
> > +	int i = 0, param;
> > +	struct sdma_buffer_descriptor *bd;
> > +	struct sdma_desc *desc;
> > +
> > +	if (!chan || !len)
> > +		return NULL;
> > +
> > +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
> > +		&dma_src, &dma_dst, len, channel);
> > +
> > +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len /
> SDMA_BD_MAX_CNT
> > +					+ 1);
> 
> this looks quite odd to read consider:
> 
>         esc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM,
>                                  len / SDMA_BD_MAX_CNT + 1);
> 
Okay, will fix on v2.
> > +	if (!desc)
> > +		goto err_out;
> > +
> > +	do {
> > +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
> > +		bd = &desc->bd[i];
> > +		bd->buffer_addr = dma_src;
> > +		bd->ext_buffer_addr = dma_dst;
> > +		bd->mode.count = count;
> > +		desc->chn_count += count;
> > +
> > +		switch (sdmac->word_size) {
> > +		case DMA_SLAVE_BUSWIDTH_4_BYTES:
> 
> This looks wrong, we are in memcpy, there is no SLAVE so no SLAVE widths..
> 
Okay, will remove check bus width.
> >  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, @@
> > -1344,9 +1431,9 @@ static struct dma_async_tx_descriptor
> > *sdma_prep_slave_sg(
> >
> >  		count = sg_dma_len(sg);
> >
> > -		if (count > 0xffff) {
> > +		if (count > SDMA_BD_MAX_CNT) {
> >  			dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg
> entry exceeded: %d > %d\n",
> > -					channel, count, 0xffff);
> > +					channel, count, SDMA_BD_MAX_CNT);
> 
> these changes dont belong to this patch
Will split in v2.
> 
> > @@ -1486,6 +1573,8 @@ static int sdma_config(struct dma_chan *chan,
> >  		sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16)
> &
> >  			SDMA_WATERMARK_LEVEL_HWML;
> >  		sdmac->word_size = dmaengine_cfg->dst_addr_width;
> > +	} else if (dmaengine_cfg->direction == DMA_MEM_TO_MEM) {
> > +		sdmac->word_size = dmaengine_cfg->dst_addr_width;
> 
> same here too, we are in .device_config which deals with slave. Not memcpy!
Will remove it.
> 
> >  	} else {
> >  		sdmac->per_address = dmaengine_cfg->dst_addr;
> >  		sdmac->watermark_level = dmaengine_cfg->dst_maxburst * @@
> -1902,6
> > +1991,7 @@ static int sdma_probe(struct platform_device *pdev)
> >
> >  	dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
> >  	dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
> > +	dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask);
> >
> >  	INIT_LIST_HEAD(&sdma->dma_device.channels);
> >  	/* Initialize channel parameters */
> > @@ -1968,9 +2058,11 @@ static int sdma_probe(struct platform_device
> *pdev)
> >  	sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
> >  	sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
> >  	sdma->dma_device.residue_granularity =
> > DMA_RESIDUE_GRANULARITY_SEGMENT;
> > +	sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy;
> >  	sdma->dma_device.device_issue_pending = sdma_issue_pending;
> >  	sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
> > -	dma_set_max_seg_size(sdma->dma_device.dev, 65535);
> > +	sdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES;
> > +	dma_set_max_seg_size(sdma->dma_device.dev, SDMA_BD_MAX_CNT);
> 
> this line should not be part of this patch
> 
> --
> ~Vinod
Sascha Hauer July 11, 2018, 6:24 a.m. UTC | #3
On Wed, Jul 11, 2018 at 12:23:10AM +0800, Robin Gong wrote:
> Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead
> of '0xffff'.
> 
> Signed-off-by: Robin Gong <yibin.gong@nxp.com>
> ---
> +static struct dma_async_tx_descriptor *sdma_prep_memcpy(
> +		struct dma_chan *chan, dma_addr_t dma_dst,
> +		dma_addr_t dma_src, size_t len, unsigned long flags)
> +{
> +	struct sdma_channel *sdmac = to_sdma_chan(chan);
> +	struct sdma_engine *sdma = sdmac->sdma;
> +	int channel = sdmac->channel;
> +	size_t count;
> +	int i = 0, param;
> +	struct sdma_buffer_descriptor *bd;
> +	struct sdma_desc *desc;
> +
> +	if (!chan || !len)
> +		return NULL;
> +
> +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
> +		&dma_src, &dma_dst, len, channel);
> +
> +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len / SDMA_BD_MAX_CNT
> +					+ 1);
> +	if (!desc)
> +		goto err_out;
> +
> +	do {
> +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);

When len is bigger than 0xffff you initialize count to 0xffff...

> +		bd = &desc->bd[i];
> +		bd->buffer_addr = dma_src;
> +		bd->ext_buffer_addr = dma_dst;
> +		bd->mode.count = count;
> +		desc->chn_count += count;
> +
> +		switch (sdmac->word_size) {
> +		case DMA_SLAVE_BUSWIDTH_4_BYTES:
> +			bd->mode.command = 0;
> +			if ((count | dma_src | dma_dst) & 3)
> +				goto err_bd_out;
> +			break;

...In which case you bail out here with an error.

Please make sure bigger transfers are working.

> +		case DMA_SLAVE_BUSWIDTH_2_BYTES:
> +			bd->mode.command = 2;
> +			if ((count | dma_src | dma_dst) & 1)
> +				goto err_bd_out;
> +			break;
> +		case DMA_SLAVE_BUSWIDTH_1_BYTE:
> +			bd->mode.command = 1;
> +			break;
> +		default:
> +			goto err_bd_out;
> +		}
> +
> +		dma_src += count;
> +		dma_dst += count;
> +		len -= count;
> +		i++;
> +
> +		param = BD_DONE | BD_EXTD | BD_CONT;

Probably better readable if you drop BD_CONT here and do a

	if (len) {
		param |= BD_CONT;
	} else  {
		...
	}

Sascha
Robin Gong July 11, 2018, 6:56 a.m. UTC | #4
> -----Original Message-----

> From: Sascha Hauer [mailto:s.hauer@pengutronix.de]

> Sent: 2018年7月11日 14:25

> To: Robin Gong <yibin.gong@nxp.com>

> Cc: vkoul@kernel.org; dan.j.williams@intel.com; shawnguo@kernel.org; Fabio

> Estevam <fabio.estevam@nxp.com>; linux@armlinux.org.uk;

> linux-arm-kernel@lists.infradead.org; kernel@pengutronix.de;

> dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org; dl-linux-imx

> <linux-imx@nxp.com>

> Subject: Re: [PATCH v1 1/4] dmaengine: imx-sdma: add memcpy interface

> 

> On Wed, Jul 11, 2018 at 12:23:10AM +0800, Robin Gong wrote:

> > Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead of

> > '0xffff'.

> >

> > Signed-off-by: Robin Gong <yibin.gong@nxp.com>

> > ---

> > +static struct dma_async_tx_descriptor *sdma_prep_memcpy(

> > +		struct dma_chan *chan, dma_addr_t dma_dst,

> > +		dma_addr_t dma_src, size_t len, unsigned long flags) {

> > +	struct sdma_channel *sdmac = to_sdma_chan(chan);

> > +	struct sdma_engine *sdma = sdmac->sdma;

> > +	int channel = sdmac->channel;

> > +	size_t count;

> > +	int i = 0, param;

> > +	struct sdma_buffer_descriptor *bd;

> > +	struct sdma_desc *desc;

> > +

> > +	if (!chan || !len)

> > +		return NULL;

> > +

> > +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",

> > +		&dma_src, &dma_dst, len, channel);

> > +

> > +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len /

> SDMA_BD_MAX_CNT

> > +					+ 1);

> > +	if (!desc)

> > +		goto err_out;

> > +

> > +	do {

> > +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);

> 

> When len is bigger than 0xffff you initialize count to 0xffff...

In this case, the data will be split into several bds, for example,
If the total count is 0x10000, two bd used then. One is for 0xffff,
Another is for the last 1
> 

> > +		bd = &desc->bd[i];

> > +		bd->buffer_addr = dma_src;

> > +		bd->ext_buffer_addr = dma_dst;

> > +		bd->mode.count = count;

> > +		desc->chn_count += count;

> > +

> > +		switch (sdmac->word_size) {

> > +		case DMA_SLAVE_BUSWIDTH_4_BYTES:

> > +			bd->mode.command = 0;

> > +			if ((count | dma_src | dma_dst) & 3)

> > +				goto err_bd_out;

> > +			break;

> 

> ...In which case you bail out here with an error.

In case dma_src/dma_dst is not align with bus width.
But I'll remove such bus width in v2 as Vinod comments.
> 

> Please make sure bigger transfers are working.

> 

> > +		case DMA_SLAVE_BUSWIDTH_2_BYTES:

> > +			bd->mode.command = 2;

> > +			if ((count | dma_src | dma_dst) & 1)

> > +				goto err_bd_out;

> > +			break;

> > +		case DMA_SLAVE_BUSWIDTH_1_BYTE:

> > +			bd->mode.command = 1;

> > +			break;

> > +		default:

> > +			goto err_bd_out;

> > +		}

> > +

> > +		dma_src += count;

> > +		dma_dst += count;

> > +		len -= count;

> > +		i++;

> > +

> > +		param = BD_DONE | BD_EXTD | BD_CONT;

> 

> Probably better readable if you drop BD_CONT here and do a

> 

> 	if (len) {

> 		param |= BD_CONT;

> 	} else  {

> 		...

> 	}

Okay. Will improve it.
> 

> Sascha

> 

> --

> Pengutronix e.K.                           |

> |

> Industrial Linux Solutions                 |

> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.

> pengutronix.de%2F&amp;data=02%7C01%7Cyibin.gong%40nxp.com%7C0aa96

> 135702b4414dbe708d5e6f709fe%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C

> 0%7C0%7C636668871060103585&amp;sdata=k2h0RIWlujaCs8ioduJsnJAfGW0

> ZS7uzlHMMtjpQ%2Fw4%3D&amp;reserved=0  |

> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |

> Amtsgericht Hildesheim, HRA 2686           | Fax:

> +49-5121-206917-5555 |
Sascha Hauer July 11, 2018, 7:01 a.m. UTC | #5
On Wed, Jul 11, 2018 at 06:56:18AM +0000, Robin Gong wrote:
> 
> > -----Original Message-----
> > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > Sent: 2018年7月11日 14:25
> > To: Robin Gong <yibin.gong@nxp.com>
> > Cc: vkoul@kernel.org; dan.j.williams@intel.com; shawnguo@kernel.org; Fabio
> > Estevam <fabio.estevam@nxp.com>; linux@armlinux.org.uk;
> > linux-arm-kernel@lists.infradead.org; kernel@pengutronix.de;
> > dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org; dl-linux-imx
> > <linux-imx@nxp.com>
> > Subject: Re: [PATCH v1 1/4] dmaengine: imx-sdma: add memcpy interface
> > 
> > On Wed, Jul 11, 2018 at 12:23:10AM +0800, Robin Gong wrote:
> > > Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead of
> > > '0xffff'.
> > >
> > > Signed-off-by: Robin Gong <yibin.gong@nxp.com>
> > > ---
> > > +static struct dma_async_tx_descriptor *sdma_prep_memcpy(
> > > +		struct dma_chan *chan, dma_addr_t dma_dst,
> > > +		dma_addr_t dma_src, size_t len, unsigned long flags) {
> > > +	struct sdma_channel *sdmac = to_sdma_chan(chan);
> > > +	struct sdma_engine *sdma = sdmac->sdma;
> > > +	int channel = sdmac->channel;
> > > +	size_t count;
> > > +	int i = 0, param;
> > > +	struct sdma_buffer_descriptor *bd;
> > > +	struct sdma_desc *desc;
> > > +
> > > +	if (!chan || !len)
> > > +		return NULL;
> > > +
> > > +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
> > > +		&dma_src, &dma_dst, len, channel);
> > > +
> > > +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len /
> > SDMA_BD_MAX_CNT
> > > +					+ 1);
> > > +	if (!desc)
> > > +		goto err_out;
> > > +
> > > +	do {
> > > +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
> > 
> > When len is bigger than 0xffff you initialize count to 0xffff...
> In this case, the data will be split into several bds, for example,
> If the total count is 0x10000, two bd used then. One is for 0xffff,
> Another is for the last 1

And you are doing byte size DMA? Wouldn't word size accesses be more
optimal?

Sascha
Robin Gong July 11, 2018, 7:05 a.m. UTC | #6
> -----Original Message-----

> From: Sascha Hauer [mailto:s.hauer@pengutronix.de]

> Sent: 2018年7月11日 15:01

> To: Robin Gong <yibin.gong@nxp.com>

> Cc: vkoul@kernel.org; dan.j.williams@intel.com; shawnguo@kernel.org; Fabio

> Estevam <fabio.estevam@nxp.com>; linux@armlinux.org.uk;

> linux-arm-kernel@lists.infradead.org; kernel@pengutronix.de;

> dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org; dl-linux-imx

> <linux-imx@nxp.com>

> Subject: Re: [PATCH v1 1/4] dmaengine: imx-sdma: add memcpy interface

> 

> On Wed, Jul 11, 2018 at 06:56:18AM +0000, Robin Gong wrote:

> >

> > > -----Original Message-----

> > > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]

> > > Sent: 2018年7月11日 14:25

> > > To: Robin Gong <yibin.gong@nxp.com>

> > > Cc: vkoul@kernel.org; dan.j.williams@intel.com; shawnguo@kernel.org;

> > > Fabio Estevam <fabio.estevam@nxp.com>; linux@armlinux.org.uk;

> > > linux-arm-kernel@lists.infradead.org; kernel@pengutronix.de;

> > > dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org;

> > > dl-linux-imx <linux-imx@nxp.com>

> > > Subject: Re: [PATCH v1 1/4] dmaengine: imx-sdma: add memcpy

> > > interface

> > >

> > > On Wed, Jul 11, 2018 at 12:23:10AM +0800, Robin Gong wrote:

> > > > Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead of

> > > > '0xffff'.

> > > >

> > > > Signed-off-by: Robin Gong <yibin.gong@nxp.com>

> > > > ---

> > > > +static struct dma_async_tx_descriptor *sdma_prep_memcpy(

> > > > +		struct dma_chan *chan, dma_addr_t dma_dst,

> > > > +		dma_addr_t dma_src, size_t len, unsigned long flags) {

> > > > +	struct sdma_channel *sdmac = to_sdma_chan(chan);

> > > > +	struct sdma_engine *sdma = sdmac->sdma;

> > > > +	int channel = sdmac->channel;

> > > > +	size_t count;

> > > > +	int i = 0, param;

> > > > +	struct sdma_buffer_descriptor *bd;

> > > > +	struct sdma_desc *desc;

> > > > +

> > > > +	if (!chan || !len)

> > > > +		return NULL;

> > > > +

> > > > +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu,

> channel=%d.\n",

> > > > +		&dma_src, &dma_dst, len, channel);

> > > > +

> > > > +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len /

> > > SDMA_BD_MAX_CNT

> > > > +					+ 1);

> > > > +	if (!desc)

> > > > +		goto err_out;

> > > > +

> > > > +	do {

> > > > +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);

> > >

> > > When len is bigger than 0xffff you initialize count to 0xffff...

> > In this case, the data will be split into several bds, for example, If

> > the total count is 0x10000, two bd used then. One is for 0xffff,

> > Another is for the last 1

> 

> And you are doing byte size DMA? Wouldn't word size accesses be more

> optimal?

> 

> Sascha

Default is words, and I'll force the buswidth to word and set into BD.
sdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES;
> 

> 

> --

> Pengutronix e.K.                           |

> |

> Industrial Linux Solutions                 |

> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.

> pengutronix.de%2F&amp;data=02%7C01%7Cyibin.gong%40nxp.com%7C41fbd

> 3765b10424a7f1e08d5e6fc196d%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C

> 0%7C0%7C636668892793035822&amp;sdata=mLKjTKaojuO1Zv%2F4ohwkkzeK

> FDFbmqYturqh6eSblIM%3D&amp;reserved=0  |

> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |

> Amtsgericht Hildesheim, HRA 2686           | Fax:

> +49-5121-206917-5555 |
Sascha Hauer July 11, 2018, 7:08 a.m. UTC | #7
On Wed, Jul 11, 2018 at 07:05:23AM +0000, Robin Gong wrote:
> 
> 
> > -----Original Message-----
> > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > Sent: 2018年7月11日 15:01
> > To: Robin Gong <yibin.gong@nxp.com>
> > Cc: vkoul@kernel.org; dan.j.williams@intel.com; shawnguo@kernel.org; Fabio
> > Estevam <fabio.estevam@nxp.com>; linux@armlinux.org.uk;
> > linux-arm-kernel@lists.infradead.org; kernel@pengutronix.de;
> > dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org; dl-linux-imx
> > <linux-imx@nxp.com>
> > Subject: Re: [PATCH v1 1/4] dmaengine: imx-sdma: add memcpy interface
> > 
> > On Wed, Jul 11, 2018 at 06:56:18AM +0000, Robin Gong wrote:
> > >
> > > > -----Original Message-----
> > > > From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
> > > > Sent: 2018年7月11日 14:25
> > > > To: Robin Gong <yibin.gong@nxp.com>
> > > > Cc: vkoul@kernel.org; dan.j.williams@intel.com; shawnguo@kernel.org;
> > > > Fabio Estevam <fabio.estevam@nxp.com>; linux@armlinux.org.uk;
> > > > linux-arm-kernel@lists.infradead.org; kernel@pengutronix.de;
> > > > dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org;
> > > > dl-linux-imx <linux-imx@nxp.com>
> > > > Subject: Re: [PATCH v1 1/4] dmaengine: imx-sdma: add memcpy
> > > > interface
> > > >
> > > > On Wed, Jul 11, 2018 at 12:23:10AM +0800, Robin Gong wrote:
> > > > > Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead of
> > > > > '0xffff'.
> > > > >
> > > > > Signed-off-by: Robin Gong <yibin.gong@nxp.com>
> > > > > ---
> > > > > +static struct dma_async_tx_descriptor *sdma_prep_memcpy(
> > > > > +		struct dma_chan *chan, dma_addr_t dma_dst,
> > > > > +		dma_addr_t dma_src, size_t len, unsigned long flags) {
> > > > > +	struct sdma_channel *sdmac = to_sdma_chan(chan);
> > > > > +	struct sdma_engine *sdma = sdmac->sdma;
> > > > > +	int channel = sdmac->channel;
> > > > > +	size_t count;
> > > > > +	int i = 0, param;
> > > > > +	struct sdma_buffer_descriptor *bd;
> > > > > +	struct sdma_desc *desc;
> > > > > +
> > > > > +	if (!chan || !len)
> > > > > +		return NULL;
> > > > > +
> > > > > +	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu,
> > channel=%d.\n",
> > > > > +		&dma_src, &dma_dst, len, channel);
> > > > > +
> > > > > +	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len /
> > > > SDMA_BD_MAX_CNT
> > > > > +					+ 1);
> > > > > +	if (!desc)
> > > > > +		goto err_out;
> > > > > +
> > > > > +	do {
> > > > > +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
> > > >
> > > > When len is bigger than 0xffff you initialize count to 0xffff...
> > > In this case, the data will be split into several bds, for example, If
> > > the total count is 0x10000, two bd used then. One is for 0xffff,
> > > Another is for the last 1
> > 
> > And you are doing byte size DMA? Wouldn't word size accesses be more
> > optimal?
> > 
> > Sascha
> Default is words, and I'll force the buswidth to word and set into BD.
> sdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES;

So guess which alignment the second transfer has when the first has the
size 0xffff.

Sascha
Vinod Koul July 11, 2018, 7:12 a.m. UTC | #8
On 11-07-18, 05:34, Robin Gong wrote:
> > On 11-07-18, 00:23, Robin Gong wrote:
> > > Add MEMCPY support, meanwhile, add SDMA_BD_MAX_CNT instead of
> > > '0xffff'.
> > 
> > latter part should be its own patch. Never mix things
> Okay, I will split it even for this minor change.

Yes, a patch should represent _one_ thing, describe that one thing and
do that one thing.

Anything else, doesn't matter how simple or complex should be an
individual patch

> > > +	if (!desc)
> > > +		goto err_out;
> > > +
> > > +	do {
> > > +		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
> > > +		bd = &desc->bd[i];
> > > +		bd->buffer_addr = dma_src;
> > > +		bd->ext_buffer_addr = dma_dst;
> > > +		bd->mode.count = count;
> > > +		desc->chn_count += count;
> > > +
> > > +		switch (sdmac->word_size) {
> > > +		case DMA_SLAVE_BUSWIDTH_4_BYTES:
> > 
> > This looks wrong, we are in memcpy, there is no SLAVE so no SLAVE widths..
> > 
> Okay, will remove check bus width.

it is not about bus_width but the fact that you are using slave
concepts. In memcpy we have _no_ slave, hence do not use anything
related to slave including dma_slave_config
diff mbox

Patch

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 3b622d6..27ccabf 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -341,6 +341,7 @@  struct sdma_desc {
  * @pc_from_device:	script address for those device_2_memory
  * @pc_to_device:	script address for those memory_2_device
  * @device_to_device:	script address for those device_2_device
+ * @pc_to_pc:		script address for those memory_2_memory
  * @flags:		loop mode or not
  * @per_address:	peripheral source or destination address in common case
  *                      destination address in p_2_p case
@@ -366,6 +367,7 @@  struct sdma_channel {
 	enum dma_slave_buswidth		word_size;
 	unsigned int			pc_from_device, pc_to_device;
 	unsigned int			device_to_device;
+	unsigned int                    pc_to_pc;
 	unsigned long			flags;
 	dma_addr_t			per_address, per_address2;
 	unsigned long			event_mask[2];
@@ -385,6 +387,8 @@  struct sdma_channel {
 
 #define SDMA_FIRMWARE_MAGIC 0x414d4453
 
+#define SDMA_BD_MAX_CNT	0xffff
+
 /**
  * struct sdma_firmware_header - Layout of the firmware image
  *
@@ -868,14 +872,16 @@  static void sdma_get_pc(struct sdma_channel *sdmac,
 	 * These are needed once we start to support transfers between
 	 * two peripherals or memory-to-memory transfers
 	 */
-	int per_2_per = 0;
+	int per_2_per = 0, emi_2_emi = 0;
 
 	sdmac->pc_from_device = 0;
 	sdmac->pc_to_device = 0;
 	sdmac->device_to_device = 0;
+	sdmac->pc_to_pc = 0;
 
 	switch (peripheral_type) {
 	case IMX_DMATYPE_MEMORY:
+		emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
 		break;
 	case IMX_DMATYPE_DSP:
 		emi_2_per = sdma->script_addrs->bp_2_ap_addr;
@@ -948,6 +954,7 @@  static void sdma_get_pc(struct sdma_channel *sdmac,
 	sdmac->pc_from_device = per_2_emi;
 	sdmac->pc_to_device = emi_2_per;
 	sdmac->device_to_device = per_2_per;
+	sdmac->pc_to_pc = emi_2_emi;
 }
 
 static int sdma_load_context(struct sdma_channel *sdmac)
@@ -964,6 +971,8 @@  static int sdma_load_context(struct sdma_channel *sdmac)
 		load_address = sdmac->pc_from_device;
 	else if (sdmac->direction == DMA_DEV_TO_DEV)
 		load_address = sdmac->device_to_device;
+	else if (sdmac->direction == DMA_MEM_TO_MEM)
+		load_address = sdmac->pc_to_pc;
 	else
 		load_address = sdmac->pc_to_device;
 
@@ -1317,6 +1326,84 @@  static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
 	return NULL;
 }
 
+static struct dma_async_tx_descriptor *sdma_prep_memcpy(
+		struct dma_chan *chan, dma_addr_t dma_dst,
+		dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	size_t count;
+	int i = 0, param;
+	struct sdma_buffer_descriptor *bd;
+	struct sdma_desc *desc;
+
+	if (!chan || !len)
+		return NULL;
+
+	dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
+		&dma_src, &dma_dst, len, channel);
+
+	desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len / SDMA_BD_MAX_CNT
+					+ 1);
+	if (!desc)
+		goto err_out;
+
+	do {
+		count = min_t(size_t, len, SDMA_BD_MAX_CNT);
+		bd = &desc->bd[i];
+		bd->buffer_addr = dma_src;
+		bd->ext_buffer_addr = dma_dst;
+		bd->mode.count = count;
+		desc->chn_count += count;
+
+		switch (sdmac->word_size) {
+		case DMA_SLAVE_BUSWIDTH_4_BYTES:
+			bd->mode.command = 0;
+			if ((count | dma_src | dma_dst) & 3)
+				goto err_bd_out;
+			break;
+		case DMA_SLAVE_BUSWIDTH_2_BYTES:
+			bd->mode.command = 2;
+			if ((count | dma_src | dma_dst) & 1)
+				goto err_bd_out;
+			break;
+		case DMA_SLAVE_BUSWIDTH_1_BYTE:
+			bd->mode.command = 1;
+			break;
+		default:
+			goto err_bd_out;
+		}
+
+		dma_src += count;
+		dma_dst += count;
+		len -= count;
+		i++;
+
+		param = BD_DONE | BD_EXTD | BD_CONT;
+		/* last bd */
+		if (!len) {
+			param |= BD_INTR;
+			param |= BD_LAST;
+			param &= ~BD_CONT;
+		}
+
+		dev_dbg(sdma->dev, "entry %d: count: %zd dma: 0x%x %s%s\n",
+				i, count, bd->buffer_addr,
+				param & BD_WRAP ? "wrap" : "",
+				param & BD_INTR ? " intr" : "");
+
+		bd->mode.status = param;
+	} while (len);
+
+	return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+	sdma_free_bd(desc);
+	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,
@@ -1344,9 +1431,9 @@  static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
 		count = sg_dma_len(sg);
 
-		if (count > 0xffff) {
+		if (count > SDMA_BD_MAX_CNT) {
 			dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
-					channel, count, 0xffff);
+					channel, count, SDMA_BD_MAX_CNT);
 			goto err_bd_out;
 		}
 
@@ -1421,9 +1508,9 @@  static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 
 	sdmac->flags |= IMX_DMA_SG_LOOP;
 
-	if (period_len > 0xffff) {
+	if (period_len > SDMA_BD_MAX_CNT) {
 		dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
-				channel, period_len, 0xffff);
+				channel, period_len, SDMA_BD_MAX_CNT);
 		goto err_bd_out;
 	}
 
@@ -1486,6 +1573,8 @@  static int sdma_config(struct dma_chan *chan,
 		sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) &
 			SDMA_WATERMARK_LEVEL_HWML;
 		sdmac->word_size = dmaengine_cfg->dst_addr_width;
+	} else if (dmaengine_cfg->direction == DMA_MEM_TO_MEM) {
+		sdmac->word_size = dmaengine_cfg->dst_addr_width;
 	} else {
 		sdmac->per_address = dmaengine_cfg->dst_addr;
 		sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
@@ -1902,6 +1991,7 @@  static int sdma_probe(struct platform_device *pdev)
 
 	dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
 	dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+	dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask);
 
 	INIT_LIST_HEAD(&sdma->dma_device.channels);
 	/* Initialize channel parameters */
@@ -1968,9 +2058,11 @@  static int sdma_probe(struct platform_device *pdev)
 	sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
 	sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
 	sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+	sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy;
 	sdma->dma_device.device_issue_pending = sdma_issue_pending;
 	sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
-	dma_set_max_seg_size(sdma->dma_device.dev, 65535);
+	sdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES;
+	dma_set_max_seg_size(sdma->dma_device.dev, SDMA_BD_MAX_CNT);
 
 	platform_set_drvdata(pdev, sdma);