diff options
| -rw-r--r-- | drivers/dma/bcm2835-dma.c | 41 |
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 | ||
| 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); | ||
| 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); |
