DMA Engine development
 help / color / mirror / Atom feed
* dmaengine: owl: Fix warnings generated during build
From: Vinod Koul @ 2018-10-15 17:10 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: afaerber, dmaengine, liuwei, 96boards, linux-arm-kernel,
	linux-kernel, hzhang, bdong, manivannanece23, thomas.liau, pn,
	edgar.righi

On 08-10-18, 22:46, Manivannan Sadhasivam wrote:
> Following warnings are generated when compiled with W=1,
> 
> drivers/dma/owl-dma.c:170: warning: Function parameter or member 'cyclic'
> not described in 'owl_dma_txd'
> drivers/dma/owl-dma.c:198: warning: Function parameter or member 'cfg' not
> described in 'owl_dma_vchan'
> drivers/dma/owl-dma.c:198: warning: Function parameter or member 'drq' not
> described in 'owl_dma_vchan'
> drivers/dma/owl-dma.c:225: warning: Function parameter or member 'irq' not
> described in 'owl_dma'
> 
> Fix this by adding comments for relevant struct members to appear in
> kernel-doc.
> 
> Fixes: d64e1b3f5cce ("dmaengine: owl: Add Slave and Cyclic mode support for
> Actions Semi Owl S900 SoC")
> 

This empty line is not required

> Reported-by: Vinod Koul <vinod.koul@linaro.org>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>


Applied after removing the bogus empty line, thanks

^ permalink raw reply

* [1/7] dmaengine: fsldma: Replace DMA_IN/OUT by FSL_DMA_IN/OUT
From: Vinod Koul @ 2018-10-15 17:07 UTC (permalink / raw)
  To: Peng Ma
  Cc: leoyang.li, robh+dt, mark.rutland, shawnguo, dan.j.williams, zw,
	dmaengine, devicetree, linux-kernel, linux-arm-kernel,
	linuxppc-dev, Wen He

On 11-10-18, 17:46, Peng Ma wrote:
> From: Wen He <wen.he_1@nxp.com>
> 
> This patch implement a standard macro call functions is
> used to NXP dma drivers.
> 
> Signed-off-by: Wen He <wen.he_1@nxp.com>

Please read Documentation/process/submitting-patches.rst, we expect each
patch you send to have your signed off and signed off from orignal
authors

Also as Rob pointed out this patch series should be v8 or so as this is
following the previous work submitted to the list

Please also indicated changes from last rev which help in the review.

^ permalink raw reply

* [v3,2/2] dmaengine: uniphier-mdmac: add UniPhier MIO DMAC driver
From: Vinod Koul @ 2018-10-15 17:03 UTC (permalink / raw)
  To: Masahiro Yamada
  Cc: open list:DMA GENERIC OFFLOAD ENGINE SUBSYSTEM, Masami Hiramatsu,
	Jassi Brar, Linux Kernel Mailing List, Dan Williams,
	linux-arm-kernel

On 12-10-18, 01:27, Masahiro Yamada wrote:
> On Sun, Oct 7, 2018 at 1:23 AM Vinod <vkoul@kernel.org> wrote:
> > > > > +static int uniphier_mdmac_probe(struct platform_device *pdev)
> > > > > +{
> > > > > +     struct device *dev = &pdev->dev;
> > > > > +     struct uniphier_mdmac_device *mdev;
> > > > > +     struct dma_device *ddev;
> > > > > +     struct resource *res;
> > > > > +     int nr_chans, ret, i;
> > > > > +
> > > > > +     nr_chans = platform_irq_count(pdev);
> > > > > +     if (nr_chans < 0)
> > > > > +             return nr_chans;
> > > > > +
> > > > > +     ret = dma_set_mask(dev, DMA_BIT_MASK(32));
> > > > > +     if (ret)
> > > > > +             return ret;
> > > > > +
> > > > > +     mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
> > > > > +                         GFP_KERNEL);
> > > > > +     if (!mdev)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > > +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > > +     mdev->reg_base = devm_ioremap_resource(dev, res);
> > > > > +     if (IS_ERR(mdev->reg_base))
> > > > > +             return PTR_ERR(mdev->reg_base);
> > > > > +
> > > > > +     mdev->clk = devm_clk_get(dev, NULL);
> > > > > +     if (IS_ERR(mdev->clk)) {
> > > > > +             dev_err(dev, "failed to get clock\n");
> > > > > +             return PTR_ERR(mdev->clk);
> > > > > +     }
> > > > > +
> > > > > +     ret = clk_prepare_enable(mdev->clk);
> > > > > +     if (ret)
> > > > > +             return ret;
> > > > > +
> > > > > +     ddev = &mdev->ddev;
> > > > > +     ddev->dev = dev;
> > > > > +     dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
> > > > > +     ddev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> > > > > +     ddev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> > > >
> > > > undefined?
> > >
> > > Precisely, I do not know the *_addr_widths.
> >
> > This is "your" controller, you know the capability!
> 
> No, I do not.
> 
> I wrote this driver, but the hardware-internal is not fully documented
> in the datasheet.
> I can see the functionality only from the software point of view.

Ah that is sad!

> > > As far as I read dmaengine/provider.rst
> > > this represents the data bytes that are read/written at a time.
> > >
> > > Really I do not know (care about) the transfer width.
> > >
> > > As I commented in v2, the connection of the device side is hard-wired.
> > > The transfer width cannot be observed from SW view.
> > >
> > > What should I do?
> >
> > Add the widths that are supported by the controller
> 
> To my best knowledge, this DMA engine is connected to a 32-bit bus.
> So, 4 bytes are read/written at a time.
> 
> This HW allows to set the transfer size by byte granularity.
> So, it would be possible to access the data bus
> by 1-byte, 2-bytes, 3-bytes as well.
> 
> I will set the OR of 1, 2, 3, 4 bytes.

that would be better. Also if you can test and verify these and add the
ones you have verified would be even better

> > > > > +static int uniphier_mdmac_remove(struct platform_device *pdev)
> > > > > +{
> > > > > +     struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
> > > > > +
> > > > > +     of_dma_controller_free(pdev->dev.of_node);
> > > > > +     dma_async_device_unregister(&mdev->ddev);
> > > > > +     clk_disable_unprepare(mdev->clk);
> > > >
> > > > at this point your irq is registered and can be fired, the tasklets are
> > > > not killed :(
> > >
> > >
> > > Please let me clarify the concerns here.
> > >
> > > Before the .remove hook is called, all the consumers should
> > > have already put the dma channels.
> > > So, no new descriptor is coming in.
> > >
> > > However,
> > >
> > > Some already-issued descriptors might be remaining, and being processed.
> > >
> > > [1] This DMA engine might be still running
> > >     when clk_disable_unprepare() is being called.
> > >     The register access with its clock disabled
> > >     would cause the system crash.
> >
> > Yes and dmaengine may fire a spurious irq..
> > >
> > > [2] vchan_cookie_complete() might being called at this point
> > >     and schedule the tasklet.
> > >     It might call uniphier_mdmac_desc_free() after
> > >     the reference disapperrs.
> > >
> > > Is this correct?
> >
> > Correct :)
> >
> > > Do you have recommendation
> > > for module removal guideline?
> >
> > Yes please free up or disable irq explictly, ensure pending irqs have
> > completed and then ensure all the tasklets are killed and in this order
> > for obvious reasons
> 
> Also, need to free up the left-over descriptor(s) right?
> Just killing the tasklets may result in memory leak.

Yes I am assuming you would have done so in terminate calls

> Please let know if the implementation in v4 is wrong.

Sure will do

^ permalink raw reply

* dmaengine: ppc4xx: fix off-by-one build failure
From: Christian Lamparter @ 2018-10-14 21:28 UTC (permalink / raw)
  To: dmaengine; +Cc: Dan Williams, Vinod Koul, Greg Kroah-Hartman

There are two poly_store, but one should have been poly_show.

|adma.c:4382:16: error: conflicting types for 'poly_store'
| static ssize_t poly_store(struct device_driver *dev, const char *buf,
|                ^~~~~~~~~~
|adma.c:4363:16: note: previous definition of 'poly_store' was here
| static ssize_t poly_store(struct device_driver *dev, char *buf)
|                ^~~~~~~~~~

Fixes: 13efe1a05384 ("dmaengine: ppc4xx: remove DRIVER_ATTR() usage")
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
 drivers/dma/ppc4xx/adma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 4cf0d4d0cecf..25610286979f 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4360,7 +4360,7 @@ static ssize_t enable_store(struct device_driver *dev, const char *buf,
 }
 static DRIVER_ATTR_RW(enable);
 
-static ssize_t poly_store(struct device_driver *dev, char *buf)
+static ssize_t poly_show(struct device_driver *dev, char *buf)
 {
 	ssize_t size = 0;
 	u32 reg;

^ permalink raw reply related

* [4/6] dma: tegra: add accurate reporting of dma state
From: kbuild test robot @ 2018-10-12 21:47 UTC (permalink / raw)
  To: Ben Dooks
  Cc: kbuild-all, dan.j.williams, vkoul, ldewangan, dmaengine,
	linux-tegra

Hi Ben,

I love your patch! Perhaps something to improve:

[auto build test WARNING on sof-driver-fuweitax/master]
[also build test WARNING on v4.19-rc7 next-20181012]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Ben-Dooks/dma-tegra-avoid-overflow-of-byte-tracking/20181013-023951
base:   https://github.com/fuweitax/linux master
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=arm 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   In file included from include/linux/printk.h:332:0,
                    from include/linux/kernel.h:14,
                    from include/linux/clk.h:16,
                    from drivers//dma/tegra20-apb-dma.c:20:
   drivers//dma/tegra20-apb-dma.c: In function 'tegra_dma_tx_status':
   include/linux/dynamic_debug.h:135:3: warning: 'done' may be used uninitialized in this function [-Wmaybe-uninitialized]
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
      ^~~~~~~~~~~~~~~~~
   drivers//dma/tegra20-apb-dma.c:816:6: note: 'done' was declared here
     int done;
         ^~~~
   In file included from include/linux/printk.h:332:0,
                    from include/linux/kernel.h:14,
                    from include/linux/clk.h:16,
                    from drivers//dma/tegra20-apb-dma.c:20:
   include/linux/dynamic_debug.h:135:3: warning: 'wcount' may be used uninitialized in this function [-Wmaybe-uninitialized]
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
      ^~~~~~~~~~~~~~~~~
   drivers//dma/tegra20-apb-dma.c:811:16: note: 'wcount' was declared here
     unsigned long wcount;
                   ^~~~~~
>> drivers//dma/tegra20-apb-dma.c:843:30: warning: 'sg_req' may be used uninitialized in this function [-Wmaybe-uninitialized]
       result = residual - sg_req->req_len;
                           ~~~~~~^~~~~~~~~
   drivers//dma/tegra20-apb-dma.c:894:27: note: 'sg_req' was declared here
     struct tegra_dma_sg_req *sg_req;
                              ^~~~~~

vim +/sg_req +843 drivers//dma/tegra20-apb-dma.c

   804	
   805	static unsigned int tegra_dma_update_residual(struct tegra_dma_channel *tdc,
   806						      struct tegra_dma_sg_req *sg_req,
   807						      struct tegra_dma_desc *dma_desc,
   808						      unsigned int residual)
   809	{
   810		unsigned long status = 0x0;
   811		unsigned long wcount;
   812		unsigned long ahbptr;
   813		unsigned long tmp = 0x0;
   814		unsigned int result;
   815		int retries = TEGRA_APBDMA_BURST_COMPLETE_TIME * 10;
   816		int done;
   817	
   818		/* if we're not the current request, then don't alter the residual */
   819		if (sg_req != list_first_entry(&tdc->pending_sg_req,
   820					       struct tegra_dma_sg_req, node)) {
   821			result = residual;
   822			ahbptr = 0xffffffff;
   823			goto done;
   824		}
   825	
   826		/* loop until we have a reliable result for residual */
   827		do {
   828			ahbptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBPTR);
   829			status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
   830			tmp =  tdc_read(tdc, 0x08);	/* total count for debug */
   831	
   832			/* check status, if channel isn't busy then skip */
   833			if (!(status & TEGRA_APBDMA_STATUS_BUSY)) {
   834				result = residual;
   835				break;
   836			}
   837	
   838			/* if we've got an interrupt pending on the channel, don't
   839			 * try and deal with the residue as the hardware has likely
   840			 * moved on to the next buffer. return all data moved.
   841			 */
   842			if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
 > 843				result = residual - sg_req->req_len;
   844				break;
   845			}
   846	
   847			if (tdc->tdma->chip_data->support_separate_wcount_reg)
   848				wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER);
   849			else
   850				wcount = status;
   851	
   852			/* If the request is at the full point, then there is a
   853			 * chance that we have read the status register in the
   854			 * middle of the hardware reloading the next buffer.
   855			 *
   856			 * The sequence seems to be at the end of the buffer, to
   857			 * load the new word count before raising the EOC flag (or
   858			 * changing the ping-pong flag which could have also been
   859			 * used to determine a new buffer). This  means there is a
   860			 * small window where we cannot determine zero-done for the
   861			 * current buffer, or moved to next buffer.
   862			 *
   863			 * If done shows 0, then retry the load, as it may hit the
   864			 * above hardware race. We will either get a new value which
   865			 * is from the first buffer, or we get an EOC (new buffer)
   866			 * or both a new value and an EOC...
   867			 */
   868			done = get_current_xferred_count(tdc, sg_req, wcount);
   869			if (done != 0) {
   870				result = residual - done;
   871				break;
   872			}
   873	
   874			ndelay(100);
   875		} while (--retries > 0);
   876	
   877		if (retries <= 0) {
   878			dev_err(tdc2dev(tdc), "timeout waiting for dma load\n");
   879			result = residual;
   880		}
   881
---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* [6/6] dma: tegra: add tracepoint for residual update
From: Steven Rostedt @ 2018-10-12 17:04 UTC (permalink / raw)
  To: Ben Dooks
  Cc: dan.j.williams, vkoul, ldewangan, dmaengine, linux-tegra,
	Ingo Molnar

On Fri, 12 Oct 2018 10:44:54 +0100
Ben Dooks <ben.dooks@codethink.co.uk> wrote:

> Add a tracepoint in the residual update instead of using dev_dbg()
> to allow debugging via the trace pipe.
> 
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
> Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
> Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
> ---
>  drivers/dma/tegra20-apb-dma.c        |  5 ++---
>  include/trace/events/tegra_apb_dma.h | 27 +++++++++++++++++++++++++++
>  2 files changed, 29 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
> index 96095a3b7edd..495cda6c21b9 100644
> --- a/drivers/dma/tegra20-apb-dma.c
> +++ b/drivers/dma/tegra20-apb-dma.c
> @@ -886,9 +886,8 @@ static unsigned int tegra_dma_update_residual(struct tegra_dma_channel *tdc,
>  	}
>  
>  done:	
> -	dev_dbg(tdc2dev(tdc), "residual: req %08lx, ahb@%08lx, wcount %08lx, done %d\n",
> -		 sg_req->ch_regs.ahb_ptr, ahbptr, wcount, done);
> -
> +	trace_tegra_dma_tx_state(&tdc->dma_chan, ahbptr, status, result,
> +				 tmp, residual);
>  	return result;
>  }
>  
> diff --git a/include/trace/events/tegra_apb_dma.h b/include/trace/events/tegra_apb_dma.h
> index 80d6f0cf4c36..a686f98a9c8b 100644
> --- a/include/trace/events/tegra_apb_dma.h
> +++ b/include/trace/events/tegra_apb_dma.h
> @@ -43,6 +43,33 @@ TRACE_EVENT(tegra_dma_complete_cb,
>  		      __entry->count, __entry->ptr)
>  );
>  
> +TRACE_EVENT(tegra_dma_tx_state,
> +	    TP_PROTO(struct dma_chan *dc, unsigned long ahb,
> +		     unsigned long wc, unsigned int done,
> +		     unsigned long byte_count, unsigned int residual),
> +	    TP_ARGS(dc, ahb, wc, done, byte_count, residual),
> +	    TP_STRUCT__entry(
> +		    __field(struct dma_chan *,	dc)
> +		    __field(unsigned long,	ahb)
> +		    __field(unsigned long,	wc)
> +		    __field(unsigned long,	done)
> +		    __field(unsigned int,	residual)
> +		    __field(unsigned long,	byte_count)
> +		    ),
> +	    TP_fast_assign(
> +		    __entry->dc = dc;
> +		    __entry->ahb = ahb;
> +		    __entry->wc = wc;
> +		    __entry->done = done;
> +		    __entry->residual = residual;
> +		    __entry->byte_count = byte_count;
> +		    ),
> +	    TP_printk("%s: txresidual: ahb %08lx wc %08lx => done %lu bc %lu residual %u",
> +		      dev_name(&__entry->dc->dev->device),

Here too. Move the dev_name() up into TP_fast_assign() which gets
executed at the time of call of the trace event. The TP_printk() can
happen any time later, when someone reads the tracing buffer.

-- Steve

> +		      __entry->ahb, __entry->wc, __entry->done,
> +		      __entry->byte_count, __entry->residual)
> +);
> +
>  TRACE_EVENT(tegra_dma_isr,
>  	    TP_PROTO(struct dma_chan *dc, int irq),
>  	    TP_ARGS(dc, irq),

^ permalink raw reply

* [5/6] dma: tegra: add tracepoints to driver
From: Steven Rostedt @ 2018-10-12 17:01 UTC (permalink / raw)
  To: Ben Dooks
  Cc: dan.j.williams, vkoul, ldewangan, dmaengine, linux-tegra,
	Ingo Molnar

On Fri, 12 Oct 2018 10:44:53 +0100
Ben Dooks <ben.dooks@codethink.co.uk> wrote:

> Add some trace-points to the driver to allow for debuging via the
> trace pipe.
> 
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
> Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
> Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
> ---
>  drivers/dma/tegra20-apb-dma.c        |  8 ++++
>  include/trace/events/tegra_apb_dma.h | 63 ++++++++++++++++++++++++++++
>  2 files changed, 71 insertions(+)
>  create mode 100644 include/trace/events/tegra_apb_dma.h
> 
> diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
> index ce2888f67254..96095a3b7edd 100644
> --- a/drivers/dma/tegra20-apb-dma.c
> +++ b/drivers/dma/tegra20-apb-dma.c
> @@ -38,6 +38,9 @@
>  
>  #include "dmaengine.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include <trace/events/tegra_apb_dma.h>
> +
>  #define TEGRA_APBDMA_GENERAL			0x0
>  #define TEGRA_APBDMA_GENERAL_ENABLE		BIT(31)
>  
> @@ -672,6 +675,8 @@ static void tegra_dma_tasklet(unsigned long data)
>  		dmaengine_desc_get_callback(&dma_desc->txd, &cb);
>  		cb_count = dma_desc->cb_count;
>  		dma_desc->cb_count = 0;
> +		trace_tegra_dma_complete_cb(&tdc->dma_chan, cb_count,
> +					    cb.callback);
>  		spin_unlock_irqrestore(&tdc->lock, flags);
>  		while (cb_count--)
>  			dmaengine_desc_callback_invoke(&cb, NULL);
> @@ -688,6 +693,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
>  
>  	spin_lock_irqsave(&tdc->lock, flags);
>  
> +	trace_tegra_dma_isr(&tdc->dma_chan, irq);
>  	status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
>  	if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
>  		tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
> @@ -931,6 +937,8 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
>  		dma_set_residue(txstate, residual);
>  	}
>  
> +	trace_tegra_dma_tx_status(&tdc->dma_chan, cookie,
> +				  txstate ? txstate->residue : -1);

