summaryrefslogtreecommitdiffstats
path: root/drivers/rapidio
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2016-03-22 17:27:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commit458bdf6e399d7d6f779b97a24645a7a38d1ae07b (patch)
tree83d6d4b96a37137c3e9c7653dd07c9370fc2d28d /drivers/rapidio
parente680b672a2b47748ee548229242b543a23b902c1 (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.c82
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 692err_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)