mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 06:33:34 +00:00
dmaengine: sa11x0-dma: fix DMA residue support
The semantics now implemented are: - If the cookie has completed successfully, the residue will be zero. - If the cookie is in progress or the channel is paused, it will be the number of bytes yet to be transferred. [*] - If the cookie is queued, it will be the number of bytes in the descriptor. * - where this is the number of bytes yet to be transferred to/from RAM. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
571fa74034
commit
63fe23c34e
@ -416,27 +416,47 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
|
||||
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
|
||||
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
|
||||
struct sa11x0_dma_phy *p;
|
||||
struct sa11x0_dma_desc *txd;
|
||||
struct virt_dma_desc *vd;
|
||||
unsigned long flags;
|
||||
enum dma_status ret;
|
||||
size_t bytes = 0;
|
||||
|
||||
ret = dma_cookie_status(&c->vc.chan, cookie, state);
|
||||
if (ret == DMA_SUCCESS)
|
||||
return ret;
|
||||
|
||||
if (!state)
|
||||
return c->status;
|
||||
|
||||
spin_lock_irqsave(&c->vc.lock, flags);
|
||||
p = c->phy;
|
||||
ret = c->status;
|
||||
if (p) {
|
||||
dma_addr_t addr = sa11x0_dma_pos(p);
|
||||
|
||||
dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
|
||||
/*
|
||||
* If the cookie is on our issue queue, then the residue is
|
||||
* its total size.
|
||||
*/
|
||||
vd = vchan_find_desc(&c->vc, cookie);
|
||||
if (vd) {
|
||||
state->residue = container_of(vd, struct sa11x0_dma_desc, vd)->size;
|
||||
} else if (!p) {
|
||||
state->residue = 0;
|
||||
} else {
|
||||
struct sa11x0_dma_desc *txd;
|
||||
size_t bytes = 0;
|
||||
|
||||
txd = p->txd_done;
|
||||
if (p->txd_done && p->txd_done->vd.tx.cookie == cookie)
|
||||
txd = p->txd_done;
|
||||
else if (p->txd_load && p->txd_load->vd.tx.cookie == cookie)
|
||||
txd = p->txd_load;
|
||||
else
|
||||
txd = NULL;
|
||||
|
||||
ret = c->status;
|
||||
if (txd) {
|
||||
dma_addr_t addr = sa11x0_dma_pos(p);
|
||||
unsigned i;
|
||||
|
||||
dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
|
||||
|
||||
for (i = 0; i < txd->sglen; i++) {
|
||||
dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
|
||||
i, txd->sg[i].addr, txd->sg[i].len);
|
||||
@ -459,18 +479,11 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
|
||||
bytes += txd->sg[i].len;
|
||||
}
|
||||
}
|
||||
if (txd != p->txd_load && p->txd_load)
|
||||
bytes += p->txd_load->size;
|
||||
}
|
||||
list_for_each_entry(txd, &c->vc.desc_issued, vd.node) {
|
||||
bytes += txd->size;
|
||||
state->residue = bytes;
|
||||
}
|
||||
spin_unlock_irqrestore(&c->vc.lock, flags);
|
||||
|
||||
if (state)
|
||||
state->residue = bytes;
|
||||
|
||||
dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
|
||||
dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", state->residue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user