Why just pass in txstate and put that logic into the trace event code?

See below.

>  	spin_unlock_irqrestore(&tdc->lock, flags);
>  	return ret;
>  }
> diff --git a/include/trace/events/tegra_apb_dma.h b/include/trace/events/tegra_apb_dma.h
> new file mode 100644
> index 000000000000..80d6f0cf4c36
> --- /dev/null
> +++ b/include/trace/events/tegra_apb_dma.h
> @@ -0,0 +1,63 @@
> +#if !defined(_TRACE_TEGRA_APB_DMA_H) || defined(TRACE_HEADER_MULTI_READ)
> +#define _TRACE_TEGRA_APM_DMA_H
> +
> +#include <linux/tracepoint.h>
> +#include <linux/dmaengine.h>
> +
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM tegra_apb_dma
> +
> +TRACE_EVENT(tegra_dma_tx_status,
> +	TP_PROTO(struct dma_chan *dc, s32 cookie, u32 residue),

	TP_PROTO(struct dma_chan *dc, s32 cookie,
		struct dma_tx_state *txstate),

> +	TP_ARGS(dc, cookie, residue),

	TP_ARGS(dc, cookie, txstate),

> +	TP_STRUCT__entry(
> +		__field(struct dma_chan *, dc)
> +		__field(__s32,	cookie)
> +		__field(__u32,	residue)
> +	),
> +	TP_fast_assign(
> +		__entry->dc = dc;
> +		__entry->cookie = cookie;
> +		__entry->residue = residue;

		__entry->residue = txstate ? txstate->residue : -1;


> +	),
> +	TP_printk("channel %s: dma cookie %d, residue %u",
> +		  dev_name(&__entry->dc->dev->device),

The dev_name must be done in the TP_fast_assign part (use __string).
What you have here can crash the system. That is, you saved the dc
pointer into the ring buffer. Now that dc pointer may be freed, and
then when you read the ring buffer, we are now dereferencing the stale
and freed dc pointer and BOOM!


> +		  __entry->cookie, __entry->residue)
> +);
> +
> +TRACE_EVENT(tegra_dma_complete_cb,
> +	    TP_PROTO(struct dma_chan *dc, int count, void *ptr),
> +	    TP_ARGS(dc, count, ptr),
> +	    TP_STRUCT__entry(
> +		    __field(struct dma_chan *,	dc)
> +		    __field(int,		count)
> +		    __field(void *,		ptr)
> +		    ),
> +	    TP_fast_assign(
> +		    __entry->dc = dc;
> +		    __entry->count = count;
> +		    __entry->ptr = ptr;
> +		    ),
> +	    TP_printk("channel %s: done %d, ptr %p",
> +		      dev_name(&__entry->dc->dev->device),

Same here.

> +		      __entry->count, __entry->ptr)
> +);
> +
> +TRACE_EVENT(tegra_dma_isr,
> +	    TP_PROTO(struct dma_chan *dc, int irq),
> +	    TP_ARGS(dc, irq),
> +	    TP_STRUCT__entry(
> +		    __field(struct dma_chan *,	dc)
> +		    __field(int,		irq)
> +		    ),
> +	    TP_fast_assign(
> +		    __entry->dc = dc;
> +		    __entry->irq = irq;
> +		    ),
> +	    TP_printk("%s: irq %d\n",  dev_name(&__entry->dc->dev->device),

And here.

-- Steve

> +		      __entry->irq));
> +
> +#endif /*  _TRACE_TEGRADMA_H */
> +
> +/* This part must be outside protection */
> +#include <trace/define_trace.h>

