[PATCH] DMA: extend documentation to provide more API details

Guennadi Liakhovetski g.liakhovetski at gmx.de
Mon Oct 7 06:45:33 EDT 2013


On Sun, 6 Oct 2013, Vinod Koul wrote:

> Pls keep Dan cced!

Sure, sorry.

> On Sun, Oct 06, 2013 at 12:31:37AM +0100, Russell King - ARM Linux wrote:
> > On Sat, Oct 05, 2013 at 11:00:45PM +0200, Guennadi Liakhovetski wrote:
> > > On Sat, 5 Oct 2013, Russell King - ARM Linux wrote:
> > > 
> > > > On Sat, Oct 05, 2013 at 07:36:20PM +0200, Guennadi Liakhovetski wrote:
> > > > > +	A DMA transaction descriptor, returned to the user by one of "prep"
> > > > > +	methods is considered as belogning to the user until it is submitted
> > > > > +	to the dmaengine driver for transfer. However, it is recommended, that
> > > > > +	the dmaengine driver keeps references to prepared descriptors too,
> > > > > +	because if dmaengine_terminate_all() is called at that time, the driver
> > > > > +	will have to recycle all allocated descriptors for the respective
> > > > > +	channel.
> > > > 
> > > > No.  That's quite dangerous.  think about what can happen.
> > > > 
> > > > Thread 1		Thread 2
> > > > Driver calls prepare
> > > > 			dmaengine_terminate_all()
> > > > 				dmaengine driver frees prepared descriptor
> > > > driver submits descriptor
> > > > 
> > > > You now have a descriptor which has been freed submitted to the DMA engine
> > > > queue.  This will cause chaos.
> > > 
> > > Yes, I understand this. So, it is intentional, that after a *_prep_* a 
> > > descriptor belongs to the user and - if the user fails - it will simply be 
> > > leaked. A terminate-all shouldn't recycle them and dmaengine driver 
> > > unbinding is impossible at that time, as long as the user hasn't released 
> > > the channel. Ok, I can rework the above just to explain this.
> > 
> > "the user fails" should be very difficult.  One of the requirements here
> > is that any "user" submits the prepared descriptor as soon as possible
> > after preparation.  Some DMA engine implementations hold a spinlock
> > between preparation and submission so this is absolutely necessary.
> > 
> > As Dan Williams explained to me, the reason for the separate submission
> > step is there to allow the callback information to be set.  So literally
> > any "user" of this should do this:
> > 
> > 	desc = prepare();
> > 	if (!desc)
> > 		goto failed_to_prepare;
> > 
> > 	desc->callback = function;
> > 	desc->callback_param = param;
> > 	dmaengine_submit(desc);
> > 
> > There should be very little possiblity of the user failing between those
> > two calls.
> > 
> > > > > -   On completion of each DMA operation, the next in queue is started and
> > > > > -   a tasklet triggered. The tasklet will then call the client driver
> >           ^^^^^^^^^^^^^^^^^^^^
> > > > > -   completion callback routine for notification, if set.
> > > > > +   On completion of each DMA operation, the next active transaction in queue is
> > > > > +   started and the ISR bottom half, e.g. a tasklet or a kernel thread is
> > > > > +   triggered.
> > > > 
> > > > Or a kernel thread?  I don't think that's right.  It's always been
> > > > specified that the callback will happen from tasklet context.
> > > 
> > > Do you see any problems using, say, a threaded interrupt handler, apart 
> > > from possible performance issues? That seems to be pretty convenient. 
> > > Otherwise we should really mandate somewhere, that bottom half processing 
> > > should take place in a tasklet?
> > 
> > The documentation has always stated that callbacks will be made from
> > tasklet context.  The problem with allowing different contexts from
> > different drivers is taht spinlocking becomes problematical.  Remember
> > that we have _bh() variants which lock against tasklets but allow IRQs.

Vinod, Dan, what do you think about the bottom half interrupt processing? 
Do we want to make the use of a tasklet compulsory or can we also allow 
other contexts?

