aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-05-10 18:45:24 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-07-01 09:16:25 -0400
commit63fe23c34e1c18725bd1459897bf3a46335d88b7 (patch)
tree2b0b806dda260ccd075e1747834669022516434b /drivers
parent571fa74034701391b1be2ad193f684acfdeb75d1 (diff)
dmaengine: sa11x0-dma: fix DMA residue support
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+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/sa11x0-dma.c45
1 files changed, 29 insertions, 16 deletions
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index 5f1d2e670837..db4fcbd80c7d 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,
416 struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 416 struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
417 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 417 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
418 struct sa11x0_dma_phy *p; 418 struct sa11x0_dma_phy *p;
419 struct sa11x0_dma_desc *txd; 419 struct virt_dma_desc *vd;
420 unsigned long flags; 420 unsigned long flags;
421 enum dma_status ret; 421 enum dma_status ret;
422 size_t bytes = 0;
423 422
424 ret = dma_cookie_status(&c->vc.chan, cookie, state); 423 ret = dma_cookie_status(&c->vc.chan, cookie, state);
425 if (ret == DMA_SUCCESS) 424 if (ret == DMA_SUCCESS)
426 return ret; 425 return ret;
427 426
427 if (!state)
428 return c->status;
429
428 spin_lock_irqsave(&c->vc.lock, flags); 430 spin_lock_irqsave(&c->vc.lock, flags);
429 p = c->phy; 431 p = c->phy;
430 ret = c->status;
431 if (p) {
432 dma_addr_t addr = sa11x0_dma_pos(p);
433 432
434 dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr); 433 /*
434 * If the cookie is on our issue queue, then the residue is
435 * its total size.
436 */
437 vd = vchan_find_desc(&c->vc, cookie);
438 if (vd) {
439 state->residue = container_of(vd, struct sa11x0_dma_desc, vd)->size;
440 } else if (!p) {
441 state->residue = 0;
442 } else {
443 struct sa11x0_dma_desc *txd;
444 size_t bytes = 0;
445
446 if (p->txd_done && p->txd_done->vd.tx.cookie == cookie)
447 txd = p->txd_done;
448 else if (p->txd_load && p->txd_load->vd.tx.cookie == cookie)
449 txd = p->txd_load;
450 else
451 txd = NULL;
435 452
436 txd = p->txd_done; 453 ret = c->status;
437 if (txd) { 454 if (txd) {
455 dma_addr_t addr = sa11x0_dma_pos(p);
438 unsigned i; 456 unsigned i;
439 457
458 dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
459
440 for (i = 0; i < txd->sglen; i++) { 460 for (i = 0; i < txd->sglen; i++) {
441 dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n", 461 dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
442 i, txd->sg[i].addr, txd->sg[i].len); 462 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,
459 bytes += txd->sg[i].len; 479 bytes += txd->sg[i].len;
460 } 480 }
461 } 481 }
462 if (txd != p->txd_load && p->txd_load) 482 state->residue = bytes;
463 bytes += p->txd_load->size;
464 }
465 list_for_each_entry(txd, &c->vc.desc_issued, vd.node) {
466 bytes += txd->size;
467 } 483 }
468 spin_unlock_irqrestore(&c->vc.lock, flags); 484 spin_unlock_irqrestore(&c->vc.lock, flags);
469 485
470 if (state) 486 dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", state->residue);
471 state->residue = bytes;
472
473 dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
474 487
475 return ret; 488 return ret;
476} 489}