^ permalink raw reply

* [v3,2/7] dt-bindings: stm32-dmamux: Add one cell to support DMA/MDMA chain
From: Rob Herring @ 2018-10-12 14:46 UTC (permalink / raw)
  To: Pierre-Yves MORDRET
  Cc: Vinod Koul, Mark Rutland, Alexandre Torgue, Maxime Coquelin,
	Dan Williams, devicetree, dmaengine, linux-arm-kernel,
	linux-kernel

On Fri, Sep 28, 2018 at 03:01:50PM +0200, Pierre-Yves MORDRET wrote:
> From: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
> 
> Add one cell to support DMA/MDMA chaining.

You aren't adding a cell. Is the change compatible with existing users 
(if you mask bits)?

> 
> Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>

Author S-o-b missing.

> ---
>   Version history:
>     v3:
>     v2:
>        * rework content
>     v1:
>        * Initial
> ---
> ---
>  Documentation/devicetree/bindings/dma/stm32-dmamux.txt | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt
> index 1b893b2..5e92b59 100644
> --- a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt
> +++ b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt
> @@ -4,9 +4,9 @@ Required properties:
>  - compatible:	"st,stm32h7-dmamux"
>  - reg:		Memory map for accessing module
>  - #dma-cells:	Should be set to <3>.
> -		First parameter is request line number.
> -		Second is DMA channel configuration
> -		Third is Fifo threshold
> +-		First parameter is request line number.
> +-		Second is DMA channel configuration
> +-		Third is a 32bit bitfield
>  		For more details about the three cells, please see
>  		stm32-dma.txt documentation binding file
>  - dma-masters:	Phandle pointing to the DMA controllers.
> -- 
> 2.7.4
>

^ permalink raw reply

* [v3,1/7] dt-bindings: stm32-dma: Add DMA/MDMA chaining support bindings
From: Rob Herring @ 2018-10-12 14:42 UTC (permalink / raw)
  To: Pierre-Yves MORDRET
  Cc: Vinod Koul, Mark Rutland, Alexandre Torgue, Maxime Coquelin,
	Dan Williams, devicetree, dmaengine, linux-arm-kernel,
	linux-kernel

On Fri, Sep 28, 2018 at 03:01:49PM +0200, Pierre-Yves MORDRET wrote:
> From: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
> 
> This patch adds dma bindings to support DMA/MDMA chaining transfer.
> 1 bit is to manage both DMA FIFO Threshold
> 1 bit is to manage DMA/MDMA Chaining features.
> 2 bits are used to specify SDRAM size to use for DMA/MDMA chaining.
> The size in bytes of a certain order is given by the formula:
>     (2 ^ order) * PAGE_SIZE.
> The order is given by those 2 bits.
> For cyclic, whether chaining is chosen, any value above 1 can be set :
> SRAM buffer size will rely on period size and not on this DT value.
> 
> Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>

Missing author S-o-b.

> ---
>   Version history:
>     v3:
>     v2:
>        * rework content
>     v1:
>        * Initial
> ---
> ---
>  .../devicetree/bindings/dma/stm32-dma.txt          | 27 +++++++++++++++++++++-
>  1 file changed, 26 insertions(+), 1 deletion(-)

^ permalink raw reply

* [RFC,2/5] dmaengine: Add function to request slave channel from a dma_device
From: Peter Ujfalusi @ 2018-10-12 12:07 UTC (permalink / raw)
  To: Vinod; +Cc: dan.j.williams, dmaengine, grygorii.strashko

On 2018-10-09 14:22, Peter Ujfalusi wrote:
> 
> 
> On 2018-10-09 13:49, Vinod wrote:
>> On 24-09-18, 16:00, Peter Ujfalusi wrote:
>>> dma_get_any_slave_channel() would skip using the filter function, which
>>> in some cases needed to be executed before the alloc_chan_resources
>>> callback to make sure that all parameters are provided for the slave
>>> channel.
>>
>> Another request API, i though you had solved that last time around :(
> 
> Yes, I thought so, but this time it is different.
> I want to drop this patch myself also, but I need to figure out a way to
> do what the dmadev_get_slave_channel() allows me to do.
> 
> In path 4, udma_of_xlate() and the udma_dma_filter_fn()
> 
> It might be possible that I look up a free udma_chan, do the setup via
> the filter_fn() and finally call the dma_get_slave_channel().
> Might work fine, but I wanted to avoid to implement my own find free
> channel code when we have it already in DMAengine core.

It is going to be racy against parallel channel requests, but

>>> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
>>> index 16c9d021988a..32010c6ae13a 100644
>>> --- a/include/linux/dmaengine.h
>>> +++ b/include/linux/dmaengine.h
>>> @@ -1542,6 +1542,8 @@ void dma_async_device_unregister(struct dma_device *device);
>>>  void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
>>>  struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);
>>>  struct dma_chan *dma_get_any_slave_channel(struct dma_device *device);
>>> +struct dma_chan *dmadev_get_slave_channel(struct dma_device *device,
>>> +					  dma_filter_fn fn, void *fn_param);

-struct dma_chan *dma_get_any_slave_channel(struct dma_device *device);
+struct dma_chan *dmadev_get_slave_channel(struct dma_device *device,
 				dma_filter_fn fn, void *fn_param);
+#define dma_get_any_slave_channel(device)\
	 dmadev_get_slave_channel(device, NULL, NULL)

Should cut down on duplicated code at least.


>>>  #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
>>>  #define dma_request_slave_channel_compat(mask, x, y, dev, name) \
>>>  	__dma_request_slave_channel_compat(&(mask), x, y, dev, name)
>>> -- 
>>> Peter
>>>
>>> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
>>> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
>>
> 
> - Péter
> 
> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply

* [7/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Rob Herring @ 2018-10-12 11:31 UTC (permalink / raw)
  To: Peng Ma
  Cc: vkoul@kernel.org, Leo Li, mark.rutland@arm.com,
	shawnguo@kernel.org, dan.j.williams@intel.com, zw@zh-kernel.org,
	dmaengine@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, Jiafei Pan

On Fri, Oct 12, 2018 at 02:25:25AM +0000, Peng Ma wrote:
> Hi Rob,
> 
> > -----Original Message-----
> > From: Rob Herring [mailto:robh@kernel.org]
> > Sent: 2018年10月12日 6:09
> > To: Peng Ma <peng.ma@nxp.com>
> > Cc: vkoul@kernel.org; Leo Li <leoyang.li@nxp.com>; mark.rutland@arm.com;
> > shawnguo@kernel.org; dan.j.williams@intel.com; zw@zh-kernel.org;
> > dmaengine@vger.kernel.org; devicetree@vger.kernel.org;
> > linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> > linuxppc-dev@lists.ozlabs.org
> > Subject: Re: [PATCH 7/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA
> > controller bindings
> > 
> > On Thu, Oct 11, 2018 at 05:46:55PM +0800, Peng Ma wrote:
> > > Document the devicetree bindings for NXP Layerscape qDMA controller
> > > which could be found on NXP QorIQ Layerscape SoCs.
> > >
> > > Signed-off-by: Peng Ma <peng.ma@nxp.com>
> > 
> > What happened to the version from Wen He that was on v7 and that I already
> > gave my Reviewed-by on?
> 
> [Peng Ma] the dma owner is changed and qdma driver made some changes, so I need send those patch again to review!

That's no reason to make changes or drop the original author. You should 
also indicate this is v9 and provide revision history.

Rob

^ permalink raw reply

* [6/6] dma: tegra: add tracepoint for residual update
From: Ben Dooks @ 2018-10-12  9:44 UTC (permalink / raw)
  To: dan.j.williams, vkoul
  Cc: ldewangan, dmaengine, linux-tegra, Ben Dooks, Ingo Molnar,
	Steven Rostedt

Add a tracepoint in the residual update instead of using dev_dbg()
to allow debugging via the trace pipe.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
---
 drivers/dma/tegra20-apb-dma.c        |  5 ++---
 include/trace/events/tegra_apb_dma.h | 27 +++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 96095a3b7edd..495cda6c21b9 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -886,9 +886,8 @@ static unsigned int tegra_dma_update_residual(struct tegra_dma_channel *tdc,
 	}
 
 done:	
-	dev_dbg(tdc2dev(tdc), "residual: req %08lx, ahb@%08lx, wcount %08lx, done %d\n",
-		 sg_req->ch_regs.ahb_ptr, ahbptr, wcount, done);
-
+	trace_tegra_dma_tx_state(&tdc->dma_chan, ahbptr, status, result,
+				 tmp, residual);
 	return result;
 }
 
diff --git a/include/trace/events/tegra_apb_dma.h b/include/trace/events/tegra_apb_dma.h
index 80d6f0cf4c36..a686f98a9c8b 100644
--- a/include/trace/events/tegra_apb_dma.h
+++ b/include/trace/events/tegra_apb_dma.h
@@ -43,6 +43,33 @@ TRACE_EVENT(tegra_dma_complete_cb,
 		      __entry->count, __entry->ptr)
 );
 