> > > > > +   The dmaengine driver also has to check the DMA_CTRL_ACK flag by calling
> > > > > +   async_tx_test_ack() on the transaction. If the function returns true, i.e.
> > > > > +   if the transaction either has been flagged from the very beginning, or
> > > > > +   the user has flagged it later, then the transaction descriptor can be
> > > > > +   recycled immediately by the dmaengine driver.
> > > > 
> > > > "has to check" I think is wrong.  This is optional for slave only drivers,
> > > > because most slave stuff doesn't use the ACK stuff - that's more for the
> > > > async_tx APIs.
> > > 
> > > "most," but some do? E.g. the mx3_camera driver. Ok, that one is very 
> > > tightly bound to the respective dmaengine driver. But if there are other 
> > > slave drivers, using that, that can run on different platforms and use 
> > > various dmaengine drivers?
> > 
> > I'm not aware of any which actually make use of the ack stuff.  Only those
> > which implement the async_tx must implement this because it gets used for
> > chaining and dependency stuff.  However, there was a plan to remove this
> > and replace it with proper refcounting.
> > 
> > > > > If the function returns
> > > > > +   false, the descriptor cannot be recycled yet and the dmaengine driver has
> > > > > +   to keep polling the descriptor until it is acknowledged by the user.
> > > > >  
> > > > >     Interface:
> > > > >  	void dma_async_issue_pending(struct dma_chan *chan);
> > > > > @@ -171,6 +192,14 @@ Further APIs:
> > > > >     discard data in the DMA FIFO which hasn't been fully transferred.
> > > > >     No callback functions will be called for any incomplete transfers.
> > > > >  
> > > > > +   Note:
> > > > > +	Transactions, aborted by this call are considered as failed. However,
> > > > > +	if the user requests their status, using dma_async_is_complete() /
> > > > > +	dma_async_is_complete(), as described below, one of DMA_IN_PROGRESS and
> > > > > +	DMA_SUCCESS will be returned. So, drivers are advised not to use those
> > > > > +	calls on transactions, submitted before a call to
> > > > > +	dmaengine_terminate_all().
> > > > 
> > > > The last sentence doesn't make sense.
> > > 
> > > Right, sorry, there is a typo in the second line (to remind: this note is 
> > > for the dmaengine_terminate_all() function):
> > > 
> > > +   Note:
> > > +	Transactions, aborted by this call are considered as failed. However,
> > > +	if the user requests their status, using dma_async_is_tx_complete() /
> > > +	dma_async_is_complete(), as described below, one of DMA_IN_PROGRESS and
> > > +	DMA_SUCCESS will be returned. So, drivers are advised not to use those
> > > +	calls on transactions, submitted before a call to
> > > +	dmaengine_terminate_all().
> If you submit a bunch of descriptors then I see no reason when something in
> middle failed, the status for first descriptor which succedded is returned as an
> error even if user aborted the channel. The status query happens for a cookie
> which represents a descriptor. It doesnt return channel status.

No, not something in the middle. I was thinking about

(1) cookie 1-3 are submitted
(2) cookie 1 succeeds
(3) a DMA error occurs, cookies 2-3 are discarded
(4) cookie 4 is submitted and succeeds
(5) the user requests status of cookie 2 and gets success back, AFAICS

> > > What I was trying to say, is that if you submit transactions, then 
> > > terminate them, then try to retrieve their status using 
> > > dma_async_is_tx_complete() / dma_async_is_complete(), this won't produce 
> > > the expected DMA_ERROR result, instead, one of DMA_IN_PROGRESS and 
> > > DMA_SUCCESS will be returned, unless the driver implements some 
> > > sophisticated .device_tx_status() method.
> Well the moment you aborted the channel all the previously submitted descriptors
> can be freed by the driver. So you cant do anything with these. In the client
> driver care should be taken to drop all the references of descriptors and then
> terminate the channel.
> 
> > Remember that dmaengine_terminate_all() is targetted to a specific
> > channel - it terminates all submitted transactions on that channel
> > and stops any in-process transaction.  It doesn't affect any other
> > channel on the controller.
> > 
> > In the case of slave DMA users, you have to "own" the channel.  This
> > means it's up to the user to sort out what happens should _they_ call
> > dmaengine_terminate_all() on it.
> > 
> > For non-slave DMA users, I don't believe that terminating transactions
> > is permitted - they're expected to complete.
> 
> -- 
> ~Vinod

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/



More information about the linux-arm-kernel mailing list