aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-06-21 05:37:35 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-07-31 07:06:21 -0400
commit3850e22f5146d2ff5b66f1b7460d4720d5f1b6c7 (patch)
treee793d4d24faf61ebedeb96280ce4564643d1235b /drivers/dma
parent7bedaa5537604f34d1d63c5ec7891e559d2a61ed (diff)
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: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/omap-dma.c69
1 files changed, 64 insertions, 5 deletions
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index fe33ddd8eb0f..82a7ac7c048b 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -194,14 +194,73 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan)
194 dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig); 194 dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig);
195} 195}
196 196
197static size_t omap_dma_sg_size(struct omap_sg *sg)
198{
199 return sg->en * sg->fn;
200}
201
202static size_t omap_dma_desc_size(struct omap_desc *d)
203{
204 unsigned i;
205 size_t size;
206
207 for (size = i = 0; i < d->sglen; i++)
208 size += omap_dma_sg_size(&d->sg[i]);
209
210 return size * es_bytes[d->es];
211}
212
213static size_t omap_dma_desc_size_pos(struct omap_desc *d, dma_addr_t addr)
214{
215 unsigned i;
216 size_t size, es_size = es_bytes[d->es];
217
218 for (size = i = 0; i < d->sglen; i++) {
219 size_t this_size = omap_dma_sg_size(&d->sg[i]) * es_size;
220
221 if (size)
222 size += this_size;
223 else if (addr >= d->sg[i].addr &&
224 addr < d->sg[i].addr + this_size)
225 size += d->sg[i].addr + this_size - addr;
226 }
227 return size;
228}
229
197static enum dma_status omap_dma_tx_status(struct dma_chan *chan, 230static enum dma_status omap_dma_tx_status(struct dma_chan *chan,
198 dma_cookie_t cookie, struct dma_tx_state *txstate) 231 dma_cookie_t cookie, struct dma_tx_state *txstate)
199{ 232{
200 /* 233 struct omap_chan *c = to_omap_dma_chan(chan);
201 * FIXME: do we need to return pending bytes? 234 struct virt_dma_desc *vd;
202 * We have no users of that info at the moment... 235 enum dma_status ret;
203 */ 236 unsigned long flags;
204 return dma_cookie_status(chan, cookie, txstate); 237
238 ret = dma_cookie_status(chan, cookie, txstate);
239 if (ret == DMA_SUCCESS || !txstate)
240 return ret;
241
242 spin_lock_irqsave(&c->vc.lock, flags);
243 vd = vchan_find_desc(&c->vc, cookie);
244 if (vd) {
245 txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx));
246 } else if (c->desc && c->desc->vd.tx.cookie == cookie) {
247 struct omap_desc *d = c->desc;
248 dma_addr_t pos;
249
250 if (d->dir == DMA_MEM_TO_DEV)
251 pos = omap_get_dma_src_pos(c->dma_ch);
252 else if (d->dir == DMA_DEV_TO_MEM)
253 pos = omap_get_dma_dst_pos(c->dma_ch);
254 else
255 pos = 0;
256
257 txstate->residue = omap_dma_desc_size_pos(d, pos);
258 } else {
259 txstate->residue = 0;
260 }
261 spin_unlock_irqrestore(&c->vc.lock, flags);
262
263 return ret;
205} 264}
206 265
207static void omap_dma_issue_pending(struct dma_chan *chan) 266static void omap_dma_issue_pending(struct dma_chan *chan)