| From 5aaba8503e49e51bc8bec760ee1903c01d568d66 Mon Sep 17 00:00:00 2001 |
| From: Esben Haabendal <esben@geanix.com> |
| Date: Fri, 21 Feb 2020 07:47:21 +0100 |
| Subject: [PATCH] net: ll_temac: Fix race condition causing TX hang |
| |
| commit 84823ff80f7403752b59e00bb198724100dc611c upstream. |
| |
| It is possible that the interrupt handler fires and frees up space in |
| the TX ring in between checking for sufficient TX ring space and |
| stopping the TX queue in temac_start_xmit. If this happens, the |
| queue wake from the interrupt handler will occur before the queue is |
| stopped, causing a lost wakeup and the adapter's transmit hanging. |
| |
| To avoid this, after stopping the queue, check again whether there is |
| sufficient space in the TX ring. If so, wake up the queue again. |
| |
| This is a port of the similar fix in axienet driver, |
| commit 7de44285c1f6 ("net: axienet: Fix race condition causing TX hang"). |
| |
| Fixes: 23ecc4bde21f ("net: ll_temac: fix checksum offload logic") |
| Signed-off-by: Esben Haabendal <esben@geanix.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c |
| index 14870d659f7d..2053001fc36e 100644 |
| --- a/drivers/net/ethernet/xilinx/ll_temac_main.c |
| +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c |
| @@ -704,6 +704,9 @@ static void temac_start_xmit_done(struct net_device *ndev) |
| stat = be32_to_cpu(cur_p->app0); |
| } |
| |
| + /* Matches barrier in temac_start_xmit */ |
| + smp_mb(); |
| + |
| netif_wake_queue(ndev); |
| } |
| |
| @@ -746,9 +749,19 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
| cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; |
| |
| if (temac_check_tx_bd_space(lp, num_frag + 1)) { |
| - if (!netif_queue_stopped(ndev)) |
| - netif_stop_queue(ndev); |
| - return NETDEV_TX_BUSY; |
| + if (netif_queue_stopped(ndev)) |
| + return NETDEV_TX_BUSY; |
| + |
| + netif_stop_queue(ndev); |
| + |
| + /* Matches barrier in temac_start_xmit_done */ |
| + smp_mb(); |
| + |
| + /* Space might have just been freed - check again */ |
| + if (temac_check_tx_bd_space(lp, num_frag)) |
| + return NETDEV_TX_BUSY; |
| + |
| + netif_wake_queue(ndev); |
| } |
| |
| cur_p->app0 = 0; |
| -- |
| 2.7.4 |
| |