[PATCH v2 1/3] dmaengine: mxs-dma: add dma support for i.MX23/28
Russell King - ARM Linux
linux at arm.linux.org.uk
Thu Feb 17 10:09:24 EST 2011
On Thu, Feb 17, 2011 at 03:38:30PM +0100, Arnd Bergmann wrote:
> On Monday 14 February 2011, Shawn Guo wrote:
> > +static void mxs_dma_tasklet(unsigned long data)
> > +{
> > + struct mxs_dma_chan *mxs_chan = (struct mxs_dma_chan *) data;
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&mxs_chan->lock, flags);
> > +
> > + if (mxs_chan->desc.callback)
> > + mxs_chan->desc.callback(mxs_chan->desc.callback_param);
> > +
> > + if (mxs_chan->status == DMA_SUCCESS)
> > + mxs_chan->last_completed = mxs_chan->desc.cookie;
> > +
> > + spin_unlock_irqrestore(&mxs_chan->lock, flags);
> > +}
>
> Here is a different problem. The entire tasklet has interrupts
> disabled and holds the spinlock that the interrupt handler does
> not hold.
>
> This actually makes the tasklet a stricter context than the
> actual interrupt handler, defeating the purpose of tasklets
> (i.e. that you can run code without disabling interrupts).
>
> I don't know what the rules for dmaengine callbacks are regarding
> the context in which they are called, but it seems you should
> either get rid of the spin_lock_irqsave here or do everything
> from the interrupt handler.
dmaengine callbacks should be made from tasklet context with no locks
held.
The generally accepted way to do this is:
dma_async_tx_callback callback;
void *callback_param;
spin_lock_irqsave(&mxs_chan->lock, flags);
callback = mxs_chan->desc.callback;
callback_param = mxs_chan->desc.callback_param;
if (mxs_chan->status == DMA_SUCCESS)
mxs_chan->last_completed = mxs_chan->desc.cookie;
spin_unlock_irqrestore(&mxs_chan->lock, flags);
if (callback)
callback(callback_param);
which also avoids the locking issue when the callback starts the next
MMC request.
More information about the linux-arm-kernel
mailing list