summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2022-10-25 17:49:22 +0300
committerJason Liu <jason.hui.liu@nxp.com>2022-10-26 11:59:52 +0200
commit855860e0613952e045bece5ab64e86c2e0d9dfa1 (patch)
tree94f045de604b7e554c35633dc9b9efffb5fad5ea /drivers/net/ethernet/freescale
parent79108149b8caa6d2194fe20a570d3d259b29c5e9 (diff)
net: enetc: prioritize ability to go down over packet processing
napi_synchronize() from enetc_stop() waits until the softirq has finished execution and does not reschedule anymore. However under high traffic load, this will never happen, and the interface can never be closed. The solution chosen here is probably not the best; it is adapted from i40e. Normally one would quiesce the RX ring and let the softirq finish what remains there. But I couldn't immediately see how to do that (plus the fact that the NAPI poll routine is written to update the consumer index which makes the device want to put more buffers in the RX ring, which restarts the madness again). Since the enetc hardirq may trigger while we have ENETC_DOWN set, it may happen that enetc_msix() masks it, but enetc_poll() never unmasks it. To prevent a stall in that case, schedule all NAPI instances when ENETC_DOWN gets cleared. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c19
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h1
2 files changed, 20 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 700a878cb8bc..f434ce9901b1 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1672,11 +1672,20 @@ static int enetc_poll(struct napi_struct *napi, int budget)
struct enetc_int_vector
*v = container_of(napi, struct enetc_int_vector, napi);
struct enetc_bdr *rx_ring = &v->rx_ring;
+ struct enetc_ndev_priv *priv;
struct bpf_prog *prog;
bool complete = true;
int work_done;
int i;
+ priv = netdev_priv(rx_ring->ndev);
+
+ /* Prioritize device ability to go down over packet processing */
+ if (test_bit(ENETC_DOWN, &priv->flags)) {
+ napi_complete(napi);
+ return 0;
+ }
+
enetc_lock_mdio();
for (i = 0; i < v->count_tx_rings; i++)
@@ -2350,6 +2359,14 @@ void enetc_start(struct net_device *ndev)
netif_carrier_on(ndev);
netif_tx_start_all_queues(ndev);
+
+ clear_bit(ENETC_DOWN, &priv->flags);
+
+ for (i = 0; i < priv->bdr_int_num; i++) {
+ struct enetc_int_vector *v = priv->int_vector[i];
+
+ napi_schedule(&v->napi);
+ }
}
static int enetc_xdp_rxq_mem_model_register(struct enetc_ndev_priv *priv,
@@ -2467,6 +2484,8 @@ void enetc_stop(struct net_device *ndev)
struct enetc_ndev_priv *priv = netdev_priv(ndev);
int i;
+ set_bit(ENETC_DOWN, &priv->flags);
+
netif_tx_stop_all_queues(ndev);
for (i = 0; i < priv->bdr_int_num; i++) {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 05f66460b155..284e649a6dc7 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -337,6 +337,7 @@ enum enetc_active_offloads {
enum enetc_flags_bit {
ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS = 0,
+ ENETC_DOWN,
};
/* interrupt coalescing modes */