Skip to content

Commit 2a597ef

Browse files
Yunsheng Lindavem330
authored andcommitted
net: hns3: fix for TX queue not restarted problem
There is timing window between ring_space checking and netif_stop_subqueue when transmiting a SKB, and the TX BD cleaning may be executed during the time window, which may caused TX queue not restarted problem. This patch fixes it by rechecking the ring_space after netif_stop_subqueue to make sure TX queue is restarted. Also, the ring->next_to_clean is updated even when pkts is zero, because all the TX BD cleaned may be non-SKB, so it needs to check if TX queue need to be restarted. Fixes: 76ad4f0 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Yunsheng Lin <[email protected]> Signed-off-by: Huazhong Tan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent aacf657 commit 2a597ef

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

drivers/net/ethernet/hisilicon/hns3/hns3_enet.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,8 +1287,10 @@ static bool hns3_skb_need_linearized(struct sk_buff *skb, unsigned int *bd_size,
12871287
}
12881288

12891289
static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
1290+
struct net_device *netdev,
12901291
struct sk_buff **out_skb)
12911292
{
1293+
struct hns3_nic_priv *priv = netdev_priv(netdev);
12921294
unsigned int bd_size[HNS3_MAX_TSO_BD_NUM + 1U];
12931295
struct sk_buff *skb = *out_skb;
12941296
unsigned int bd_num;
@@ -1320,10 +1322,23 @@ static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
13201322
}
13211323

13221324
out:
1323-
if (unlikely(ring_space(ring) < bd_num))
1324-
return -EBUSY;
1325+
if (likely(ring_space(ring) >= bd_num))
1326+
return bd_num;
13251327

1326-
return bd_num;
1328+
netif_stop_subqueue(netdev, ring->queue_index);
1329+
smp_mb(); /* Memory barrier before checking ring_space */
1330+
1331+
/* Start queue in case hns3_clean_tx_ring has just made room
1332+
* available and has not seen the queue stopped state performed
1333+
* by netif_stop_subqueue above.
1334+
*/
1335+
if (ring_space(ring) >= bd_num && netif_carrier_ok(netdev) &&
1336+
!test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) {
1337+
netif_start_subqueue(netdev, ring->queue_index);
1338+
return bd_num;
1339+
}
1340+
1341+
return -EBUSY;
13271342
}
13281343

13291344
static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
@@ -1400,13 +1415,13 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
14001415
/* Prefetch the data used later */
14011416
prefetch(skb->data);
14021417

1403-
ret = hns3_nic_maybe_stop_tx(ring, &skb);
1418+
ret = hns3_nic_maybe_stop_tx(ring, netdev, &skb);
14041419
if (unlikely(ret <= 0)) {
14051420
if (ret == -EBUSY) {
14061421
u64_stats_update_begin(&ring->syncp);
14071422
ring->stats.tx_busy++;
14081423
u64_stats_update_end(&ring->syncp);
1409-
goto out_net_tx_busy;
1424+
return NETDEV_TX_BUSY;
14101425
} else if (ret == -ENOMEM) {
14111426
u64_stats_update_begin(&ring->syncp);
14121427
ring->stats.sw_err_cnt++;
@@ -1457,12 +1472,6 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
14571472
out_err_tx_ok:
14581473
dev_kfree_skb_any(skb);
14591474
return NETDEV_TX_OK;
1460-
1461-
out_net_tx_busy:
1462-
netif_stop_subqueue(netdev, ring->queue_index);
1463-
smp_mb(); /* Commit all data before submit */
1464-
1465-
return NETDEV_TX_BUSY;
14661475
}
14671476

14681477
static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p)
@@ -2519,7 +2528,7 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring)
25192528
dev_queue = netdev_get_tx_queue(netdev, ring->tqp->tqp_index);
25202529
netdev_tx_completed_queue(dev_queue, pkts, bytes);
25212530

2522-
if (unlikely(pkts && netif_carrier_ok(netdev) &&
2531+
if (unlikely(netif_carrier_ok(netdev) &&
25232532
ring_space(ring) > HNS3_MAX_TSO_BD_NUM)) {
25242533
/* Make sure that anybody stopping the queue after this
25252534
* sees the new next_to_clean.

0 commit comments

Comments
 (0)