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_chan *c = to_sa11x0_dma_chan(chan);
|
||||||
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
|
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
|
||||||
struct sa11x0_dma_phy *p;
|
struct sa11x0_dma_phy *p;
|
||||||
struct sa11x0_dma_desc *txd;
|
struct virt_dma_desc *vd;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
enum dma_status ret;
|
enum dma_status ret;
|
||||||
size_t bytes = 0;
|
|
||||||
|
|
||||||
ret = dma_cookie_status(&c->vc.chan, cookie, state);
|
ret = dma_cookie_status(&c->vc.chan, cookie, state);
|
||||||
if (ret == DMA_SUCCESS)
|
if (ret == DMA_SUCCESS)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
return c->status;
|
||||||
|
|
||||||
spin_lock_irqsave(&c->vc.lock, flags);
|
spin_lock_irqsave(&c->vc.lock, flags);
|
||||||
p = c->phy;
|
p = c->phy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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;
|
ret = c->status;
|
||||||
if (p) {
|
if (txd) {
|
||||||
dma_addr_t addr = sa11x0_dma_pos(p);
|
dma_addr_t addr = sa11x0_dma_pos(p);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
|
dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
|
||||||
|
|
||||||
txd = p->txd_done;
|
|
||||||
if (txd) {
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < txd->sglen; i++) {
|
for (i = 0; i < txd->sglen; i++) {
|
||||||
dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
|
dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
|
||||||
i, txd->sg[i].addr, txd->sg[i].len);
|
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;
|
bytes += txd->sg[i].len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txd != p->txd_load && p->txd_load)
|
state->residue = bytes;
|
||||||
bytes += p->txd_load->size;
|
|
||||||
}
|
|
||||||
list_for_each_entry(txd, &c->vc.desc_issued, vd.node) {
|
|
||||||
bytes += txd->size;
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&c->vc.lock, flags);
|
spin_unlock_irqrestore(&c->vc.lock, flags);
|
||||||
|
|
||||||
if (state)
|
dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", state->residue);
|
||||||
state->residue = bytes;
|
|
||||||
|
|
||||||
dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue