aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-03-04 08:40:30 -0500
committerDan Williams <dan.j.williams@intel.com>2010-03-24 17:24:44 -0400
commit84c8447c544bc7579097649273bc3f4e1b5de6af (patch)
tree7b91a03a61044612d511283e03f545893ba8c464 /drivers/dma
parentcecd87da83869ad4157295b87a2e51e38c3e03bf (diff)
DMAENGINE: COH 901 318 fix bytesleft
This makes the function to get the number of bytes left in the ongoing DMA transaction actually work: the old code did not take neither lli:s nor queued jobs into account. Also fix a missing spinlock while we're at it. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/coh901318.c96
1 files changed, 88 insertions, 8 deletions
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index 20889c98e9b0..f636c4a87c7f 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -408,25 +408,100 @@ coh901318_first_queued(struct coh901318_chan *cohc)
408 return d; 408 return d;
409} 409}
410 410
411static inline u32 coh901318_get_bytes_in_lli(struct coh901318_lli *in_lli)
412{
413 struct coh901318_lli *lli = in_lli;
414 u32 bytes = 0;
415
416 while (lli) {
417 bytes += lli->control & COH901318_CX_CTRL_TC_VALUE_MASK;
418 lli = lli->virt_link_addr;
419 }
420 return bytes;
421}
422
411/* 423/*
412 * DMA start/stop controls 424 * Get the number of bytes left to transfer on this channel,
425 * it is unwise to call this before stopping the channel for
426 * absolute measures, but for a rough guess you can still call
427 * it.
413 */ 428 */
414u32 coh901318_get_bytes_left(struct dma_chan *chan) 429u32 coh901318_get_bytes_left(struct dma_chan *chan)
415{ 430{
416 unsigned long flags;
417 u32 ret;
418 struct coh901318_chan *cohc = to_coh901318_chan(chan); 431 struct coh901318_chan *cohc = to_coh901318_chan(chan);
432 struct coh901318_desc *cohd;
433 struct list_head *pos;
434 unsigned long flags;
435 u32 left = 0;
436 int i = 0;
419 437
420 spin_lock_irqsave(&cohc->lock, flags); 438 spin_lock_irqsave(&cohc->lock, flags);
421 439
422 /* Read transfer count value */ 440 /*
423 ret = readl(cohc->base->virtbase + 441 * If there are many queued jobs, we iterate and add the
424 COH901318_CX_CTRL+COH901318_CX_CTRL_SPACING * 442 * size of them all. We take a special look on the first
425 cohc->id) & COH901318_CX_CTRL_TC_VALUE_MASK; 443 * job though, since it is probably active.
444 */
445 list_for_each(pos, &cohc->active) {
446 /*
447 * The first job in the list will be working on the
448 * hardware. The job can be stopped but still active,
449 * so that the transfer counter is somewhere inside
450 * the buffer.
451 */
452 cohd = list_entry(pos, struct coh901318_desc, node);
453
454 if (i == 0) {
455 struct coh901318_lli *lli;
456 dma_addr_t ladd;
457
458 /* Read current transfer count value */
459 left = readl(cohc->base->virtbase +
460 COH901318_CX_CTRL +
461 COH901318_CX_CTRL_SPACING * cohc->id) &
462 COH901318_CX_CTRL_TC_VALUE_MASK;
463
464 /* See if the transfer is linked... */
465 ladd = readl(cohc->base->virtbase +
466 COH901318_CX_LNK_ADDR +
467 COH901318_CX_LNK_ADDR_SPACING *
468 cohc->id) &
469 ~COH901318_CX_LNK_LINK_IMMEDIATE;
470 /* Single transaction */
471 if (!ladd)
472 continue;
473
474 /*
475 * Linked transaction, follow the lli, find the
476 * currently processing lli, and proceed to the next
477 */
478 lli = cohd->lli;
479 while (lli && lli->link_addr != ladd)
480 lli = lli->virt_link_addr;
481
482 if (lli)
483 lli = lli->virt_link_addr;
484
485 /*
486 * Follow remaining lli links around to count the total
487 * number of bytes left
488 */
489 left += coh901318_get_bytes_in_lli(lli);
490 } else {
491 left += coh901318_get_bytes_in_lli(cohd->lli);
492 }
493 i++;
494 }
495
496 /* Also count bytes in the queued jobs */
497 list_for_each(pos, &cohc->queue) {
498 cohd = list_entry(pos, struct coh901318_desc, node);
499 left += coh901318_get_bytes_in_lli(cohd->lli);
500 }
426 501
427 spin_unlock_irqrestore(&cohc->lock, flags); 502 spin_unlock_irqrestore(&cohc->lock, flags);
428 503
429 return ret; 504 return left;
430} 505}
431EXPORT_SYMBOL(coh901318_get_bytes_left); 506EXPORT_SYMBOL(coh901318_get_bytes_left);
432 507
@@ -831,6 +906,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
831static int coh901318_alloc_chan_resources(struct dma_chan *chan) 906static int coh901318_alloc_chan_resources(struct dma_chan *chan)
832{ 907{
833 struct coh901318_chan *cohc = to_coh901318_chan(chan); 908 struct coh901318_chan *cohc = to_coh901318_chan(chan);
909 unsigned long flags;
834 910
835 dev_vdbg(COHC_2_DEV(cohc), "[%s] DMA channel %d\n", 911 dev_vdbg(COHC_2_DEV(cohc), "[%s] DMA channel %d\n",
836 __func__, cohc->id); 912 __func__, cohc->id);
@@ -838,11 +914,15 @@ static int coh901318_alloc_chan_resources(struct dma_chan *chan)
838 if (chan->client_count > 1) 914 if (chan->client_count > 1)
839 return -EBUSY; 915 return -EBUSY;
840 916
917 spin_lock_irqsave(&cohc->lock, flags);
918
841 coh901318_config(cohc, NULL); 919 coh901318_config(cohc, NULL);
842 920
843 cohc->allocated = 1; 921 cohc->allocated = 1;
844 cohc->completed = chan->cookie = 1; 922 cohc->completed = chan->cookie = 1;
845 923
924 spin_unlock_irqrestore(&cohc->lock, flags);
925
846 return 1; 926 return 1;
847} 927}
848 928