aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/bcm2835-dma.c41
1 files changed, 9 insertions, 32 deletions
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 0c3f5c71bb48..ae10f5614f95 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -406,13 +406,11 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
406 } 406 }
407} 407}
408 408
409static int bcm2835_dma_abort(void __iomem *chan_base) 409static int bcm2835_dma_abort(struct bcm2835_chan *c)
410{ 410{
411 unsigned long cs; 411 void __iomem *chan_base = c->chan_base;
412 long int timeout = 10000; 412 long int timeout = 10000;
413 413
414 cs = readl(chan_base + BCM2835_DMA_CS);
415
416 /* 414 /*
417 * A zero control block address means the channel is idle. 415 * A zero control block address means the channel is idle.
418 * (The ACTIVE flag in the CS register is not a reliable indicator.) 416 * (The ACTIVE flag in the CS register is not a reliable indicator.)
@@ -424,25 +422,16 @@ static int bcm2835_dma_abort(void __iomem *chan_base)
424 writel(0, chan_base + BCM2835_DMA_CS); 422 writel(0, chan_base + BCM2835_DMA_CS);
425 423
426 /* Wait for any current AXI transfer to complete */ 424 /* Wait for any current AXI transfer to complete */
427 while ((cs & BCM2835_DMA_ISPAUSED) && --timeout) { 425 while ((readl(chan_base + BCM2835_DMA_CS) &
426 BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
428 cpu_relax(); 427 cpu_relax();
429 cs = readl(chan_base + BCM2835_DMA_CS);
430 }
431 428
432 /* We'll un-pause when we set of our next DMA */ 429 /* Peripheral might be stuck and fail to signal AXI write responses */
433 if (!timeout) 430 if (!timeout)
434 return -ETIMEDOUT; 431 dev_err(c->vc.chan.device->dev,
435 432 "failed to complete outstanding writes\n");
436 if (!(cs & BCM2835_DMA_ACTIVE))
437 return 0;
438
439 /* Terminate the control block chain */
440 writel(0, chan_base + BCM2835_DMA_NEXTCB);
441
442 /* Abort the whole DMA */
443 writel(BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE,
444 chan_base + BCM2835_DMA_CS);
445 433
434 writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS);
446 return 0; 435 return 0;
447} 436}
448 437
@@ -787,7 +776,6 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
787 struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); 776 struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
788 struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device); 777 struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device);
789 unsigned long flags; 778 unsigned long flags;
790 int timeout = 10000;
791 LIST_HEAD(head); 779 LIST_HEAD(head);
792 780
793 spin_lock_irqsave(&c->vc.lock, flags); 781 spin_lock_irqsave(&c->vc.lock, flags);
@@ -801,18 +789,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
801 if (c->desc) { 789 if (c->desc) {
802 vchan_terminate_vdesc(&c->desc->vd); 790 vchan_terminate_vdesc(&c->desc->vd);
803 c->desc = NULL; 791 c->desc = NULL;
804 bcm2835_dma_abort(c->chan_base); 792 bcm2835_dma_abort(c);
805
806 /* Wait for stopping */
807 while (--timeout) {
808 if (!readl(c->chan_base + BCM2835_DMA_ADDR))
809 break;
810
811 cpu_relax();
812 }
813
814 if (!timeout)
815 dev_err(d->ddev.dev, "DMA transfer could not be terminated\n");
816 } 793 }
817 794
818 vchan_get_all_descriptors(&c->vc, &head); 795 vchan_get_all_descriptors(&c->vc, &head);