|
@@ -1258,6 +1258,57 @@ 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);
|
|
|
+
|
|
|
+ /* Initialize TX and RX buffers */
|
|
|
+ for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
|
|
|
+ queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma));
|
|
|
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
|
|
|
+ if (bp->hw_dma_cap & HW_DMA_CAP_64B)
|
|
|
+ queue_writel(queue, RBQPH,
|
|
|
+ upper_32_bits(queue->rx_ring_dma));
|
|
|
+#endif
|
|
|
+ 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
|
|
|
+
|
|
|
+ /* 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;
|
|
@@ -1347,10 +1398,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)
|
|
@@ -3937,6 +3985,9 @@ static int macb_probe(struct platform_device *pdev)
|
|
|
goto err_out_unregister_mdio;
|
|
|
}
|
|
|
|
|
|
+ tasklet_init(&bp->hresp_err_tasklet, macb_hresp_error_task,
|
|
|
+ (unsigned long)bp);
|
|
|
+
|
|
|
phy_attached_info(phydev);
|
|
|
|
|
|
netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
|