* [net-next PATCH v4 4/4] octeontx2-pf: cn20k: Use unified Halo context
From: Subbaraya Sundeep @ 2026-03-31 7:08 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, sgoutham, gakula,
bbhushan2
Cc: netdev, linux-kernel, Subbaraya Sundeep
In-Reply-To: <1774940919-1599-1-git-send-email-sbhatta@marvell.com>
Use unified Halo context present in CN20K hardware for
octeontx2 netdevs instead of aura and pool contexts.
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
---
.../ethernet/marvell/octeontx2/nic/cn20k.c | 213 +++++++++---------
.../ethernet/marvell/octeontx2/nic/cn20k.h | 3 +
.../marvell/octeontx2/nic/otx2_common.h | 3 +
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 8 +
4 files changed, 124 insertions(+), 103 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c
index a5a8f4558717..08033858c59d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c
@@ -242,15 +242,6 @@ int cn20k_register_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs)
#define RQ_BP_LVL_AURA (255 - ((85 * 256) / 100)) /* BP when 85% is full */
-static u8 cn20k_aura_bpid_idx(struct otx2_nic *pfvf, int aura_id)
-{
-#ifdef CONFIG_DCB
- return pfvf->queue_to_pfc_map[aura_id];
-#else
- return 0;
-#endif
-}
-
static int cn20k_tc_get_entry_index(struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node)
{
@@ -517,84 +508,7 @@ int cn20k_tc_alloc_entry(struct otx2_nic *nic,
return 0;
}
-static int cn20k_aura_aq_init(struct otx2_nic *pfvf, int aura_id,
- int pool_id, int numptrs)
-{
- struct npa_cn20k_aq_enq_req *aq;
- struct otx2_pool *pool;
- u8 bpid_idx;
- int err;
-
- pool = &pfvf->qset.pool[pool_id];
-
- /* Allocate memory for HW to update Aura count.
- * Alloc one cache line, so that it fits all FC_STYPE modes.
- */
- if (!pool->fc_addr) {
- err = qmem_alloc(pfvf->dev, &pool->fc_addr, 1, OTX2_ALIGN);
- if (err)
- return err;
- }
-
- /* Initialize this aura's context via AF */
- aq = otx2_mbox_alloc_msg_npa_cn20k_aq_enq(&pfvf->mbox);
- if (!aq) {
- /* Shared mbox memory buffer is full, flush it and retry */
- err = otx2_sync_mbox_msg(&pfvf->mbox);
- if (err)
- return err;
- aq = otx2_mbox_alloc_msg_npa_cn20k_aq_enq(&pfvf->mbox);
- if (!aq)
- return -ENOMEM;
- }
-
- aq->aura_id = aura_id;
-
- /* Will be filled by AF with correct pool context address */
- aq->aura.pool_addr = pool_id;
- aq->aura.pool_caching = 1;
- aq->aura.shift = ilog2(numptrs) - 8;
- aq->aura.count = numptrs;
- aq->aura.limit = numptrs;
- aq->aura.avg_level = 255;
- aq->aura.ena = 1;
- aq->aura.fc_ena = 1;
- aq->aura.fc_addr = pool->fc_addr->iova;
- aq->aura.fc_hyst_bits = 0; /* Store count on all updates */
-
- /* Enable backpressure for RQ aura */
- if (aura_id < pfvf->hw.rqpool_cnt && !is_otx2_lbkvf(pfvf->pdev)) {
- aq->aura.bp_ena = 0;
- /* If NIX1 LF is attached then specify NIX1_RX.
- *
- * Below NPA_AURA_S[BP_ENA] is set according to the
- * NPA_BPINTF_E enumeration given as:
- * 0x0 + a*0x1 where 'a' is 0 for NIX0_RX and 1 for NIX1_RX so
- * NIX0_RX is 0x0 + 0*0x1 = 0
- * NIX1_RX is 0x0 + 1*0x1 = 1
- * But in HRM it is given that
- * "NPA_AURA_S[BP_ENA](w1[33:32]) - Enable aura backpressure to
- * NIX-RX based on [BP] level. One bit per NIX-RX; index
- * enumerated by NPA_BPINTF_E."
- */
- if (pfvf->nix_blkaddr == BLKADDR_NIX1)
- aq->aura.bp_ena = 1;
-
- bpid_idx = cn20k_aura_bpid_idx(pfvf, aura_id);
- aq->aura.bpid = pfvf->bpid[bpid_idx];
-
- /* Set backpressure level for RQ's Aura */
- aq->aura.bp = RQ_BP_LVL_AURA;
- }
-
- /* Fill AQ info */
- aq->ctype = NPA_AQ_CTYPE_AURA;
- aq->op = NPA_AQ_INSTOP_INIT;
-
- return 0;
-}
-
-static int cn20k_pool_aq_init(struct otx2_nic *pfvf, u16 pool_id,
+static int cn20k_halo_aq_init(struct otx2_nic *pfvf, u16 pool_id,
int stack_pages, int numptrs, int buf_size,
int type)
{
@@ -610,36 +524,57 @@ static int cn20k_pool_aq_init(struct otx2_nic *pfvf, u16 pool_id,
if (err)
return err;
+ /* Allocate memory for HW to update Aura count.
+ * Alloc one cache line, so that it fits all FC_STYPE modes.
+ */
+ if (!pool->fc_addr) {
+ err = qmem_alloc(pfvf->dev, &pool->fc_addr, 1, OTX2_ALIGN);
+ if (err) {
+ qmem_free(pfvf->dev, pool->stack);
+ return err;
+ }
+ }
+
pool->rbsize = buf_size;
- /* Initialize this pool's context via AF */
+ /* Initialize this aura's context via AF */
aq = otx2_mbox_alloc_msg_npa_cn20k_aq_enq(&pfvf->mbox);
if (!aq) {
/* Shared mbox memory buffer is full, flush it and retry */
err = otx2_sync_mbox_msg(&pfvf->mbox);
- if (err) {
- qmem_free(pfvf->dev, pool->stack);
- return err;
- }
+ if (err)
+ goto free_mem;
aq = otx2_mbox_alloc_msg_npa_cn20k_aq_enq(&pfvf->mbox);
if (!aq) {
- qmem_free(pfvf->dev, pool->stack);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto free_mem;
}
}
aq->aura_id = pool_id;
- aq->pool.stack_base = pool->stack->iova;
- aq->pool.stack_caching = 1;
- aq->pool.ena = 1;
- aq->pool.buf_size = buf_size / 128;
- aq->pool.stack_max_pages = stack_pages;
- aq->pool.shift = ilog2(numptrs) - 8;
- aq->pool.ptr_start = 0;
- aq->pool.ptr_end = ~0ULL;
+
+ aq->halo.stack_base = pool->stack->iova;
+ aq->halo.stack_caching = 1;
+ aq->halo.ena = 1;
+ aq->halo.buf_size = buf_size / 128;
+ aq->halo.stack_max_pages = stack_pages;
+ aq->halo.shift = ilog2(numptrs) - 8;
+ aq->halo.ptr_start = 0;
+ aq->halo.ptr_end = ~0ULL;
+
+ aq->halo.avg_level = 255;
+ aq->halo.fc_ena = 1;
+ aq->halo.fc_addr = pool->fc_addr->iova;
+ aq->halo.fc_hyst_bits = 0; /* Store count on all updates */
+
+ if (pfvf->npa_dpc_valid) {
+ aq->halo.op_dpc_ena = 1;
+ aq->halo.op_dpc_set = pfvf->npa_dpc;
+ }
+ aq->halo.unified_ctx = 1;
/* Fill AQ info */
- aq->ctype = NPA_AQ_CTYPE_POOL;
+ aq->ctype = NPA_AQ_CTYPE_HALO;
aq->op = NPA_AQ_INSTOP_INIT;
if (type != AURA_NIX_RQ) {
@@ -661,6 +596,78 @@ static int cn20k_pool_aq_init(struct otx2_nic *pfvf, u16 pool_id,
}
return 0;
+
+free_mem:
+ qmem_free(pfvf->dev, pool->stack);
+ qmem_free(pfvf->dev, pool->fc_addr);
+ return err;
+}
+
+static int cn20k_aura_aq_init(struct otx2_nic *pfvf, int aura_id,
+ int pool_id, int numptrs)
+{
+ return 0;
+}
+
+static int cn20k_pool_aq_init(struct otx2_nic *pfvf, u16 pool_id,
+ int stack_pages, int numptrs, int buf_size,
+ int type)
+{
+ return cn20k_halo_aq_init(pfvf, pool_id, stack_pages,
+ numptrs, buf_size, type);
+}
+
+int cn20k_npa_alloc_dpc(struct otx2_nic *nic)
+{
+ struct npa_cn20k_dpc_alloc_req *req;
+ struct npa_cn20k_dpc_alloc_rsp *rsp;
+ int err;
+
+ req = otx2_mbox_alloc_msg_npa_cn20k_dpc_alloc(&nic->mbox);
+ if (!req)
+ return -ENOMEM;
+
+ /* Count successful ALLOC requests only */
+ req->dpc_conf = 1ULL << 4;
+
+ err = otx2_sync_mbox_msg(&nic->mbox);
+ if (err)
+ return err;
+
+ rsp = (struct npa_cn20k_dpc_alloc_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox,
+ 0, &req->hdr);
+ if (IS_ERR(rsp))
+ return PTR_ERR(rsp);
+
+ nic->npa_dpc = rsp->cntr_id;
+ nic->npa_dpc_valid = true;
+
+ return 0;
+}
+
+int cn20k_npa_free_dpc(struct otx2_nic *nic)
+{
+ struct npa_cn20k_dpc_free_req *req;
+ int err;
+
+ if (!nic->npa_dpc_valid)
+ return 0;
+
+ mutex_lock(&nic->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_npa_cn20k_dpc_free(&nic->mbox);
+ if (!req) {
+ mutex_unlock(&nic->mbox.lock);
+ return -ENOMEM;
+ }
+
+ req->cntr_id = nic->npa_dpc;
+
+ err = otx2_sync_mbox_msg(&nic->mbox);
+
+ mutex_unlock(&nic->mbox.lock);
+
+ return err;
}
static int cn20k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h b/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h
index b5e527f6d7eb..16a69d84ea79 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn20k.h
@@ -28,4 +28,7 @@ int cn20k_tc_alloc_entry(struct otx2_nic *nic,
struct otx2_tc_flow *new_node,
struct npc_install_flow_req *dummy);
int cn20k_tc_free_mcam_entry(struct otx2_nic *nic, u16 entry);
+int cn20k_npa_alloc_dpc(struct otx2_nic *nic);
+int cn20k_npa_free_dpc(struct otx2_nic *nic);
+
#endif /* CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index eecee612b7b2..f997dfc0fedd 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -592,6 +592,9 @@ struct otx2_nic {
struct cn10k_ipsec ipsec;
/* af_xdp zero-copy */
unsigned long *af_xdp_zc_qidx;
+
+ bool npa_dpc_valid;
+ u8 npa_dpc; /* NPA DPC counter id */
};
static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index ee623476e5ff..2b5fe67d297c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1651,6 +1651,9 @@ int otx2_init_hw_resources(struct otx2_nic *pf)
if (!is_otx2_lbkvf(pf->pdev))
otx2_nix_config_bp(pf, true);
+ if (is_cn20k(pf->pdev))
+ cn20k_npa_alloc_dpc(pf);
+
/* Init Auras and pools used by NIX RQ, for free buffer ptrs */
err = otx2_rq_aura_pool_init(pf);
if (err) {
@@ -1726,6 +1729,8 @@ int otx2_init_hw_resources(struct otx2_nic *pf)
otx2_ctx_disable(mbox, NPA_AQ_CTYPE_AURA, true);
otx2_aura_pool_free(pf);
err_free_nix_lf:
+ if (pf->npa_dpc_valid)
+ cn20k_npa_free_dpc(pf);
mutex_lock(&mbox->lock);
free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
if (free_req) {
@@ -1790,6 +1795,9 @@ void otx2_free_hw_resources(struct otx2_nic *pf)
otx2_free_sq_res(pf);
+ if (is_cn20k(pf->pdev))
+ cn20k_npa_free_dpc(pf);
+
/* Free RQ buffer pointers*/
otx2_free_aura_ptr(pf, AURA_NIX_RQ);
--
2.48.1
^ permalink raw reply related
* [net-next PATCH v4 3/4] octeontx2-af: npa: cn20k: Add debugfs for Halo
From: Subbaraya Sundeep @ 2026-03-31 7:08 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, sgoutham, gakula,
bbhushan2
Cc: netdev, linux-kernel, Linu Cherian, Subbaraya Sundeep
In-Reply-To: <1774940919-1599-1-git-send-email-sbhatta@marvell.com>
From: Linu Cherian <lcherian@marvell.com>
Similar to other hardware contexts add debugfs support for
unified Halo context.
Sample output on cn20k::
/sys/kernel/debug/cn20k/npa # cat halo_ctx
======halo : 2=======
W0: Stack base ffffff790000
W1: ena 1
W1: nat_align 0
W1: stack_caching 1
W1: aura drop ena 0
W1: aura drop 0
W1: buf_offset 0
W1: buf_size 32
W1: ref_cnt_prof 0
W2: stack_max_pages 13
W2: stack_pages 11
W3: bp_0 0
W3: bp_1 0
W3: bp_2 0
snip ..
Signed-off-by: Linu Cherian <lcherian@marvell.com>
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
---
.../marvell/octeontx2/af/cn20k/debugfs.c | 60 ++++++++++++++++
.../marvell/octeontx2/af/cn20k/debugfs.h | 2 +
.../marvell/octeontx2/af/rvu_debugfs.c | 71 ++++++++++++++++---
3 files changed, 125 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
index 3debf2fae1a4..c0cfd3a39c23 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
@@ -489,3 +489,63 @@ void print_npa_cn20k_pool_ctx(struct seq_file *m,
pool->thresh_qint_idx, pool->err_qint_idx);
seq_printf(m, "W8: fc_msh_dst\t\t%d\n", pool->fc_msh_dst);
}
+
+void print_npa_cn20k_halo_ctx(struct seq_file *m, struct npa_aq_enq_rsp *rsp)
+{
+ struct npa_cn20k_aq_enq_rsp *cn20k_rsp;
+ struct npa_cn20k_halo_s *halo;
+
+ cn20k_rsp = (struct npa_cn20k_aq_enq_rsp *)rsp;
+ halo = &cn20k_rsp->halo;
+
+ seq_printf(m, "W0: Stack base\t\t%llx\n", halo->stack_base);
+
+ seq_printf(m, "W1: ena \t\t%d\nW1: nat_align \t\t%d\n",
+ halo->ena, halo->nat_align);
+ seq_printf(m, "W1: stack_caching\t%d\n",
+ halo->stack_caching);
+ seq_printf(m, "W1: aura drop ena\t%d\n", halo->aura_drop_ena);
+ seq_printf(m, "W1: aura drop\t\t%d\n", halo->aura_drop);
+ seq_printf(m, "W1: buf_offset\t\t%d\nW1: buf_size\t\t%d\n",
+ halo->buf_offset, halo->buf_size);
+ seq_printf(m, "W1: ref_cnt_prof\t\t%d\n", halo->ref_cnt_prof);
+ seq_printf(m, "W2: stack_max_pages \t%d\nW2: stack_pages\t\t%d\n",
+ halo->stack_max_pages, halo->stack_pages);
+ seq_printf(m, "W3: bp_0\t\t%d\nW3: bp_1\t\t%d\nW3: bp_2\t\t%d\n",
+ halo->bp_0, halo->bp_1, halo->bp_2);
+ seq_printf(m, "W3: bp_3\t\t%d\nW3: bp_4\t\t%d\nW3: bp_5\t\t%d\n",
+ halo->bp_3, halo->bp_4, halo->bp_5);
+ seq_printf(m, "W3: bp_6\t\t%d\nW3: bp_7\t\t%d\nW3: bp_ena_0\t\t%d\n",
+ halo->bp_6, halo->bp_7, halo->bp_ena_0);
+ seq_printf(m, "W3: bp_ena_1\t\t%d\nW3: bp_ena_2\t\t%d\n",
+ halo->bp_ena_1, halo->bp_ena_2);
+ seq_printf(m, "W3: bp_ena_3\t\t%d\nW3: bp_ena_4\t\t%d\n",
+ halo->bp_ena_3, halo->bp_ena_4);
+ seq_printf(m, "W3: bp_ena_5\t\t%d\nW3: bp_ena_6\t\t%d\n",
+ halo->bp_ena_5, halo->bp_ena_6);
+ seq_printf(m, "W3: bp_ena_7\t\t%d\n", halo->bp_ena_7);
+ seq_printf(m, "W4: stack_offset\t%d\nW4: shift\t\t%d\nW4: avg_level\t\t%d\n",
+ halo->stack_offset, halo->shift, halo->avg_level);
+ seq_printf(m, "W4: avg_con \t\t%d\nW4: fc_ena\t\t%d\nW4: fc_stype\t\t%d\n",
+ halo->avg_con, halo->fc_ena, halo->fc_stype);
+ seq_printf(m, "W4: fc_hyst_bits\t%d\nW4: fc_up_crossing\t%d\n",
+ halo->fc_hyst_bits, halo->fc_up_crossing);
+ seq_printf(m, "W4: update_time\t\t%d\n", halo->update_time);
+ seq_printf(m, "W5: fc_addr\t\t%llx\n", halo->fc_addr);
+ seq_printf(m, "W6: ptr_start\t\t%llx\n", halo->ptr_start);
+ seq_printf(m, "W7: ptr_end\t\t%llx\n", halo->ptr_end);
+ seq_printf(m, "W8: bpid_0\t\t%d\n", halo->bpid_0);
+ seq_printf(m, "W8: err_int \t\t%d\nW8: err_int_ena\t\t%d\n",
+ halo->err_int, halo->err_int_ena);
+ seq_printf(m, "W8: thresh_int\t\t%d\nW8: thresh_int_ena \t%d\n",
+ halo->thresh_int, halo->thresh_int_ena);
+ seq_printf(m, "W8: thresh_up\t\t%d\nW8: thresh_qint_idx\t%d\n",
+ halo->thresh_up, halo->thresh_qint_idx);
+ seq_printf(m, "W8: err_qint_idx \t%d\n", halo->err_qint_idx);
+ seq_printf(m, "W9: thresh\t\t%llu\n", (u64)halo->thresh);
+ seq_printf(m, "W9: fc_msh_dst\t\t%d\n", halo->fc_msh_dst);
+ seq_printf(m, "W9: op_dpc_ena\t\t%d\nW9: op_dpc_set\t\t%d\n",
+ halo->op_dpc_ena, halo->op_dpc_set);
+ seq_printf(m, "W9: stream_ctx\t\t%d\nW9: unified_ctx\t\t%d\n",
+ halo->stream_ctx, halo->unified_ctx);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
index 0c5f05883666..7e00c7499e35 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.h
@@ -27,5 +27,7 @@ void print_npa_cn20k_aura_ctx(struct seq_file *m,
struct npa_cn20k_aq_enq_rsp *rsp);
void print_npa_cn20k_pool_ctx(struct seq_file *m,
struct npa_cn20k_aq_enq_rsp *rsp);
+void print_npa_cn20k_halo_ctx(struct seq_file *m,
+ struct npa_aq_enq_rsp *rsp);
#endif
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index fa461489acdd..0ac59103b4a4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -968,6 +968,9 @@ static void print_npa_qsize(struct seq_file *m, struct rvu_pfvf *pfvf)
seq_printf(m, "Aura count : %d\n", pfvf->aura_ctx->qsize);
seq_printf(m, "Aura context ena/dis bitmap : %*pb\n",
pfvf->aura_ctx->qsize, pfvf->aura_bmap);
+ if (pfvf->halo_bmap)
+ seq_printf(m, "Halo context ena/dis bitmap : %*pb\n",
+ pfvf->aura_ctx->qsize, pfvf->halo_bmap);
}
if (!pfvf->pool_ctx) {
@@ -1195,6 +1198,20 @@ static void print_npa_pool_ctx(struct seq_file *m, struct npa_aq_enq_rsp *rsp)
seq_printf(m, "W8: fc_msh_dst\t\t%d\n", pool->fc_msh_dst);
}
+static const char *npa_ctype_str(int ctype)
+{
+ switch (ctype) {
+ case NPA_AQ_CTYPE_AURA:
+ return "aura";
+ case NPA_AQ_CTYPE_HALO:
+ return "halo";
+ case NPA_AQ_CTYPE_POOL:
+ return "pool";
+ default:
+ return "unknown";
+ }
+}
+
/* Reads aura/pool's ctx from admin queue */
static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype)
{
@@ -1211,6 +1228,7 @@ static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype)
switch (ctype) {
case NPA_AQ_CTYPE_AURA:
+ case NPA_AQ_CTYPE_HALO:
npalf = rvu->rvu_dbg.npa_aura_ctx.lf;
id = rvu->rvu_dbg.npa_aura_ctx.id;
all = rvu->rvu_dbg.npa_aura_ctx.all;
@@ -1235,6 +1253,9 @@ static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype)
} else if (ctype == NPA_AQ_CTYPE_POOL && !pfvf->pool_ctx) {
seq_puts(m, "Pool context is not initialized\n");
return -EINVAL;
+ } else if (ctype == NPA_AQ_CTYPE_HALO && !pfvf->aura_ctx) {
+ seq_puts(m, "Halo context is not initialized\n");
+ return -EINVAL;
}
memset(&aq_req, 0, sizeof(struct npa_aq_enq_req));
@@ -1244,6 +1265,9 @@ static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype)
if (ctype == NPA_AQ_CTYPE_AURA) {
max_id = pfvf->aura_ctx->qsize;
print_npa_ctx = print_npa_aura_ctx;
+ } else if (ctype == NPA_AQ_CTYPE_HALO) {
+ max_id = pfvf->aura_ctx->qsize;
+ print_npa_ctx = print_npa_cn20k_halo_ctx;
} else {
max_id = pfvf->pool_ctx->qsize;
print_npa_ctx = print_npa_pool_ctx;
@@ -1251,8 +1275,7 @@ static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype)
if (id < 0 || id >= max_id) {
seq_printf(m, "Invalid %s, valid range is 0-%d\n",
- (ctype == NPA_AQ_CTYPE_AURA) ? "aura" : "pool",
- max_id - 1);
+ npa_ctype_str(ctype), max_id - 1);
return -EINVAL;
}
@@ -1265,12 +1288,19 @@ static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype)
aq_req.aura_id = aura;
/* Skip if queue is uninitialized */
+ if (ctype == NPA_AQ_CTYPE_AURA &&
+ !test_bit(aura, pfvf->aura_bmap))
+ continue;
+
+ if (ctype == NPA_AQ_CTYPE_HALO &&
+ !test_bit(aura, pfvf->halo_bmap))
+ continue;
+
if (ctype == NPA_AQ_CTYPE_POOL && !test_bit(aura, pfvf->pool_bmap))
continue;
- seq_printf(m, "======%s : %d=======\n",
- (ctype == NPA_AQ_CTYPE_AURA) ? "AURA" : "POOL",
- aq_req.aura_id);
+ seq_printf(m, "======%s : %d=======\n", npa_ctype_str(ctype),
+ aq_req.aura_id);
rc = rvu_npa_aq_enq_inst(rvu, &aq_req, &rsp);
if (rc) {
seq_puts(m, "Failed to read context\n");
@@ -1299,6 +1329,12 @@ static int write_npa_ctx(struct rvu *rvu, bool all,
return -EINVAL;
}
max_id = pfvf->aura_ctx->qsize;
+ } else if (ctype == NPA_AQ_CTYPE_HALO) {
+ if (!pfvf->aura_ctx) {
+ dev_warn(rvu->dev, "Halo context is not initialized\n");
+ return -EINVAL;
+ }
+ max_id = pfvf->aura_ctx->qsize;
} else if (ctype == NPA_AQ_CTYPE_POOL) {
if (!pfvf->pool_ctx) {
dev_warn(rvu->dev, "Pool context is not initialized\n");
@@ -1309,13 +1345,14 @@ static int write_npa_ctx(struct rvu *rvu, bool all,
if (id < 0 || id >= max_id) {
dev_warn(rvu->dev, "Invalid %s, valid range is 0-%d\n",
- (ctype == NPA_AQ_CTYPE_AURA) ? "aura" : "pool",
+ npa_ctype_str(ctype),
max_id - 1);
return -EINVAL;
}
switch (ctype) {
case NPA_AQ_CTYPE_AURA:
+ case NPA_AQ_CTYPE_HALO:
rvu->rvu_dbg.npa_aura_ctx.lf = npalf;
rvu->rvu_dbg.npa_aura_ctx.id = id;
rvu->rvu_dbg.npa_aura_ctx.all = all;
@@ -1374,12 +1411,12 @@ static ssize_t rvu_dbg_npa_ctx_write(struct file *filp,
const char __user *buffer,
size_t count, loff_t *ppos, int ctype)
{
- char *cmd_buf, *ctype_string = (ctype == NPA_AQ_CTYPE_AURA) ?
- "aura" : "pool";
+ const char *ctype_string = npa_ctype_str(ctype);
struct seq_file *seqfp = filp->private_data;
struct rvu *rvu = seqfp->private;
int npalf, id = 0, ret;
bool all = false;
+ char *cmd_buf;
if ((*ppos != 0) || !count)
return -EINVAL;
@@ -1417,6 +1454,21 @@ static int rvu_dbg_npa_aura_ctx_display(struct seq_file *filp, void *unused)
RVU_DEBUG_SEQ_FOPS(npa_aura_ctx, npa_aura_ctx_display, npa_aura_ctx_write);
+static ssize_t rvu_dbg_npa_halo_ctx_write(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return rvu_dbg_npa_ctx_write(filp, buffer, count, ppos,
+ NPA_AQ_CTYPE_HALO);
+}
+
+static int rvu_dbg_npa_halo_ctx_display(struct seq_file *filp, void *unused)
+{
+ return rvu_dbg_npa_ctx_display(filp, unused, NPA_AQ_CTYPE_HALO);
+}
+
+RVU_DEBUG_SEQ_FOPS(npa_halo_ctx, npa_halo_ctx_display, npa_halo_ctx_write);
+
static ssize_t rvu_dbg_npa_pool_ctx_write(struct file *filp,
const char __user *buffer,
size_t count, loff_t *ppos)
@@ -2798,6 +2850,9 @@ static void rvu_dbg_npa_init(struct rvu *rvu)
&rvu_dbg_npa_qsize_fops);
debugfs_create_file("aura_ctx", 0600, rvu->rvu_dbg.npa, rvu,
&rvu_dbg_npa_aura_ctx_fops);
+ if (is_cn20k(rvu->pdev))
+ debugfs_create_file("halo_ctx", 0600, rvu->rvu_dbg.npa, rvu,
+ &rvu_dbg_npa_halo_ctx_fops);
debugfs_create_file("pool_ctx", 0600, rvu->rvu_dbg.npa, rvu,
&rvu_dbg_npa_pool_ctx_fops);
--
2.48.1
^ permalink raw reply related
* [net-next PATCH v4 2/4] octeontx2-af: npa: cn20k: Add DPC support
From: Subbaraya Sundeep @ 2026-03-31 7:08 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, sgoutham, gakula,
bbhushan2
Cc: netdev, linux-kernel, Linu Cherian, Subbaraya Sundeep
In-Reply-To: <1774940919-1599-1-git-send-email-sbhatta@marvell.com>
From: Linu Cherian <lcherian@marvell.com>
CN20k introduces 32 diagnostic and performance
counters that are shared across all NPA LFs.
Counters being shared, each PF driver need to request
for a counter with the required configuration to the AF,
so that a counter can be allocated and mapped to the
respective LF with the requested configuration.
Add new mbox messages, npa_dpc_alloc/free to handle this.
Also ensure all the LF to DPC counter mappings are cleared
at the time of LF free/teardown.
Signed-off-by: Linu Cherian <lcherian@marvell.com>
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/api.h | 6 +
.../ethernet/marvell/octeontx2/af/cn20k/npa.c | 129 ++++++++++++++++++
.../ethernet/marvell/octeontx2/af/cn20k/reg.h | 7 +
.../net/ethernet/marvell/octeontx2/af/mbox.h | 19 +++
.../net/ethernet/marvell/octeontx2/af/rvu.h | 3 +
.../ethernet/marvell/octeontx2/af/rvu_npa.c | 14 +-
6 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/api.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/api.h
index 4285b5d6a6a2..b13e7628f767 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/api.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/api.h
@@ -29,4 +29,10 @@ int cn20k_mbox_setup(struct otx2_mbox *mbox, struct pci_dev *pdev,
void *reg_base, int direction, int ndevs);
void cn20k_rvu_enable_afvf_intr(struct rvu *rvu, int vfs);
void cn20k_rvu_disable_afvf_intr(struct rvu *rvu, int vfs);
+
+int npa_cn20k_dpc_alloc(struct rvu *rvu, struct npa_cn20k_dpc_alloc_req *req,
+ struct npa_cn20k_dpc_alloc_rsp *rsp);
+int npa_cn20k_dpc_free(struct rvu *rvu, struct npa_cn20k_dpc_free_req *req);
+void npa_cn20k_dpc_free_all(struct rvu *rvu, u16 pcifunc);
+
#endif /* CN20K_API_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c
index c963f43dc7b0..24a710f4f5fc 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c
@@ -8,6 +8,8 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include "cn20k/api.h"
+#include "cn20k/reg.h"
#include "struct.h"
#include "../rvu.h"
@@ -46,3 +48,130 @@ int rvu_npa_halo_hwctx_disable(struct npa_aq_enq_req *req)
return 0;
}
+
+int npa_cn20k_dpc_alloc(struct rvu *rvu, struct npa_cn20k_dpc_alloc_req *req,
+ struct npa_cn20k_dpc_alloc_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int cntr, lf, blkaddr, ridx;
+ struct rvu_block *block;
+ struct rvu_pfvf *pfvf;
+ u64 val, lfmask;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+ if (!pfvf->npalf || blkaddr < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ block = &hw->block[blkaddr];
+ lf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (lf < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ mutex_lock(&rvu->rsrc_lock);
+
+ /* allocate a new counter */
+ cntr = rvu_alloc_rsrc(&rvu->npa_dpc);
+ if (cntr < 0) {
+ mutex_unlock(&rvu->rsrc_lock);
+ return cntr;
+ }
+
+ rsp->cntr_id = cntr;
+
+ /* DPC counter config */
+ rvu_write64(rvu, blkaddr, NPA_AF_DPCX_CFG(cntr), req->dpc_conf);
+
+ /* 0 to 63 lfs -> idx 0, 64 - 127 lfs -> idx 1 */
+ ridx = lf >> 6;
+ lfmask = BIT_ULL(ridx ? lf - NPA_DPC_LFS_PER_REG : lf);
+
+ ridx = 2 * cntr + ridx;
+ /* Give permission for LF access */
+ val = rvu_read64(rvu, blkaddr, NPA_AF_DPC_PERMITX(ridx));
+ val |= lfmask;
+ rvu_write64(rvu, blkaddr, NPA_AF_DPC_PERMITX(ridx), val);
+
+ mutex_unlock(&rvu->rsrc_lock);
+
+ return 0;
+}
+
+int rvu_mbox_handler_npa_cn20k_dpc_alloc(struct rvu *rvu,
+ struct npa_cn20k_dpc_alloc_req *req,
+ struct npa_cn20k_dpc_alloc_rsp *rsp)
+{
+ return npa_cn20k_dpc_alloc(rvu, req, rsp);
+}
+
+int npa_cn20k_dpc_free(struct rvu *rvu, struct npa_cn20k_dpc_free_req *req)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int cntr, lf, blkaddr, ridx;
+ struct rvu_block *block;
+ struct rvu_pfvf *pfvf;
+ u64 val, lfmask;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+ if (!pfvf->npalf || blkaddr < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ block = &hw->block[blkaddr];
+ lf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (lf < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ if (req->cntr_id >= NPA_DPC_MAX)
+ return NPA_AF_ERR_PARAM;
+
+ mutex_lock(&rvu->rsrc_lock);
+
+ /* 0 to 63 lfs -> idx 0, 64 - 127 lfs -> idx 1 */
+ ridx = lf >> 6;
+ lfmask = BIT_ULL(ridx ? lf - NPA_DPC_LFS_PER_REG : lf);
+ cntr = req->cntr_id;
+
+ ridx = 2 * cntr + ridx;
+
+ val = rvu_read64(rvu, blkaddr, NPA_AF_DPC_PERMITX(ridx));
+ /* Check if the counter is allotted to this LF */
+ if (!(val & lfmask)) {
+ mutex_unlock(&rvu->rsrc_lock);
+ return 0;
+ }
+
+ /* Revert permission */
+ val &= ~lfmask;
+ rvu_write64(rvu, blkaddr, NPA_AF_DPC_PERMITX(ridx), val);
+
+ /* Free this counter */
+ rvu_free_rsrc(&rvu->npa_dpc, req->cntr_id);
+
+ mutex_unlock(&rvu->rsrc_lock);
+
+ return 0;
+}
+
+void npa_cn20k_dpc_free_all(struct rvu *rvu, u16 pcifunc)
+{
+ struct npa_cn20k_dpc_free_req req;
+ int i;
+
+ req.hdr.pcifunc = pcifunc;
+ for (i = 0; i < NPA_DPC_MAX; i++) {
+ req.cntr_id = i;
+ npa_cn20k_dpc_free(rvu, &req);
+ }
+}
+
+int rvu_mbox_handler_npa_cn20k_dpc_free(struct rvu *rvu,
+ struct npa_cn20k_dpc_free_req *req,
+ struct msg_rsp *rsp)
+{
+ return npa_cn20k_dpc_free(rvu, req);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
index 8bfaa507ee50..9b49e376878e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/reg.h
@@ -143,4 +143,11 @@
offset = (0xb000000ull | (a) << 4 | (b) << 20); \
offset; })
+/* NPA Registers */
+#define NPA_AF_DPCX_CFG(a) (0x800 | (a) << 6)
+#define NPA_AF_DPC_PERMITX(a) (0x1000 | (a) << 3)
+
+#define NPA_DPC_MAX 32
+#define NPA_DPC_LFS_PER_REG 64
+
#endif /* RVU_MBOX_REG_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 4a97bd93d882..b29ec26b66b7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -213,6 +213,10 @@ M(NPA_AQ_ENQ, 0x402, npa_aq_enq, npa_aq_enq_req, npa_aq_enq_rsp) \
M(NPA_HWCTX_DISABLE, 0x403, npa_hwctx_disable, hwctx_disable_req, msg_rsp)\
M(NPA_CN20K_AQ_ENQ, 0x404, npa_cn20k_aq_enq, npa_cn20k_aq_enq_req, \
npa_cn20k_aq_enq_rsp) \
+M(NPA_CN20K_DPC_ALLOC, 0x405, npa_cn20k_dpc_alloc, npa_cn20k_dpc_alloc_req, \
+ npa_cn20k_dpc_alloc_rsp) \
+M(NPA_CN20K_DPC_FREE, 0x406, npa_cn20k_dpc_free, npa_cn20k_dpc_free_req, \
+ msg_rsp) \
/* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \
/* TIM mbox IDs (range 0x800 - 0x9FF) */ \
/* CPT mbox IDs (range 0xA00 - 0xBFF) */ \
@@ -910,6 +914,21 @@ struct npa_cn20k_aq_enq_rsp {
};
};
+struct npa_cn20k_dpc_alloc_req {
+ struct mbox_msghdr hdr;
+ u16 dpc_conf;
+};
+
+struct npa_cn20k_dpc_alloc_rsp {
+ struct mbox_msghdr hdr;
+ u8 cntr_id;
+};
+
+struct npa_cn20k_dpc_free_req {
+ struct mbox_msghdr hdr;
+ u8 cntr_id;
+};
+
/* Disable all contexts of type 'ctype' */
struct hwctx_disable_req {
struct mbox_msghdr hdr;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 36a71d32b894..0299fa1bd3bc 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -663,6 +663,9 @@ struct rvu {
/* CPT interrupt lock */
spinlock_t cpt_intr_lock;
+ /* NPA */
+ struct rsrc_bmap npa_dpc;
+
struct mutex mbox_lock; /* Serialize mbox up and down msgs */
u16 rep_pcifunc;
bool altaf_ready;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
index 809386c6bcba..f7916ac79c69 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
@@ -8,6 +8,8 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include "cn20k/api.h"
+#include "cn20k/reg.h"
#include "rvu_struct.h"
#include "rvu_reg.h"
#include "rvu.h"
@@ -504,6 +506,8 @@ int rvu_mbox_handler_npa_lf_free(struct rvu *rvu, struct msg_req *req,
return NPA_AF_ERR_LF_RESET;
}
+ if (is_cn20k(rvu->pdev))
+ npa_cn20k_dpc_free_all(rvu, pcifunc);
npa_ctx_free(rvu, pfvf);
return 0;
@@ -569,12 +573,17 @@ static int npa_aq_init(struct rvu *rvu, struct rvu_block *block)
int rvu_npa_init(struct rvu *rvu)
{
struct rvu_hwinfo *hw = rvu->hw;
- int blkaddr;
+ int err, blkaddr;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
if (blkaddr < 0)
return 0;
+ rvu->npa_dpc.max = NPA_DPC_MAX;
+ err = rvu_alloc_bitmap(&rvu->npa_dpc);
+ if (err)
+ return err;
+
/* Initialize admin queue */
return npa_aq_init(rvu, &hw->block[blkaddr]);
}
@@ -591,6 +600,7 @@ void rvu_npa_freemem(struct rvu *rvu)
block = &hw->block[blkaddr];
rvu_aq_free(rvu, block->aq);
+ kfree(rvu->npa_dpc.bmap);
}
void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf)
@@ -611,6 +621,8 @@ void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf)
ctx_req.ctype = NPA_AQ_CTYPE_HALO;
npa_lf_hwctx_disable(rvu, &ctx_req);
+ if (is_cn20k(rvu->pdev))
+ npa_cn20k_dpc_free_all(rvu, pcifunc);
npa_ctx_free(rvu, pfvf);
}
--
2.48.1
^ permalink raw reply related
* [net-next PATCH v4 1/4] octeontx2-af: npa: cn20k: Add NPA Halo support
From: Subbaraya Sundeep @ 2026-03-31 7:08 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, sgoutham, gakula,
bbhushan2
Cc: netdev, linux-kernel, Linu Cherian, Subbaraya Sundeep
In-Reply-To: <1774940919-1599-1-git-send-email-sbhatta@marvell.com>
From: Linu Cherian <lcherian@marvell.com>
CN20K silicon implements unified aura and pool context
type called Halo for better resource usage. Add support to
handle Halo context type operations.
Signed-off-by: Linu Cherian <lcherian@marvell.com>
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npa.c | 27 +++++++
.../marvell/octeontx2/af/cn20k/struct.h | 81 +++++++++++++++++++
.../net/ethernet/marvell/octeontx2/af/mbox.h | 6 ++
.../net/ethernet/marvell/octeontx2/af/rvu.h | 2 +
.../ethernet/marvell/octeontx2/af/rvu_npa.c | 63 +++++++++++++--
.../marvell/octeontx2/af/rvu_struct.h | 1 +
6 files changed, 173 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c
index fe8f926c8b75..c963f43dc7b0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npa.c
@@ -19,3 +19,30 @@ int rvu_mbox_handler_npa_cn20k_aq_enq(struct rvu *rvu,
(struct npa_aq_enq_rsp *)rsp);
}
EXPORT_SYMBOL(rvu_mbox_handler_npa_cn20k_aq_enq);
+
+int rvu_npa_halo_hwctx_disable(struct npa_aq_enq_req *req)
+{
+ struct npa_cn20k_aq_enq_req *hreq;
+
+ hreq = (struct npa_cn20k_aq_enq_req *)req;
+
+ hreq->halo.bp_ena_0 = 0;
+ hreq->halo.bp_ena_1 = 0;
+ hreq->halo.bp_ena_2 = 0;
+ hreq->halo.bp_ena_3 = 0;
+ hreq->halo.bp_ena_4 = 0;
+ hreq->halo.bp_ena_5 = 0;
+ hreq->halo.bp_ena_6 = 0;
+ hreq->halo.bp_ena_7 = 0;
+
+ hreq->halo_mask.bp_ena_0 = 1;
+ hreq->halo_mask.bp_ena_1 = 1;
+ hreq->halo_mask.bp_ena_2 = 1;
+ hreq->halo_mask.bp_ena_3 = 1;
+ hreq->halo_mask.bp_ena_4 = 1;
+ hreq->halo_mask.bp_ena_5 = 1;
+ hreq->halo_mask.bp_ena_6 = 1;
+ hreq->halo_mask.bp_ena_7 = 1;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/struct.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/struct.h
index 763f6cabd7c2..2364bafd329d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/struct.h
@@ -377,4 +377,85 @@ struct npa_cn20k_pool_s {
static_assert(sizeof(struct npa_cn20k_pool_s) == NIX_MAX_CTX_SIZE);
+struct npa_cn20k_halo_s {
+ u64 stack_base : 64;
+ u64 ena : 1;
+ u64 nat_align : 1;
+ u64 reserved_66_67 : 2;
+ u64 stack_caching : 1;
+ u64 reserved_69_71 : 3;
+ u64 aura_drop_ena : 1;
+ u64 reserved_73_79 : 7;
+ u64 aura_drop : 8;
+ u64 buf_offset : 12;
+ u64 reserved_100_103 : 4;
+ u64 buf_size : 12;
+ u64 reserved_116_119 : 4;
+ u64 ref_cnt_prof : 3;
+ u64 reserved_123_127 : 5;
+ u64 stack_max_pages : 32;
+ u64 stack_pages : 32;
+ u64 bp_0 : 7;
+ u64 bp_1 : 7;
+ u64 bp_2 : 7;
+ u64 bp_3 : 7;
+ u64 bp_4 : 7;
+ u64 bp_5 : 7;
+ u64 bp_6 : 7;
+ u64 bp_7 : 7;
+ u64 bp_ena_0 : 1;
+ u64 bp_ena_1 : 1;
+ u64 bp_ena_2 : 1;
+ u64 bp_ena_3 : 1;
+ u64 bp_ena_4 : 1;
+ u64 bp_ena_5 : 1;
+ u64 bp_ena_6 : 1;
+ u64 bp_ena_7 : 1;
+ u64 stack_offset : 4;
+ u64 reserved_260_263 : 4;
+ u64 shift : 6;
+ u64 reserved_270_271 : 2;
+ u64 avg_level : 8;
+ u64 avg_con : 9;
+ u64 fc_ena : 1;
+ u64 fc_stype : 2;
+ u64 fc_hyst_bits : 4;
+ u64 fc_up_crossing : 1;
+ u64 reserved_297_299 : 3;
+ u64 update_time : 16;
+ u64 reserved_316_319 : 4;
+ u64 fc_addr : 64;
+ u64 ptr_start : 64;
+ u64 ptr_end : 64;
+ u64 bpid_0 : 12;
+ u64 reserved_524_535 : 12;
+ u64 err_int : 8;
+ u64 err_int_ena : 8;
+ u64 thresh_int : 1;
+ u64 thresh_int_ena : 1;
+ u64 thresh_up : 1;
+ u64 reserved_555 : 1;
+ u64 thresh_qint_idx : 7;
+ u64 reserved_563 : 1;
+ u64 err_qint_idx : 7;
+ u64 reserved_571_575 : 5;
+ u64 thresh : 36;
+ u64 reserved_612_615 : 4;
+ u64 fc_msh_dst : 11;
+ u64 reserved_627_630 : 4;
+ u64 op_dpc_ena : 1;
+ u64 op_dpc_set : 5;
+ u64 reserved_637_637 : 1;
+ u64 stream_ctx : 1;
+ u64 unified_ctx : 1;
+ u64 reserved_640_703 : 64;
+ u64 reserved_704_767 : 64;
+ u64 reserved_768_831 : 64;
+ u64 reserved_832_895 : 64;
+ u64 reserved_896_959 : 64;
+ u64 reserved_960_1023 : 64;
+};
+
+static_assert(sizeof(struct npa_cn20k_halo_s) == NIX_MAX_CTX_SIZE);
+
#endif
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index dc42c81c0942..4a97bd93d882 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -884,6 +884,8 @@ struct npa_cn20k_aq_enq_req {
struct npa_cn20k_aura_s aura;
/* Valid when op == WRITE/INIT and ctype == POOL */
struct npa_cn20k_pool_s pool;
+ /* Valid when op == WRITE/INIT and ctype == HALO */
+ struct npa_cn20k_halo_s halo;
};
/* Mask data when op == WRITE (1=write, 0=don't write) */
union {
@@ -891,6 +893,8 @@ struct npa_cn20k_aq_enq_req {
struct npa_cn20k_aura_s aura_mask;
/* Valid when op == WRITE and ctype == POOL */
struct npa_cn20k_pool_s pool_mask;
+ /* Valid when op == WRITE/INIT and ctype == HALO */
+ struct npa_cn20k_halo_s halo_mask;
};
};
@@ -901,6 +905,8 @@ struct npa_cn20k_aq_enq_rsp {
struct npa_cn20k_aura_s aura;
/* Valid when op == READ and ctype == POOL */
struct npa_cn20k_pool_s pool;
+ /* Valid when op == READ and ctype == HALO */
+ struct npa_cn20k_halo_s halo;
};
};
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index a466181cf908..36a71d32b894 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -261,6 +261,7 @@ struct rvu_pfvf {
struct qmem *pool_ctx;
struct qmem *npa_qints_ctx;
unsigned long *aura_bmap;
+ unsigned long *halo_bmap; /* Aura and Halo are mutually exclusive */
unsigned long *pool_bmap;
/* NIX contexts */
@@ -1008,6 +1009,7 @@ void rvu_npa_freemem(struct rvu *rvu);
void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf);
int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
struct npa_aq_enq_rsp *rsp);
+int rvu_npa_halo_hwctx_disable(struct npa_aq_enq_req *req);
/* NIX APIs */
bool is_nixlf_attached(struct rvu *rvu, u16 pcifunc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
index e2a33e46b48a..809386c6bcba 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
@@ -12,6 +12,11 @@
#include "rvu_reg.h"
#include "rvu.h"
+static bool npa_ctype_invalid(struct rvu *rvu, int ctype)
+{
+ return !is_cn20k(rvu->pdev) && ctype == NPA_AQ_CTYPE_HALO;
+}
+
static int npa_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
struct npa_aq_inst_s *inst)
{
@@ -72,13 +77,19 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
bool ena;
pfvf = rvu_get_pfvf(rvu, pcifunc);
- if (!pfvf->aura_ctx || req->aura_id >= pfvf->aura_ctx->qsize)
+ if (!pfvf->aura_ctx || req->aura_id >= pfvf->aura_ctx->qsize ||
+ npa_ctype_invalid(rvu, req->ctype))
return NPA_AF_ERR_AQ_ENQUEUE;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc);
if (!pfvf->npalf || blkaddr < 0)
return NPA_AF_ERR_AF_LF_INVALID;
+ /* Ensure halo bitmap is exclusive to halo ctype */
+ if (is_cn20k(rvu->pdev) && req->ctype != NPA_AQ_CTYPE_HALO &&
+ test_bit(req->aura_id, pfvf->halo_bmap))
+ return NPA_AF_ERR_AQ_ENQUEUE;
+
block = &hw->block[blkaddr];
aq = block->aq;
if (!aq) {
@@ -119,7 +130,7 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
memcpy(mask, &req->aura_mask,
sizeof(struct npa_aura_s));
memcpy(ctx, &req->aura, sizeof(struct npa_aura_s));
- } else {
+ } else { /* Applies to pool and halo since size is same */
memcpy(mask, &req->pool_mask,
sizeof(struct npa_pool_s));
memcpy(ctx, &req->pool, sizeof(struct npa_pool_s));
@@ -135,7 +146,7 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
req->aura.pool_addr = pfvf->pool_ctx->iova +
(req->aura.pool_addr * pfvf->pool_ctx->entry_sz);
memcpy(ctx, &req->aura, sizeof(struct npa_aura_s));
- } else { /* POOL's context */
+ } else { /* Applies to pool and halo since size is same */
memcpy(ctx, &req->pool, sizeof(struct npa_pool_s));
}
break;
@@ -176,6 +187,20 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
}
}
+ if (req->ctype == NPA_AQ_CTYPE_HALO) {
+ if (req->op == NPA_AQ_INSTOP_INIT && req->aura.ena)
+ __set_bit(req->aura_id, pfvf->halo_bmap);
+ if (req->op == NPA_AQ_INSTOP_WRITE) {
+ ena = (req->aura.ena & req->aura_mask.ena) |
+ (test_bit(req->aura_id, pfvf->halo_bmap) &
+ ~req->aura_mask.ena);
+ if (ena)
+ __set_bit(req->aura_id, pfvf->halo_bmap);
+ else
+ __clear_bit(req->aura_id, pfvf->halo_bmap);
+ }
+ }
+
/* Set pool bitmap if pool hw context is enabled */
if (req->ctype == NPA_AQ_CTYPE_POOL) {
if (req->op == NPA_AQ_INSTOP_INIT && req->pool.ena)
@@ -198,7 +223,7 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
if (req->ctype == NPA_AQ_CTYPE_AURA)
memcpy(&rsp->aura, ctx,
sizeof(struct npa_aura_s));
- else
+ else /* Applies to pool and halo since size is same */
memcpy(&rsp->pool, ctx,
sizeof(struct npa_pool_s));
}
@@ -210,12 +235,14 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
+ const char *context = "Unknown";
struct npa_aq_enq_req aq_req;
unsigned long *bmap;
int id, cnt = 0;
int err = 0, rc;
- if (!pfvf->pool_ctx || !pfvf->aura_ctx)
+ if (!pfvf->pool_ctx || !pfvf->aura_ctx ||
+ npa_ctype_invalid(rvu, req->ctype))
return NPA_AF_ERR_AQ_ENQUEUE;
memset(&aq_req, 0, sizeof(struct npa_aq_enq_req));
@@ -226,6 +253,7 @@ static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
aq_req.pool_mask.ena = 1;
cnt = pfvf->pool_ctx->qsize;
bmap = pfvf->pool_bmap;
+ context = "Pool";
} else if (req->ctype == NPA_AQ_CTYPE_AURA) {
aq_req.aura.ena = 0;
aq_req.aura_mask.ena = 1;
@@ -233,6 +261,14 @@ static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
aq_req.aura_mask.bp_ena = 1;
cnt = pfvf->aura_ctx->qsize;
bmap = pfvf->aura_bmap;
+ context = "Aura";
+ } else if (req->ctype == NPA_AQ_CTYPE_HALO) {
+ aq_req.aura.ena = 0;
+ aq_req.aura_mask.ena = 1;
+ rvu_npa_halo_hwctx_disable(&aq_req);
+ cnt = pfvf->aura_ctx->qsize;
+ bmap = pfvf->halo_bmap;
+ context = "Halo";
}
aq_req.ctype = req->ctype;
@@ -246,8 +282,7 @@ static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
if (rc) {
err = rc;
dev_err(rvu->dev, "Failed to disable %s:%d context\n",
- (req->ctype == NPA_AQ_CTYPE_AURA) ?
- "Aura" : "Pool", id);
+ context, id);
}
}
@@ -311,6 +346,9 @@ static void npa_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf)
kfree(pfvf->aura_bmap);
pfvf->aura_bmap = NULL;
+ kfree(pfvf->halo_bmap);
+ pfvf->halo_bmap = NULL;
+
qmem_free(rvu->dev, pfvf->aura_ctx);
pfvf->aura_ctx = NULL;
@@ -374,6 +412,13 @@ int rvu_mbox_handler_npa_lf_alloc(struct rvu *rvu,
if (!pfvf->aura_bmap)
goto free_mem;
+ if (is_cn20k(rvu->pdev)) {
+ pfvf->halo_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz),
+ sizeof(long), GFP_KERNEL);
+ if (!pfvf->halo_bmap)
+ goto free_mem;
+ }
+
/* Alloc memory for pool HW contexts */
hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
err = qmem_alloc(rvu->dev, &pfvf->pool_ctx, req->nr_pools, hwctx_size);
@@ -562,6 +607,10 @@ void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf)
ctx_req.ctype = NPA_AQ_CTYPE_AURA;
npa_lf_hwctx_disable(rvu, &ctx_req);
+ /* Disable all Halos */
+ ctx_req.ctype = NPA_AQ_CTYPE_HALO;
+ npa_lf_hwctx_disable(rvu, &ctx_req);
+
npa_ctx_free(rvu, pfvf);
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index 8e868f815de1..d37cf2cf0fee 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -130,6 +130,7 @@ enum npa_aq_comp {
enum npa_aq_ctype {
NPA_AQ_CTYPE_AURA = 0x0,
NPA_AQ_CTYPE_POOL = 0x1,
+ NPA_AQ_CTYPE_HALO = 0x2,
};
/* NPA admin queue instruction opcodes */
--
2.48.1
^ permalink raw reply related
* [net-next PATCH v4 0/4] octeontx2: CN20K NPA Halo context support
From: Subbaraya Sundeep @ 2026-03-31 7:08 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, sgoutham, gakula,
bbhushan2
Cc: netdev, linux-kernel, Subbaraya Sundeep
This series adds NPA Halo support for CN20K in the octeontx2 AF and
PF drivers. On CN20K, NPA supports a unified "Halo" context that combines
aura and pool contexts in a single structure. This is a simplification
in hardware so that there is no need to initialize both Aura and Pool
contexts for queues. Separate Aura and Pool contexts are needed say if
we have to point many Auras to a single pool but we always use 1:1 Aura
and Pool map in Octeontx2 netdev driver. Hence for CN20K use Halo
context for netdevs.
The series:
1) Adds Halo context type, mbox handling, and halo_bmap tracking in AF.
2) Adds NPA DPC (diagnostic/performance counters) 32 counters with
per-LF permit registers, mbox alloc/free, and teardown handling.
3) Adds debugfs for Halo (halo_ctx file and NPA context display/write
for HALO ctype).
4) Switches the CN20K PF driver to use the unified Halo context and
allocates a DPC counter for the NPA LF.
Changes for v4:
Fixed DPC counter leak as per AI review
Changes for v3:
Fixed all AI reviews
Removed inline for npa_ctype_invalid(as per Simon)
Changes for v2:
Fixed all AI reviews
Removed inline and added const for npa_ctype_str(as per Simon)
Fixed build warning flagged with W=1
Thanks,
Sundeep
Linu Cherian (3):
octeontx2-af: npa: cn20k: Add NPA Halo support
octeontx2-af: npa: cn20k: Add DPC support
octeontx2-af: npa: cn20k: Add debugfs for Halo
Subbaraya Sundeep (1):
octeontx2-pf: cn20k: Use unified Halo context
.../ethernet/marvell/octeontx2/af/cn20k/api.h | 6 +
.../marvell/octeontx2/af/cn20k/debugfs.c | 60 +++++
.../marvell/octeontx2/af/cn20k/debugfs.h | 2 +
.../ethernet/marvell/octeontx2/af/cn20k/npa.c | 156 +++++++++++++
.../ethernet/marvell/octeontx2/af/cn20k/reg.h | 7 +
.../marvell/octeontx2/af/cn20k/struct.h | 81 +++++++
.../net/ethernet/marvell/octeontx2/af/mbox.h | 25 ++
.../net/ethernet/marvell/octeontx2/af/rvu.h | 5 +
.../marvell/octeontx2/af/rvu_debugfs.c | 71 +++++-
.../ethernet/marvell/octeontx2/af/rvu_npa.c | 77 ++++++-
.../marvell/octeontx2/af/rvu_struct.h | 1 +
.../ethernet/marvell/octeontx2/nic/cn20k.c | 213 +++++++++---------
.../ethernet/marvell/octeontx2/nic/cn20k.h | 3 +
.../marvell/octeontx2/nic/otx2_common.h | 3 +
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 8 +
15 files changed, 599 insertions(+), 119 deletions(-)
--
2.48.1
^ permalink raw reply
* Re: [PATCH 1/1] net: fix skb_ext_total_length() BUILD_BUG_ON with CONFIG_GCOV_PROFILE_ALL
From: Thomas Weißschuh @ 2026-03-31 7:07 UTC (permalink / raw)
To: Konstantin Khorenko
Cc: davem, edumazet, kuba, pabeni, horms, arnd, netdev, linux-kernel
In-Reply-To: <d4305d64-2632-4714-8291-d948c515c34d@virtuozzo.com>
On 2026-03-30 19:23:01+0200, Konstantin Khorenko wrote:
(...)
> Thus we can probably use this hack and create the following patch instead:
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 0e217041958a..47c7f0ab6e84 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -5145,7 +5145,7 @@ static const u8 skb_ext_type_len[] = {
> #endif
> };
>
> -static __always_inline unsigned int skb_ext_total_length(void)
> +static __always_inline __no_profile unsigned int skb_ext_total_length(void)
> {
> unsigned int l = SKB_EXT_CHUNKSIZEOF(struct skb_ext);
> int i;
> @@ -5159,9 +5159,7 @@ static __always_inline unsigned int skb_ext_total_length(void)
> static void skb_extensions_init(void)
> {
> BUILD_BUG_ON(SKB_EXT_NUM > 8);
> -#if !IS_ENABLED(CONFIG_KCOV_INSTRUMENT_ALL)
> BUILD_BUG_ON(skb_ext_total_length() > 255);
> -#endif
>
> skbuff_ext_cache = kmem_cache_create("skbuff_ext_cache",
> SKB_EXT_ALIGN_VALUE * skb_ext_total_length(),
>
>
> Tomas, do you want me to send the v2 patch with that solution?
Yeah, I think this should have been the correct solution from beginning.
If you send this patch feel free to add my Reviewed-by.
Thomas
^ permalink raw reply
* Re: [PATCH net-next] pppoe: update Kconfig URLs
From: Jaco Kroon @ 2026-03-31 6:21 UTC (permalink / raw)
To: Qingfang Deng, linux-ppp, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Eric Biggers, netdev,
linux-kernel
Cc: Paul Mackerras, Dianne Skoll, James Carlson
In-Reply-To: <20260331033303.5664-1-dqfext@gmail.com>
Hi,
On 2026/03/31 05:33, Qingfang Deng wrote:
> Both links are no longer valid. Update them to the correct URLs.
>
> Signed-off-by: Qingfang Deng <dqfext@gmail.com>
> ---
> drivers/net/ppp/Kconfig | 9 ++++-----
> 1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
> index a1806b4b84be..c751959c53a1 100644
> --- a/drivers/net/ppp/Kconfig
> +++ b/drivers/net/ppp/Kconfig
> @@ -122,11 +122,10 @@ config PPPOE
> help
> Support for PPP over Ethernet.
>
> - This driver requires the latest version of pppd from the CVS
> - repository at cvs.samba.org. Alternatively, see the
> - RoaringPenguin package (<http://www.roaringpenguin.com/pppoe>)
> - which contains instruction on how to use this driver (under
> - the heading "Kernel mode PPPoE").
> + This driver requires the latest version of pppd at
> + <https://ppp.samba.org>.
> + Alternatively, see the out-of-tree RP-PPPoE plugin at
> + <https://dianne.skoll.ca/projects/rp-pppoe/>.
ppp now exclusively has the plugin code (originally from roaring penguin
I believe). Latest version is no longer relevant, that plugin has been
available since at least a few versions back already (at least a decade,
probably closer to two).
That same code has recently been dropped from rp-pppoe, which now
primarily focusses on pppoe-server, and relies on the plugin now part of
ppp package itself. rp-pppoe is only required if you're running a
pppoe-server, and I don't think rp-pppoe at this stage will function
without ppp.
Most people will never need rp-pppoe.
Kind regards,
Jaco
>
> choice
> prompt "Number of PPPoE hash bits"
^ permalink raw reply
* [PATCH net v2 3/3] bnxt_en: Restore default stat ctxs for ULP when resource is available
From: Michael Chan @ 2026-03-31 6:51 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek, Kalesh AP
In-Reply-To: <20260331065138.948205-1-michael.chan@broadcom.com>
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
During resource reservation, if the L2 driver does not have enough
MSIX vectors to provide to the RoCE driver, it sets the stat ctxs for
ULP also to 0 so that we don't have to reserve it unnecessarily.
However, subsequently the user may reduce L2 rings thereby freeing up
some resources that the L2 driver can now earmark for RoCE. In this
case, the driver should restore the default ULP stat ctxs to make
sure that all RoCE resources are ready for use.
The RoCE driver may fail to initialize in this scenario without this
fix.
Fixes: d630624ebd70 ("bnxt_en: Utilize ulp client resources if RoCE is not registered")
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index f11f3a704da5..3f775196ef81 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -8045,6 +8045,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
if (!ulp_msix)
bnxt_set_ulp_stat_ctxs(bp, 0);
+ else
+ bnxt_set_dflt_ulp_stat_ctxs(bp);
if (ulp_msix > bp->ulp_num_msix_want)
ulp_msix = bp->ulp_num_msix_want;
--
2.51.0
^ permalink raw reply related
* [PATCH net v2 2/3] bnxt_en: Don't assume XDP is never enabled in bnxt_init_dflt_ring_mode()
From: Michael Chan @ 2026-03-31 6:51 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek, Kalesh AP
In-Reply-To: <20260331065138.948205-1-michael.chan@broadcom.com>
The original code made the assumption that when we set up the initial
default ring mode, we must be just loading the driver and XDP cannot
be enabled yet. This is not true when the FW goes through a resource
or capability change. Resource reservations will be cancelled and
reinitialized with XDP already enabled. devlink reload with XDP enabled
will also have the same issue. This scenario will cause the ring
arithmetic to be all wrong in the bnxt_init_dflt_ring_mode() path
causing failure:
bnxt_en 0000:a1:00.0 ens2f0np0: bnxt_setup_int_mode err: ffffffea
bnxt_en 0000:a1:00.0 ens2f0np0: bnxt_request_irq err: ffffffea
bnxt_en 0000:a1:00.0 ens2f0np0: nic open fail (rc: ffffffea)
Fix it by properly accounting for XDP in the bnxt_init_dflt_ring_mode()
path by using the refactored helper functions in the previous patch.
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Fixes: ec5d31e3c15d ("bnxt_en: Handle firmware reset status during IF_UP.")
Fixes: 228ea8c187d8 ("bnxt_en: implement devlink dev reload driver_reinit")
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
v2: Fix commit ID of a Fixes tag
v1: https://lore.kernel.org/netdev/20260329232528.870637-3-michael.chan@broadcom.com/
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 173f962fc2ab..f11f3a704da5 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -16547,6 +16547,10 @@ static void bnxt_adj_dflt_rings(struct bnxt *bp, bool sh)
else
bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
+ if (sh && READ_ONCE(bp->xdp_prog)) {
+ bnxt_set_xdp_tx_rings(bp);
+ bnxt_set_cp_rings(bp, true);
+ }
}
static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
@@ -16588,16 +16592,17 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
rc = __bnxt_reserve_rings(bp);
if (rc && rc != -ENODEV)
netdev_warn(bp->dev, "Unable to reserve tx rings\n");
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+
+ bnxt_adj_tx_rings(bp);
if (sh)
- bnxt_trim_dflt_sh_rings(bp);
+ bnxt_adj_dflt_rings(bp, true);
/* Rings may have been trimmed, re-reserve the trimmed rings. */
if (bnxt_need_reserve_rings(bp)) {
rc = __bnxt_reserve_rings(bp);
if (rc && rc != -ENODEV)
netdev_warn(bp->dev, "2nd rings reservation failed.\n");
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+ bnxt_adj_tx_rings(bp);
}
if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
bp->rx_nr_rings++;
@@ -16631,7 +16636,7 @@ static int bnxt_init_dflt_ring_mode(struct bnxt *bp)
if (rc)
goto init_dflt_ring_err;
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+ bnxt_adj_tx_rings(bp);
bnxt_set_dflt_rfs(bp);
--
2.51.0
^ permalink raw reply related
* [PATCH net v2 1/3] bnxt_en: Refactor some basic ring setup and adjustment logic
From: Michael Chan @ 2026-03-31 6:51 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek, Kalesh AP
In-Reply-To: <20260331065138.948205-1-michael.chan@broadcom.com>
Refactor out the basic code that trims the default rings, sets up and
adjusts XDP TX rings and CP rings. There is no change in behavior.
This is to prepare for the next bug fix patch.
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 53 +++++++++++++------
drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
.../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 5 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 5 +-
4 files changed, 41 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 7ed805713fbb..173f962fc2ab 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -12992,6 +12992,21 @@ static int bnxt_tx_nr_rings_per_tc(struct bnxt *bp)
return bp->num_tc ? bp->tx_nr_rings / bp->num_tc : bp->tx_nr_rings;
}
+static void bnxt_set_xdp_tx_rings(struct bnxt *bp)
+{
+ bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc;
+ bp->tx_nr_rings += bp->tx_nr_rings_xdp;
+}
+
+static void bnxt_adj_tx_rings(struct bnxt *bp)
+{
+ /* Make adjustments if reserved TX rings are less than requested */
+ bp->tx_nr_rings -= bp->tx_nr_rings_xdp;
+ bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+ if (bp->tx_nr_rings_xdp)
+ bnxt_set_xdp_tx_rings(bp);
+}
+
static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
{
int rc = 0;
@@ -13009,13 +13024,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
if (rc)
return rc;
- /* Make adjustments if reserved TX rings are less than requested */
- bp->tx_nr_rings -= bp->tx_nr_rings_xdp;
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
- if (bp->tx_nr_rings_xdp) {
- bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc;
- bp->tx_nr_rings += bp->tx_nr_rings_xdp;
- }
+ bnxt_adj_tx_rings(bp);
rc = bnxt_alloc_mem(bp, irq_re_init);
if (rc) {
netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
@@ -15436,11 +15445,19 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+void bnxt_set_cp_rings(struct bnxt *bp, bool sh)
+{
+ int tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+
+ bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
+ tx_cp + bp->rx_nr_rings;
+}
+
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
{
struct bnxt *bp = netdev_priv(dev);
bool sh = false;
- int rc, tx_cp;
+ int rc;
if (tc > bp->max_tc) {
netdev_err(dev, "Too many traffic classes requested: %d. Max supported is %d.\n",
@@ -15473,9 +15490,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
bp->num_tc = 0;
}
bp->tx_nr_rings += bp->tx_nr_rings_xdp;
- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
- bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
- tx_cp + bp->rx_nr_rings;
+ bnxt_set_cp_rings(bp, sh);
if (netif_running(bp->dev))
return bnxt_open_nic(bp, true, false);
@@ -16525,6 +16540,15 @@ static void bnxt_trim_dflt_sh_rings(struct bnxt *bp)
bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
}
+static void bnxt_adj_dflt_rings(struct bnxt *bp, bool sh)
+{
+ if (sh)
+ bnxt_trim_dflt_sh_rings(bp);
+ else
+ bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
+ bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
+}
+
static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
{
int dflt_rings, max_rx_rings, max_tx_rings, rc;
@@ -16550,11 +16574,8 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
return rc;
bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings);
bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings);
- if (sh)
- bnxt_trim_dflt_sh_rings(bp);
- else
- bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
- bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
+
+ bnxt_adj_dflt_rings(bp, sh);
avail_msix = bnxt_get_max_func_irqs(bp) - bp->cp_nr_rings;
if (avail_msix >= BNXT_MIN_ROCE_CP_RINGS) {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index a97d651130df..4bc7f7aeaab3 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -2985,6 +2985,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
int tx_xdp);
int bnxt_fw_init_one(struct bnxt *bp);
bool bnxt_hwrm_reset_permitted(struct bnxt *bp);
+void bnxt_set_cp_rings(struct bnxt *bp, bool sh);
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
struct bnxt_ntuple_filter *bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp,
struct bnxt_ntuple_filter *fltr, u32 idx);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index 28d0ece2e7b1..0407aa1b3190 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -945,7 +945,6 @@ static int bnxt_set_channels(struct net_device *dev,
bool sh = false;
int tx_xdp = 0;
int rc = 0;
- int tx_cp;
if (channel->other_count)
return -EINVAL;
@@ -1013,9 +1012,7 @@ static int bnxt_set_channels(struct net_device *dev,
if (tcs > 1)
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
- bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
- tx_cp + bp->rx_nr_rings;
+ bnxt_set_cp_rings(bp, sh);
/* After changing number of rx channels, update NTUPLE feature. */
netdev_update_features(dev);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index 85cbeb35681c..bebe37e139c9 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -384,7 +384,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
struct net_device *dev = bp->dev;
- int tx_xdp = 0, tx_cp, rc, tc;
+ int tx_xdp = 0, rc, tc;
struct bpf_prog *old;
netdev_assert_locked(dev);
@@ -431,8 +431,7 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
- bp->cp_nr_rings = max_t(int, tx_cp, bp->rx_nr_rings);
+ bnxt_set_cp_rings(bp, true);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
--
2.51.0
^ permalink raw reply related
* [PATCH net v2 0/3] bnxt_en: Bug fixes
From: Michael Chan @ 2026-03-31 6:51 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek
The first patch is a refactor patch needed by the second patch to
fix XDP ring initialization during FW reset. The third patch
fixes an issue related to stats context reservation for RoCE.
v2: Fix Fixes tag commit ID for patch #2
v1: https://lore.kernel.org/netdev/20260329232528.870637-1-michael.chan@broadcom.com/
Michael Chan (2):
bnxt_en: Refactor some basic ring setup and adjustment logic
bnxt_en: Don't assume XDP is never enabled in
bnxt_init_dflt_ring_mode()
Pavan Chebbi (1):
bnxt_en: Restore default stat ctxs for ULP when resource is available
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 68 +++++++++++++------
drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
.../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 5 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 5 +-
4 files changed, 52 insertions(+), 27 deletions(-)
--
2.51.0
^ permalink raw reply
* Re: [PATCH v2] netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT absent
From: Qi Tang @ 2026-03-31 6:21 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal; +Cc: netfilter-devel, netdev, Qi Tang
In-Reply-To: <20260331061434.84238-1-tpluszz77@gmail.com>
Please ignore this mis-threaded v2. The correct standalone v2 has
been sent separately.
Qi Tang
^ permalink raw reply
* [PATCH v2] netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT absent
From: Qi Tang @ 2026-03-31 6:17 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal
Cc: Phil Sutter, netfilter-devel, coreteam, netdev, kernel test robot,
Qi Tang
ctnetlink_alloc_expect() allocates expectations from a non-zeroing
slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
present in the netlink message, saved_addr and saved_proto are
never initialized. Stale data from a previous slab occupant can
then be dumped to userspace by ctnetlink_exp_dump_expect(), which
checks these fields to decide whether to emit CTA_EXPECT_NAT.
The safe sibling nf_ct_expect_init(), used by the packet path,
explicitly zeroes these fields.
Zero saved_addr, saved_proto and dir in the else branch, guarded
by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
NAT is enabled.
Confirmed by priming the expect slab with NAT-bearing expectations,
freeing them, creating a new expectation without CTA_EXPECT_NAT,
and observing that the ctnetlink dump emits a spurious
CTA_EXPECT_NAT containing stale data from the prior allocation.
Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202603310541.XVM8V7WG-lkp@intel.com/
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
---
Changes in v2:
- Wrap zeroing in #if IS_ENABLED(CONFIG_NF_NAT) to fix build
when CONFIG_NF_NAT is disabled (kernel test robot)
Link: https://lore.kernel.org/all/20260329165217.241038-1-tpluszz77@gmail.com/
net/netfilter/nf_conntrack_netlink.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index c57c665363e0..6d7eab7e8cf8 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3593,6 +3593,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp, nf_ct_l3num(ct));
if (err < 0)
goto err_out;
+#if IS_ENABLED(CONFIG_NF_NAT)
+ } else {
+ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
+ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+ exp->dir = 0;
+#endif
}
return exp;
err_out:
--
2.43.0
^ permalink raw reply related
* [PATCH v2] netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT absent
From: Qi Tang @ 2026-03-31 6:14 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal
Cc: Phil Sutter, netfilter-devel, coreteam, netdev, kernel test robot,
Qi Tang
In-Reply-To: <20260329165217.241038-1-tpluszz77@gmail.com>
ctnetlink_alloc_expect() allocates expectations from a non-zeroing
slab cache via nf_ct_expect_alloc(). When CTA_EXPECT_NAT is not
present in the netlink message, saved_addr and saved_proto are
never initialized. Stale data from a previous slab occupant can
then be dumped to userspace by ctnetlink_exp_dump_expect(), which
checks these fields to decide whether to emit CTA_EXPECT_NAT.
The safe sibling nf_ct_expect_init(), used by the packet path,
explicitly zeroes these fields.
Zero saved_addr, saved_proto and dir in the else branch, guarded
by IS_ENABLED(CONFIG_NF_NAT) since these fields only exist when
NAT is enabled.
Confirmed by priming the expect slab with NAT-bearing expectations,
freeing them, creating a new expectation without CTA_EXPECT_NAT,
and observing that the ctnetlink dump emits a spurious
CTA_EXPECT_NAT containing stale data from the prior allocation.
Fixes: 076a0ca02644 ("netfilter: ctnetlink: add NAT support for expectations")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202603310541.XVM8V7WG-lkp@intel.com/
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
---
Changes in v2:
- Wrap zeroing in #if IS_ENABLED(CONFIG_NF_NAT) to fix build
when CONFIG_NF_NAT is disabled (kernel test robot)
Link: https://lore.kernel.org/all/20260329165217.241038-1-tpluszz77@gmail.com/
net/netfilter/nf_conntrack_netlink.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index c57c665363e0..6d7eab7e8cf8 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3593,6 +3593,12 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp, nf_ct_l3num(ct));
if (err < 0)
goto err_out;
+#if IS_ENABLED(CONFIG_NF_NAT)
+ } else {
+ memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
+ memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+ exp->dir = 0;
+#endif
}
return exp;
err_out:
--
2.43.0
^ permalink raw reply related
* RE: [PATCH net-next v2 13/13] net: renesas: rswitch: add vlan aware switching
From: Michael Dege @ 2026-03-31 6:10 UTC (permalink / raw)
To: kernel test robot, Yoshihiro Shimoda, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: oe-kbuild-all@lists.linux.dev, netdev@vger.kernel.org,
linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <202603300436.ryIgiB0z-lkp@intel.com>
Hello,
Who can kindly help me with this?
> -----Original Message-----
> From: kernel test robot <lkp@intel.com>
> Sent: Sunday, March 29, 2026 10:37 PM
> To: Michael Dege <michael.dege@renesas.com>; Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>;
> Andrew Lunn <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>
> Cc: oe-kbuild-all@lists.linux.dev; netdev@vger.kernel.org; linux-renesas-soc@vger.kernel.org; linux-
> kernel@vger.kernel.org; Michael Dege <michael.dege@renesas.com>
> Subject: Re: [PATCH net-next v2 13/13] net: renesas: rswitch: add vlan aware switching
>
> Hi Michael,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681]
>
> url: https://github.com/intel-lab-
> lkp%2Flinux%2Fcommits%2FMichael-Dege%2Fnet-renesas-rswitch-improve-port-change-mode-
> functions%2F20260329-
> 154812&data=05%7C02%7Cmichael.dege%40renesas.com%7C27cab84d6f7640e15b4f08de8dd3108a%7C53d82571da1947e4
> 9cb4625a166a4a2a%7C0%7C0%7C639104134822998103%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIw
> LjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=uP5U8NPFi2wo7VJDRGZ%2B
> ubwH50bZDvNuapBP0t76lL0%3D&reserved=0
> base: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
> patch link:
> https://lore.kernel.org/r/20260327-
> rswitch_add_vlans-v2-13-
> d7f4358ca57a%2540renesas.com&data=05%7C02%7Cmichael.dege%40renesas.com%7C27cab84d6f7640e15b4f08de8dd31
> 08a%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%7C639104134823016624%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU
> 1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=
> 2QTz%2BFk8tDeHuE2Ac5ddl8tJ2mFSrm9l9mGnnLDsdW4%3D&reserved=0
> patch subject: [PATCH net-next v2 13/13] net: renesas: rswitch: add vlan aware switching
> config: arm64-defconfig
> (https://download.01.org/0day-
> ci%2Farchive%2F20260330%2F202603300436.ryIgiB0z-
> lkp%40intel.com%2Fconfig&data=05%7C02%7Cmichael.dege%40renesas.com%7C27cab84d6f7640e15b4f08de8dd3108a%
> 7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%7C639104134823028947%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcG
> kiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=vhwu
> KaGAF4bhfSTb1VhDnII4SXsKbZ0zEPRt8ma49aM%3D&reserved=0)
> compiler: aarch64-linux-gcc (GCC) 15.2.0 reproduce (this is a W=1 build):
> (https://download.01.org/0day-
> ci%2Farchive%2F20260330%2F202603300436.ryIgiB0z-
> lkp%40intel.com%2Freproduce&data=05%7C02%7Cmichael.dege%40renesas.com%7C27cab84d6f7640e15b4f08de8dd310
> 8a%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%7C639104134823040554%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1
> hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=Y
> TddyGPjtxfccjUPlLwizqOqUHOuiRxPxMqoNaHWW%2Bk%3D&reserved=0)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of the same
> patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes:
> | https://lore/
> | .kernel.org%2Foe-kbuild-all%2F202603300436.ryIgiB0z-lkp%40intel.com%2F
> | &data=05%7C02%7Cmichael.dege%40renesas.com%7C27cab84d6f7640e15b4f08de8
> | dd3108a%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%7C63910413482305219
> | 2%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIs
> | IlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=4B
> | 1hVOdPuyjze1HZCUi2v3gamNPgyeYcmx5NNzrDFjw%3D&reserved=0
>
> All errors (new ones prefixed by >>):
>
> aarch64-linux-ld: Unexpected GOT/PLT entries detected!
> aarch64-linux-ld: Unexpected run-time procedure linkages detected!
> aarch64-linux-ld: drivers/net/ethernet/renesas/rswitch_l2.o: in function
> `rswitch_port_obj_do_add_gwca':
> >> drivers/net/ethernet/renesas/rswitch_l2.c:443:(.text+0x11e0): undefined reference to
> `br_vlan_enabled'
> aarch64-linux-ld: drivers/net/ethernet/renesas/rswitch_l2.o: in function `rswitch_port_obj_do_add':
> drivers/net/ethernet/renesas/rswitch_l2.c:412:(.text+0x135c): undefined reference to
> `br_vlan_enabled'
> >> aarch64-linux-ld: drivers/net/ethernet/renesas/rswitch_l2.c:423:(.text+0x13bc): undefined reference
> to `br_vlan_enabled'
>
>
> vim +443 drivers/net/ethernet/renesas/rswitch_l2.c
>
> 402
> 403 static int rswitch_port_obj_do_add(struct net_device *ndev,
> 404 struct switchdev_obj_port_vlan *p_vlan)
> 405 {
> 406 struct rswitch_device *rdev = netdev_priv(ndev);
> 407 struct rswitch_private *priv = rdev->priv;
> 408 struct rswitch_etha *etha = rdev->etha;
> 409 int err;
> 410
> 411 /* Set Rswitch VLAN mode */
> 412 iowrite32(br_vlan_enabled(rdev->brdev) ? FIELD_PREP(FWGC_SVM, C_TAG) : 0,
> 413 priv->addr + FWGC);
> 414
> 415 err = rswitch_write_vlan_table(priv, p_vlan->vid, etha->index);
> 416 if (err < 0)
> 417 return err;
> 418
> 419 /* If the default vlan for this port has been set, don't overwrite it. */
> 420 if (ioread32(etha->addr + EAVCC))
> 421 return NOTIFY_DONE;
> 422
> > 423 if (br_vlan_enabled(rdev->brdev))
> 424 rswitch_modify(priv->addr, FWPC0(etha->index), 0, FWPC0_VLANSA |
> FWPC0_VLANRU);
> 425
> 426 rswitch_modify(priv->addr, FWPC2(AGENT_INDEX_GWCA),
> 427 FIELD_PREP(FWPC2_LTWFW, BIT(etha->index)),
> 428 0);
> 429
> 430 return rswitch_port_set_vlan_tag(etha, p_vlan, false);
> 431 }
> 432
> 433 static int rswitch_port_obj_do_add_gwca(struct net_device *ndev,
> 434 struct rswitch_private *priv,
> 435 struct switchdev_obj_port_vlan *p_vlan)
> 436 {
> 437 int err;
> 438
> 439 if (!(p_vlan->flags & BRIDGE_VLAN_INFO_BRENTRY))
> 440 return NOTIFY_DONE;
> 441
> 442 /* Set Rswitch VLAN mode */
> > 443 iowrite32(br_vlan_enabled(ndev) ? FIELD_PREP(FWGC_SVM, C_TAG) : 0, priv->addr +
> FWGC);
> 444
> 445 err = rswitch_write_vlan_table(priv, p_vlan->vid, AGENT_INDEX_GWCA);
> 446 if (err < 0)
> 447 return err;
> 448
> 449 /* If the default vlan for this port has been set, don't overwrite it. */
> 450 if (ioread32(priv->addr + GWVCC))
> 451 return NOTIFY_DONE;
> 452
> 453 return rswitch_gwca_set_vlan_tag(priv, p_vlan, false);
> 454 }
> 455
>
The function br_vlan_enabled() is exported from br_vlan.c and the header file is if_bridge.h. Can anyone
give me a hint what might be wrong?
Thank you and best regards,
Michael
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-
> tests%2Fwiki&data=05%7C02%7Cmichael.dege%40renesas.com%7C27cab84d6f7640e15b4f08de8dd3108a%7C53d82571da
> 1947e49cb4625a166a4a2a%7C0%7C0%7C639104134823063970%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIl
> YiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=wG2VKo2Ln60Ld4KV
> 8wHTcxRyskg0hzu0dZSVMg4v73g%3D&reserved=0
^ permalink raw reply
* Re: [PATCH net v2] bridge: mrp: reject zero test interval to avoid OOM panic
From: Ido Schimmel @ 2026-03-31 6:05 UTC (permalink / raw)
To: Xiang Mei
Cc: netdev, bridge, horms, razor, kuba, davem, edumazet, pabeni,
bestswngs
In-Reply-To: <20260328063000.1845376-1-xmei5@asu.edu>
On Fri, Mar 27, 2026 at 11:30:00PM -0700, Xiang Mei wrote:
> br_mrp_start_test() and br_mrp_start_in_test() accept the user-supplied
> interval value from netlink without validation. When interval is 0,
> usecs_to_jiffies(0) yields 0, causing the delayed work
> (br_mrp_test_work_expired / br_mrp_in_test_work_expired) to reschedule
> itself with zero delay. This creates a tight loop on system_percpu_wq
> that allocates and transmits MRP test frames at maximum rate, exhausting
> all system memory and causing a kernel panic via OOM deadlock.
>
> The same zero-interval issue applies to br_mrp_start_in_test_parse()
> for interconnect test frames.
>
> Use NLA_POLICY_MIN(NLA_U32, 1) in the nla_policy tables for both
> IFLA_BRIDGE_MRP_START_TEST_INTERVAL and
> IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, so zero is rejected at the
> netlink attribute parsing layer before the value ever reaches the
> workqueue scheduling code. This is consistent with how other bridge
> subsystems (br_fdb, br_mst) enforce range constraints on netlink
> attributes.
>
> Fixes: 20f6a05ef635 ("bridge: mrp: Rework the MRP netlink interface")
> Fixes: 7ab1748e4ce6 ("bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect")
> Reported-by: Weiming Shi <bestswngs@gmail.com>
> Signed-off-by: Xiang Mei <xmei5@asu.edu>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* Re: [PATCH net-next] net: vxlan: check ipv6_mod_enabled() on neigh_reduce()
From: Ido Schimmel @ 2026-03-31 5:56 UTC (permalink / raw)
To: Fernando Fernandez Mancera
Cc: netdev, sdf, petrm, razor, pabeni, kuba, edumazet, davem,
andrew+netdev
In-Reply-To: <20260330121033.4479-1-fmancera@suse.de>
On Mon, Mar 30, 2026 at 02:10:33PM +0200, Fernando Fernandez Mancera wrote:
> IPv6 must be enabled or otherwise neigh_reduce() might cause a kernel
> panic. This was prevented by a check on in6_dev. Use ipv6_mod_enabled()
> instead as it is cleaner and also consistent with the code at
> route_shortcircuit().
>
> Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
I believe the RCU read-side critical section could be reduced a bit, but
it's not critical, so:
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* Re: [PATCH] ppp: dead code cleanup in Kconfig
From: Qingfang Deng @ 2026-03-31 5:55 UTC (permalink / raw)
To: Julian Braha
Cc: andrew+netdev, pabeni, davem, kuba, ebiggers, edumazet, netdev,
linux-kernel
In-Reply-To: <20260330213258.13982-1-julianbraha@gmail.com>
On Mon, 30 Mar 2026 22:32:58 +0100, Julian Braha wrote:
> There is already an 'if PPP' condition wrapping several config options
> e.g. PPP_MPPE and PPPOE, making the 'depends on PPP' statement for each of
> these a duplicate dependency (dead code).
>
> I propose leaving the outer 'if PPP...endif' and removing the individual
> 'depends on PPP' statement from each option.
>
> This dead code was found by kconfirm, a static analysis tool for Kconfig.
>
> Signed-off-by: Julian Braha <julianbraha@gmail.com>
Reviewed-by: Qingfang Deng <dqfext@gmail.com>
^ permalink raw reply
* RE: [PATCH net-next v4 3/3] r8152: add helper functions for PHY OCP registers
From: Chih Kai Hsu @ 2026-03-31 5:45 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem@davemloft.net, netdev@vger.kernel.org, nic_swsd,
linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
edumazet@google.com, bjorn@mork.no, pabeni@redhat.com
In-Reply-To: <20260331020156.3518006-2-kuba@kernel.org>
On 31/03/26 10:02 am, Jakub Kicinski wrote:
>
> > diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index
> > 32a4e8d423115..8747c55e0a484 100644
> > --- a/drivers/net/usb/r8152.c
> > +++ b/drivers/net/usb/r8152.c
> [ ... ]
> > +static void sram_write_w0w1(struct r8152 *tp, u16 addr, u16 clear,
> > +u16 set) {
> > + u16 data;
> > +
> > + data = sram_read(tp, addr);
> > + data = (data & ~clear) | set;
> > + ocp_reg_write(tp, OCP_SRAM_DATA, data);
>
> AI flags:
>
> Does writing directly to OCP_SRAM_DATA here actually write to the
> intended
> address?
Yes, this actually writes to the intended address.
>
> Because hardware indirect SRAM access ports typically auto-increment their
> internal address pointer upon access, the sram_read() call will advance the
> pointer. By writing directly to OCP_SRAM_DATA instead of using
> sram_write(tp, addr, data) to re-establish the address, the updated value
> would be written to the next address (addr + 1) rather than the original addr.
>
> Could this corrupt the PHY configuration memory across the initialization
> paths
> that now use sram_clr_bits() and sram_set_bits()?
>
> Can you confirm if this is legit? Not sure whether this device / register
> auto-increments or where AI got it from.
The address pointer, OCP_SRAM_ADDR, is not auto-incremented after sram_read(tp, addr).
However, the address pointer is incremented automatically after ocp_reg_write(tp, OCP_SRAM_DATA, data).
Best Regards,
Chih-Kai
^ permalink raw reply
* [PATCH net-next 7/7] selftests: net: Add tests for team driver decoupled tx and rx control
From: Marc Harvey @ 2026-03-31 5:33 UTC (permalink / raw)
To: jiri, andrew+netdev
Cc: willemb, maheshb, netdev, linux-kselftest, Marc Harvey
In-Reply-To: <20260331053353.2504254-1-marcharvey@google.com>
Use ping and tcpdump to verify that independent rx and tx enablement
of team driver member interfaces works as intended.
Signed-off-by: Marc Harvey <marcharvey@google.com>
---
.../selftests/drivers/net/team/Makefile | 1 +
.../drivers/net/team/decoupled_enablement.sh | 200 ++++++++++++++++++
.../selftests/drivers/net/team/options.sh | 96 +++++++++
.../selftests/drivers/net/team/team_lib.sh | 16 ++
4 files changed, 313 insertions(+)
create mode 100755 tools/testing/selftests/drivers/net/team/decoupled_enablement.sh
diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile
index 621c8eba2c32..e46460820e13 100644
--- a/tools/testing/selftests/drivers/net/team/Makefile
+++ b/tools/testing/selftests/drivers/net/team/Makefile
@@ -2,6 +2,7 @@
# Makefile for net selftests
TEST_PROGS := \
+ decoupled_enablement.sh \
dev_addr_lists.sh \
non_ether_header_ops.sh \
options.sh \
diff --git a/tools/testing/selftests/drivers/net/team/decoupled_enablement.sh b/tools/testing/selftests/drivers/net/team/decoupled_enablement.sh
new file mode 100755
index 000000000000..23ea2cf666b1
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/team/decoupled_enablement.sh
@@ -0,0 +1,200 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# These tests verify the decoupled RX and TX enablement of team driver member
+# interfaces.
+#
+# Topology
+#
+# +---------------------+ NS1
+# | test_team1 |
+# | | |
+# | eth0 |
+# | | |
+# | | |
+# +---------------------+
+# |
+# +---------------------+ NS2
+# | | |
+# | | |
+# | eth0 |
+# | | |
+# | test_team2 |
+# +---------------------+
+
+ALL_TESTS="
+ team_test_tx_enablement
+ team_test_rx_enablement
+"
+
+test_dir="$(dirname "$0")"
+source "${test_dir}/../../../net/lib.sh"
+
+NS1=""
+NS2=""
+NODAD="nodad"
+PREFIX_LENGTH="64"
+NS1_IP="fd00::1"
+NS2_IP="fd00::2"
+NS1_IP4="192.168.0.1"
+NS2_IP4="192.168.0.2"
+MEMBERS=("eth0")
+PING_COUNT=5
+PING_TIMEOUT_S=1
+PING_INTERVAL=0.1
+
+while getopts "4" opt; do
+ case $opt in
+ 4)
+ echo "IPv4 mode selected."
+ NODAD=
+ PREFIX_LENGTH="24"
+ NS1_IP="${NS1_IP4}"
+ NS2_IP="${NS2_IP4}"
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ exit 1
+ ;;
+ esac
+done
+
+# This has to be sourced after opts are gathered... (because of the forwarding
+# lib)
+source "${test_dir}/team_lib.sh"
+
+# Create the network namespaces, veth pair, and team devices in the specified
+# mode.
+# Globals:
+# RET - Used by test infra, set by `check_err` functions.
+# Arguments:
+# mode - The team driver mode to use for the team devices.
+environment_create()
+{
+ trap cleanup_all_ns EXIT
+ setup_ns ns1 ns2
+ NS1="${NS_LIST[0]}"
+ NS2="${NS_LIST[1]}"
+
+ # Create the interfaces.
+ ip -n "${NS1}" link add eth0 type veth peer name eth0 netns "${NS2}"
+ ip -n "${NS1}" link add test_team1 type team
+ ip -n "${NS2}" link add test_team2 type team
+
+ # Set up the receiving network namespace's team interface.
+ setup_team "${NS2}" test_team2 roundrobin "${NS2_IP}" \
+ "${PREFIX_LENGTH}" "${MEMBERS[@]}"
+}
+
+set_option_value()
+{
+ local namespace="$1"
+ local option_name="$2"
+ local option_value="$3"
+ local team_name="$4"
+ local member_name="$5"
+ local port_flag="--port=${member_name}"
+
+ ip netns exec "${namespace}" teamnl "${team_name}" setoption \
+ "${option_name}" "${option_value}" "${port_flag}"
+ return $?
+}
+
+try_ping()
+{
+ ip netns exec "${NS1}" ping -i "${PING_INTERVAL}" -c "${PING_COUNT}" \
+ "${NS2_IP}" -W "${PING_TIMEOUT_S}"
+}
+
+team_test_mode_tx_enablement()
+{
+ local mode="$1"
+ RET=0
+
+ # Set up the sender team with the correct mode.
+ setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \
+ "${PREFIX_LENGTH}" "${MEMBERS[@]}"
+ check_err $? "Failed to set up sender team"
+
+ ### Scenario 1: Member interface initially enabled.
+ # Expect ping to pass
+ try_ping
+ check_err $? "Ping failed when TX enabled"
+
+ ### Scenario 2: Once tx-side interface disabled.
+ # Expect ping to fail.
+ set_option_value "${NS1}" tx_enabled false test_team1 eth0
+ check_err $? "Failed to disable TX"
+ tcpdump_start eth0 "${NS2}"
+ try_ping
+ check_fail $? "Ping succeeded when TX disabled"
+ tcpdump_stop eth0
+ # Expect no packets to be transmitted, since TX is disabled.
+ did_interface_receive_icmp eth0 "${NS2_IP}"
+ check_fail $? "eth0 IS transmitting when TX disabled"
+
+ ### Scenario 3: The interface has tx re-enabled.
+ # Expect ping to pass.
+ set_option_value "${NS1}" tx_enabled true test_team1 eth0
+ check_err $? "Failed to reenable TX"
+ try_ping
+ check_err $? "Ping failed when TX reenabled"
+
+ log_test "TX failover of '${mode}' test"
+}
+
+team_test_mode_rx_enablement()
+{
+ local mode="$1"
+ RET=0
+
+ # Set up the sender team with the correct mode.
+ setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \
+ "${PREFIX_LENGTH}" "${MEMBERS[@]}"
+ check_err $? "Failed to set up sender team"
+
+ ### Scenario 1: Member interface initially enabled.
+ # Expect ping to pass
+ try_ping
+ check_err $? "Ping failed when RX enabled"
+
+ ### Scenario 2: Once rx-side interface disabled.
+ # Expect ping to fail.
+ set_option_value "${NS1}" rx_enabled false test_team1 eth0
+ check_err $? "Failed to disable RX"
+ tcpdump_start eth0 "${NS2}"
+ try_ping
+ check_fail $? "Ping succeeded when RX disabled"
+ tcpdump_stop eth0
+ # Expect packets to be transmitted, since only RX is disabled.
+ did_interface_receive_icmp eth0 "${NS2_IP}"
+ check_err $? "eth0 not transmitting when RX disabled"
+
+ ### Scenario 3: The interface has tx re-enabled.
+ # Expect ping to pass.
+ set_option_value "${NS1}" rx_enabled true test_team1 eth0
+ check_err $? "Failed to reenable RX"
+ try_ping
+ check_err $? "Ping failed when RX reenabled"
+
+ log_test "RX failover of '${mode}' test"
+}
+
+team_test_tx_enablement()
+{
+ team_test_mode_tx_enablement broadcast
+ team_test_mode_tx_enablement roundrobin
+ team_test_mode_tx_enablement random
+}
+
+team_test_rx_enablement()
+{
+ team_test_mode_rx_enablement broadcast
+ team_test_mode_rx_enablement roundrobin
+ team_test_mode_rx_enablement random
+}
+
+require_command teamnl ping pv
+environment_create
+tests_run
+exit "${EXIT_STATUS}"
diff --git a/tools/testing/selftests/drivers/net/team/options.sh b/tools/testing/selftests/drivers/net/team/options.sh
index 44888f32b513..75ebfe9f8d95 100755
--- a/tools/testing/selftests/drivers/net/team/options.sh
+++ b/tools/testing/selftests/drivers/net/team/options.sh
@@ -13,6 +13,9 @@ fi
ALL_TESTS="
team_test_options
+ team_test_enabled_implicit_changes
+ team_test_rx_enabled_implicit_changes
+ team_test_tx_enabled_implicit_changes
"
source "${test_dir}/../../../net/lib.sh"
@@ -176,12 +179,105 @@ team_test_options()
team_test_option mcast_rejoin_count 0 5
team_test_option mcast_rejoin_interval 0 5
team_test_option enabled true false "${MEMBER_PORT}"
+ team_test_option rx_enabled true false "${MEMBER_PORT}"
+ team_test_option tx_enabled true false "${MEMBER_PORT}"
team_test_option user_linkup true false "${MEMBER_PORT}"
team_test_option user_linkup_enabled true false "${MEMBER_PORT}"
team_test_option priority 10 20 "${MEMBER_PORT}"
team_test_option queue_id 0 1 "${MEMBER_PORT}"
}
+team_test_enabled_implicit_changes()
+{
+ RET=0
+
+ attach_port_if_specified "${MEMBER_PORT}"
+ check_err $? "Couldn't attach ${MEMBER_PORT} to master"
+
+ # Set enabled to true.
+ set_and_check_get enabled true "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'enabled' to true"
+
+ # Show that both rx enabled and tx enabled are true.
+ get_and_check_value rx_enabled true "--port=${MEMBER_PORT}"
+ check_err $? "'Rx_enabled' wasn't implicitly set to true"
+ get_and_check_value tx_enabled true "--port=${MEMBER_PORT}"
+ check_err $? "'Tx_enabled' wasn't implicitly set to true"
+
+ # Set enabled to false.
+ set_and_check_get enabled false "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'enabled' to true"
+
+ # Show that both rx enabled and tx enabled are false.
+ get_and_check_value rx_enabled false "--port=${MEMBER_PORT}"
+ check_err $? "'Rx_enabled' wasn't implicitly set to true"
+ get_and_check_value tx_enabled false "--port=${MEMBER_PORT}"
+ check_err $? "'Tx_enabled' wasn't implicitly set to true"
+
+ log_test "'Enabled' implicit changes"
+}
+
+team_test_rx_enabled_implicit_changes()
+{
+ RET=0
+
+ attach_port_if_specified "${MEMBER_PORT}"
+ check_err $? "Couldn't attach ${MEMBER_PORT} to master"
+
+ # Set enabled to true.
+ set_and_check_get enabled true "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'enabled' to true"
+
+ # Set rx_enabled to false.
+ set_and_check_get rx_enabled false "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'rx_enabled' to false"
+
+ # Show that enabled is false.
+ get_and_check_value enabled false "--port=${MEMBER_PORT}"
+ check_err $? "'enabled' wasn't implicitly set to false"
+
+ # Set rx_enabled to true.
+ set_and_check_get rx_enabled true "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'rx_enabled' to true"
+
+ # Show that enabled is true.
+ get_and_check_value enabled true "--port=${MEMBER_PORT}"
+ check_err $? "'enabled' wasn't implicitly set to true"
+
+ log_test "'Rx_enabled' implicit changes"
+}
+
+team_test_tx_enabled_implicit_changes()
+{
+ RET=0
+
+ attach_port_if_specified "${MEMBER_PORT}"
+ check_err $? "Couldn't attach ${MEMBER_PORT} to master"
+
+ # Set enabled to true.
+ set_and_check_get enabled true "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'enabled' to true"
+
+ # Set tx_enabled to false.
+ set_and_check_get tx_enabled false "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'tx_enabled' to false"
+
+ # Show that enabled is false.
+ get_and_check_value enabled false "--port=${MEMBER_PORT}"
+ check_err $? "'enabled' wasn't implicitly set to false"
+
+ # Set tx_enabled to true.
+ set_and_check_get tx_enabled true "--port=${MEMBER_PORT}"
+ check_err $? "Failed to set 'tx_enabled' to true"
+
+ # Show that enabled is true.
+ get_and_check_value enabled true "--port=${MEMBER_PORT}"
+ check_err $? "'enabled' wasn't implicitly set to true"
+
+ log_test "'Tx_enabled' implicit changes"
+}
+
+
require_command teamnl
setup
tests_run
diff --git a/tools/testing/selftests/drivers/net/team/team_lib.sh b/tools/testing/selftests/drivers/net/team/team_lib.sh
index 94fdb07edc30..f0f41a19ec47 100644
--- a/tools/testing/selftests/drivers/net/team/team_lib.sh
+++ b/tools/testing/selftests/drivers/net/team/team_lib.sh
@@ -127,3 +127,19 @@ did_interface_receive()
false
fi
}
+
+did_interface_receive_icmp()
+{
+ local interface="$1"
+ local ip_address="$2"
+
+ local packet_count=$(tcpdump_show "$interface" | grep \
+ "> ${ip_address}: ICMP" | wc -l)
+ echo "Packet count for ${interface} was ${packet_count}"
+
+ if [[ "$packet_count" -gt 0 ]]; then
+ true
+ else
+ false
+ fi
+}
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH net-next 6/7] net: team: Decouple rx and tx enablement in the team driver
From: Marc Harvey @ 2026-03-31 5:33 UTC (permalink / raw)
To: jiri, andrew+netdev
Cc: willemb, maheshb, netdev, linux-kselftest, Marc Harvey
In-Reply-To: <20260331053353.2504254-1-marcharvey@google.com>
There are use cases where an aggregated port should send traffic, but
not receive traffic, and vice versa. For example, in the IEEE
802.3ad-2000 specification, there is an optional "Independent Control"
version of the mux machine. Currently there is no way create
implementations like this for the team driver.
Separate the existing "enabled" per-port option into tx and rx
specific enablement options, but do so without breaking the existing
"enabled" option. The existing "enabled" option is now defined as
(rx_enabled AND tx_enabled), so if one is independently disabled, then
the old "enabled" option will also not be enabled. However, setting
the old "enabled" option affects both the rx_enabled and tx_enabled
options. This is the first case where setting an option can affect
another option.
Note that teamd and any other software that exclusively uses "coupled"
enablement will continue to work without any changes.
Signed-off-by: Marc Harvey <marcharvey@google.com>
---
drivers/net/team/team_core.c | 238 +++++++++++++++++++----
drivers/net/team/team_mode_loadbalance.c | 4 +-
drivers/net/team/team_mode_random.c | 4 +-
drivers/net/team/team_mode_roundrobin.c | 2 +-
include/linux/if_team.h | 60 +++---
5 files changed, 245 insertions(+), 63 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index 2ce31999c99f..308ff7cd4b15 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -87,7 +87,7 @@ static void team_lower_state_changed(struct team_port *port)
struct netdev_lag_lower_state_info info;
info.link_up = port->linkup;
- info.tx_enabled = team_port_enabled(port);
+ info.tx_enabled = team_port_tx_enabled(port);
netdev_lower_state_changed(port->dev, &info);
}
@@ -532,13 +532,13 @@ static void team_adjust_ops(struct team *team)
* correct ops are always set.
*/
- if (!team->en_port_count || !team_is_mode_set(team) ||
+ if (!team->tx_en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->transmit)
team->ops.transmit = team_dummy_transmit;
else
team->ops.transmit = team->mode->ops->transmit;
- if (!team->en_port_count || !team_is_mode_set(team) ||
+ if (!team->rx_en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->receive)
team->ops.receive = team_dummy_receive;
else
@@ -734,7 +734,7 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
port = team_port_get_rcu(skb->dev);
team = port->team;
- if (!team_port_enabled(port)) {
+ if (!team_port_rx_enabled(port)) {
if (is_link_local_ether_addr(eth_hdr(skb)->h_dest))
/* link-local packets are mostly useful when stack receives them
* with the link they arrive on.
@@ -831,7 +831,7 @@ static bool team_queue_override_port_has_gt_prio_than(struct team_port *port,
return true;
if (port->priority > cur->priority)
return false;
- if (port->index < cur->index)
+ if (port->tx_index < cur->tx_index)
return true;
return false;
}
@@ -876,7 +876,7 @@ static void __team_queue_override_enabled_check(struct team *team)
static void team_queue_override_port_prio_changed(struct team *team,
struct team_port *port)
{
- if (!port->queue_id || !team_port_enabled(port))
+ if (!port->queue_id || !team_port_tx_enabled(port))
return;
__team_queue_override_port_del(team, port);
__team_queue_override_port_add(team, port);
@@ -887,7 +887,7 @@ static void team_queue_override_port_change_queue_id(struct team *team,
struct team_port *port,
u16 new_queue_id)
{
- if (team_port_enabled(port)) {
+ if (team_port_tx_enabled(port)) {
__team_queue_override_port_del(team, port);
port->queue_id = new_queue_id;
__team_queue_override_port_add(team, port);
@@ -927,58 +927,172 @@ static bool team_port_find(const struct team *team,
return false;
}
+static void __team_port_enable_rx(struct team *team,
+ struct team_port *port)
+{
+ team->rx_en_port_count++;
+ WRITE_ONCE(port->rx_enabled, true);
+}
+
+static void __team_port_disable_rx(struct team *team,
+ struct team_port *port)
+{
+ team->rx_en_port_count--;
+ WRITE_ONCE(port->rx_enabled, false);
+}
+
+static void team_port_enable_rx(struct team *team,
+ struct team_port *port)
+{
+ if (team_port_rx_enabled(port))
+ return;
+
+ __team_port_enable_rx(team, port);
+
+ team_adjust_ops(team);
+
+ team_notify_peers(team);
+ team_mcast_rejoin(team);
+}
+
+static void team_port_disable_rx(struct team *team,
+ struct team_port *port)
+{
+ if (!team_port_rx_enabled(port))
+ return;
+
+ __team_port_disable_rx(team, port);
+ team_adjust_ops(team);
+}
+
+/*
+ * Enable just TX on the port by adding to tx-enabled port hashlist and
+ * setting port->tx_index (Might be racy so reader could see incorrect
+ * ifindex when processing a flying packet, but that is not a problem).
+ * Write guarded by RTNL.
+ */
+static void __team_port_enable_tx(struct team *team,
+ struct team_port *port)
+{
+ WRITE_ONCE(port->tx_index, team->tx_en_port_count);
+ WRITE_ONCE(team->tx_en_port_count, team->tx_en_port_count + 1);
+ hlist_add_head_rcu(&port->tx_hlist,
+ team_tx_port_index_hash(team, port->tx_index));
+}
+
+static void team_port_enable_tx(struct team *team,
+ struct team_port *port)
+{
+ if (team_port_tx_enabled(port))
+ return;
+
+ __team_port_enable_tx(team, port);
+ team_adjust_ops(team);
+ team_queue_override_port_add(team, port);
+
+ /* Don't rejoin multicast, since this port might not be receiving. */
+ team_notify_peers(team);
+ team_lower_state_changed(port);
+}
+
/*
- * Enable/disable port by adding to enabled port hashlist and setting
- * port->index (Might be racy so reader could see incorrect ifindex when
- * processing a flying packet, but that is not a problem). Write guarded
- * by RTNL.
+ * Enable TX AND RX on the port.
*/
static void team_port_enable(struct team *team,
struct team_port *port)
{
+ bool rx_was_enabled;
+ bool tx_was_enabled;
+
if (team_port_enabled(port))
return;
- WRITE_ONCE(port->index, team->en_port_count);
- WRITE_ONCE(team->en_port_count, team->en_port_count + 1);
- hlist_add_head_rcu(&port->hlist,
- team_port_index_hash(team, port->index));
+
+ rx_was_enabled = team_port_rx_enabled(port);
+ tx_was_enabled = team_port_tx_enabled(port);
+
+ if (!rx_was_enabled)
+ __team_port_enable_rx(team, port);
+ if (!tx_was_enabled) {
+ __team_port_enable_tx(team, port);
+ team_queue_override_port_add(team, port);
+ }
+
team_adjust_ops(team);
- team_queue_override_port_add(team, port);
team_notify_peers(team);
- team_mcast_rejoin(team);
- team_lower_state_changed(port);
+
+ if (!rx_was_enabled)
+ team_mcast_rejoin(team);
+ if (!tx_was_enabled)
+ team_lower_state_changed(port);
}
static void __reconstruct_port_hlist(struct team *team, int rm_index)
{
- int i;
+ struct hlist_head *tx_port_index_hash;
struct team_port *port;
+ int i;
- for (i = rm_index + 1; i < team->en_port_count; i++) {
- port = team_get_port_by_index(team, i);
- hlist_del_rcu(&port->hlist);
- WRITE_ONCE(port->index, port->index - 1);
- hlist_add_head_rcu(&port->hlist,
- team_port_index_hash(team, port->index));
+ for (i = rm_index + 1; i < team->tx_en_port_count; i++) {
+ port = team_get_port_by_tx_index(team, i);
+ hlist_del_rcu(&port->tx_hlist);
+ WRITE_ONCE(port->tx_index, port->tx_index - 1);
+ tx_port_index_hash = team_tx_port_index_hash(team,
+ port->tx_index);
+ hlist_add_head_rcu(&port->tx_hlist, tx_port_index_hash);
}
}
-static void team_port_disable(struct team *team,
- struct team_port *port)
+static void __team_port_disable_tx(struct team *team,
+ struct team_port *port)
{
- if (!team_port_enabled(port))
- return;
if (team->ops.port_tx_disabled)
team->ops.port_tx_disabled(team, port);
- hlist_del_rcu(&port->hlist);
- __reconstruct_port_hlist(team, port->index);
- WRITE_ONCE(port->index, -1);
- WRITE_ONCE(team->en_port_count, team->en_port_count - 1);
+
+ hlist_del_rcu(&port->tx_hlist);
+ __reconstruct_port_hlist(team, port->tx_index);
+
+ WRITE_ONCE(port->tx_index, -1);
+ WRITE_ONCE(team->tx_en_port_count, team->tx_en_port_count - 1);
+}
+
+static void team_port_disable_tx(struct team *team,
+ struct team_port *port)
+{
+ if (!team_port_tx_enabled(port))
+ return;
+
+ __team_port_disable_tx(team, port);
+
team_queue_override_port_del(team, port);
team_adjust_ops(team);
team_lower_state_changed(port);
}
+static void team_port_disable(struct team *team,
+ struct team_port *port)
+{
+ bool rx_was_enabled;
+ bool tx_was_enabled;
+
+ if (!team_port_tx_enabled(port) && !team_port_rx_enabled(port))
+ return;
+
+ rx_was_enabled = team_port_rx_enabled(port);
+ tx_was_enabled = team_port_tx_enabled(port);
+
+ if (tx_was_enabled) {
+ __team_port_disable_tx(team, port);
+ team_queue_override_port_del(team, port);
+ }
+ if (rx_was_enabled)
+ __team_port_disable_rx(team, port);
+
+ team_adjust_ops(team);
+
+ if (tx_was_enabled)
+ team_lower_state_changed(port);
+}
+
static int team_port_enter(struct team *team, struct team_port *port)
{
int err = 0;
@@ -1244,7 +1358,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
netif_addr_unlock_bh(dev);
}
- WRITE_ONCE(port->index, -1);
+ WRITE_ONCE(port->tx_index, -1);
list_add_tail_rcu(&port->list, &team->port_list);
team_port_enable(team, port);
netdev_compute_master_upper_features(dev, true);
@@ -1429,6 +1543,46 @@ static int team_port_en_option_set(struct team *team,
return 0;
}
+static void team_port_tx_en_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
+{
+ struct team_port *port = ctx->info->port;
+
+ ctx->data.bool_val = team_port_tx_enabled(port);
+}
+
+static int team_port_tx_en_option_set(struct team *team,
+ struct team_gsetter_ctx *ctx)
+{
+ struct team_port *port = ctx->info->port;
+
+ if (ctx->data.bool_val)
+ team_port_enable_tx(team, port);
+ else
+ team_port_disable_tx(team, port);
+ return 0;
+}
+
+static void team_port_rx_en_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
+{
+ struct team_port *port = ctx->info->port;
+
+ ctx->data.bool_val = team_port_rx_enabled(port);
+}
+
+static int team_port_rx_en_option_set(struct team *team,
+ struct team_gsetter_ctx *ctx)
+{
+ struct team_port *port = ctx->info->port;
+
+ if (ctx->data.bool_val)
+ team_port_enable_rx(team, port);
+ else
+ team_port_disable_rx(team, port);
+ return 0;
+}
+
static void team_user_linkup_option_get(struct team *team,
struct team_gsetter_ctx *ctx)
{
@@ -1550,6 +1704,20 @@ static const struct team_option team_options[] = {
.getter = team_port_en_option_get,
.setter = team_port_en_option_set,
},
+ {
+ .name = "tx_enabled",
+ .type = TEAM_OPTION_TYPE_BOOL,
+ .per_port = true,
+ .getter = team_port_tx_en_option_get,
+ .setter = team_port_tx_en_option_set,
+ },
+ {
+ .name = "rx_enabled",
+ .type = TEAM_OPTION_TYPE_BOOL,
+ .per_port = true,
+ .getter = team_port_rx_en_option_get,
+ .setter = team_port_rx_en_option_set,
+ },
{
.name = "user_linkup",
.type = TEAM_OPTION_TYPE_BOOL,
@@ -1595,7 +1763,7 @@ static int team_init(struct net_device *dev)
return -ENOMEM;
for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
- INIT_HLIST_HEAD(&team->en_port_hlist[i]);
+ INIT_HLIST_HEAD(&team->tx_en_port_hlist[i]);
INIT_LIST_HEAD(&team->port_list);
err = team_queue_override_init(team);
if (err)
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 840f409d250b..38a459649569 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -120,7 +120,7 @@ static struct team_port *lb_hash_select_tx_port(struct team *team,
{
int port_index = team_num_to_port_index(team, hash);
- return team_get_port_by_index_rcu(team, port_index);
+ return team_get_port_by_tx_index_rcu(team, port_index);
}
/* Hash to port mapping select tx port */
@@ -380,7 +380,7 @@ static int lb_tx_hash_to_port_mapping_set(struct team *team,
list_for_each_entry(port, &team->port_list, list) {
if (ctx->data.u32_val == port->dev->ifindex &&
- team_port_enabled(port)) {
+ team_port_tx_enabled(port)) {
rcu_assign_pointer(LB_HTPM_PORT_BY_HASH(lb_priv, hash),
port);
return 0;
diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c
index 169a7bc865b2..370e974f3dca 100644
--- a/drivers/net/team/team_mode_random.c
+++ b/drivers/net/team/team_mode_random.c
@@ -16,8 +16,8 @@ static bool rnd_transmit(struct team *team, struct sk_buff *skb)
struct team_port *port;
int port_index;
- port_index = get_random_u32_below(READ_ONCE(team->en_port_count));
- port = team_get_port_by_index_rcu(team, port_index);
+ port_index = get_random_u32_below(READ_ONCE(team->tx_en_port_count));
+ port = team_get_port_by_tx_index_rcu(team, port_index);
if (unlikely(!port))
goto drop;
port = team_get_first_port_txable_rcu(team, port);
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index dd405d82c6ac..ecbeef28c221 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -27,7 +27,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb)
port_index = team_num_to_port_index(team,
rr_priv(team)->sent_packets++);
- port = team_get_port_by_index_rcu(team, port_index);
+ port = team_get_port_by_tx_index_rcu(team, port_index);
if (unlikely(!port))
goto drop;
port = team_get_first_port_txable_rcu(team, port);
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 740cb3100dfc..3d21e06fda67 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -27,10 +27,11 @@ struct team;
struct team_port {
struct net_device *dev;
- struct hlist_node hlist; /* node in enabled ports hash list */
+ struct hlist_node tx_hlist; /* node in tx-enabled ports hash list */
struct list_head list; /* node in ordinary list */
struct team *team;
- int index; /* index of enabled port. If disabled, it's set to -1 */
+ int tx_index; /* index of tx enabled port. If disabled, -1 */
+ bool rx_enabled;
bool linkup; /* either state.linkup or user.linkup */
@@ -75,14 +76,24 @@ static inline struct team_port *team_port_get_rcu(const struct net_device *dev)
return rcu_dereference(dev->rx_handler_data);
}
+static inline bool team_port_rx_enabled(struct team_port *port)
+{
+ return READ_ONCE(port->rx_enabled);
+}
+
+static inline bool team_port_tx_enabled(struct team_port *port)
+{
+ return READ_ONCE(port->tx_index) != -1;
+}
+
static inline bool team_port_enabled(struct team_port *port)
{
- return READ_ONCE(port->index) != -1;
+ return team_port_rx_enabled(port) && team_port_tx_enabled(port);
}
static inline bool team_port_txable(struct team_port *port)
{
- return port->linkup && team_port_enabled(port);
+ return port->linkup && team_port_tx_enabled(port);
}
static inline bool team_port_dev_txable(const struct net_device *port_dev)
@@ -190,10 +201,11 @@ struct team {
const struct header_ops *header_ops_cache;
/*
- * List of enabled ports and their count
+ * List of tx-enabled ports and counts of rx and tx-enabled ports.
*/
- int en_port_count;
- struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES];
+ int tx_en_port_count;
+ int rx_en_port_count;
+ struct hlist_head tx_en_port_hlist[TEAM_PORT_HASHENTRIES];
struct list_head port_list; /* list of all ports */
@@ -237,41 +249,43 @@ static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
return dev_queue_xmit(skb);
}
-static inline struct hlist_head *team_port_index_hash(struct team *team,
- int port_index)
+static inline struct hlist_head *team_tx_port_index_hash(struct team *team,
+ int tx_port_index)
{
- return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
+ unsigned int list_entry = tx_port_index & (TEAM_PORT_HASHENTRIES - 1);
+
+ return &team->tx_en_port_hlist[list_entry];
}
-static inline struct team_port *team_get_port_by_index(struct team *team,
- int port_index)
+static inline struct team_port *team_get_port_by_tx_index(struct team *team,
+ int tx_port_index)
{
+ struct hlist_head *head = team_tx_port_index_hash(team, tx_port_index);
struct team_port *port;
- struct hlist_head *head = team_port_index_hash(team, port_index);
- hlist_for_each_entry(port, head, hlist)
- if (port->index == port_index)
+ hlist_for_each_entry(port, head, tx_hlist)
+ if (port->tx_index == tx_port_index)
return port;
return NULL;
}
static inline int team_num_to_port_index(struct team *team, unsigned int num)
{
- int en_port_count = READ_ONCE(team->en_port_count);
+ int tx_en_port_count = READ_ONCE(team->tx_en_port_count);
- if (unlikely(!en_port_count))
+ if (unlikely(!tx_en_port_count))
return 0;
- return num % en_port_count;
+ return num % tx_en_port_count;
}
-static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
- int port_index)
+static inline struct team_port *team_get_port_by_tx_index_rcu(struct team *team,
+ int tx_port_index)
{
+ struct hlist_head *head = team_tx_port_index_hash(team, tx_port_index);
struct team_port *port;
- struct hlist_head *head = team_port_index_hash(team, port_index);
- hlist_for_each_entry_rcu(port, head, hlist)
- if (READ_ONCE(port->index) == port_index)
+ hlist_for_each_entry_rcu(port, head, tx_hlist)
+ if (READ_ONCE(port->tx_index) == tx_port_index)
return port;
return NULL;
}
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH net-next 5/7] selftests: net: Add test for enablement of ports with teamd
From: Marc Harvey @ 2026-03-31 5:33 UTC (permalink / raw)
To: jiri, andrew+netdev
Cc: willemb, maheshb, netdev, linux-kselftest, Marc Harvey
In-Reply-To: <20260331053353.2504254-1-marcharvey@google.com>
There are no tests that verify enablement and disablement of team driver
ports with teamd. This should work even with changes to the enablement
option, so it is important to test.
This test sets up an active-backup network configuration across two
network namespaces, and tries to send traffic while changing which
link is the active one.
Signed-off-by: Marc Harvey <marcharvey@google.com>
---
.../selftests/drivers/net/team/Makefile | 1 +
.../drivers/net/team/teamd_activebackup.sh | 208 ++++++++++++++++++
tools/testing/selftests/net/lib.sh | 13 ++
3 files changed, 222 insertions(+)
create mode 100755 tools/testing/selftests/drivers/net/team/teamd_activebackup.sh
diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile
index ed11edf07655..621c8eba2c32 100644
--- a/tools/testing/selftests/drivers/net/team/Makefile
+++ b/tools/testing/selftests/drivers/net/team/Makefile
@@ -7,6 +7,7 @@ TEST_PROGS := \
options.sh \
propagation.sh \
refleak.sh \
+ teamd_activebackup.sh \
transmit_failover.sh \
# end of TEST_PROGS
diff --git a/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh b/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh
new file mode 100755
index 000000000000..fe8a30a8d5e6
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh
@@ -0,0 +1,208 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# These tests verify that teamd is able to enable and disable ports via the
+# active backup runner.
+#
+# Topology:
+#
+# +-------------------------+ NS1
+# | test_team1 |
+# | + |
+# | eth0 | eth1 |
+# | +---+---+ |
+# | | | |
+# +-------------------------+
+# | |
+# +-------------------------+ NS2
+# | | | |
+# | +-------+ |
+# | eth0 | eth1 |
+# | + |
+# | test_team2 |
+# +-------------------------+
+
+ALL_TESTS="teamd_test_active_backup"
+
+test_dir="$(dirname "$0")"
+source "${test_dir}/../../../net/lib.sh"
+
+NS1=""
+NS2=""
+NODAD="nodad"
+PREFIX_LENGTH="64"
+NS1_IP="fd00::1"
+NS2_IP="fd00::2"
+NS1_IP4="192.168.0.1"
+NS2_IP4="192.168.0.2"
+MEMBERS=("eth0" "eth1")
+NS1_TEAMD_CONF=""
+NS2_TEAMD_CONF=""
+
+while getopts "4" opt; do
+ case $opt in
+ 4)
+ echo "IPv4 mode selected."
+ NODAD=
+ PREFIX_LENGTH="24"
+ NS1_IP="${NS1_IP4}"
+ NS2_IP="${NS2_IP4}"
+ ;;
+ \?)
+ echo "Invalid option: -${OPTARG}" >&2
+ exit 1
+ ;;
+ esac
+done
+
+# This has to be sourced after opts are gathered... (because of the forwarding
+# lib)
+source "${test_dir}/team_lib.sh"
+
+teamd_config_create()
+{
+ local runner=$1
+ local dev=$2
+ local conf
+
+ conf=$(mktemp)
+
+ cat > $conf <<-EOF
+ {
+ "device": "${dev}",
+ "runner": {"name": "${runner}"},
+ "ports": {
+ "eth0": {},
+ "eth1": {}
+ }
+ }
+ EOF
+ echo $conf
+}
+
+# Create the network namespaces, veth pair, and team devices in the specified
+# runner.
+# Globals:
+# RET - Used by test infra, set by `check_err` functions.
+# Arguments:
+# runner - The Teamd runner to use for the Team devices.
+environment_create()
+{
+ local runner=$1
+
+ echo "Setting up two-link aggregation for runner ${runner}"
+ trap environment_destroy EXIT
+
+ setup_ns ns1 ns2
+ NS1="${NS_LIST[0]}"
+ NS2="${NS_LIST[1]}"
+
+ for link in $(seq 0 1); do
+ ip -n "${NS1}" link add "eth${link}" type veth peer name \
+ "eth${link}" netns "${NS2}"
+ check_err $? "Failed to create veth pair"
+ done
+
+ NS1_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team1")
+ NS2_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team2")
+ echo "Conf files are ${NS1_TEAMD_CONF} and ${NS2_TEAMD_CONF}"
+
+ ip netns exec "${NS1}" teamd -d -f "${NS1_TEAMD_CONF}"
+ check_err $? "Failed to create team device in ${NS1}"
+ ip netns exec "${NS2}" teamd -d -f "${NS2_TEAMD_CONF}"
+ check_err $? "Failed to create team device in ${NS2}"
+ echo "Created team devices"
+
+ rm "${NS1_TEAMD_CONF}"
+ rm "${NS2_TEAMD_CONF}"
+ NS1_TEAMD_CONF=""
+ NS2_TEAMD_CONF=""
+
+ for link in $(seq 0 1); do
+ in_all_ns "ip link set eth${link} up"
+ check_err $? "Failed to set eth${link} up"
+ done
+
+ ip -n "${NS1}" link set test_team1 up
+ check_err $? "Failed to set test_team1 up in ${NS1}"
+ ip -n "${NS2}" link set test_team2 up
+ check_err $? "Failed to set test_team2 up in ${NS2}"
+
+ ip -n "${NS1}" addr add "${NS1_IP}/${PREFIX_LENGTH}" dev test_team1
+ check_err $? "Failed to add address to team device in ${NS1}"
+ ip -n "${NS2}" addr add "${NS2_IP}/${PREFIX_LENGTH}" dev test_team2
+ check_err $? "Failed to add address to team device in ${NS2}"
+
+ slowwait 2 timeout 0.5 ip netns exec "${NS1}" ping -W 1 -c 1 "${NS2_IP}"
+}
+
+# Tear down the environment: kill teamd and delete network namespaces.
+environment_destroy()
+{
+ echo "Tearing down two-link aggregation"
+ ip netns exec "${NS1}" teamd -k -t test_team1
+ ip netns exec "${NS2}" teamd -k -t test_team2
+ cleanup_all_ns
+}
+
+# Change the active port for an active-backup mode team.
+# Arguments:
+# namespace - The network namespace that the team is in.
+# team - The name of the team.
+# active_port - The port to make active.
+set_active_port()
+{
+ local namespace=$1
+ local team=$2
+ local active_port=$3
+
+ ip netns exec "${namespace}" teamdctl "${team}" state item set \
+ runner.active_port "${active_port}"
+ slowwait 2 bash -c "ip netns exec ${namespace} teamdctl ${team} state \
+ item get runner.active_port | grep -q ${active_port}"
+}
+
+# Test that active backup runner can change active ports.
+# Globals:
+# RET - Used by test infra, set by `check_err` functions.
+teamd_test_active_backup()
+{
+ RET=0
+
+ start_listening_and_sending
+
+ ### Scenario 1: Don't manually set active port, just make sure team
+ # works.
+ save_tcpdump_outputs "${NS2}" test_team2
+ did_interface_receive test_team2 "${NS2_IP}"
+ check_err $? "Traffic did not reach team interface in NS2."
+
+ ### Scenario 2: Choose active port.
+ set_active_port "${NS1}" test_team1 eth1
+ set_active_port "${NS2}" test_team2 eth1
+ save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
+
+ did_interface_receive eth0 "${NS2_IP}"
+ check_fail $? "eth0 IS transmitting when disabled"
+ did_interface_receive eth1 "${NS2_IP}"
+ check_err $? "eth1 not transmitting when enabled"
+
+ ### Scenario 3: Change active port.
+ set_active_port "${NS1}" test_team1 eth0
+ set_active_port "${NS2}" test_team2 eth0
+ save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
+
+ did_interface_receive eth0 "${NS2_IP}"
+ check_err $? "eth0 not transmitting when enabled"
+ did_interface_receive eth1 "${NS2_IP}"
+ check_fail $? "eth1 IS transmitting when disabled"
+
+ log_test "teamd active backup runner test"
+
+ stop_sending_and_listening
+}
+
+require_command teamd teamdctl nc pv
+environment_create activebackup
+tests_run
+exit "${EXIT_STATUS}"
diff --git a/tools/testing/selftests/net/lib.sh b/tools/testing/selftests/net/lib.sh
index b40694573f4c..992342b1dd7c 100644
--- a/tools/testing/selftests/net/lib.sh
+++ b/tools/testing/selftests/net/lib.sh
@@ -224,6 +224,19 @@ setup_ns()
NS_LIST+=("${ns_list[@]}")
}
+in_all_ns()
+{
+ local ret=0
+ local ns_list=("${NS_LIST[@]}")
+
+ for ns in "${ns_list[@]}"; do
+ ip netns exec "${ns}" bash -c "$@"
+ (( ret = ret || $? ))
+ done
+
+ return "${ret}"
+}
+
# Create netdevsim with given id and net namespace.
create_netdevsim() {
local id="$1"
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH net-next 4/7] selftests: net: Add tests for failover of team-aggregated ports
From: Marc Harvey @ 2026-03-31 5:33 UTC (permalink / raw)
To: jiri, andrew+netdev
Cc: willemb, maheshb, netdev, linux-kselftest, Marc Harvey
In-Reply-To: <20260331053353.2504254-1-marcharvey@google.com>
There are currently no kernel tests that verify the effect of setting
the enabled team driver option. In a followup patch, there will be
changes to this option, so it will be important to make sure it still
behaves as it does now.
The test verifies that tcp continues to work across two different team
devices in separate network namespaces, even when member links are
manually disabled.
Signed-off-by: Marc Harvey <marcharvey@google.com>
---
.../selftests/drivers/net/team/Makefile | 1 +
.../testing/selftests/drivers/net/team/config | 4 +
.../selftests/drivers/net/team/team_lib.sh | 129 +++++++++++++++
.../drivers/net/team/transmit_failover.sh | 155 ++++++++++++++++++
tools/testing/selftests/net/forwarding/lib.sh | 13 +-
5 files changed, 300 insertions(+), 2 deletions(-)
create mode 100644 tools/testing/selftests/drivers/net/team/team_lib.sh
create mode 100755 tools/testing/selftests/drivers/net/team/transmit_failover.sh
diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile
index 02d6f51d5a06..ed11edf07655 100644
--- a/tools/testing/selftests/drivers/net/team/Makefile
+++ b/tools/testing/selftests/drivers/net/team/Makefile
@@ -7,6 +7,7 @@ TEST_PROGS := \
options.sh \
propagation.sh \
refleak.sh \
+ transmit_failover.sh \
# end of TEST_PROGS
TEST_INCLUDES := \
diff --git a/tools/testing/selftests/drivers/net/team/config b/tools/testing/selftests/drivers/net/team/config
index 5d36a22ef080..8f04ae419c53 100644
--- a/tools/testing/selftests/drivers/net/team/config
+++ b/tools/testing/selftests/drivers/net/team/config
@@ -6,4 +6,8 @@ CONFIG_NETDEVSIM=m
CONFIG_NET_IPGRE=y
CONFIG_NET_TEAM=y
CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=y
+CONFIG_NET_TEAM_MODE_BROADCAST=y
CONFIG_NET_TEAM_MODE_LOADBALANCE=y
+CONFIG_NET_TEAM_MODE_RANDOM=y
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=y
+CONFIG_VETH=y
diff --git a/tools/testing/selftests/drivers/net/team/team_lib.sh b/tools/testing/selftests/drivers/net/team/team_lib.sh
new file mode 100644
index 000000000000..94fdb07edc30
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/team/team_lib.sh
@@ -0,0 +1,129 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+REQUIRE_MZ=no
+NUM_NETIFS=0
+source "${test_dir}/../../../net/forwarding/lib.sh"
+
+# Create a team interface inside of a given network namespace with a given
+# mode, members, and IP address.
+# Arguments:
+# namespace - Network namespace to put the team interface into.
+# team - The name of the team interface to setup.
+# mode - The team mode of the interface.
+# ip_address - The IP address to assign to the team interface.
+# prefix_length - The prefix length for the IP address subnet.
+# $@ - members - The member interfaces of the aggregation.
+setup_team()
+{
+ local namespace=$1
+ local team=$2
+ local mode=$3
+ local ip_address=$4
+ local prefix_length=$5
+ shift 5
+ local members=("$@")
+
+ # Prerequisite: team must have no members
+ for member in "${members[@]}"; do
+ ip -n "${namespace}" link set "${member}" nomaster
+ done
+
+ # Prerequisite: team must have no address in order to set it
+ ip -n "${namespace}" addr del "${ip_address}/${prefix_length}" \
+ ${NODAD} dev "${team}"
+
+ echo "Setting team in ${namespace} to mode ${mode}"
+
+ if ! ip -n "${namespace}" link set "${team}" down; then
+ echo "Failed to bring team device down"
+ return 1
+ fi
+ if ! ip netns exec "${namespace}" teamnl "${team}" setoption mode \
+ "${mode}"; then
+ echo "Failed to set ${team} mode to '${mode}'"
+ return 1
+ fi
+
+ # Aggregate the members into teams.
+ for member in "${members[@]}"; do
+ ip -n "${namespace}" link set ${member} master "${team}"
+ done
+
+ # Bring team devices up and give them addresses.
+ if ! ip -n "${namespace}" link set "${team}" up; then
+ echo "Failed to set ${team} up"
+ return 1
+ fi
+
+ if ! ip -n ${namespace} addr add "${ip_address}/${prefix_length}" \
+ ${NODAD} dev "${team}"; then
+ echo "Failed to give ${team} IP address in ${namespace}"
+ return 1
+ fi
+}
+
+# This is global used to keep track of the sender's netcat process, so that it
+# can be terminated.
+declare sender_pid
+
+# Start sending and receiving TCP traffic with netcat.
+# Globals:
+# sender_pid - The process ID of the netcat sender process. Used to kill it
+# later.
+start_listening_and_sending()
+{
+ ip netns exec "${NS2}" nc -l "${NS2_IP}" 1234 > /dev/null &
+ ip netns exec "${NS1}" /bin/bash -c "cat /dev/urandom | pv -q -L 1m | \
+ nc ${NS2_IP} 1234 &"
+ sender_pid=$!
+}
+
+# Stop sending TCP traffic with netcat.
+# Globals:
+# sender_pid - The process IF of the netcat sender process.
+stop_sending_and_listening()
+{
+ kill "${sender_pid}" && wait "${sender_pid}"
+}
+
+# Monitor for TCP traffic with Tcpdump, save results to temp files.
+# Arguments:
+# namespace - The network namespace to run tcpdump inside of.
+# $@ - interfaces - The interfaces to listen to.
+save_tcpdump_outputs()
+{
+ local namespace=$1
+ shift 1
+ local interfaces=("$@")
+
+ for interface in "${interfaces[@]}"; do
+ tcpdump_start_nosleep "${interface}" "${namespace}"
+ done
+
+ sleep 1
+
+ for interface in "${interfaces[@]}"; do
+ tcpdump_stop_nosleep "${interface}"
+ done
+}
+
+# Read Tcpdump output, determine packet counts.
+# Arguments:
+# interface - The name of the interface to count packets for.
+# ip_address - The destination IP address.
+did_interface_receive()
+{
+ local interface="$1"
+ local ip_address="$2"
+
+ local packet_count=$(tcpdump_show "$interface" | grep \
+ "> ${ip_address}.1234" | wc -l)
+ echo "Packet count for ${interface} was ${packet_count}"
+
+ if [[ "${packet_count}" -gt 0 ]]; then
+ true
+ else
+ false
+ fi
+}
diff --git a/tools/testing/selftests/drivers/net/team/transmit_failover.sh b/tools/testing/selftests/drivers/net/team/transmit_failover.sh
new file mode 100755
index 000000000000..c53743e26c24
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/team/transmit_failover.sh
@@ -0,0 +1,155 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# These tests verify the basic failover capability of the team driver via the
+# `enabled` team driver option across different team driver modes. This does not
+# rely on teamd, and instead just uses teamnl to set the `enabled` option
+# directly.
+#
+# Topology:
+#
+# +-------------------------+ NS1
+# | test_team1 |
+# | + |
+# | eth0 | eth1 |
+# | +---+---+ |
+# | | | |
+# +-------------------------+
+# | |
+# +-------------------------+ NS2
+# | | | |
+# | +-------+ |
+# | eth0 | eth1 |
+# | + |
+# | test_team2 |
+# +-------------------------+
+
+ALL_TESTS="team_test_failover"
+
+test_dir="$(dirname "$0")"
+source "${test_dir}/../../../net/lib.sh"
+
+NS1=""
+NS2=""
+NODAD="nodad"
+PREFIX_LENGTH="64"
+NS1_IP="fd00::1"
+NS2_IP="fd00::2"
+NS1_IP4="192.168.0.1"
+NS2_IP4="192.168.0.2"
+MEMBERS=("eth0" "eth1")
+
+while getopts "4" opt; do
+ case $opt in
+ 4)
+ echo "IPv4 mode selected."
+ NODAD=
+ PREFIX_LENGTH="24"
+ NS1_IP="${NS1_IP4}"
+ NS2_IP="${NS2_IP4}"
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ exit 1
+ ;;
+ esac
+done
+
+# This has to be sourced after opts are gathered... (because of the forwarding
+# lib)
+source "${test_dir}/team_lib.sh"
+
+# Create the network namespaces, veth pair, and team devices in the specified
+# mode.
+# Globals:
+# RET - Used by test infra, set by `check_err` functions.
+# Arguments:
+# mode - The team driver mode to use for the team devices.
+environment_create()
+{
+ trap cleanup_all_ns EXIT
+ setup_ns ns1 ns2
+ NS1="${NS_LIST[0]}"
+ NS2="${NS_LIST[1]}"
+
+ # Create the interfaces.
+ ip -n "${NS1}" link add eth0 type veth peer name eth0 netns "${NS2}"
+ ip -n "${NS1}" link add eth1 type veth peer name eth1 netns "${NS2}"
+ ip -n "${NS1}" link add test_team1 type team
+ ip -n "${NS2}" link add test_team2 type team
+
+ # Set up the receiving network namespace's team interface.
+ setup_team "${NS2}" test_team2 roundrobin "${NS2_IP}" \
+ "${PREFIX_LENGTH}" "${MEMBERS[@]}"
+}
+
+
+# Check that failover works for a specific team driver mode.
+# Globals:
+# RET - Used by test infra, set by `check_err` functions.
+# Arguments:
+# mode - The mode to set the team interfaces to.
+team_test_mode_failover()
+{
+ local mode="$1"
+ RET=0
+
+ # Set up the sender team with the correct mode.
+ echo "Members: ${MEMBERS[@]}"
+ setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \
+ "${PREFIX_LENGTH}" "${MEMBERS[@]}"
+ check_err $? "Failed to set up sender team"
+
+ start_listening_and_sending
+
+ ### Scenario 1: All interfaces initially enabled.
+ save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
+ did_interface_receive eth0 "${NS2_IP}"
+ check_err $? "eth0 not transmitting when both links enabled"
+ did_interface_receive eth1 "${NS2_IP}"
+ check_err $? "eth1 not transmitting when both links enabled"
+
+ ### Scenario 2: One tx-side interface disabled.
+ ip netns exec "${NS1}" teamnl test_team1 setoption enabled false \
+ --port=eth0
+ slowwait 2 bash -c "ip netns exec ${NS1} teamnl test_team1 getoption \
+ enabled --port=eth0 | grep -q false"
+ save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
+
+ did_interface_receive eth0 "${NS2_IP}"
+ check_fail $? "eth0 IS transmitting when disabled"
+ did_interface_receive eth1 "${NS2_IP}"
+ check_err $? "eth1 not transmitting when enabled"
+
+ ### Scenario 3: The interface is re-enabled.
+ ip netns exec "${NS1}" teamnl test_team1 setoption enabled true \
+ --port=eth0
+ slowwait 2 bash -c "ip netns exec ${NS1} teamnl test_team1 getoption \
+ enabled --port=eth0 | grep -q true"
+ save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
+
+ did_interface_receive eth0 "${NS2_IP}"
+ check_err $? "eth0 not transmitting when both links enabled"
+ did_interface_receive eth1 "${NS2_IP}"
+ check_err $? "eth1 not transmitting when both links enabled"
+
+ log_test "Failover of '${mode}' test"
+
+ # Clean up
+ stop_sending_and_listening
+}
+
+team_test_failover()
+{
+ team_test_mode_failover broadcast
+ team_test_mode_failover roundrobin
+ team_test_mode_failover random
+ # Don't test `activebackup` or `loadbalance` modes, since they are too
+ # complicated for just setting `enabled` to work. They use more than
+ # the `enabled` option for transmit.
+}
+
+require_command teamnl nc pv
+environment_create
+tests_run
+exit "${EXIT_STATUS}"
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
index a9034f0bb58b..5733f9437521 100644
--- a/tools/testing/selftests/net/forwarding/lib.sh
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -1582,7 +1582,7 @@ declare -A cappid
declare -A capfile
declare -A capout
-tcpdump_start()
+tcpdump_start_nosleep()
{
local if_name=$1; shift
local ns=$1; shift
@@ -1606,16 +1606,25 @@ tcpdump_start()
-s 65535 -B 32768 $capuser -w ${capfile[$if_name]} \
> "${capout[$if_name]}" 2>&1 &
cappid[$if_name]=$!
+}
+tcpdump_start()
+{
+ tcpdump_start_nosleep $1 $2
sleep 1
}
-tcpdump_stop()
+tcpdump_stop_nosleep()
{
local if_name=$1
local pid=${cappid[$if_name]}
$ns_cmd kill "$pid" && wait "$pid"
+}
+
+tcpdump_stop()
+{
+ tcpdump_stop_nosleep $1
sleep 1
}
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH net-next 3/7] net: team: Rename port_disabled team mode op to port_tx_disabled
From: Marc Harvey @ 2026-03-31 5:33 UTC (permalink / raw)
To: jiri, andrew+netdev
Cc: willemb, maheshb, netdev, linux-kselftest, Marc Harvey
In-Reply-To: <20260331053353.2504254-1-marcharvey@google.com>
This team mode op is only used by the load balance mode, and it only
uses it in the tx path.
Signed-off-by: Marc Harvey <marcharvey@google.com>
---
drivers/net/team/team_core.c | 4 ++--
drivers/net/team/team_mode_loadbalance.c | 4 ++--
include/linux/if_team.h | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index e54bd21bd068..2ce31999c99f 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -968,8 +968,8 @@ static void team_port_disable(struct team *team,
{
if (!team_port_enabled(port))
return;
- if (team->ops.port_disabled)
- team->ops.port_disabled(team, port);
+ if (team->ops.port_tx_disabled)
+ team->ops.port_tx_disabled(team, port);
hlist_del_rcu(&port->hlist);
__reconstruct_port_hlist(team, port->index);
WRITE_ONCE(port->index, -1);
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 684954c2a8de..840f409d250b 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -655,7 +655,7 @@ static void lb_port_leave(struct team *team, struct team_port *port)
free_percpu(lb_port_priv->pcpu_stats);
}
-static void lb_port_disabled(struct team *team, struct team_port *port)
+static void lb_port_tx_disabled(struct team *team, struct team_port *port)
{
lb_tx_hash_to_port_mapping_null_port(team, port);
}
@@ -665,7 +665,7 @@ static const struct team_mode_ops lb_mode_ops = {
.exit = lb_exit,
.port_enter = lb_port_enter,
.port_leave = lb_port_leave,
- .port_disabled = lb_port_disabled,
+ .port_tx_disabled = lb_port_tx_disabled,
.receive = lb_receive,
.transmit = lb_transmit,
};
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index a761f5282bcf..740cb3100dfc 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -121,7 +121,7 @@ struct team_mode_ops {
int (*port_enter)(struct team *team, struct team_port *port);
void (*port_leave)(struct team *team, struct team_port *port);
void (*port_change_dev_addr)(struct team *team, struct team_port *port);
- void (*port_disabled)(struct team *team, struct team_port *port);
+ void (*port_tx_disabled)(struct team *team, struct team_port *port);
};
extern int team_modeop_port_enter(struct team *team, struct team_port *port);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH net-next 2/7] net: team: Remove unused team_mode_op, port_enabled
From: Marc Harvey @ 2026-03-31 5:33 UTC (permalink / raw)
To: jiri, andrew+netdev
Cc: willemb, maheshb, netdev, linux-kselftest, Marc Harvey
In-Reply-To: <20260331053353.2504254-1-marcharvey@google.com>
This team_mode_op wasn't used by any of the team modes, so remove it.
Signed-off-by: Marc Harvey <marcharvey@google.com>
---
drivers/net/team/team_core.c | 2 --
include/linux/if_team.h | 1 -
2 files changed, 3 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index becd066279a6..e54bd21bd068 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -944,8 +944,6 @@ static void team_port_enable(struct team *team,
team_port_index_hash(team, port->index));
team_adjust_ops(team);
team_queue_override_port_add(team, port);
- if (team->ops.port_enabled)
- team->ops.port_enabled(team, port);
team_notify_peers(team);
team_mcast_rejoin(team);
team_lower_state_changed(port);
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 06f4d7400c1e..a761f5282bcf 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -121,7 +121,6 @@ struct team_mode_ops {
int (*port_enter)(struct team *team, struct team_port *port);
void (*port_leave)(struct team *team, struct team_port *port);
void (*port_change_dev_addr)(struct team *team, struct team_port *port);
- void (*port_enabled)(struct team *team, struct team_port *port);
void (*port_disabled)(struct team *team, struct team_port *port);
};
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox