Skip to content
Browse files

dmaengine: bcm2835: Fix polling for completion of DMA with interrupts…

… masked.

The tx_status hook is supposed to be safe to call from interrupt
context, but it wouldn't ever return completion for the last transfer,
meaning you couldn't poll for DMA completion with interrupts masked.

This fixes IRQ handling for bcm2835's DSI1, which requires using the
DMA engine to write its registers due to a bug in the AXI bridge.

Signed-off-by: Eric Anholt <>
  • Loading branch information
anholt authored and popcornmix committed Jun 4, 2016
1 parent 47b63bd commit 635503edf5d60f758d50e945213b1e23dc4952cd
Showing with 19 additions and 5 deletions.
  1. +19 −5 drivers/dma/bcm2835-dma.c
@@ -588,16 +588,16 @@ static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan,
struct virt_dma_desc *vd;
enum dma_status ret;
unsigned long flags;
u32 residue;

ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_COMPLETE || !txstate)
if (ret == DMA_COMPLETE)
return ret;

spin_lock_irqsave(&c->vc.lock, flags);
vd = vchan_find_desc(&c->vc, cookie);
if (vd) {
txstate->residue =
residue = bcm2835_dma_desc_size(to_bcm2835_dma_desc(&vd->tx));
} else if (c->desc && c->desc->vd.tx.cookie == cookie) {
struct bcm2835_desc *d = c->desc;
dma_addr_t pos;
@@ -609,11 +609,25 @@ static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan,
pos = 0;

txstate->residue = bcm2835_dma_desc_size_pos(d, pos);
residue = bcm2835_dma_desc_size_pos(d, pos);

* If our non-cyclic transfer is done, then report
* complete and trigger the next tx now. This lets
* the dmaengine API be used synchronously from an IRQ
* handler.
if (!d->cyclic && residue == 0) {
ret = dma_cookie_status(chan, cookie, txstate);
} else {
txstate->residue = 0;
residue = 0;

dma_set_residue(txstate, residue);

spin_unlock_irqrestore(&c->vc.lock, flags);

return ret;

0 comments on commit 635503e

Please sign in to comment.
You can’t perform that action at this time.