From ea0a85a78fbe77f5d1f10f9696968a619223749d Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Thu, 8 Mar 2018 18:20:47 +0530 Subject: [PATCH] net: macb: Handle HRESP error Handle HRESP error by doing a SW reset of RX and TX and re-initializing the descriptors, RX and TX queue pointers. Signed-off-by: Harini Katakam Signed-off-by: Michal Simek --- drivers/net/ethernet/cadence/macb.h | 3 ++ drivers/net/ethernet/cadence/macb_main.c | 64 ++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 40f6e32fa992..5fbd2c36e55d 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -13,6 +13,7 @@ #include #include #include +#include #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP) #define MACB_EXT_DESC @@ -1057,6 +1058,8 @@ struct macb { u32 wol; + struct tasklet_struct hresp_err_tasklet; + struct macb_ptp_info *ptp_info; /* macb-ptp interface */ #ifdef MACB_EXT_DESC uint8_t hw_dma_cap; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 1fc0eea34320..5847a4576473 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1233,6 +1233,62 @@ static int macb_poll(struct napi_struct *napi, int budget) return work_done; } +static void macb_hresp_error_task(unsigned long data) +{ + struct macb *bp = (struct macb *)data; + struct net_device *dev = bp->dev; + struct macb_queue *queue = bp->queues; + unsigned int q; + u32 ctrl; + + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue_writel(queue, IDR, MACB_RX_INT_FLAGS | + MACB_TX_INT_FLAGS | + MACB_BIT(HRESP)); + } + ctrl = macb_readl(bp, NCR); + ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE)); + macb_writel(bp, NCR, ctrl); + + netif_tx_stop_all_queues(dev); + netif_carrier_off(dev); + + bp->macbgem_ops.mog_init_rings(bp); + + macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma)); +#endif + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); +#endif + /* We only use the first queue at the moment. Remaining + * queues must be tied-off before we enable the receiver. + * + * See the documentation for receive_q1_ptr for more info. + */ + if (q) + queue_writel(queue, RBQP, + lower_32_bits(bp->rx_ring_tieoff_dma)); + + /* Enable interrupts */ + queue_writel(queue, IER, + MACB_RX_INT_FLAGS | + MACB_TX_INT_FLAGS | + MACB_BIT(HRESP)); + } + + ctrl |= MACB_BIT(RE) | MACB_BIT(TE); + macb_writel(bp, NCR, ctrl); + + netif_carrier_on(dev); + netif_tx_start_all_queues(dev); +} + static irqreturn_t macb_interrupt(int irq, void *dev_id) { struct macb_queue *queue = dev_id; @@ -1322,10 +1378,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) } if (status & MACB_BIT(HRESP)) { - /* TODO: Reset the hardware, and maybe move the - * netdev_err to a lower-priority context as well - * (work queue?) - */ + tasklet_schedule(&bp->hresp_err_tasklet); netdev_err(dev, "DMA bus error: HRESP not OK\n"); if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) @@ -3625,6 +3678,9 @@ static int macb_probe(struct platform_device *pdev) netif_carrier_off(dev); + tasklet_init(&bp->hresp_err_tasklet, macb_hresp_error_task, + (unsigned long)bp); + netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), dev->base_addr, dev->irq, dev->dev_addr); -- 2.39.2