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+ker...@arm.linux.org.uk>
---
 drivers/dma/sa11x0-dma.c |   45 +++++++++++++++++++++++++++++----------------
 1 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index 5f1d2e6..db4fcbd 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -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;
+
+               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;
 
-               txd = p->txd_done;
+               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;
 }
-- 
1.7.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to