Skip to content

Commit f241592

Browse files
anholtDigitalDreamtime
authored andcommitted
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 <[email protected]>
1 parent d212dcf commit f241592

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

drivers/dma/bcm2835-dma.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -588,16 +588,16 @@ static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan,
588588
struct virt_dma_desc *vd;
589589
enum dma_status ret;
590590
unsigned long flags;
591+
u32 residue;
591592

592593
ret = dma_cookie_status(chan, cookie, txstate);
593-
if (ret == DMA_COMPLETE || !txstate)
594+
if (ret == DMA_COMPLETE)
594595
return ret;
595596

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

612-
txstate->residue = bcm2835_dma_desc_size_pos(d, pos);
612+
residue = bcm2835_dma_desc_size_pos(d, pos);
613+
614+
/*
615+
* If our non-cyclic transfer is done, then report
616+
* complete and trigger the next tx now. This lets
617+
* the dmaengine API be used synchronously from an IRQ
618+
* handler.
619+
*/
620+
if (!d->cyclic && residue == 0) {
621+
vchan_cookie_complete(&c->desc->vd);
622+
bcm2835_dma_start_desc(c);
623+
ret = dma_cookie_status(chan, cookie, txstate);
624+
}
613625
} else {
614-
txstate->residue = 0;
626+
residue = 0;
615627
}
616628

629+
dma_set_residue(txstate, residue);
630+
617631
spin_unlock_irqrestore(&c->vc.lock, flags);
618632

619633
return ret;

0 commit comments

Comments
 (0)