+TRACE_EVENT(tegra_dma_tx_state,
+	    TP_PROTO(struct dma_chan *dc, unsigned long ahb,
+		     unsigned long wc, unsigned int done,
+		     unsigned long byte_count, unsigned int residual),
+	    TP_ARGS(dc, ahb, wc, done, byte_count, residual),
+	    TP_STRUCT__entry(
+		    __field(struct dma_chan *,	dc)
+		    __field(unsigned long,	ahb)
+		    __field(unsigned long,	wc)
+		    __field(unsigned long,	done)
+		    __field(unsigned int,	residual)
+		    __field(unsigned long,	byte_count)
+		    ),
+	    TP_fast_assign(
+		    __entry->dc = dc;
+		    __entry->ahb = ahb;
+		    __entry->wc = wc;
+		    __entry->done = done;
+		    __entry->residual = residual;
+		    __entry->byte_count = byte_count;
+		    ),
+	    TP_printk("%s: txresidual: ahb %08lx wc %08lx => done %lu bc %lu residual %u",
+		      dev_name(&__entry->dc->dev->device),
+		      __entry->ahb, __entry->wc, __entry->done,
+		      __entry->byte_count, __entry->residual)
+);
+
 TRACE_EVENT(tegra_dma_isr,
 	    TP_PROTO(struct dma_chan *dc, int irq),
 	    TP_ARGS(dc, irq),

^ permalink raw reply related

* [5/6] dma: tegra: add tracepoints to driver
From: Ben Dooks @ 2018-10-12  9:44 UTC (permalink / raw)
  To: dan.j.williams, vkoul
  Cc: ldewangan, dmaengine, linux-tegra, Ben Dooks, Ingo Molnar,
	Steven Rostedt

Add some trace-points to the driver to allow for debuging via the
trace pipe.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
---
 drivers/dma/tegra20-apb-dma.c        |  8 ++++
 include/trace/events/tegra_apb_dma.h | 63 ++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 include/trace/events/tegra_apb_dma.h

diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index ce2888f67254..96095a3b7edd 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -38,6 +38,9 @@
 
 #include "dmaengine.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/tegra_apb_dma.h>
+
 #define TEGRA_APBDMA_GENERAL			0x0
 #define TEGRA_APBDMA_GENERAL_ENABLE		BIT(31)
 
@@ -672,6 +675,8 @@ static void tegra_dma_tasklet(unsigned long data)
 		dmaengine_desc_get_callback(&dma_desc->txd, &cb);
 		cb_count = dma_desc->cb_count;
 		dma_desc->cb_count = 0;
+		trace_tegra_dma_complete_cb(&tdc->dma_chan, cb_count,
+					    cb.callback);
 		spin_unlock_irqrestore(&tdc->lock, flags);
 		while (cb_count--)
 			dmaengine_desc_callback_invoke(&cb, NULL);
@@ -688,6 +693,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
 
 	spin_lock_irqsave(&tdc->lock, flags);
 
+	trace_tegra_dma_isr(&tdc->dma_chan, irq);
 	status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
 	if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
 		tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
@@ -931,6 +937,8 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
 		dma_set_residue(txstate, residual);
 	}
 
+	trace_tegra_dma_tx_status(&tdc->dma_chan, cookie,
+				  txstate ? txstate->residue : -1);
 	spin_unlock_irqrestore(&tdc->lock, flags);
 	return ret;
 }
diff --git a/include/trace/events/tegra_apb_dma.h b/include/trace/events/tegra_apb_dma.h
new file mode 100644
index 000000000000..80d6f0cf4c36
--- /dev/null
+++ b/include/trace/events/tegra_apb_dma.h
@@ -0,0 +1,63 @@
+#if !defined(_TRACE_TEGRA_APB_DMA_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TEGRA_APM_DMA_H
+
+#include <linux/tracepoint.h>
+#include <linux/dmaengine.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM tegra_apb_dma
+
+TRACE_EVENT(tegra_dma_tx_status,
+	TP_PROTO(struct dma_chan *dc, s32 cookie, u32 residue),
+	TP_ARGS(dc, cookie, residue),
+	TP_STRUCT__entry(
+		__field(struct dma_chan *, dc)
+		__field(__s32,	cookie)
+		__field(__u32,	residue)
+	),
+	TP_fast_assign(
+		__entry->dc = dc;
+		__entry->cookie = cookie;
+		__entry->residue = residue;
+	),
+	TP_printk("channel %s: dma cookie %d, residue %u",
+		  dev_name(&__entry->dc->dev->device),
+		  __entry->cookie, __entry->residue)
+);
+
+TRACE_EVENT(tegra_dma_complete_cb,
+	    TP_PROTO(struct dma_chan *dc, int count, void *ptr),
+	    TP_ARGS(dc, count, ptr),
+	    TP_STRUCT__entry(
+		    __field(struct dma_chan *,	dc)
+		    __field(int,		count)
+		    __field(void *,		ptr)
+		    ),
+	    TP_fast_assign(
+		    __entry->dc = dc;
+		    __entry->count = count;
+		    __entry->ptr = ptr;
+		    ),
+	    TP_printk("channel %s: done %d, ptr %p",
+		      dev_name(&__entry->dc->dev->device),
+		      __entry->count, __entry->ptr)
+);
+
+TRACE_EVENT(tegra_dma_isr,
+	    TP_PROTO(struct dma_chan *dc, int irq),
+	    TP_ARGS(dc, irq),
+	    TP_STRUCT__entry(
+		    __field(struct dma_chan *,	dc)
+		    __field(int,		irq)
+		    ),
+	    TP_fast_assign(
+		    __entry->dc = dc;
+		    __entry->irq = irq;
+		    ),
+	    TP_printk("%s: irq %d\n",  dev_name(&__entry->dc->dev->device),
+		      __entry->irq));
+
+#endif /*  _TRACE_TEGRADMA_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>

^ permalink raw reply related

* [4/6] dma: tegra: add accurate reporting of dma state
From: Ben Dooks @ 2018-10-12  9:44 UTC (permalink / raw)
  To: dan.j.williams, vkoul; +Cc: ldewangan, dmaengine, linux-tegra, Ben Dooks

The tx_status callback does not report the state of the transfer
beyond complete segments. This causes problems with users such as
ALSA when applications want to know accurately how much data has
been moved.

This patch addes a function tegra_dma_update_residual() to query
the hardware and modify the residual information accordinly. It
takes into account any hardware issues when trying to read the
state, such as delays between finishing a buffer and signalling
the interrupt.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
 drivers/dma/tegra20-apb-dma.c | 92 ++++++++++++++++++++++++++++++++---
 1 file changed, 86 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 4f7d1e576d03..ce2888f67254 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -802,6 +802,90 @@ static int tegra_dma_terminate_all(struct dma_chan *dc)
 	return 0;
 }
 
+static unsigned int tegra_dma_update_residual(struct tegra_dma_channel *tdc,
+					      struct tegra_dma_sg_req *sg_req,
+					      struct tegra_dma_desc *dma_desc,
+					      unsigned int residual)
+{
+	unsigned long status = 0x0;
+	unsigned long wcount;
+	unsigned long ahbptr;
+	unsigned long tmp = 0x0;
+	unsigned int result;
+	int retries = TEGRA_APBDMA_BURST_COMPLETE_TIME * 10;
+	int done;
+
+	/* if we're not the current request, then don't alter the residual */
+	if (sg_req != list_first_entry(&tdc->pending_sg_req,
+				       struct tegra_dma_sg_req, node)) {
+		result = residual;
+		ahbptr = 0xffffffff;
+		goto done;
+	}
+
+	/* loop until we have a reliable result for residual */
+	do {
+		ahbptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBPTR);
+		status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+		tmp =  tdc_read(tdc, 0x08);	/* total count for debug */
+
+		/* check status, if channel isn't busy then skip */
+		if (!(status & TEGRA_APBDMA_STATUS_BUSY)) {
+			result = residual;
+			break;
+		}
+
+		/* if we've got an interrupt pending on the channel, don't
+		 * try and deal with the residue as the hardware has likely
+		 * moved on to the next buffer. return all data moved.
+		 */
+		if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
+			result = residual - sg_req->req_len;
+			break;
+		}
+
+		if (tdc->tdma->chip_data->support_separate_wcount_reg)
+			wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER);
+		else
+			wcount = status;
+
+		/* If the request is at the full point, then there is a
+		 * chance that we have read the status register in the
+		 * middle of the hardware reloading the next buffer.
+		 *
+		 * The sequence seems to be at the end of the buffer, to
+		 * load the new word count before raising the EOC flag (or
+		 * changing the ping-pong flag which could have also been
+		 * used to determine a new buffer). This  means there is a
+		 * small window where we cannot determine zero-done for the
+		 * current buffer, or moved to next buffer.
+		 *
+		 * If done shows 0, then retry the load, as it may hit the
+		 * above hardware race. We will either get a new value which
+		 * is from the first buffer, or we get an EOC (new buffer)
+		 * or both a new value and an EOC...
+		 */
+		done = get_current_xferred_count(tdc, sg_req, wcount);
+		if (done != 0) {
+			result = residual - done;
+			break;
+		}
+
+		ndelay(100);
+	} while (--retries > 0);
+
+	if (retries <= 0) {
+		dev_err(tdc2dev(tdc), "timeout waiting for dma load\n");
+		result = residual;
+	}
+
+done:	
+	dev_dbg(tdc2dev(tdc), "residual: req %08lx, ahb@%08lx, wcount %08lx, done %d\n",
+		 sg_req->ch_regs.ahb_ptr, ahbptr, wcount, done);
+
+	return result;
+}
+
 static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
 	dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
@@ -843,6 +927,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
 		residual = dma_desc->bytes_requested -
 			   (dma_desc->bytes_transferred %
 			    dma_desc->bytes_requested);
+		residual = tegra_dma_update_residual(tdc, sg_req, dma_desc, residual);
 		dma_set_residue(txstate, residual);
 	}
 
@@ -1436,12 +1521,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
 		BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
 		BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
 	tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
-	/*
-	 * XXX The hardware appears to support
-	 * DMA_RESIDUE_GRANULARITY_BURST-level reporting, but it's
-	 * only used by this driver during tegra_dma_terminate_all()
-	 */
-	tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+	tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
 	tdma->dma_dev.device_config = tegra_dma_slave_config;
 	tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all;
 	tdma->dma_dev.device_tx_status = tegra_dma_tx_status;

^ permalink raw reply related

* [3/6] dma: tegra: fix incorrect case of DMA
From: Ben Dooks @ 2018-10-12  9:44 UTC (permalink / raw)
  To: dan.j.williams, vkoul; +Cc: ldewangan, dmaengine, linux-tegra, Ben Dooks

