Commit 3850e22f authored by Russell King's avatar Russell King

dmaengine: omap: add support for returning residue in tx_state method

Add support for returning the residue for a particular descriptor by
reading the current DMA address for the source or destination side of
the transfer as appropriate, and walking the scatterlist until we find
an entry containing the current DMA address.
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 7bedaa55
...@@ -194,14 +194,73 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan) ...@@ -194,14 +194,73 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan)
dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig); dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig);
} }
static size_t omap_dma_sg_size(struct omap_sg *sg)
{
return sg->en * sg->fn;
}
static size_t omap_dma_desc_size(struct omap_desc *d)
{
unsigned i;
size_t size;
for (size = i = 0; i < d->sglen; i++)
size += omap_dma_sg_size(&d->sg[i]);
return size * es_bytes[d->es];
}
static size_t omap_dma_desc_size_pos(struct omap_desc *d, dma_addr_t addr)
{
unsigned i;
size_t size, es_size = es_bytes[d->es];
for (size = i = 0; i < d->sglen; i++) {
size_t this_size = omap_dma_sg_size(&d->sg[i]) * es_size;
if (size)
size += this_size;
else if (addr >= d->sg[i].addr &&
addr < d->sg[i].addr + this_size)
size += d->sg[i].addr + this_size - addr;
}
return size;
}
static enum dma_status omap_dma_tx_status(struct dma_chan *chan, static enum dma_status omap_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 omap_chan *c = to_omap_dma_chan(chan);
* FIXME: do we need to return pending bytes? struct virt_dma_desc *vd;
* We have no users of that info at the moment... enum dma_status ret;
*/ unsigned long flags;
return dma_cookie_status(chan, cookie, txstate);
ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_SUCCESS || !txstate)
return ret;
spin_lock_irqsave(&c->vc.lock, flags);
vd = vchan_find_desc(&c->vc, cookie);
if (vd) {
txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx));
} else if (c->desc && c->desc->vd.tx.cookie == cookie) {
struct omap_desc *d = c->desc;
dma_addr_t pos;
if (d->dir == DMA_MEM_TO_DEV)
pos = omap_get_dma_src_pos(c->dma_ch);
else if (d->dir == DMA_DEV_TO_MEM)
pos = omap_get_dma_dst_pos(c->dma_ch);
else
pos = 0;
txstate->residue = omap_dma_desc_size_pos(d, pos);
} else {
txstate->residue = 0;
}
spin_unlock_irqrestore(&c->vc.lock, flags);
return ret;
} }
static void omap_dma_issue_pending(struct dma_chan *chan) static void omap_dma_issue_pending(struct dma_chan *chan)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment