aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/omap-dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/omap-dma.c')
-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)