@@ -406,38 +406,32 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
406406 }
407407}
408408
409- static int bcm2835_dma_abort (void __iomem * chan_base )
409+ static int bcm2835_dma_abort (struct bcm2835_chan * c )
410410{
411- unsigned long cs ;
411+ void __iomem * chan_base = c -> chan_base ;
412412 long int timeout = 10000 ;
413413
414- cs = readl (chan_base + BCM2835_DMA_CS );
415- if (!(cs & BCM2835_DMA_ACTIVE ))
414+ /*
415+ * A zero control block address means the channel is idle.
416+ * (The ACTIVE flag in the CS register is not a reliable indicator.)
417+ */
418+ if (!readl (chan_base + BCM2835_DMA_ADDR ))
416419 return 0 ;
417420
418421 /* Write 0 to the active bit - Pause the DMA */
419422 writel (0 , chan_base + BCM2835_DMA_CS );
420423
421424 /* Wait for any current AXI transfer to complete */
422- while ((cs & BCM2835_DMA_ISPAUSED ) && -- timeout ) {
425+ while ((readl (chan_base + BCM2835_DMA_CS ) &
426+ BCM2835_DMA_WAITING_FOR_WRITES ) && -- timeout )
423427 cpu_relax ();
424- cs = readl (chan_base + BCM2835_DMA_CS );
425- }
426428
427- /* We'll un-pause when we set of our next DMA */
429+ /* Peripheral might be stuck and fail to signal AXI write responses */
428430 if (!timeout )
429- return - ETIMEDOUT ;
430-
431- if (!(cs & BCM2835_DMA_ACTIVE ))
432- return 0 ;
433-
434- /* Terminate the control block chain */
435- writel (0 , chan_base + BCM2835_DMA_NEXTCB );
436-
437- /* Abort the whole DMA */
438- writel (BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE ,
439- chan_base + BCM2835_DMA_CS );
431+ dev_err (c -> vc .chan .device -> dev ,
432+ "failed to complete outstanding writes\n" );
440433
434+ writel (BCM2835_DMA_RESET , chan_base + BCM2835_DMA_CS );
441435 return 0 ;
442436}
443437
@@ -476,20 +470,23 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
476470
477471 spin_lock_irqsave (& c -> vc .lock , flags );
478472
479- /* Acknowledge interrupt */
480- writel (BCM2835_DMA_INT , c -> chan_base + BCM2835_DMA_CS );
473+ /*
474+ * Clear the INT flag to receive further interrupts. Keep the channel
475+ * active in case the descriptor is cyclic or in case the client has
476+ * already terminated the descriptor and issued a new one. (May happen
477+ * if this IRQ handler is threaded.) If the channel is finished, it
478+ * will remain idle despite the ACTIVE flag being set.
479+ */
480+ writel (BCM2835_DMA_INT | BCM2835_DMA_ACTIVE ,
481+ c -> chan_base + BCM2835_DMA_CS );
481482
482483 d = c -> desc ;
483484
484485 if (d ) {
485486 if (d -> cyclic ) {
486487 /* call the cyclic callback */
487488 vchan_cyclic_callback (& d -> vd );
488-
489- /* Keep the DMA engine running */
490- writel (BCM2835_DMA_ACTIVE ,
491- c -> chan_base + BCM2835_DMA_CS );
492- } else {
489+ } else if (!readl (c -> chan_base + BCM2835_DMA_ADDR )) {
493490 vchan_cookie_complete (& c -> desc -> vd );
494491 bcm2835_dma_start_desc (c );
495492 }
@@ -779,7 +776,6 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
779776 struct bcm2835_chan * c = to_bcm2835_dma_chan (chan );
780777 struct bcm2835_dmadev * d = to_bcm2835_dma_dev (c -> vc .chan .device );
781778 unsigned long flags ;
782- int timeout = 10000 ;
783779 LIST_HEAD (head );
784780
785781 spin_lock_irqsave (& c -> vc .lock , flags );
@@ -789,27 +785,11 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
789785 list_del_init (& c -> node );
790786 spin_unlock (& d -> lock );
791787
792- /*
793- * Stop DMA activity: we assume the callback will not be called
794- * after bcm_dma_abort() returns (even if it does, it will see
795- * c->desc is NULL and exit.)
796- */
788+ /* stop DMA activity */
797789 if (c -> desc ) {
798790 vchan_terminate_vdesc (& c -> desc -> vd );
799791 c -> desc = NULL ;
800- bcm2835_dma_abort (c -> chan_base );
801-
802- /* Wait for stopping */
803- while (-- timeout ) {
804- if (!(readl (c -> chan_base + BCM2835_DMA_CS ) &
805- BCM2835_DMA_ACTIVE ))
806- break ;
807-
808- cpu_relax ();
809- }
810-
811- if (!timeout )
812- dev_err (d -> ddev .dev , "DMA transfer could not be terminated\n" );
792+ bcm2835_dma_abort (c );
813793 }
814794
815795 vchan_get_all_descriptors (& c -> vc , & head );
0 commit comments