Skip to content

Commit

Permalink
bnxt: don't lock the tx queue from napi poll
Browse files Browse the repository at this point in the history
[ Upstream commit 3c60313 ]

We can't take the tx lock from the napi poll routine, because
netpoll can poll napi at any moment, including with the tx lock
already held.

The tx lock is protecting against two paths - the disable
path, and (as Michael points out) the NETDEV_TX_BUSY case
which may occur if NAPI completions race with start_xmit
and both decide to re-enable the queue.

For the disable/ifdown path use synchronize_net() to make sure
closing the device does not race we restarting the queues.
Annotate accesses to dev_state against data races.

For the NAPI cleanup vs start_xmit path - appropriate barriers
are already in place in the main spot where Tx queue is stopped
but we need to do the same careful dance in the TX_BUSY case.

Fixes: c0c050c ("bnxt_en: New Broadcom ethernet driver.")
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Reviewed-by: Edwin Peer <edwin.peer@broadcom.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
kuba-moo authored and Sasha Levin committed Aug 26, 2021
1 parent a89ba11 commit 7edc1a0
Showing 1 changed file with 32 additions and 22 deletions.
54 changes: 32 additions & 22 deletions drivers/net/ethernet/broadcom/bnxt/bnxt.c
Expand Up @@ -362,6 +362,26 @@ static u16 bnxt_xmit_get_cfa_action(struct sk_buff *skb)
return md_dst->u.port_info.port_id;
}

static bool bnxt_txr_netif_try_stop_queue(struct bnxt *bp,
struct bnxt_tx_ring_info *txr,
struct netdev_queue *txq)
{
netif_tx_stop_queue(txq);

/* netif_tx_stop_queue() must be done before checking
* tx index in bnxt_tx_avail() below, because in
* bnxt_tx_int(), we update tx index before checking for
* netif_tx_queue_stopped().
*/
smp_mb();
if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh) {
netif_tx_wake_queue(txq);
return false;
}

return true;
}

static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
Expand Down Expand Up @@ -390,8 +410,8 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)

free_size = bnxt_tx_avail(bp, txr);
if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) {
netif_tx_stop_queue(txq);
return NETDEV_TX_BUSY;
if (bnxt_txr_netif_try_stop_queue(bp, txr, txq))
return NETDEV_TX_BUSY;
}

length = skb->len;
Expand Down Expand Up @@ -605,16 +625,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (netdev_xmit_more() && !tx_buf->is_push)
bnxt_db_write(bp, &txr->tx_db, prod);

netif_tx_stop_queue(txq);

/* netif_tx_stop_queue() must be done before checking
* tx index in bnxt_tx_avail() below, because in
* bnxt_tx_int(), we update tx index before checking for
* netif_tx_queue_stopped().
*/
smp_mb();
if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh)
netif_tx_wake_queue(txq);
bnxt_txr_netif_try_stop_queue(bp, txr, txq);
}
return NETDEV_TX_OK;

Expand Down Expand Up @@ -698,14 +709,9 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
smp_mb();

if (unlikely(netif_tx_queue_stopped(txq)) &&
(bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
__netif_tx_lock(txq, smp_processor_id());
if (netif_tx_queue_stopped(txq) &&
bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh &&
txr->dev_state != BNXT_DEV_STATE_CLOSING)
netif_tx_wake_queue(txq);
__netif_tx_unlock(txq);
}
bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh &&
READ_ONCE(txr->dev_state) != BNXT_DEV_STATE_CLOSING)
netif_tx_wake_queue(txq);
}

static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
Expand Down Expand Up @@ -9055,9 +9061,11 @@ void bnxt_tx_disable(struct bnxt *bp)
if (bp->tx_ring) {
for (i = 0; i < bp->tx_nr_rings; i++) {
txr = &bp->tx_ring[i];
txr->dev_state = BNXT_DEV_STATE_CLOSING;
WRITE_ONCE(txr->dev_state, BNXT_DEV_STATE_CLOSING);
}
}
/* Make sure napi polls see @dev_state change */
synchronize_net();
/* Drop carrier first to prevent TX timeout */
netif_carrier_off(bp->dev);
/* Stop all TX queues */
Expand All @@ -9071,8 +9079,10 @@ void bnxt_tx_enable(struct bnxt *bp)

for (i = 0; i < bp->tx_nr_rings; i++) {
txr = &bp->tx_ring[i];
txr->dev_state = 0;
WRITE_ONCE(txr->dev_state, 0);
}
/* Make sure napi polls see @dev_state change */
synchronize_net();
netif_tx_wake_all_queues(bp->dev);
if (bp->link_info.link_up)
netif_carrier_on(bp->dev);
Expand Down

0 comments on commit 7edc1a0

Please sign in to comment.