dmaengine: PL08x: fix tx_status function to return correct residue

Now that we're converted to use the generic vchan support, we can fix
the residue return from tx_status to be compliant with dmaengine.  This
returns the number of bytes remaining for the _specified_ cookie, not
the number of bytes in all pending transfers on the channel.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Tested-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Russell King 2012-05-26 15:05:52 +01:00
parent 18536134ab
commit 06e885b735
1 changed files with 34 additions and 27 deletions

View File

@ -473,10 +473,8 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
{ {
struct pl08x_phy_chan *ch; struct pl08x_phy_chan *ch;
struct pl08x_txd *txd; struct pl08x_txd *txd;
unsigned long flags;
size_t bytes = 0; size_t bytes = 0;
spin_lock_irqsave(&plchan->vc.lock, flags);
ch = plchan->phychan; ch = plchan->phychan;
txd = plchan->at; txd = plchan->at;
@ -516,27 +514,6 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
} }
} }
/* Sum up all queued transactions */
if (!list_empty(&plchan->vc.desc_issued)) {
struct pl08x_txd *txdi;
list_for_each_entry(txdi, &plchan->vc.desc_issued, vd.node) {
struct pl08x_sg *dsg;
list_for_each_entry(dsg, &txd->dsg_list, node)
bytes += dsg->len;
}
}
if (!list_empty(&plchan->vc.desc_submitted)) {
struct pl08x_txd *txdi;
list_for_each_entry(txdi, &plchan->vc.desc_submitted, vd.node) {
struct pl08x_sg *dsg;
list_for_each_entry(dsg, &txd->dsg_list, node)
bytes += dsg->len;
}
}
spin_unlock_irqrestore(&plchan->vc.lock, flags);
return bytes; return bytes;
} }
@ -1171,23 +1148,53 @@ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *txstate) dma_cookie_t cookie, struct dma_tx_state *txstate)
{ {
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct virt_dma_desc *vd;
unsigned long flags;
enum dma_status ret; enum dma_status ret;
size_t bytes = 0;
ret = dma_cookie_status(chan, cookie, txstate); ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_SUCCESS) if (ret == DMA_SUCCESS)
return ret; return ret;
/*
* There's no point calculating the residue if there's
* no txstate to store the value.
*/
if (!txstate) {
if (plchan->state == PL08X_CHAN_PAUSED)
ret = DMA_PAUSED;
return ret;
}
spin_lock_irqsave(&plchan->vc.lock, flags);
ret = dma_cookie_status(chan, cookie, txstate);
if (ret != DMA_SUCCESS) {
vd = vchan_find_desc(&plchan->vc, cookie);
if (vd) {
/* On the issued list, so hasn't been processed yet */
struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
struct pl08x_sg *dsg;
list_for_each_entry(dsg, &txd->dsg_list, node)
bytes += dsg->len;
} else {
bytes = pl08x_getbytes_chan(plchan);
}
}
spin_unlock_irqrestore(&plchan->vc.lock, flags);
/* /*
* This cookie not complete yet * This cookie not complete yet
* Get number of bytes left in the active transactions and queue * Get number of bytes left in the active transactions and queue
*/ */
dma_set_residue(txstate, pl08x_getbytes_chan(plchan)); dma_set_residue(txstate, bytes);
if (plchan->state == PL08X_CHAN_PAUSED) if (plchan->state == PL08X_CHAN_PAUSED && ret == DMA_IN_PROGRESS)
return DMA_PAUSED; ret = DMA_PAUSED;
/* Whether waiting or running, we're in progress */ /* Whether waiting or running, we're in progress */
return DMA_IN_PROGRESS; return ret;
} }
/* PrimeCell DMA extension */ /* PrimeCell DMA extension */