[PATCH v2 1/3] dmaengine: mxs-dma: add dma support for i.MX23/28

Shawn Guo shawn.guo at freescale.com
Fri Feb 18 08:41:35 EST 2011


On Fri, Feb 18, 2011 at 02:22:39PM +0100, Arnd Bergmann wrote:
> On Friday 18 February 2011, Shawn Guo wrote:
> > > > +static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan)
> > > > +{
> > > > +   dma_cookie_t cookie = mxs_chan->chan.cookie;
> > > > +
> > > > +   if (++cookie < 0)
> > > > +           cookie = 1;
> > > > +
> > > > +   mxs_chan->chan.cookie = cookie;
> > > > +   mxs_chan->desc.cookie = cookie;
> > > > +
> > > > +   return cookie;
> > > > +}
> > > > +
> > > > +static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
> > > > +{
> > > > +   return container_of(chan, struct mxs_dma_chan, chan);
> > > > +}
> > > > +
> > > > +static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
> > > > +{
> > > > +   struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(tx->chan);
> > > > +   dma_cookie_t cookie;
> > > > +   unsigned long flags;
> > > > +
> > > > +   spin_lock_irqsave(&mxs_chan->lock, flags);
> > > > +
> > > > +   cookie = mxs_dma_assign_cookie(mxs_chan);
> > > > +
> > > > +   mxs_dma_enable_chan(mxs_chan);
> > > > +
> > > > +   spin_unlock_irqrestore(&mxs_chan->lock, flags);
> > > > +
> > > > +   return cookie;
> > > > +}
> > > 
> > > Just like the MMC driver, you use spin_lock_irqsave() in the functions that
> > > are called by other drivers, but then don't actually lock in the interrupt
> > > handler. This is clearly wrong, as I explained before:
> > > 
> > > The interrupt handler may already be running on another CPU, so it
> > > is not at all serialized with this code.
> > > 
> > I may be wrong on this point, but spin_lock_irqsave/irqrestore pair
> > is only for the protection you described?  I learnt that the pair
> > should be used to protect the critical region, where I'm not sure
> > if it's called from interrupt context.  Here I'm intending to protect
> > the dma registers accessed in mxs_dma_enable_chan.
> 
> To generalize this further, a lock should protect specific data,
> not portions of the code, and ideally you should document
> exactly what you protect near the definition of the lock.
> 
> If you use the lock to protect all the DMA registers, you should use
> it consistently, including inside of the interrupt handler, where
> you access some other registers.
> 
> If you can prove that the registers used in the IRQ handler are
> totally independent of the other ones, you don't need to use the
> lock there, but then I'd advise documenting your assumptions.
> 
When I change code to use readl/writel pair, I found the register
protection in mxs_dma_enable_chan is actually unnecessary, because
the registers are either channel specific or get set/clear address
to avoid read-modify-write operation.

So I'm removing the locking there.

> > Thanks for teaching.  I intend to take the fix that Russell offered.
> > (Thanks, Russell).  Does that look good to you, or spin_lock_bh
> > version should be used than spin_lock_irqsave?
> 
> Russell's change looks correct to me.
> 
> Regarding the choice between spin_lock_bh and spin_lock_irqsave,
> I always prefer to use the one that expresses best to the reader
> what the intention is. spin_lock_irqsave() is stronger than
> spin_lock_bh(), and can always be used in its place.
> 
> A short form of the strict rules (there are better documentations
> out there) is:
> 
> * If all users are outside of interrupt or tasklet context,
>   use a bare spin_lock().
> 
> * If one user is in a tasklet context, use spin_lock() inside
>   the tasklet, but spin_lock_bh() outside, to prevent the
>   tasklet from interrupting the critical section. Code that
>   can be called in either tasklet or regular context needs
>   to use spin_lock_bh() as well.
> 
> * If one user is in interrupt context, use spin_lock() inside
>   of the interrupt handler, but spin_lock_irq() in tasklet
>   and normal context (not spin_lock_irqsave()), to prevent
>   the interrupt from happening during the critical section.
> 
> * Use spin_lock_irqsave() only for functions that can be called
>   in either interrupt or non-interrupt context. Most drivers
>   don't need this at all.
> 
> The simplified rule would be to always use spin_lock_irqsave(),
> because that does not require you to understand what you are doing.
> 
> My position is that it is better to use the stricter rules, because
> that documents that you actually do understand what you are doing ;-)
> It's also slightly more efficient, because it avoids having to
> save the interrupt status in a variable.
> 
Thanks for this document.  It helps.

I'm changing the tasklet to have callback only, and move others into
interrupt handler, so that I can remove the locking completely from
the driver.

-- 
Regards,
Shawn




More information about the linux-arm-kernel mailing list