]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
net: macb: Handle HRESP error
authorHarini Katakam <harini.katakam@xilinx.com>
Thu, 8 Mar 2018 12:50:47 +0000 (18:20 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Fri, 16 Mar 2018 09:25:55 +0000 (10:25 +0100)
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 <harinik@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cadence/macb_main.c

index 40f6e32fa992b2f4dcb712588f0416b4faa3a90c..5fbd2c36e55d702983e5c2c284dc3ef658a7c7ab 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/phy.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/net_tstamp.h>
+#include <linux/interrupt.h>
 
 #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;
index 1fc0eea343206741f5a9a688de1fdfb0907e4af0..5847a457647322441b664803ee7d0c082f9601fc 100644 (file)
@@ -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);