diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2016-03-22 17:27:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-22 18:36:02 -0400 |
commit | 458bdf6e399d7d6f779b97a24645a7a38d1ae07b (patch) | |
tree | 83d6d4b96a37137c3e9c7653dd07c9370fc2d28d /drivers/rapidio | |
parent | e680b672a2b47748ee548229242b543a23b902c1 (diff) |
rapidio/tsi721_dma: fix hardware error handling
Add DMA channel re-initialization after an error to avoid termination of
all pending transfer requests.
Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Reported-by: Barry Wood <barry.wood@idt.com>
Tested-by: Barry Wood <barry.wood@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com>
Cc: Barry Wood <barry.wood@idt.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio')
-rw-r--r-- | drivers/rapidio/devices/tsi721_dma.c | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c index 03637330c482..155cae1e62de 100644 --- a/drivers/rapidio/devices/tsi721_dma.c +++ b/drivers/rapidio/devices/tsi721_dma.c | |||
@@ -282,7 +282,7 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan) | |||
282 | /* Disable BDMA channel interrupts */ | 282 | /* Disable BDMA channel interrupts */ |
283 | iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE); | 283 | iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE); |
284 | if (bdma_chan->active) | 284 | if (bdma_chan->active) |
285 | tasklet_schedule(&bdma_chan->tasklet); | 285 | tasklet_hi_schedule(&bdma_chan->tasklet); |
286 | } | 286 | } |
287 | 287 | ||
288 | #ifdef CONFIG_PCI_MSI | 288 | #ifdef CONFIG_PCI_MSI |
@@ -298,7 +298,7 @@ static irqreturn_t tsi721_bdma_msix(int irq, void *ptr) | |||
298 | struct tsi721_bdma_chan *bdma_chan = ptr; | 298 | struct tsi721_bdma_chan *bdma_chan = ptr; |
299 | 299 | ||
300 | if (bdma_chan->active) | 300 | if (bdma_chan->active) |
301 | tasklet_schedule(&bdma_chan->tasklet); | 301 | tasklet_hi_schedule(&bdma_chan->tasklet); |
302 | return IRQ_HANDLED; | 302 | return IRQ_HANDLED; |
303 | } | 303 | } |
304 | #endif /* CONFIG_PCI_MSI */ | 304 | #endif /* CONFIG_PCI_MSI */ |
@@ -584,13 +584,71 @@ static void tsi721_dma_tasklet(unsigned long data) | |||
584 | iowrite32(dmac_int, bdma_chan->regs + TSI721_DMAC_INT); | 584 | iowrite32(dmac_int, bdma_chan->regs + TSI721_DMAC_INT); |
585 | 585 | ||
586 | if (dmac_int & TSI721_DMAC_INT_ERR) { | 586 | if (dmac_int & TSI721_DMAC_INT_ERR) { |
587 | int i = 10000; | ||
588 | struct tsi721_tx_desc *desc; | ||
589 | |||
590 | desc = bdma_chan->active_tx; | ||
587 | dmac_sts = ioread32(bdma_chan->regs + TSI721_DMAC_STS); | 591 | dmac_sts = ioread32(bdma_chan->regs + TSI721_DMAC_STS); |
588 | tsi_err(&bdma_chan->dchan.dev->device, | 592 | tsi_err(&bdma_chan->dchan.dev->device, |
589 | "ERR - DMAC%d_STS = 0x%x", | 593 | "DMAC%d_STS = 0x%x did=%d raddr=0x%llx", |
590 | bdma_chan->id, dmac_sts); | 594 | bdma_chan->id, dmac_sts, desc->destid, desc->rio_addr); |
595 | |||
596 | /* Re-initialize DMA channel if possible */ | ||
597 | |||
598 | if ((dmac_sts & TSI721_DMAC_STS_ABORT) == 0) | ||
599 | goto err_out; | ||
600 | |||
601 | tsi721_clr_stat(bdma_chan); | ||
591 | 602 | ||
592 | spin_lock(&bdma_chan->lock); | 603 | spin_lock(&bdma_chan->lock); |
604 | |||
605 | /* Put DMA channel into init state */ | ||
606 | iowrite32(TSI721_DMAC_CTL_INIT, | ||
607 | bdma_chan->regs + TSI721_DMAC_CTL); | ||
608 | do { | ||
609 | udelay(1); | ||
610 | dmac_sts = ioread32(bdma_chan->regs + TSI721_DMAC_STS); | ||
611 | i--; | ||
612 | } while ((dmac_sts & TSI721_DMAC_STS_ABORT) && i); | ||
613 | |||
614 | if (dmac_sts & TSI721_DMAC_STS_ABORT) { | ||
615 | tsi_err(&bdma_chan->dchan.dev->device, | ||
616 | "Failed to re-initiate DMAC%d", bdma_chan->id); | ||
617 | spin_unlock(&bdma_chan->lock); | ||
618 | goto err_out; | ||
619 | } | ||
620 | |||
621 | /* Setup DMA descriptor pointers */ | ||
622 | iowrite32(((u64)bdma_chan->bd_phys >> 32), | ||
623 | bdma_chan->regs + TSI721_DMAC_DPTRH); | ||
624 | iowrite32(((u64)bdma_chan->bd_phys & TSI721_DMAC_DPTRL_MASK), | ||
625 | bdma_chan->regs + TSI721_DMAC_DPTRL); | ||
626 | |||
627 | /* Setup descriptor status FIFO */ | ||
628 | iowrite32(((u64)bdma_chan->sts_phys >> 32), | ||
629 | bdma_chan->regs + TSI721_DMAC_DSBH); | ||
630 | iowrite32(((u64)bdma_chan->sts_phys & TSI721_DMAC_DSBL_MASK), | ||
631 | bdma_chan->regs + TSI721_DMAC_DSBL); | ||
632 | iowrite32(TSI721_DMAC_DSSZ_SIZE(bdma_chan->sts_size), | ||
633 | bdma_chan->regs + TSI721_DMAC_DSSZ); | ||
634 | |||
635 | /* Clear interrupt bits */ | ||
636 | iowrite32(TSI721_DMAC_INT_ALL, | ||
637 | bdma_chan->regs + TSI721_DMAC_INT); | ||
638 | |||
639 | ioread32(bdma_chan->regs + TSI721_DMAC_INT); | ||
640 | |||
641 | bdma_chan->wr_count = bdma_chan->wr_count_next = 0; | ||
642 | bdma_chan->sts_rdptr = 0; | ||
643 | udelay(10); | ||
644 | |||
645 | desc = bdma_chan->active_tx; | ||
646 | desc->status = DMA_ERROR; | ||
647 | dma_cookie_complete(&desc->txd); | ||
648 | list_add(&desc->desc_node, &bdma_chan->free_list); | ||
593 | bdma_chan->active_tx = NULL; | 649 | bdma_chan->active_tx = NULL; |
650 | if (bdma_chan->active) | ||
651 | tsi721_advance_work(bdma_chan, NULL); | ||
594 | spin_unlock(&bdma_chan->lock); | 652 | spin_unlock(&bdma_chan->lock); |
595 | } | 653 | } |
596 | 654 | ||
@@ -619,16 +677,19 @@ static void tsi721_dma_tasklet(unsigned long data) | |||
619 | } | 677 | } |
620 | list_add(&desc->desc_node, &bdma_chan->free_list); | 678 | list_add(&desc->desc_node, &bdma_chan->free_list); |
621 | bdma_chan->active_tx = NULL; | 679 | bdma_chan->active_tx = NULL; |
622 | tsi721_advance_work(bdma_chan, NULL); | 680 | if (bdma_chan->active) |
681 | tsi721_advance_work(bdma_chan, NULL); | ||
623 | spin_unlock(&bdma_chan->lock); | 682 | spin_unlock(&bdma_chan->lock); |
624 | if (callback) | 683 | if (callback) |
625 | callback(param); | 684 | callback(param); |
626 | } else { | 685 | } else { |
627 | tsi721_advance_work(bdma_chan, bdma_chan->active_tx); | 686 | if (bdma_chan->active) |
687 | tsi721_advance_work(bdma_chan, | ||
688 | bdma_chan->active_tx); | ||
628 | spin_unlock(&bdma_chan->lock); | 689 | spin_unlock(&bdma_chan->lock); |
629 | } | 690 | } |
630 | } | 691 | } |
631 | 692 | err_out: | |
632 | /* Re-Enable BDMA channel interrupts */ | 693 | /* Re-Enable BDMA channel interrupts */ |
633 | iowrite32(TSI721_DMAC_INT_ALL, bdma_chan->regs + TSI721_DMAC_INTE); | 694 | iowrite32(TSI721_DMAC_INT_ALL, bdma_chan->regs + TSI721_DMAC_INTE); |
634 | } | 695 | } |
@@ -841,7 +902,6 @@ static int tsi721_terminate_all(struct dma_chan *dchan) | |||
841 | { | 902 | { |
842 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); | 903 | struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); |
843 | struct tsi721_tx_desc *desc, *_d; | 904 | struct tsi721_tx_desc *desc, *_d; |
844 | u32 dmac_int; | ||
845 | LIST_HEAD(list); | 905 | LIST_HEAD(list); |
846 | 906 | ||
847 | tsi_debug(DMA, &dchan->dev->device, "DMAC%d", bdma_chan->id); | 907 | tsi_debug(DMA, &dchan->dev->device, "DMAC%d", bdma_chan->id); |
@@ -850,7 +910,10 @@ static int tsi721_terminate_all(struct dma_chan *dchan) | |||
850 | 910 | ||
851 | bdma_chan->active = false; | 911 | bdma_chan->active = false; |
852 | 912 | ||
853 | if (!tsi721_dma_is_idle(bdma_chan)) { | 913 | while (!tsi721_dma_is_idle(bdma_chan)) { |
914 | |||
915 | udelay(5); | ||
916 | #if (0) | ||
854 | /* make sure to stop the transfer */ | 917 | /* make sure to stop the transfer */ |
855 | iowrite32(TSI721_DMAC_CTL_SUSP, | 918 | iowrite32(TSI721_DMAC_CTL_SUSP, |
856 | bdma_chan->regs + TSI721_DMAC_CTL); | 919 | bdma_chan->regs + TSI721_DMAC_CTL); |
@@ -859,6 +922,7 @@ static int tsi721_terminate_all(struct dma_chan *dchan) | |||
859 | do { | 922 | do { |
860 | dmac_int = ioread32(bdma_chan->regs + TSI721_DMAC_INT); | 923 | dmac_int = ioread32(bdma_chan->regs + TSI721_DMAC_INT); |
861 | } while ((dmac_int & TSI721_DMAC_INT_SUSP) == 0); | 924 | } while ((dmac_int & TSI721_DMAC_INT_SUSP) == 0); |
925 | #endif | ||
862 | } | 926 | } |
863 | 927 | ||
864 | if (bdma_chan->active_tx) | 928 | if (bdma_chan->active_tx) |