[PATCH net-next 5/7] bnge: Quiesce NQ0 around ring teardown in bnge_free_core()

From: Bhargava Marreddy

Date: Tue Sep 01 2026 - 15:27:29 EST


Add bnge_quiesce_nq0() and bnge_resume_nq0() helpers to temporarily disable
and re-enable NQ0 NAPI. Use these helpers to bracket ring teardown in
bnge_free_core() and ring rebuild in bnge_alloc_core().

Both helpers currently no-op, since no bnge_napi has BNGE_NAPI_FLAG_NQ0 set
yet. The next patch creates NQ0 during probe and sets this flag, at which
point these helpers become load-bearing: because NQ0 will remain active
while administratively down, its NAPI is not disabled by the standard close
paths, so temporarily quiescing it during core resource free/rebuild windows
is required to prevent stray completions from accessing uninitialized or
freed memory.

Signed-off-by: Bhargava Marreddy <bhargava.marreddy@xxxxxxxxxxxx>
Reviewed-by: Vikas Gupta <vikas.gupta@xxxxxxxxxxxx>
Reviewed-by: Rajashekar Hudumula <rajashekar.hudumula@xxxxxxxxxxxx>
---
.../net/ethernet/broadcom/bnge/bnge_netdev.c | 70 ++++++++++++++-----
.../net/ethernet/broadcom/bnge/bnge_netdev.h | 10 +++
2 files changed, 61 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
index dc3d51f31e5e..10d54568f2c5 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
@@ -442,6 +442,25 @@ static void bnge_sp_task(struct work_struct *work)
netdev_unlock(bn->netdev);
}

+static void bnge_db_nq_arm(struct bnge_net *bn,
+ struct bnge_db_info *db, u32 idx)
+{
+ bnge_writeq(bn->bd, db->db_key64 | DBR_TYPE_NQ_ARM |
+ DB_RING_IDX(db, idx), db->doorbell);
+}
+
+static void bnge_db_nq(struct bnge_net *bn, struct bnge_db_info *db, u32 idx)
+{
+ bnge_writeq(bn->bd, db->db_key64 | DBR_TYPE_NQ_MASK |
+ DB_RING_IDX(db, idx), db->doorbell);
+}
+
+static void bnge_db_cq(struct bnge_net *bn, struct bnge_db_info *db, u32 idx)
+{
+ bnge_writeq(bn->bd, db->db_key64 | DBR_TYPE_CQ_ARMALL |
+ DB_RING_IDX(db, idx), db->doorbell);
+}
+
static void bnge_free_nq_desc_arr(struct bnge_nq_ring_info *nqr)
{
struct bnge_ring_struct *ring = &nqr->ring_struct;
@@ -563,6 +582,34 @@ static void bnge_free_nq_tree(struct bnge_net *bn)
}
}

+static void bnge_quiesce_nq0(struct bnge_net *bn)
+{
+ struct bnge_napi *bnapi = bn->bnapi[BNGE_NQ0_NAPI_IDX];
+ struct bnge_nq_ring_info *nqr = &bnapi->nq_ring;
+ struct bnge_ring_struct *ring;
+ struct bnge_dev *bd = bn->bd;
+
+ if (!BNGE_NQ0_NAPI(bnapi))
+ return;
+
+ ring = &nqr->ring_struct;
+ bnge_db_nq(bn, &nqr->nq_db, nqr->nq_raw_cons);
+ synchronize_irq(bd->irq_tbl[ring->map_idx].vector);
+ napi_disable_locked(&bnapi->napi);
+}
+
+static void bnge_resume_nq0(struct bnge_net *bn)
+{
+ struct bnge_napi *bnapi = bn->bnapi[BNGE_NQ0_NAPI_IDX];
+ struct bnge_nq_ring_info *nqr = &bnapi->nq_ring;
+
+ if (!BNGE_NQ0_NAPI(bnapi))
+ return;
+
+ napi_enable_locked(&bnapi->napi);
+ bnge_db_nq_arm(bn, &nqr->nq_db, nqr->nq_raw_cons);
+}
+
static int alloc_one_cp_ring(struct bnge_net *bn,
struct bnge_cp_ring_info *cpr)
{
@@ -1253,6 +1300,7 @@ static void bnge_clear_bnapi_queues(struct bnge_net *bn)
static void bnge_free_core(struct bnge_net *bn)
{
bnge_free_vnic_attributes(bn);
+ bnge_quiesce_nq0(bn);
bnge_free_tx_rings(bn);
bnge_free_rx_rings(bn);
bnge_free_nq_tree(bn);
@@ -1268,6 +1316,7 @@ static void bnge_free_core(struct bnge_net *bn)
bn->rx_ring = NULL;

bnge_clear_bnapi_queues(bn);
+ bnge_resume_nq0(bn);
}

static int bnge_alloc_core(struct bnge_net *bn)
@@ -1345,7 +1394,9 @@ static int bnge_alloc_core(struct bnge_net *bn)
if (rc)
goto err_free_core;

+ bnge_quiesce_nq0(bn);
rc = bnge_alloc_nq_tree(bn);
+ bnge_resume_nq0(bn);
if (rc)
goto err_free_core;

@@ -1372,25 +1423,6 @@ u32 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr)
return txr->tx_cpr->ring_struct.fw_ring_id;
}

-static void bnge_db_nq_arm(struct bnge_net *bn,
- struct bnge_db_info *db, u32 idx)
-{
- bnge_writeq(bn->bd, db->db_key64 | DBR_TYPE_NQ_ARM |
- DB_RING_IDX(db, idx), db->doorbell);
-}
-
-static void bnge_db_nq(struct bnge_net *bn, struct bnge_db_info *db, u32 idx)
-{
- bnge_writeq(bn->bd, db->db_key64 | DBR_TYPE_NQ_MASK |
- DB_RING_IDX(db, idx), db->doorbell);
-}
-
-static void bnge_db_cq(struct bnge_net *bn, struct bnge_db_info *db, u32 idx)
-{
- bnge_writeq(bn->bd, db->db_key64 | DBR_TYPE_CQ_ARMALL |
- DB_RING_IDX(db, idx), db->doorbell);
-}
-
static int bnge_cp_num_to_irq_num(struct bnge_net *bn, int n)
{
struct bnge_napi *bnapi = bn->bnapi[n];
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
index 476b5bab96fe..4d84f109ad5f 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
@@ -539,6 +539,14 @@ struct bnge_tx_ring_info {
struct bnge_ring_struct tx_ring_struct;
};

+#define BNGE_NQ0_NAPI_IDX 0
+
+enum bnge_napi_flag {
+ BNGE_NAPI_FLAG_NQ0,
+};
+
+#define BNGE_NQ0_NAPI(bnapi) (test_bit(BNGE_NAPI_FLAG_NQ0, &(bnapi)->flags))
+
struct bnge_napi {
struct napi_struct napi;
struct bnge_net *bn;
@@ -555,6 +563,8 @@ struct bnge_napi {
#define BNGE_TX_CMP_EVENT 0x10
bool in_reset;
bool tx_fault;
+
+ unsigned long flags;
};

#define INVALID_STATS_CTX_ID -1
--
2.47.3