Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: bcmgenet: improve TX timeout

Dump useful ring statistics along with interrupt status, software
maintained pointers and hardware registers to help troubleshoot TX queue
stalls.

When a timeout occurs, disable TX NAPI for the rings, dump their states
while interrupts are disabled, re-enable interrupts, NAPI and queue flow
control to help with the recovery.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Florian Fainelli and committed by
David S. Miller
13ea6578 80edb722

+67
+67
drivers/net/ethernet/broadcom/genet/bcmgenet.c
··· 2770 2770 return ret; 2771 2771 } 2772 2772 2773 + static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) 2774 + { 2775 + struct bcmgenet_priv *priv = ring->priv; 2776 + u32 p_index, c_index, intsts, intmsk; 2777 + struct netdev_queue *txq; 2778 + unsigned int free_bds; 2779 + unsigned long flags; 2780 + bool txq_stopped; 2781 + 2782 + if (!netif_msg_tx_err(priv)) 2783 + return; 2784 + 2785 + txq = netdev_get_tx_queue(priv->dev, ring->queue); 2786 + 2787 + spin_lock_irqsave(&ring->lock, flags); 2788 + if (ring->index == DESC_INDEX) { 2789 + intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); 2790 + intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; 2791 + } else { 2792 + intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); 2793 + intmsk = 1 << ring->index; 2794 + } 2795 + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); 2796 + p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); 2797 + txq_stopped = netif_tx_queue_stopped(txq); 2798 + free_bds = ring->free_bds; 2799 + spin_unlock_irqrestore(&ring->lock, flags); 2800 + 2801 + netif_err(priv, tx_err, priv->dev, "Ring %d queue %d status summary\n" 2802 + "TX queue status: %s, interrupts: %s\n" 2803 + "(sw)free_bds: %d (sw)size: %d\n" 2804 + "(sw)p_index: %d (hw)p_index: %d\n" 2805 + "(sw)c_index: %d (hw)c_index: %d\n" 2806 + "(sw)clean_p: %d (sw)write_p: %d\n" 2807 + "(sw)cb_ptr: %d (sw)end_ptr: %d\n", 2808 + ring->index, ring->queue, 2809 + txq_stopped ? "stopped" : "active", 2810 + intsts & intmsk ? "enabled" : "disabled", 2811 + free_bds, ring->size, 2812 + ring->prod_index, p_index & DMA_P_INDEX_MASK, 2813 + ring->c_index, c_index & DMA_C_INDEX_MASK, 2814 + ring->clean_ptr, ring->write_ptr, 2815 + ring->cb_ptr, ring->end_ptr); 2816 + } 2817 + 2773 2818 static void bcmgenet_timeout(struct net_device *dev) 2774 2819 { 2775 2820 struct bcmgenet_priv *priv = netdev_priv(dev); 2821 + u32 int0_enable = 0; 2822 + u32 int1_enable = 0; 2823 + unsigned int q; 2776 2824 2777 2825 netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); 2826 + 2827 + bcmgenet_disable_tx_napi(priv); 2828 + 2829 + for (q = 0; q < priv->hw_params->tx_queues; q++) 2830 + bcmgenet_dump_tx_queue(&priv->tx_rings[q]); 2831 + bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); 2832 + 2833 + bcmgenet_tx_reclaim_all(dev); 2834 + 2835 + for (q = 0; q < priv->hw_params->tx_queues; q++) 2836 + int1_enable |= (1 << q); 2837 + 2838 + int0_enable = UMAC_IRQ_TXDMA_DONE; 2839 + 2840 + /* Re-enable TX interrupts if disabled */ 2841 + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); 2842 + bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); 2843 + 2844 + bcmgenet_enable_tx_napi(priv); 2778 2845 2779 2846 dev->trans_start = jiffies; 2780 2847