Skip to content

Commit 62f94c2

Browse files
grygoriySdavem330
authored andcommitted
net: ethernet: ti: cpsw: fix net watchdog timeout
It was discovered that simple program which indefinitely sends 200b UDP packets and runs on TI AM574x SoC (SMP) under RT Kernel triggers network watchdog timeout in TI CPSW driver (<6 hours run). The network watchdog timeout is triggered due to race between cpsw_ndo_start_xmit() and cpsw_tx_handler() [NAPI] cpsw_ndo_start_xmit() if (unlikely(!cpdma_check_free_tx_desc(txch))) { txq = netdev_get_tx_queue(ndev, q_idx); netif_tx_stop_queue(txq); ^^ as per [1] barier has to be used after set_bit() otherwise new value might not be visible to other cpus } cpsw_tx_handler() if (unlikely(netif_tx_queue_stopped(txq))) netif_tx_wake_queue(txq); and when it happens ndev TX queue became disabled forever while driver's HW TX queue is empty. Fix this, by adding smp_mb__after_atomic() after netif_tx_stop_queue() calls and double check for free TX descriptors after stopping ndev TX queue - if there are free TX descriptors wake up ndev TX queue. [1] https://www.kernel.org/doc/html/latest/core-api/atomic_ops.html Signed-off-by: Grygorii Strashko <[email protected]> Reviewed-by: Ivan Khoronzhuk <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b0992ec commit 62f94c2

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

drivers/net/ethernet/ti/cpsw.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
16361636
q_idx = q_idx % cpsw->tx_ch_num;
16371637

16381638
txch = cpsw->txv[q_idx].ch;
1639+
txq = netdev_get_tx_queue(ndev, q_idx);
16391640
ret = cpsw_tx_packet_submit(priv, skb, txch);
16401641
if (unlikely(ret != 0)) {
16411642
cpsw_err(priv, tx_err, "desc submit failed\n");
@@ -1646,15 +1647,26 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
16461647
* tell the kernel to stop sending us tx frames.
16471648
*/
16481649
if (unlikely(!cpdma_check_free_tx_desc(txch))) {
1649-
txq = netdev_get_tx_queue(ndev, q_idx);
16501650
netif_tx_stop_queue(txq);
1651+
1652+
/* Barrier, so that stop_queue visible to other cpus */
1653+
smp_mb__after_atomic();
1654+
1655+
if (cpdma_check_free_tx_desc(txch))
1656+
netif_tx_wake_queue(txq);
16511657
}
16521658

16531659
return NETDEV_TX_OK;
16541660
fail:
16551661
ndev->stats.tx_dropped++;
1656-
txq = netdev_get_tx_queue(ndev, skb_get_queue_mapping(skb));
16571662
netif_tx_stop_queue(txq);
1663+
1664+
/* Barrier, so that stop_queue visible to other cpus */
1665+
smp_mb__after_atomic();
1666+
1667+
if (cpdma_check_free_tx_desc(txch))
1668+
netif_tx_wake_queue(txq);
1669+
16581670
return NETDEV_TX_BUSY;
16591671
}
16601672

0 commit comments

Comments
 (0)