1
0
Fork 0

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>
hifive-unleashed-5.1
Russell King 2012-05-10 23:45:24 +01:00
parent 571fa74034
commit 63fe23c34e
1 changed files with 29 additions and 16 deletions

View File

@ -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;
}