diff options
Diffstat (limited to 'drivers/dma/omap-dma.c')
-rw-r--r-- | drivers/dma/omap-dma.c | 69 |
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 | ||
197 | static size_t omap_dma_sg_size(struct omap_sg *sg) | ||
198 | { | ||
199 | return sg->en * sg->fn; | ||
200 | } | ||
201 | |||
202 | static 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 | |||
213 | static 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 | |||
197 | static enum dma_status omap_dma_tx_status(struct dma_chan *chan, | 230 | static 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 | ||
207 | static void omap_dma_issue_pending(struct dma_chan *chan) | 266 | static void omap_dma_issue_pending(struct dma_chan *chan) |