Commit 0af8c8ae authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-enetc-fix-some-issues-of-xdp'

Wei Fang says:

====================
net: enetc: fix some issues of XDP

We found some bugs when testing the XDP function of enetc driver,
and these bugs are easy to reproduce. This is not only causes XDP
to not work, but also the network cannot be restored after exiting
the XDP program. So the patch set is mainly to fix these bugs. For
details, please see the commit message of each patch.

v1: https://lore.kernel.org/bpf/20240919084104.661180-1-wei.fang@nxp.com/
v2: https://lore.kernel.org/netdev/20241008224806.2onzkt3gbslw5jxb@skbuf/
v3: https://lore.kernel.org/imx/20241009090327.146461-1-wei.fang@nxp.com/
====================

Link: https://patch.msgid.link/20241010092056.298128-1-wei.fang@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 8a6be4bd 6b58fadd
...@@ -902,6 +902,7 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget) ...@@ -902,6 +902,7 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) && if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) &&
__netif_subqueue_stopped(ndev, tx_ring->index) && __netif_subqueue_stopped(ndev, tx_ring->index) &&
!test_bit(ENETC_TX_DOWN, &priv->flags) &&
(enetc_bd_unused(tx_ring) >= ENETC_TXBDS_MAX_NEEDED))) { (enetc_bd_unused(tx_ring) >= ENETC_TXBDS_MAX_NEEDED))) {
netif_wake_subqueue(ndev, tx_ring->index); netif_wake_subqueue(ndev, tx_ring->index);
} }
...@@ -1377,6 +1378,9 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, ...@@ -1377,6 +1378,9 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
int xdp_tx_bd_cnt, i, k; int xdp_tx_bd_cnt, i, k;
int xdp_tx_frm_cnt = 0; int xdp_tx_frm_cnt = 0;
if (unlikely(test_bit(ENETC_TX_DOWN, &priv->flags)))
return -ENETDOWN;
enetc_lock_mdio(); enetc_lock_mdio();
tx_ring = priv->xdp_tx_ring[smp_processor_id()]; tx_ring = priv->xdp_tx_ring[smp_processor_id()];
...@@ -1521,7 +1525,6 @@ static void enetc_xdp_drop(struct enetc_bdr *rx_ring, int rx_ring_first, ...@@ -1521,7 +1525,6 @@ static void enetc_xdp_drop(struct enetc_bdr *rx_ring, int rx_ring_first,
&rx_ring->rx_swbd[rx_ring_first]); &rx_ring->rx_swbd[rx_ring_first]);
enetc_bdr_idx_inc(rx_ring, &rx_ring_first); enetc_bdr_idx_inc(rx_ring, &rx_ring_first);
} }
rx_ring->stats.xdp_drops++;
} }
static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring,
...@@ -1586,6 +1589,7 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, ...@@ -1586,6 +1589,7 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring,
fallthrough; fallthrough;
case XDP_DROP: case XDP_DROP:
enetc_xdp_drop(rx_ring, orig_i, i); enetc_xdp_drop(rx_ring, orig_i, i);
rx_ring->stats.xdp_drops++;
break; break;
case XDP_PASS: case XDP_PASS:
rxbd = orig_rxbd; rxbd = orig_rxbd;
...@@ -1602,6 +1606,12 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring, ...@@ -1602,6 +1606,12 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring,
break; break;
case XDP_TX: case XDP_TX:
tx_ring = priv->xdp_tx_ring[rx_ring->index]; tx_ring = priv->xdp_tx_ring[rx_ring->index];
if (unlikely(test_bit(ENETC_TX_DOWN, &priv->flags))) {
enetc_xdp_drop(rx_ring, orig_i, i);
tx_ring->stats.xdp_tx_drops++;
break;
}
xdp_tx_bd_cnt = enetc_rx_swbd_to_xdp_tx_swbd(xdp_tx_arr, xdp_tx_bd_cnt = enetc_rx_swbd_to_xdp_tx_swbd(xdp_tx_arr,
rx_ring, rx_ring,
orig_i, i); orig_i, i);
...@@ -2223,18 +2233,24 @@ static void enetc_enable_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) ...@@ -2223,18 +2233,24 @@ static void enetc_enable_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr); enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
} }
static void enetc_enable_bdrs(struct enetc_ndev_priv *priv) static void enetc_enable_rx_bdrs(struct enetc_ndev_priv *priv)
{ {
struct enetc_hw *hw = &priv->si->hw; struct enetc_hw *hw = &priv->si->hw;
int i; int i;
for (i = 0; i < priv->num_tx_rings; i++)
enetc_enable_txbdr(hw, priv->tx_ring[i]);
for (i = 0; i < priv->num_rx_rings; i++) for (i = 0; i < priv->num_rx_rings; i++)
enetc_enable_rxbdr(hw, priv->rx_ring[i]); enetc_enable_rxbdr(hw, priv->rx_ring[i]);
} }
static void enetc_enable_tx_bdrs(struct enetc_ndev_priv *priv)
{
struct enetc_hw *hw = &priv->si->hw;
int i;
for (i = 0; i < priv->num_tx_rings; i++)
enetc_enable_txbdr(hw, priv->tx_ring[i]);
}
static void enetc_disable_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) static void enetc_disable_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
{ {
int idx = rx_ring->index; int idx = rx_ring->index;
...@@ -2251,18 +2267,24 @@ static void enetc_disable_txbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) ...@@ -2251,18 +2267,24 @@ static void enetc_disable_txbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
enetc_txbdr_wr(hw, idx, ENETC_TBMR, 0); enetc_txbdr_wr(hw, idx, ENETC_TBMR, 0);
} }
static void enetc_disable_bdrs(struct enetc_ndev_priv *priv) static void enetc_disable_rx_bdrs(struct enetc_ndev_priv *priv)
{ {
struct enetc_hw *hw = &priv->si->hw; struct enetc_hw *hw = &priv->si->hw;
int i; int i;
for (i = 0; i < priv->num_tx_rings; i++)
enetc_disable_txbdr(hw, priv->tx_ring[i]);
for (i = 0; i < priv->num_rx_rings; i++) for (i = 0; i < priv->num_rx_rings; i++)
enetc_disable_rxbdr(hw, priv->rx_ring[i]); enetc_disable_rxbdr(hw, priv->rx_ring[i]);
} }
static void enetc_disable_tx_bdrs(struct enetc_ndev_priv *priv)
{
struct enetc_hw *hw = &priv->si->hw;
int i;
for (i = 0; i < priv->num_tx_rings; i++)
enetc_disable_txbdr(hw, priv->tx_ring[i]);
}
static void enetc_wait_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) static void enetc_wait_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
{ {
int delay = 8, timeout = 100; int delay = 8, timeout = 100;
...@@ -2460,9 +2482,13 @@ void enetc_start(struct net_device *ndev) ...@@ -2460,9 +2482,13 @@ void enetc_start(struct net_device *ndev)
enable_irq(irq); enable_irq(irq);
} }
enetc_enable_bdrs(priv); enetc_enable_tx_bdrs(priv);
enetc_enable_rx_bdrs(priv);
netif_tx_start_all_queues(ndev); netif_tx_start_all_queues(ndev);
clear_bit(ENETC_TX_DOWN, &priv->flags);
} }
EXPORT_SYMBOL_GPL(enetc_start); EXPORT_SYMBOL_GPL(enetc_start);
...@@ -2520,9 +2546,15 @@ void enetc_stop(struct net_device *ndev) ...@@ -2520,9 +2546,15 @@ void enetc_stop(struct net_device *ndev)
struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_ndev_priv *priv = netdev_priv(ndev);
int i; int i;
set_bit(ENETC_TX_DOWN, &priv->flags);
netif_tx_stop_all_queues(ndev); netif_tx_stop_all_queues(ndev);
enetc_disable_bdrs(priv); enetc_disable_rx_bdrs(priv);
enetc_wait_bdrs(priv);
enetc_disable_tx_bdrs(priv);
for (i = 0; i < priv->bdr_int_num; i++) { for (i = 0; i < priv->bdr_int_num; i++) {
int irq = pci_irq_vector(priv->si->pdev, int irq = pci_irq_vector(priv->si->pdev,
...@@ -2533,8 +2565,6 @@ void enetc_stop(struct net_device *ndev) ...@@ -2533,8 +2565,6 @@ void enetc_stop(struct net_device *ndev)
napi_disable(&priv->int_vector[i]->napi); napi_disable(&priv->int_vector[i]->napi);
} }
enetc_wait_bdrs(priv);
enetc_clear_interrupts(priv); enetc_clear_interrupts(priv);
} }
EXPORT_SYMBOL_GPL(enetc_stop); EXPORT_SYMBOL_GPL(enetc_stop);
......
...@@ -325,6 +325,7 @@ enum enetc_active_offloads { ...@@ -325,6 +325,7 @@ enum enetc_active_offloads {
enum enetc_flags_bit { enum enetc_flags_bit {
ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS = 0, ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS = 0,
ENETC_TX_DOWN,
}; };
/* interrupt coalescing modes */ /* interrupt coalescing modes */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment