diff options
author | Vinod Koul | 2019-02-04 01:27:56 -0600 |
---|---|---|
committer | Vinod Koul | 2019-02-04 01:27:56 -0600 |
commit | 6d66c8d1a034eeb1bbf4a0a8dd99fa6f33a8db5d (patch) | |
tree | 7e3cd8b94a7f4779168950dbb3c0f4361e0891b8 | |
parent | 341198eda723c8c1cddbb006a89ad9e362502ea2 (diff) | |
parent | 9e528c799d17a4ac37d788c81440b50377dd592d (diff) | |
download | dmurphy-analog-6d66c8d1a034eeb1bbf4a0a8dd99fa6f33a8db5d.tar.gz dmurphy-analog-6d66c8d1a034eeb1bbf4a0a8dd99fa6f33a8db5d.tar.xz dmurphy-analog-6d66c8d1a034eeb1bbf4a0a8dd99fa6f33a8db5d.zip |
Merge branch 'fix/brcm' into fixes
-rw-r--r-- | drivers/dma/bcm2835-dma.c | 70 |
1 files changed, 25 insertions, 45 deletions
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 1a44c8086d77..ae10f5614f95 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c | |||
@@ -406,38 +406,32 @@ static void bcm2835_dma_fill_cb_chain_with_sg( | |||
406 | } | 406 | } |
407 | } | 407 | } |
408 | 408 | ||
409 | static int bcm2835_dma_abort(void __iomem *chan_base) | 409 | static 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); | 414 | /* |
415 | if (!(cs & BCM2835_DMA_ACTIVE)) | 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)) | ||
416 | return 0; | 419 | return 0; |
417 | 420 | ||
418 | /* Write 0 to the active bit - Pause the DMA */ | 421 | /* Write 0 to the active bit - Pause the DMA */ |
419 | writel(0, chan_base + BCM2835_DMA_CS); | 422 | writel(0, chan_base + BCM2835_DMA_CS); |
420 | 423 | ||
421 | /* Wait for any current AXI transfer to complete */ | 424 | /* 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) | ||
423 | cpu_relax(); | 427 | cpu_relax(); |
424 | cs = readl(chan_base + BCM2835_DMA_CS); | ||
425 | } | ||
426 | 428 | ||
427 | /* We'll un-pause when we set of our next DMA */ | 429 | /* Peripheral might be stuck and fail to signal AXI write responses */ |
428 | if (!timeout) | 430 | if (!timeout) |
429 | return -ETIMEDOUT; | 431 | dev_err(c->vc.chan.device->dev, |
430 | 432 | "failed to complete outstanding writes\n"); | |
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); | ||
440 | 433 | ||
434 | writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); | ||
441 | return 0; | 435 | return 0; |
442 | } | 436 | } |
443 | 437 | ||
@@ -476,8 +470,15 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) | |||
476 | 470 | ||
477 | spin_lock_irqsave(&c->vc.lock, flags); | 471 | spin_lock_irqsave(&c->vc.lock, flags); |
478 | 472 | ||
479 | /* Acknowledge interrupt */ | 473 | /* |
480 | writel(BCM2835_DMA_INT, c->chan_base + BCM2835_DMA_CS); | 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); | ||
481 | 482 | ||
482 | d = c->desc; | 483 | d = c->desc; |
483 | 484 | ||
@@ -485,11 +486,7 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) | |||
485 | if (d->cyclic) { | 486 | if (d->cyclic) { |
486 | /* call the cyclic callback */ | 487 | /* call the cyclic callback */ |
487 | vchan_cyclic_callback(&d->vd); | 488 | vchan_cyclic_callback(&d->vd); |
488 | 489 | } else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) { | |
489 | /* Keep the DMA engine running */ | ||
490 | writel(BCM2835_DMA_ACTIVE, | ||
491 | c->chan_base + BCM2835_DMA_CS); | ||
492 | } else { | ||
493 | vchan_cookie_complete(&c->desc->vd); | 490 | vchan_cookie_complete(&c->desc->vd); |
494 | bcm2835_dma_start_desc(c); | 491 | bcm2835_dma_start_desc(c); |
495 | } | 492 | } |
@@ -779,7 +776,6 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) | |||
779 | struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); | 776 | struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); |
780 | 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); |
781 | unsigned long flags; | 778 | unsigned long flags; |
782 | int timeout = 10000; | ||
783 | LIST_HEAD(head); | 779 | LIST_HEAD(head); |
784 | 780 | ||
785 | spin_lock_irqsave(&c->vc.lock, flags); | 781 | spin_lock_irqsave(&c->vc.lock, flags); |
@@ -789,27 +785,11 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) | |||
789 | list_del_init(&c->node); | 785 | list_del_init(&c->node); |
790 | spin_unlock(&d->lock); | 786 | spin_unlock(&d->lock); |
791 | 787 | ||
792 | /* | 788 | /* stop DMA activity */ |
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 | */ | ||
797 | if (c->desc) { | 789 | if (c->desc) { |
798 | vchan_terminate_vdesc(&c->desc->vd); | 790 | vchan_terminate_vdesc(&c->desc->vd); |
799 | c->desc = NULL; | 791 | c->desc = NULL; |
800 | bcm2835_dma_abort(c->chan_base); | 792 | bcm2835_dma_abort(c); |
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"); | ||
813 | } | 793 | } |
814 | 794 | ||
815 | vchan_get_all_descriptors(&c->vc, &head); | 795 | vchan_get_all_descriptors(&c->vc, &head); |