Skip to content

Commit 458bdf6

Browse files
Alexandre Bouninetorvalds
authored andcommitted
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 <[email protected]> Reported-by: Barry Wood <[email protected]> Tested-by: Barry Wood <[email protected]> Cc: Matt Porter <[email protected]> Cc: Aurelien Jacquiot <[email protected]> Cc: Andre van Herk <[email protected]> Cc: Barry Wood <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent e680b67 commit 458bdf6

File tree

1 file changed

+73
-9
lines changed

1 file changed

+73
-9
lines changed

drivers/rapidio/devices/tsi721_dma.c

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
282282
/* Disable BDMA channel interrupts */
283283
iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
284284
if (bdma_chan->active)
285-
tasklet_schedule(&bdma_chan->tasklet);
285+
tasklet_hi_schedule(&bdma_chan->tasklet);
286286
}
287287

288288
#ifdef CONFIG_PCI_MSI
@@ -298,7 +298,7 @@ static irqreturn_t tsi721_bdma_msix(int irq, void *ptr)
298298
struct tsi721_bdma_chan *bdma_chan = ptr;
299299

300300
if (bdma_chan->active)
301-
tasklet_schedule(&bdma_chan->tasklet);
301+
tasklet_hi_schedule(&bdma_chan->tasklet);
302302
return IRQ_HANDLED;
303303
}
304304
#endif /* CONFIG_PCI_MSI */
@@ -584,13 +584,71 @@ static void tsi721_dma_tasklet(unsigned long data)
584584
iowrite32(dmac_int, bdma_chan->regs + TSI721_DMAC_INT);
585585

586586
if (dmac_int & TSI721_DMAC_INT_ERR) {
587+
int i = 10000;
588+
struct tsi721_tx_desc *desc;
589+
590+
desc = bdma_chan->active_tx;
587591
dmac_sts = ioread32(bdma_chan->regs + TSI721_DMAC_STS);
588592
tsi_err(&bdma_chan->dchan.dev->device,
589-
"ERR - DMAC%d_STS = 0x%x",
590-
bdma_chan->id, dmac_sts);
593+
"DMAC%d_STS = 0x%x did=%d raddr=0x%llx",
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);
591602

592603
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);
593649
bdma_chan->active_tx = NULL;
650+
if (bdma_chan->active)
651+
tsi721_advance_work(bdma_chan, NULL);
594652
spin_unlock(&bdma_chan->lock);
595653
}
596654

@@ -619,16 +677,19 @@ static void tsi721_dma_tasklet(unsigned long data)
619677
}
620678
list_add(&desc->desc_node, &bdma_chan->free_list);
621679
bdma_chan->active_tx = NULL;
622-
tsi721_advance_work(bdma_chan, NULL);
680+
if (bdma_chan->active)
681+
tsi721_advance_work(bdma_chan, NULL);
623682
spin_unlock(&bdma_chan->lock);
624683
if (callback)
625684
callback(param);
626685
} 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);
628689
spin_unlock(&bdma_chan->lock);
629690
}
630691
}
631-
692+
err_out:
632693
/* Re-Enable BDMA channel interrupts */
633694
iowrite32(TSI721_DMAC_INT_ALL, bdma_chan->regs + TSI721_DMAC_INTE);
634695
}
@@ -841,7 +902,6 @@ static int tsi721_terminate_all(struct dma_chan *dchan)
841902
{
842903
struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
843904
struct tsi721_tx_desc *desc, *_d;
844-
u32 dmac_int;
845905
LIST_HEAD(list);
846906

847907
tsi_debug(DMA, &dchan->dev->device, "DMAC%d", bdma_chan->id);
@@ -850,7 +910,10 @@ static int tsi721_terminate_all(struct dma_chan *dchan)
850910

851911
bdma_chan->active = false;
852912

853-
if (!tsi721_dma_is_idle(bdma_chan)) {
913+
while (!tsi721_dma_is_idle(bdma_chan)) {
914+
915+
udelay(5);
916+
#if (0)
854917
/* make sure to stop the transfer */
855918
iowrite32(TSI721_DMAC_CTL_SUSP,
856919
bdma_chan->regs + TSI721_DMAC_CTL);
@@ -859,6 +922,7 @@ static int tsi721_terminate_all(struct dma_chan *dchan)
859922
do {
860923
dmac_int = ioread32(bdma_chan->regs + TSI721_DMAC_INT);
861924
} while ((dmac_int & TSI721_DMAC_INT_SUSP) == 0);
925+
#endif
862926
}
863927

864928
if (bdma_chan->active_tx)

0 commit comments

Comments
 (0)