diff options
author | Nicolas Ferre <nicolas.ferre@microchip.com> | 2019-04-03 06:23:58 -0400 |
---|---|---|
committer | Vinod Koul <vkoul@kernel.org> | 2019-04-23 01:08:56 -0400 |
commit | 223a4f4cfe93de2fce47a8f1f719cf4d0da4e3e6 (patch) | |
tree | dfc362162c6c8a3e890d8d628680403a42aff370 | |
parent | e2c114c06da2d9ffad5b16690abf008d6696f689 (diff) |
dmaengine: at_xdmac: enhance channel errors handling in tasklet
Complement the identification of errors with stopping the channel and
dumping the descriptor that led to the error case.
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
-rw-r--r-- | drivers/dma/at_xdmac.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 37a269420435..1dd7edaefbdc 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c | |||
@@ -1575,6 +1575,46 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan) | |||
1575 | dmaengine_desc_get_callback_invoke(txd, NULL); | 1575 | dmaengine_desc_get_callback_invoke(txd, NULL); |
1576 | } | 1576 | } |
1577 | 1577 | ||
1578 | static void at_xdmac_handle_error(struct at_xdmac_chan *atchan) | ||
1579 | { | ||
1580 | struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device); | ||
1581 | struct at_xdmac_desc *bad_desc; | ||
1582 | |||
1583 | /* | ||
1584 | * The descriptor currently at the head of the active list is | ||
1585 | * broken. Since we don't have any way to report errors, we'll | ||
1586 | * just have to scream loudly and try to continue with other | ||
1587 | * descriptors queued (if any). | ||
1588 | */ | ||
1589 | if (atchan->irq_status & AT_XDMAC_CIS_RBEIS) | ||
1590 | dev_err(chan2dev(&atchan->chan), "read bus error!!!"); | ||
1591 | if (atchan->irq_status & AT_XDMAC_CIS_WBEIS) | ||
1592 | dev_err(chan2dev(&atchan->chan), "write bus error!!!"); | ||
1593 | if (atchan->irq_status & AT_XDMAC_CIS_ROIS) | ||
1594 | dev_err(chan2dev(&atchan->chan), "request overflow error!!!"); | ||
1595 | |||
1596 | spin_lock_bh(&atchan->lock); | ||
1597 | |||
1598 | /* Channel must be disabled first as it's not done automatically */ | ||
1599 | at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask); | ||
1600 | while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask) | ||
1601 | cpu_relax(); | ||
1602 | |||
1603 | bad_desc = list_first_entry(&atchan->xfers_list, | ||
1604 | struct at_xdmac_desc, | ||
1605 | xfer_node); | ||
1606 | |||
1607 | spin_unlock_bh(&atchan->lock); | ||
1608 | |||
1609 | /* Print bad descriptor's details if needed */ | ||
1610 | dev_dbg(chan2dev(&atchan->chan), | ||
1611 | "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n", | ||
1612 | __func__, &bad_desc->lld.mbr_sa, &bad_desc->lld.mbr_da, | ||
1613 | bad_desc->lld.mbr_ubc); | ||
1614 | |||
1615 | /* Then continue with usual descriptor management */ | ||
1616 | } | ||
1617 | |||
1578 | static void at_xdmac_tasklet(unsigned long data) | 1618 | static void at_xdmac_tasklet(unsigned long data) |
1579 | { | 1619 | { |
1580 | struct at_xdmac_chan *atchan = (struct at_xdmac_chan *)data; | 1620 | struct at_xdmac_chan *atchan = (struct at_xdmac_chan *)data; |
@@ -1594,12 +1634,8 @@ static void at_xdmac_tasklet(unsigned long data) | |||
1594 | || (atchan->irq_status & error_mask)) { | 1634 | || (atchan->irq_status & error_mask)) { |
1595 | struct dma_async_tx_descriptor *txd; | 1635 | struct dma_async_tx_descriptor *txd; |
1596 | 1636 | ||
1597 | if (atchan->irq_status & AT_XDMAC_CIS_RBEIS) | 1637 | if (atchan->irq_status & error_mask) |
1598 | dev_err(chan2dev(&atchan->chan), "read bus error!!!"); | 1638 | at_xdmac_handle_error(atchan); |
1599 | if (atchan->irq_status & AT_XDMAC_CIS_WBEIS) | ||
1600 | dev_err(chan2dev(&atchan->chan), "write bus error!!!"); | ||
1601 | if (atchan->irq_status & AT_XDMAC_CIS_ROIS) | ||
1602 | dev_err(chan2dev(&atchan->chan), "request overflow error!!!"); | ||
1603 | 1639 | ||
1604 | spin_lock(&atchan->lock); | 1640 | spin_lock(&atchan->lock); |
1605 | desc = list_first_entry(&atchan->xfers_list, | 1641 | desc = list_first_entry(&atchan->xfers_list, |