The use of Dma is annoying, since it is an acronym so should be all
upper case. Fix this throughout the driver.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
 drivers/dma/tegra20-apb-dma.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index adfd918baedc..4f7d1e576d03 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -146,7 +146,7 @@ struct tegra_dma_channel_regs {
 };
 
 /*
- * tegra_dma_sg_req: Dma request details to configure hardware. This
+ * tegra_dma_sg_req: DMA request details to configure hardware. This
  * contains the details for one transfer to configure DMA hw.
  * The client's request for data transfer can be broken into multiple
  * sub-transfer as per requester details and hw support.
@@ -574,7 +574,7 @@ static bool handle_continuous_head_request(struct tegra_dma_channel *tdc,
 	struct tegra_dma_sg_req *hsgreq = NULL;
 
 	if (list_empty(&tdc->pending_sg_req)) {
-		dev_err(tdc2dev(tdc), "Dma is running without req\n");
+		dev_err(tdc2dev(tdc), "DMA is running without req\n");
 		tegra_dma_stop(tdc);
 		return false;
 	}
@@ -922,7 +922,7 @@ static int get_transfer_param(struct tegra_dma_channel *tdc,
 		return 0;
 
 	default:
-		dev_err(tdc2dev(tdc), "Dma direction is not supported\n");
+		dev_err(tdc2dev(tdc), "DMA direction is not supported\n");
 		return -EINVAL;
 	}
 	return -EINVAL;
@@ -988,7 +988,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
 
 	dma_desc = tegra_dma_desc_get(tdc);
 	if (!dma_desc) {
-		dev_err(tdc2dev(tdc), "Dma descriptors not available\n");
+		dev_err(tdc2dev(tdc), "DMA descriptors not available\n");
 		return NULL;
 	}
 	INIT_LIST_HEAD(&dma_desc->tx_list);
@@ -1008,14 +1008,14 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
 		if ((len & 3) || (mem & 3) ||
 				(len > tdc->tdma->chip_data->max_dma_count)) {
 			dev_err(tdc2dev(tdc),
-				"Dma length/memory address is not supported\n");
+				"DMA length/memory address is not supported\n");
 			tegra_dma_desc_put(tdc, dma_desc);
 			return NULL;
 		}
 
 		sg_req = tegra_dma_sg_req_get(tdc);
 		if (!sg_req) {
-			dev_err(tdc2dev(tdc), "Dma sg-req not available\n");
+			dev_err(tdc2dev(tdc), "DMA sg-req not available\n");
 			tegra_dma_desc_put(tdc, dma_desc);
 			return NULL;
 		}
@@ -1147,7 +1147,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
 	while (remain_len) {
 		sg_req = tegra_dma_sg_req_get(tdc);
 		if (!sg_req) {
-			dev_err(tdc2dev(tdc), "Dma sg-req not available\n");
+			dev_err(tdc2dev(tdc), "DMA sg-req not available\n");
 			tegra_dma_desc_put(tdc, dma_desc);
 			return NULL;
 		}

^ permalink raw reply related

* [2/6] dma: tegra: make byte counters unsigned int
From: Ben Dooks @ 2018-10-12  9:44 UTC (permalink / raw)
  To: dan.j.williams, vkoul; +Cc: ldewangan, dmaengine, linux-tegra, Ben Dooks

The buffer byte request length and counter are declared as signed integers
but the values should never be below zero, so make these unsigned integers
instead.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
 drivers/dma/tegra20-apb-dma.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 8219ab88a507..adfd918baedc 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -155,7 +155,7 @@ struct tegra_dma_channel_regs {
  */
 struct tegra_dma_sg_req {
 	struct tegra_dma_channel_regs	ch_regs;
-	int				req_len;
+	unsigned int			req_len;
 	bool				configured;
 	bool				last_sg;
 	struct list_head		node;
@@ -169,8 +169,8 @@ struct tegra_dma_sg_req {
  */
 struct tegra_dma_desc {
 	struct dma_async_tx_descriptor	txd;
-	int				bytes_requested;
-	int				bytes_transferred;
+	unsigned int			bytes_requested;
+	unsigned int			bytes_transferred;
 	enum dma_status			dma_status;
 	struct list_head		node;
 	struct list_head		tx_list;

^ permalink raw reply related

* [1/6] dma: tegra: avoid overflow of byte tracking
From: Ben Dooks @ 2018-10-12  9:44 UTC (permalink / raw)
  To: dan.j.williams, vkoul; +Cc: ldewangan, dmaengine, linux-tegra, Ben Dooks

The dma_desc->bytes_transferred counter tracks the number of bytes
moved by the DMA channel. This is then used to calculate the information
passed back in the in the tegra_dma_tx_status callback, which is usually
fine.

When the DMA channel is configured as continous, then the bytes_transferred
counter will increase over time and eventually overflow to become negative
so the residue count will become invalid and the ALSA sound-dma code will
report invalid hardware pointer values to the application. This results in
some users becoming confused about the playout position and putting audio
data in the wrong place.

To fix this issue, always ensure the bytes_transferred field is modulo the
size of the request. We only do this for the case of the cyclic transfer
done ISR as anyone attempting to move 2GiB of DMA data in one transfer
is unlikely.

Note, we don't fix the issue that we should /never/ transfer a negative
number of bytes so we could make those fields unsigned.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
 drivers/dma/tegra20-apb-dma.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 9a558e30c461..8219ab88a507 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -636,7 +636,10 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
 
 	sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node);
 	dma_desc = sgreq->dma_desc;
-	dma_desc->bytes_transferred += sgreq->req_len;
+	/* if we dma for long enough the transfer count will wrap */
+	dma_desc->bytes_transferred =
+		(dma_desc->bytes_transferred + sgreq->req_len) %
+		dma_desc->bytes_requested;
 
 	/* Callback need to be call */
 	if (!dma_desc->cb_count)

^ permalink raw reply related

* [RFC,5/5] dmaengine: ti: k3-udma: Add glue layer for non DMAengine users
From: Peter Ujfalusi @ 2018-10-12  9:18 UTC (permalink / raw)
  To: Vinod; +Cc: dan.j.williams, dmaengine, grygorii.strashko

Vinod,

On 2018-10-10 12:44, Peter Ujfalusi wrote:
> 
> 
> On 2018-10-10 07:05, Vinod wrote:
>> On 24-09-18, 16:00, Peter Ujfalusi wrote:
>>> From: Grygorii Strashko <grygorii.strashko@ti.com>
>>>
>>> Certain users can not use right now the DMAengine API due to missing
>>> features in the core. Prime example is Networking.
>>
>> What are the features you have in mind?
> 
> The two big ones are:
> 1. Support for out of order completion of descriptors (cookie management)
> 
> This mostly concerns the DEV_TO_MEM.
> Currently we have dma_cookie_t (s32) to track which descriptor is
> completed, which one is issued and which one is pending.
> It is mandatory that descriptors are completed in the same order as they
> were issued.
> 
> We need to have support for out of order completion of the issued
> descriptors and thus the s32 way of tracking is not working.
> 
> We basically have three use cases needed to be supported:
> 1a: in order completion (currently supported by DMAengine)
> 1b: out of order completion in a channel, descriptors can complete in
> different order.
> 1c: out of order completion in a channel, the completion is ordered
> within 'classification type' of descriptors via the channel
> 
> If we issue descriptors 1, 2, 3, 4, 5, 6, 7
> 
> We could receive back them
> 1a: 1, 2, 3, 4, 5, 6, 7
> 1b: 4, 7, 2, 1, 3, 5, 6
> 
> in case of 1c we can classify descriptors when issuing:
> 1(c0), 2(c0), 3(c0), 4(c1), 5(c1), 6(c1), 7(c1)
> 
> and we receive the back like:
> 4(c1), 5(c1), 1(c0), 2(c0), 6(c1), 3(c0), 7(c1)
> 
> The descriptors are coming back in 'random' order, however they are in
> order within their classification.
> 
> The must supported one is 1b at the moment, 1c should be reasonably
> simple to add support for.
> 
> 2. NAPI support
> 
> Via NAPI an RX looks something like this:
> - give the hardware bunch of descriptors to receive packets
> - when the first packet is received get notification
>  - disable the interrupts
>  - schedule NAPI
> - in the NAPI poll function read out the completed descriptors one by
> one, process them, then give back the descriptor (with new buffer) to
> the hardware.
> - after poll finished (no more packets or got the number of packets NAPI
> told us to read out) enable the interrupts and wait for packets to start
> to flow in.

I have spent some time reading the http://www.ti.com/lit/pdf/spruid7
regarding to networking (cpsw, Chapter 12.2.1) and while 1 and 2 is
still valid as missing features there is one more issue I have
discovered which might prevent us using generic (DMAengine) API.

cpsw supports up to 9 ports (net_device) and have one RX DMA channel.
By default it uses 8 priority levels (flows) so depending on the packet
priority the packets are going to be received to different rings
(defined by the rflow configuration).

This is all fine if we could handle the out of order completion, but
packets from _all_ 9 ports are going to be received to these rings and
to make things a bit more problematic the port ID is coming within the
CPPI5 packet itself in the scr_dst_tag:

struct cppi5_desc_hdr_t {
	u32 pkt_info0;	/* Packet info word 0 (n/a in Buffer desc) */
	u32 pkt_info1;	/* Packet info word 1 (n/a in Buffer desc) */
	u32 pkt_info2;	/* Packet info word 2 Buffer reclamation info */
	u32 src_dst_tag; /* Packet info word 3 (n/a in Buffer desc) */
} __packed;

/**
 * Host-mode packet and buffer descriptor definition
 */
struct cppi5_host_desc_t {
	struct cppi5_desc_hdr_t hdr;
	u64 next_desc;	/* w4/5: Linking word */
	u64 buf_ptr;	/* w6/7: Buffer pointer */
	u32 buf_info1;	/* w8: Buffer valid data length */
	u32 org_buf_len; /* w9: Original buffer length */
	u64 org_buf_ptr; /* w10/11: Original buffer pointer */
	u32 epib[0]; /* Extended Packet Info Data (optional, 4 words) */
	/*
	 * Protocol Specific Data (optional, 0-128 bytes in multiples
	 * of 4), and/or Other Software Data (0-N bytes, optional)
	 */
} __packed;

It is not around the metadata section which starts at epib[].
In order to know which port received the packet the cpsw driver needs to
read the src_dst_tag and based on the value can select the correct
net_device.

So far I could only think two ways of handling this, which would be:
a. support for direct hw descriptor submission, so the client driver is
doing all the descriptor setup and the DMA driver is just provides an
interface to submit receive raw descriptors in kind of a passthrough mode.

b. Do not allow metadata pointer mode and create a CPPI5 specific struct
which would be attached and we would copy with CPU to/from it.

struct cppi5_metadata {
	u32 src_dst_tag;
	bool has_epib;
	u32 psdata_len;
	u32 swdata_len;
	u32 data[0];
};

This certainly going to add some overhead in the gigabit speed.

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply

* [7/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Peng Ma @ 2018-10-12  2:25 UTC (permalink / raw)
  To: Rob Herring
  Cc: vkoul@kernel.org, Leo Li, mark.rutland@arm.com,
	shawnguo@kernel.org, dan.j.williams@intel.com, zw@zh-kernel.org,
	dmaengine@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, Jiafei Pan

Hi Rob,

> -----Original Message-----
> From: Rob Herring [mailto:robh@kernel.org]
> Sent: 2018年10月12日 6:09
> To: Peng Ma <peng.ma@nxp.com>
> Cc: vkoul@kernel.org; Leo Li <leoyang.li@nxp.com>; mark.rutland@arm.com;
> shawnguo@kernel.org; dan.j.williams@intel.com; zw@zh-kernel.org;
> dmaengine@vger.kernel.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> linuxppc-dev@lists.ozlabs.org
> Subject: Re: [PATCH 7/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA
> controller bindings
> 
> On Thu, Oct 11, 2018 at 05:46:55PM +0800, Peng Ma wrote:
> > Document the devicetree bindings for NXP Layerscape qDMA controller
> > which could be found on NXP QorIQ Layerscape SoCs.
> >
> > Signed-off-by: Peng Ma <peng.ma@nxp.com>
> 
> What happened to the version from Wen He that was on v7 and that I already
> gave my Reviewed-by on?

[Peng Ma] the dma owner is changed and qdma driver made some changes, so I need send those patch again to review!

Best regards
	Peng Ma
> 
> > ---
> >  Documentation/devicetree/bindings/dma/fsl-qdma.txt |   53
> ++++++++++++++++++++
> >  1 files changed, 53 insertions(+), 0 deletions(-)  create mode 100644
> > Documentation/devicetree/bindings/dma/fsl-qdma.txt

^ permalink raw reply

* [7/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Rob Herring @ 2018-10-11 22:08 UTC (permalink / raw)
  To: Peng Ma
  Cc: vkoul, leoyang.li, mark.rutland, shawnguo, dan.j.williams, zw,
	dmaengine, devicetree, linux-kernel, linux-arm-kernel,
	linuxppc-dev

On Thu, Oct 11, 2018 at 05:46:55PM +0800, Peng Ma wrote:
> Document the devicetree bindings for NXP Layerscape qDMA controller
> which could be found on NXP QorIQ Layerscape SoCs.
> 
> Signed-off-by: Peng Ma <peng.ma@nxp.com>

What happened to the version from Wen He that was on v7 and that I 
already gave my Reviewed-by on?

> ---
>  Documentation/devicetree/bindings/dma/fsl-qdma.txt |   53 ++++++++++++++++++++
>  1 files changed, 53 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/dma/fsl-qdma.txt

^ permalink raw reply

* [v4,2/2] dmaengine: uniphier-mdmac: add UniPhier MIO DMAC driver
From: Masahiro Yamada @ 2018-10-11 16:41 UTC (permalink / raw)
  To: Vinod Koul, dmaengine
  Cc: Masami Hiramatsu, Jassi Brar, Masahiro Yamada, linux-kernel,
	Dan Williams, linux-arm-kernel

The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
Pro4, and sLD8 SoCs.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v4:
 - Use C style comments instead of C++ ones
 - Move long return types to the previous line
 - Remove distracting double-underscore prefixing
 - Fix a double-spacing between sentences
 - Remove the empty ->device_config hook
 - Fix residue calculation
 - Fix ->{src,dst}_addr_widths
 - Add ->device_free_chan_resources() hook
 - Make sure to stop the hardware in .remove hook
   and avoid memory leak

Changes in v3:
 - Get residue from on-flight chunk
 - Use GFP_NOWAIT instead of GFP_KERNEL in prep_slave_sg
 - Use device_config hook
 - Add NULL pointer check for txstate

Changes in v2:
 - Use platform_irq_count() to get the number of channels

 MAINTAINERS                  |   1 +
 drivers/dma/Kconfig          |  11 +
 drivers/dma/Makefile         |   1 +
 drivers/dma/uniphier-mdmac.c | 506 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 519 insertions(+)
 create mode 100644 drivers/dma/uniphier-mdmac.c

diff --git a/MAINTAINERS b/MAINTAINERS
index e38ba7e..847fa12 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2192,6 +2192,7 @@ F:	arch/arm/mm/cache-uniphier.c
 F:	arch/arm64/boot/dts/socionext/uniphier*
 F:	drivers/bus/uniphier-system-bus.c
 F:	drivers/clk/uniphier/
+F:	drivers/dmaengine/uniphier-mdmac.c
 F:	drivers/gpio/gpio-uniphier.c
 F:	drivers/i2c/busses/i2c-uniphier*
 F:	drivers/irqchip/irq-uniphier-aidet.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index dacf3f4..8b8c7f0 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -576,6 +576,17 @@ config TIMB_DMA
 	help
 	  Enable support for the Timberdale FPGA DMA engine.
 
+config UNIPHIER_MDMAC
+	tristate "UniPhier MIO DMAC"
+	depends on ARCH_UNIPHIER || COMPILE_TEST
+	depends on OF
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Enable support for the MIO DMAC (Media I/O DMA controller) on the
+	  UniPhier platform.  This DMA controller is used as the external
+	  DMA engine of the SD/eMMC controllers of the LD4, Pro4, sLD8 SoCs.
+
 config XGENE_DMA
 	tristate "APM X-Gene DMA support"
 	depends on ARCH_XGENE || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index c91702d..973a170 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
 obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
 obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
+obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
 obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
 obj-$(CONFIG_ZX_DMA) += zx_dma.o
 obj-$(CONFIG_ST_FDMA) += st_fdma.o
diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c
new file mode 100644
index 0000000..ec65a7430
--- /dev/null
+++ b/drivers/dma/uniphier-mdmac.c
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 Socionext Inc.
+//   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "virt-dma.h"
+
+/* registers common for all channels */
+#define UNIPHIER_MDMAC_CMD		0x000	/* issue DMA start/abort */
+#define   UNIPHIER_MDMAC_CMD_ABORT		BIT(31) /* 1: abort, 0: start */
+
+/* per-channel registers */
+#define UNIPHIER_MDMAC_CH_OFFSET	0x100
+#define UNIPHIER_MDMAC_CH_STRIDE	0x040
+
+#define UNIPHIER_MDMAC_CH_IRQ_STAT	0x010	/* current hw status (RO) */
+#define UNIPHIER_MDMAC_CH_IRQ_REQ	0x014	/* latched STAT (WOC) */
+#define UNIPHIER_MDMAC_CH_IRQ_EN	0x018	/* IRQ enable mask */
+#define UNIPHIER_MDMAC_CH_IRQ_DET	0x01c	/* REQ & EN (RO) */
+#define   UNIPHIER_MDMAC_CH_IRQ__ABORT		BIT(13)
+#define   UNIPHIER_MDMAC_CH_IRQ__DONE		BIT(1)
+#define UNIPHIER_MDMAC_CH_SRC_MODE	0x020	/* mode of source */
+#define UNIPHIER_MDMAC_CH_DEST_MODE	0x024	/* mode of destination */
+#define   UNIPHIER_MDMAC_CH_MODE__ADDR_INC	(0 << 4)
+#define   UNIPHIER_MDMAC_CH_MODE__ADDR_DEC	(1 << 4)
+#define   UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED	(2 << 4)
+#define UNIPHIER_MDMAC_CH_SRC_ADDR	0x028	/* source address */
+#define UNIPHIER_MDMAC_CH_DEST_ADDR	0x02c	/* destination address */
+#define UNIPHIER_MDMAC_CH_SIZE		0x030	/* transfer bytes */
+
+#define UNIPHIER_MDMAC_SLAVE_BUSWIDTHS \
+	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+	 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+	 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
+	 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
+struct uniphier_mdmac_desc {
+	struct virt_dma_desc vd;
+	struct scatterlist *sgl;
+	unsigned int sg_len;
+	unsigned int sg_cur;
+	enum dma_transfer_direction dir;
+};
+
+struct uniphier_mdmac_chan {
+	struct virt_dma_chan vc;
+	struct uniphier_mdmac_device *mdev;
+	struct uniphier_mdmac_desc *md;
+	void __iomem *reg_ch_base;
+	unsigned int chan_id;
+};
+
+struct uniphier_mdmac_device {
+	struct dma_device ddev;
+	struct clk *clk;
+	void __iomem *reg_base;
+	struct uniphier_mdmac_chan channels[0];
+};
+
+static struct uniphier_mdmac_chan *
+to_uniphier_mdmac_chan(struct virt_dma_chan *vc)
+{
+	return container_of(vc, struct uniphier_mdmac_chan, vc);
+}
+
+static struct uniphier_mdmac_desc *
+to_uniphier_mdmac_desc(struct virt_dma_desc *vd)
+{
+	return container_of(vd, struct uniphier_mdmac_desc, vd);
+}
+
+/* mc->vc.lock must be held by caller */
+static struct uniphier_mdmac_desc *
+uniphier_mdmac_next_desc(struct uniphier_mdmac_chan *mc)
+{
+	struct virt_dma_desc *vd;
+
+	vd = vchan_next_desc(&mc->vc);
+	if (!vd) {
+		mc->md = NULL;
+		return NULL;
+	}
+
+	list_del(&vd->node);
+
+	mc->md = to_uniphier_mdmac_desc(vd);
+
+	return mc->md;
+}
+
+/* mc->vc.lock must be held by caller */
+static void uniphier_mdmac_handle(struct uniphier_mdmac_chan *mc,
+				  struct uniphier_mdmac_desc *md)
+{
+	struct uniphier_mdmac_device *mdev = mc->mdev;
+	struct scatterlist *sg;
+	u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__DONE;
+	u32 src_mode, src_addr, dest_mode, dest_addr, chunk_size;
+
+	sg = &md->sgl[md->sg_cur];
+
+	if (md->dir == DMA_MEM_TO_DEV) {
+		src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
+		src_addr = sg_dma_address(sg);
+		dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
+		dest_addr = 0;
+	} else {
+		src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
+		src_addr = 0;
+		dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
+		dest_addr = sg_dma_address(sg);
+	}
+
+	chunk_size = sg_dma_len(sg);
+
+	writel(src_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_MODE);
+	writel(dest_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_MODE);
+	writel(src_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_ADDR);
+	writel(dest_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_ADDR);
+	writel(chunk_size, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SIZE);
+
+	/* write 1 to clear */
+	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
+
+	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_EN);
+
+	writel(BIT(mc->chan_id), mdev->reg_base + UNIPHIER_MDMAC_CMD);
+}
+
+/* mc->vc.lock must be held by caller */
+static void uniphier_mdmac_start(struct uniphier_mdmac_chan *mc)
+{
+	struct uniphier_mdmac_desc *md;
+
+	md = uniphier_mdmac_next_desc(mc);
+	if (md)
+		uniphier_mdmac_handle(mc, md);
+}
+
+/* mc->vc.lock must be held by caller */
+static int uniphier_mdmac_abort(struct uniphier_mdmac_chan *mc)
+{
+	struct uniphier_mdmac_device *mdev = mc->mdev;
+	u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__ABORT;
+	u32 val;
+
+	/* write 1 to clear */
+	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
+
+	writel(UNIPHIER_MDMAC_CMD_ABORT | BIT(mc->chan_id),
+	       mdev->reg_base + UNIPHIER_MDMAC_CMD);
+
+	/*
+	 * Abort should be accepted soon. We poll the bit here instead of
+	 * waiting for the interrupt.
+	 */
+	return readl_poll_timeout(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ,
+				  val, val & irq_flag, 0, 20);
+}
+
+static irqreturn_t uniphier_mdmac_interrupt(int irq, void *dev_id)
+{
+	struct uniphier_mdmac_chan *mc = dev_id;
+	struct uniphier_mdmac_desc *md;
+	irqreturn_t ret = IRQ_HANDLED;
+	u32 irq_stat;
+
+	spin_lock(&mc->vc.lock);
+
+	irq_stat = readl(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_DET);
+
+	/*
+	 * Some channels share a single interrupt line. If the IRQ status is 0,
+	 * this is probably triggered by a different channel.
+	 */
+	if (!irq_stat) {
+		ret = IRQ_NONE;
+		goto out;
+	}
+
+	/* write 1 to clear */
+	writel(irq_stat, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
+
+	/*
+	 * UNIPHIER_MDMAC_CH_IRQ__DONE interrupt is asserted even when the DMA
+	 * is aborted. To distinguish the normal completion and the abort,
+	 * check mc->md. If it is NULL, we are aborting.
+	 */
+	md = mc->md;
+	if (!md)
+		goto out;
+
+	md->sg_cur++;
+
+	if (md->sg_cur >= md->sg_len) {
+		vchan_cookie_complete(&md->vd);
+		md = uniphier_mdmac_next_desc(mc);
+		if (!md)
+			goto out;
+	}
+
+	uniphier_mdmac_handle(mc, md);
+
+out:
+	spin_unlock(&mc->vc.lock);
+
+	return ret;
+}
+
+static void uniphier_mdmac_free_chan_resources(struct dma_chan *chan)
+{
+	vchan_free_chan_resources(to_virt_chan(chan));
+}
+
+static struct dma_async_tx_descriptor *
+uniphier_mdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+			     unsigned int sg_len,
+			     enum dma_transfer_direction direction,
+			     unsigned long flags, void *context)
+{
+	struct virt_dma_chan *vc = to_virt_chan(chan);
+	struct uniphier_mdmac_desc *md;
+
+	if (!is_slave_direction(direction))
+		return NULL;
+
+	md = kzalloc(sizeof(*md), GFP_NOWAIT);
+	if (!md)
+		return NULL;
+
+	md->sgl = sgl;
+	md->sg_len = sg_len;
+	md->dir = direction;
+
+	return vchan_tx_prep(vc, &md->vd, flags);
+}
+
+static int uniphier_mdmac_terminate_all(struct dma_chan *chan)
+{
+	struct virt_dma_chan *vc = to_virt_chan(chan);
+	struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
+	unsigned long flags;
+	int ret = 0;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&vc->lock, flags);
+
+	if (mc->md) {
+		vchan_terminate_vdesc(&mc->md->vd);
+		mc->md = NULL;
+		ret = uniphier_mdmac_abort(mc);
+	}
+	vchan_get_all_descriptors(vc, &head);
+
+	spin_unlock_irqrestore(&vc->lock, flags);
+
+	vchan_dma_desc_free_list(vc, &head);
+
+	return ret;
+}
+
+static void uniphier_mdmac_synchronize(struct dma_chan *chan)
+{
+	vchan_synchronize(to_virt_chan(chan));
+}
+
+static enum dma_status uniphier_mdmac_tx_status(struct dma_chan *chan,
+						dma_cookie_t cookie,
+						struct dma_tx_state *txstate)
+{
+	struct virt_dma_chan *vc;
+	struct virt_dma_desc *vd;
+	struct uniphier_mdmac_chan *mc;
+	struct uniphier_mdmac_desc *md = NULL;
+	enum dma_status stat;
+	unsigned long flags;
+	int i;
+
+	stat = dma_cookie_status(chan, cookie, txstate);
+	/* Return immediately if we do not need to compute the residue. */
+	if (stat == DMA_COMPLETE || !txstate)
+		return stat;
+
+	vc = to_virt_chan(chan);
+
+	spin_lock_irqsave(&vc->lock, flags);
+
+	mc = to_uniphier_mdmac_chan(vc);
+
+	if (mc->md && mc->md->vd.tx.cookie == cookie) {
+		/* residue from the on-flight chunk */
+		txstate->residue = readl(mc->reg_ch_base +
+					 UNIPHIER_MDMAC_CH_SIZE);
+		md = mc->md;
+	}
+
+	if (!md) {
+		vd = vchan_find_desc(vc, cookie);
+		if (vd)
+			md = to_uniphier_mdmac_desc(vd);
+	}
+
+	if (md) {
+		/* residue from the queued chunks */
+		for (i = md->sg_cur; i < md->sg_len; i++)
+			txstate->residue += sg_dma_len(&md->sgl[i]);
+	}
+
+	spin_unlock_irqrestore(&vc->lock, flags);
+
+	return stat;
+}
+
+static void uniphier_mdmac_issue_pending(struct dma_chan *chan)
+{
+	struct virt_dma_chan *vc = to_virt_chan(chan);
+	struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&vc->lock, flags);
+
+	if (vchan_issue_pending(vc) && !mc->md)
+		uniphier_mdmac_start(mc);
+
+	spin_unlock_irqrestore(&vc->lock, flags);
+}
+
+static void uniphier_mdmac_desc_free(struct virt_dma_desc *vd)
+{
+	kfree(to_uniphier_mdmac_desc(vd));
+}
+
+static int uniphier_mdmac_chan_init(struct platform_device *pdev,
+				    struct uniphier_mdmac_device *mdev,
+				    int chan_id)
+{
+	struct device *dev = &pdev->dev;
+	struct uniphier_mdmac_chan *mc = &mdev->channels[chan_id];
+	char *irq_name;
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, chan_id);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get IRQ number for ch%d\n",
+			chan_id);
+		return irq;
+	}
+
+	irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d",
+				  chan_id);
+	if (!irq_name)
+		return -ENOMEM;
+
+	ret = devm_request_irq(dev, irq, uniphier_mdmac_interrupt,
+			       IRQF_SHARED, irq_name, mc);
+	if (ret)
+		return ret;
+
+	mc->mdev = mdev;
+	mc->reg_ch_base = mdev->reg_base + UNIPHIER_MDMAC_CH_OFFSET +
+					UNIPHIER_MDMAC_CH_STRIDE * chan_id;
+	mc->chan_id = chan_id;
+	mc->vc.desc_free = uniphier_mdmac_desc_free;
+	vchan_init(&mc->vc, &mdev->ddev);
+
+	return 0;
+}
+
+static int uniphier_mdmac_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct uniphier_mdmac_device *mdev;
+	struct dma_device *ddev;
+	struct resource *res;
+	int nr_chans, ret, i;
+
+	nr_chans = platform_irq_count(pdev);
+	if (nr_chans < 0)
+		return nr_chans;
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
+			    GFP_KERNEL);
+	if (!mdev)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mdev->reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mdev->reg_base))
+		return PTR_ERR(mdev->reg_base);
+
+	mdev->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(mdev->clk)) {
+		dev_err(dev, "failed to get clock\n");
+		return PTR_ERR(mdev->clk);
+	}
+
+	ret = clk_prepare_enable(mdev->clk);
+	if (ret)
+		return ret;
+
+	ddev = &mdev->ddev;
+	ddev->dev = dev;
+	dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
+	ddev->src_addr_widths = UNIPHIER_MDMAC_SLAVE_BUSWIDTHS;
+	ddev->dst_addr_widths = UNIPHIER_MDMAC_SLAVE_BUSWIDTHS;
+	ddev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+	ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+	ddev->device_free_chan_resources = uniphier_mdmac_free_chan_resources;
+	ddev->device_prep_slave_sg = uniphier_mdmac_prep_slave_sg;
+	ddev->device_terminate_all = uniphier_mdmac_terminate_all;
+	ddev->device_synchronize = uniphier_mdmac_synchronize;
+	ddev->device_tx_status = uniphier_mdmac_tx_status;
+	ddev->device_issue_pending = uniphier_mdmac_issue_pending;
+	INIT_LIST_HEAD(&ddev->channels);
+
+	for (i = 0; i < nr_chans; i++) {
+		ret = uniphier_mdmac_chan_init(pdev, mdev, i);
+		if (ret)
+			goto disable_clk;
+	}
+
+	ret = dma_async_device_register(ddev);
+	if (ret)
+		goto disable_clk;
+
+	ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id,
+					 ddev);
+	if (ret)
+		goto unregister_dmac;
+
+	platform_set_drvdata(pdev, mdev);
+
+	return 0;
+
+unregister_dmac:
+	dma_async_device_unregister(ddev);
+disable_clk:
+	clk_disable_unprepare(mdev->clk);
+
+	return ret;
+}
+
+static int uniphier_mdmac_remove(struct platform_device *pdev)
+{
+	struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
+	struct dma_chan *chan;
+	int ret;
+
+	/*
+	 * Before reaching here, almost all descriptors have been freed by the
+	 * ->device_free_chan_resources() hook. However, each channel might
+	 * be still holding one descriptor that was on-flight at that moment.
+	 * Terminate it to make sure this hardware is no longer running. Then,
+	 * free the channel resources once again to avoid memory leak.
+	 */
+	list_for_each_entry(chan, &mdev->ddev.channels, device_node) {
+		ret = dmaengine_terminate_sync(chan);
+		if (ret)
+			return ret;
+		uniphier_mdmac_free_chan_resources(chan);
+	}
+
+	of_dma_controller_free(pdev->dev.of_node);
+	dma_async_device_unregister(&mdev->ddev);
+	clk_disable_unprepare(mdev->clk);
+
+	return 0;
+}
+
+static const struct of_device_id uniphier_mdmac_match[] = {
+	{ .compatible = "socionext,uniphier-mio-dmac" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_mdmac_match);
+
+static struct platform_driver uniphier_mdmac_driver = {
+	.probe = uniphier_mdmac_probe,
+	.remove = uniphier_mdmac_remove,
+	.driver = {
+		.name = "uniphier-mio-dmac",
+		.of_match_table = uniphier_mdmac_match,
+	},
+};
+module_platform_driver(uniphier_mdmac_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier MIO DMAC driver");
+MODULE_LICENSE("GPL v2");

^ permalink raw reply related

* [v4,1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Masahiro Yamada @ 2018-10-11 16:41 UTC (permalink / raw)
  To: Vinod Koul, dmaengine
  Cc: Masami Hiramatsu, Jassi Brar, Masahiro Yamada, devicetree,
	linux-kernel, Rob Herring, Mark Rutland, linux-arm-kernel

The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
Pro4, and sLD8 SoCs.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---

Changes in v4: None
Changes in v3:
 - Add Rob's Reviewed-by

Changes in v2:
 - Rename the node "dmac" to "dma-controller"
 - Remove dma-channels property

 .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt

diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
new file mode 100644
index 0000000..b12388d
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
@@ -0,0 +1,25 @@
+UniPhier Media IO DMA controller
+
+This works as an external DMA engine for SD/eMMC controllers etc.
+found in UniPhier LD4, Pro4, sLD8 SoCs.
+
+Required properties:
+- compatible: should be "socionext,uniphier-mio-dmac".
+- reg: offset and length of the register set for the device.
+- interrupts: a list of interrupt specifiers associated with the DMA channels.
+- clocks: a single clock specifier.
+- #dma-cells: should be <1>. The single cell represents the channel index.
+
+Example:
+	dmac: dma-controller@5a000000 {
+		compatible = "socionext,uniphier-mio-dmac";
+		reg = <0x5a000000 0x1000>;
+		interrupts = <0 68 4>, <0 68 4>, <0 69 4>, <0 70 4>,
+			     <0 71 4>, <0 72 4>, <0 73 4>, <0 74 4>;
+		clocks = <&mio_clk 7>;
+		#dma-cells = <1>;
+	};
+
+Note:
+In the example above, "interrupts = <0 68 4>, <0 68 4>, ..." is not a typo.
+The first two channels share a single interrupt line.

^ permalink raw reply related

* [v3,2/2] dmaengine: uniphier-mdmac: add UniPhier MIO DMAC driver
From: Masahiro Yamada @ 2018-10-11 16:27 UTC (permalink / raw)
  To: Vinod Koul
  Cc: open list:DMA GENERIC OFFLOAD ENGINE SUBSYSTEM, Masami Hiramatsu,
	Jassi Brar, Linux Kernel Mailing List, Dan Williams,
	linux-arm-kernel

On Sun, Oct 7, 2018 at 1:23 AM Vinod <vkoul@kernel.org> wrote:
> > > > +static int uniphier_mdmac_probe(struct platform_device *pdev)
> > > > +{
> > > > +     struct device *dev = &pdev->dev;
> > > > +     struct uniphier_mdmac_device *mdev;
> > > > +     struct dma_device *ddev;
> > > > +     struct resource *res;
> > > > +     int nr_chans, ret, i;
> > > > +
> > > > +     nr_chans = platform_irq_count(pdev);
> > > > +     if (nr_chans < 0)
> > > > +             return nr_chans;
> > > > +
> > > > +     ret = dma_set_mask(dev, DMA_BIT_MASK(32));
> > > > +     if (ret)
> > > > +             return ret;
> > > > +
> > > > +     mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
> > > > +                         GFP_KERNEL);
> > > > +     if (!mdev)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > +     mdev->reg_base = devm_ioremap_resource(dev, res);
> > > > +     if (IS_ERR(mdev->reg_base))
> > > > +             return PTR_ERR(mdev->reg_base);
> > > > +
> > > > +     mdev->clk = devm_clk_get(dev, NULL);
> > > > +     if (IS_ERR(mdev->clk)) {
> > > > +             dev_err(dev, "failed to get clock\n");
> > > > +             return PTR_ERR(mdev->clk);
> > > > +     }
> > > > +
> > > > +     ret = clk_prepare_enable(mdev->clk);
> > > > +     if (ret)
> > > > +             return ret;
> > > > +
> > > > +     ddev = &mdev->ddev;
> > > > +     ddev->dev = dev;
> > > > +     dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
> > > > +     ddev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> > > > +     ddev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> > >
> > > undefined?
> >
> > Precisely, I do not know the *_addr_widths.
>
> This is "your" controller, you know the capability!

No, I do not.

I wrote this driver, but the hardware-internal is not fully documented
in the datasheet.
I can see the functionality only from the software point of view.


> >
> > As far as I read dmaengine/provider.rst
> > this represents the data bytes that are read/written at a time.
> >
> > Really I do not know (care about) the transfer width.
> >
> > As I commented in v2, the connection of the device side is hard-wired.
> > The transfer width cannot be observed from SW view.
> >
> > What should I do?
>
> Add the widths that are supported by the controller

To my best knowledge, this DMA engine is connected to a 32-bit bus.
So, 4 bytes are read/written at a time.

This HW allows to set the transfer size by byte granularity.
So, it would be possible to access the data bus
by 1-byte, 2-bytes, 3-bytes as well.

I will set the OR of 1, 2, 3, 4 bytes.





> > > > +static int uniphier_mdmac_remove(struct platform_device *pdev)
> > > > +{
> > > > +     struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
> > > > +
> > > > +     of_dma_controller_free(pdev->dev.of_node);
> > > > +     dma_async_device_unregister(&mdev->ddev);
> > > > +     clk_disable_unprepare(mdev->clk);
> > >
> > > at this point your irq is registered and can be fired, the tasklets are
> > > not killed :(
> >
> >
> > Please let me clarify the concerns here.
> >
> > Before the .remove hook is called, all the consumers should
> > have already put the dma channels.
> > So, no new descriptor is coming in.
> >
> > However,
> >
> > Some already-issued descriptors might be remaining, and being processed.
> >
> > [1] This DMA engine might be still running
> >     when clk_disable_unprepare() is being called.
> >     The register access with its clock disabled
> >     would cause the system crash.
>
> Yes and dmaengine may fire a spurious irq..
> >
> > [2] vchan_cookie_complete() might being called at this point
> >     and schedule the tasklet.
> >     It might call uniphier_mdmac_desc_free() after
> >     the reference disapperrs.
> >
> > Is this correct?
>
> Correct :)
>
> > Do you have recommendation
> > for module removal guideline?
>
> Yes please free up or disable irq explictly, ensure pending irqs have
> completed and then ensure all the tasklets are killed and in this order
> for obvious reasons

Also, need to free up the left-over descriptor(s) right?
Just killing the tasklets may result in memory leak.

Please let know if the implementation in v4 is wrong.

^ permalink raw reply

* [7/7] dt-bindings: fsl-qdma: Add NXP Layerscpae qDMA controller bindings
From: Peng Ma @ 2018-10-11  9:46 UTC (permalink / raw)
  To: vkoul, leoyang.li
  Cc: robh+dt, mark.rutland, shawnguo, dan.j.williams, zw, dmaengine,
	devicetree, linux-kernel, linux-arm-kernel, linuxppc-dev, Peng Ma

Document the devicetree bindings for NXP Layerscape qDMA controller
which could be found on NXP QorIQ Layerscape SoCs.

Signed-off-by: Peng Ma <peng.ma@nxp.com>
---
 Documentation/devicetree/bindings/dma/fsl-qdma.txt |   53 ++++++++++++++++++++
 1 files changed, 53 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..7e2160b
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/fsl-qdma.txt
@@ -0,0 +1,53 @@
+NXP Layerscape SoC qDMA Controller
+==================================
+
+The qDMA supports channel virtualization by allowing DMA jobs to be enqueued into
+different command queues. Core can initiate a DMA transaction by preparing a command
+descriptor for each DMA job and enqueuing this job to a command queue.
+
+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 : Specifies base physical address(s) and size of the qDMA registers.
+	The 1st region is qDMA control register's address and size.
+	The 2nd region is status queue control register's address and size.
+	The 3rd region is virtual block control register's address and size.
+- interrupts : A list of interrupt-specifiers, one for each entry in
+	interrupt-names.
+- interrupt-names : Should contain:
+	"qdma-queue0" - the block0 interrupt
+	"qdma-queue1" - the block1 interrupt
+	"qdma-queue2" - the block2 interrupt
+	"qdma-queue3" - the block3 interrupt
+	"qdma-error"  - the error interrupt
+- channels : Number of DMA channels supported
+- block-number : the virtual block number
+- block-offset : the offset of different virtual block
+- queues : the number of command queue per virtual block
+- status-sizes : status queue size of per virtual block
+- queue-sizes : command queue size of per virtual block, the size number based on queues
+- big-endian: If present registers and hardware scatter/gather descriptors
+	of the qDMA are implemented in big endian mode, otherwise in little
+	mode.
+
+Examples:
+	qdma: qdma@8390000 {
+				compatible = "fsl,ls1021a-qdma";
+				reg = <0x0 0x8388000 0x0 0x1000>, /* Controller regs */
+				      <0x0 0x8389000 0x0 0x1000>, /* Status regs */
+				      <0x0 0x838a000 0x0 0x2000>; /* Block regs */
+				interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "qdma-error",
+					"qdma-queue0", "qdma-queue1";
+				channels = <8>;
+				block-number = <2>;
+				block-offset = <0x1000>;
+				queues = <2>;
+				status-sizes = <64>;
+				queue-sizes = <64 64>;
+				big-endian;
+			};

^ permalink raw reply related

* [6/7] arm64: dts: ls1046a: add qdma device tree nodes
From: Peng Ma @ 2018-10-11  9:46 UTC (permalink / raw)
  To: vkoul, leoyang.li
  Cc: robh+dt, mark.rutland, shawnguo, dan.j.williams, zw, dmaengine,
	devicetree, linux-kernel, linux-arm-kernel, linuxppc-dev, Peng Ma

add the qDMA device tree nodes for LS1046A devices.

Signed-off-by: Peng Ma <peng.ma@nxp.com>
---
 arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index ef83786..9f36293 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -704,6 +704,27 @@
 					<0000 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		qdma: qdma@8380000 {
+			compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma";
+			reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */
+			      <0x0 0x8390000 0x0 0x10000>, /* Status regs */
+			      <0x0 0x83a0000 0x0 0x40000>; /* Block regs */
+			interrupts = <0 153 0x4>,
+				     <0 39 0x4>,
+				     <0 40 0x4>,
+				     <0 41 0x4>,
+				     <0 42 0x4>;
+			interrupt-names = "qdma-error", "qdma-queue0",
+				"qdma-queue1", "qdma-queue2", "qdma-queue3";
+			channels = <8>;
+			block-number = <1>;
+			block-offset = <0x10000>;
+			queues = <2>;
+			status-sizes = <64>;
+			queue-sizes = <64 64>;
+			big-endian;
+		};
+
 	};
 
 	reserved-memory {

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox