[PATCH net-next 04/11] bnge: add helper functions for multi RSS contexts
From: Vikas Gupta
Date: Thu Aug 13 2026 - 21:18:19 EST
Add infrastructure for creating, modifying, and deleting user-defined
RSS contexts. This helps the next patch implement commands for ethtool.
For each user RSS context, a VNIC is allocated.
Signed-off-by: Vikas Gupta <vikas.gupta@xxxxxxxxxxxx>
Reviewed-by: Bhargava Chenna Marreddy <bhargava.marreddy@xxxxxxxxxxxx>
Reviewed-by: Dharmender Garg <dharmender.garg@xxxxxxxxxxxx>
---
.../net/ethernet/broadcom/bnge/bnge_netdev.h | 2 +
.../net/ethernet/broadcom/bnge/bnge_resc.c | 2 +-
.../net/ethernet/broadcom/bnge/bnge_vnic.c | 113 ++++++++++++++++++
.../net/ethernet/broadcom/bnge/bnge_vnic.h | 15 +++
4 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
index c47a874df4ba..3c0fea0a7608 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
@@ -371,6 +371,8 @@ struct bnge_net {
u8 pri2cos_idx[8];
bool pri2cos_valid;
+
+ u16 num_rss_ctx;
};
#define BNGE_DEFAULT_RX_RING_SIZE 511
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
index e4090982099b..9604bd05ba37 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
@@ -213,7 +213,7 @@ static u16 bnge_get_total_vnics(struct bnge_dev *bd)
struct bnge_net *bn = netdev_priv(bd->netdev);
if (bn->priv_flags & BNGE_NET_EN_NTUPLE)
- return 2;
+ return 2 + bn->num_rss_ctx;
} else if (bnge_is_arfs_cap(bd)) {
return 2;
}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c
index c79eb403844a..417abc7e8c74 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c
@@ -125,3 +125,116 @@ int bnge_alloc_rfs_vnic(struct bnge_net *bn)
vnic = &bn->vnic_info[BNGE_VNIC_NTUPLE];
return bnge_alloc_and_setup_vnic(bn, vnic, bn->bd->rx_nr_rings);
}
+
+void bnge_modify_rss(struct bnge_net *bn, struct ethtool_rxfh_context *ctx,
+ struct bnge_rss_ctx *rss_ctx,
+ const struct ethtool_rxfh_param *rxfh)
+{
+ struct bnge_dev *bd = bn->bd;
+
+ if (rxfh->key) {
+ if (rss_ctx) {
+ memcpy(rss_ctx->vnic.rss_hash_key, rxfh->key,
+ HW_HASH_KEY_SIZE);
+ } else {
+ memcpy(bn->rss_hash_key, rxfh->key, HW_HASH_KEY_SIZE);
+ bn->rss_hash_key_updated = true;
+ }
+ }
+
+ if (rxfh->indir) {
+ u32 i, pad, tbl_size = bnge_get_rxfh_indir_size(bd);
+ u32 *indir_tbl = bd->rss_indir_tbl;
+
+ if (rss_ctx)
+ indir_tbl = ethtool_rxfh_context_indir(ctx);
+ for (i = 0; i < tbl_size; i++)
+ indir_tbl[i] = rxfh->indir[i];
+ pad = bd->rss_indir_tbl_entries - tbl_size;
+ if (pad)
+ memset(&indir_tbl[i], 0, pad * sizeof(*indir_tbl));
+ }
+}
+
+void bnge_del_one_rss_ctx(struct bnge_net *bn, struct bnge_rss_ctx *rss_ctx,
+ bool all)
+{
+ struct bnge_vnic_info *vnic = &rss_ctx->vnic;
+ int i;
+
+ bnge_hwrm_vnic_free_one(bn->bd, &rss_ctx->vnic);
+ for (i = 0; i < BNGE_MAX_CTX_PER_VNIC; i++) {
+ if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
+ bnge_hwrm_vnic_ctx_free_one(bn->bd, vnic, i);
+ }
+
+ if (!all)
+ return;
+
+ if (vnic->rss_table)
+ dma_free_coherent(bn->bd->dev, vnic->rss_table_size,
+ vnic->rss_table,
+ vnic->rss_table_dma_addr);
+ bn->num_rss_ctx--;
+}
+
+void bnge_hwrm_realloc_rss_ctx_vnic(struct bnge_net *bn)
+{
+ bool set_tpa = !!(bn->priv_flags & BNGE_NET_EN_TPA);
+ struct ethtool_rxfh_context *ctx;
+ unsigned long context;
+
+ xa_for_each(&bn->netdev->ethtool->rss_ctx, context, ctx) {
+ struct bnge_rss_ctx *rss_ctx = ethtool_rxfh_context_priv(ctx);
+ struct bnge_vnic_info *vnic = &rss_ctx->vnic;
+
+ if (bnge_hwrm_vnic_alloc(bn->bd, vnic, bn->bd->rx_nr_rings) ||
+ bnge_hwrm_vnic_set_tpa(bn->bd, vnic, set_tpa) ||
+ bnge_setup_vnic(bn, vnic)) {
+ netdev_err(bn->netdev, "Failed to restore RSS ctx %d\n",
+ rss_ctx->index);
+ bnge_del_one_rss_ctx(bn, rss_ctx, true);
+ ethtool_rxfh_context_lost(bn->netdev, rss_ctx->index);
+ }
+ }
+}
+
+void bnge_clear_rss_ctxs(struct bnge_net *bn)
+{
+ struct ethtool_rxfh_context *ctx;
+ unsigned long context;
+
+ xa_for_each(&bn->netdev->ethtool->rss_ctx, context, ctx) {
+ struct bnge_rss_ctx *rss_ctx = ethtool_rxfh_context_priv(ctx);
+
+ bnge_del_one_rss_ctx(bn, rss_ctx, false);
+ }
+}
+
+struct bnge_rss_ctx *bnge_get_rss_ctx_from_index(struct bnge_net *bn, u32 idx)
+{
+ struct ethtool_rxfh_context *ctx;
+
+ ctx = xa_load(&bn->netdev->ethtool->rss_ctx, idx);
+ if (!ctx)
+ return NULL;
+ return ethtool_rxfh_context_priv(ctx);
+}
+
+int bnge_alloc_vnic_rss_table(struct bnge_net *bn,
+ struct bnge_vnic_info *vnic)
+{
+ unsigned int size = L1_CACHE_ALIGN(BNGE_MAX_RSS_TABLE_SIZE);
+
+ vnic->rss_table_size = size + HW_HASH_KEY_SIZE;
+ vnic->rss_table = dma_alloc_coherent(bn->bd->dev,
+ vnic->rss_table_size,
+ &vnic->rss_table_dma_addr,
+ GFP_KERNEL);
+ if (!vnic->rss_table)
+ return -ENOMEM;
+
+ vnic->rss_hash_key = ((void *)vnic->rss_table) + size;
+ vnic->rss_hash_key_dma_addr = vnic->rss_table_dma_addr + size;
+ return 0;
+}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
index 93c6d736cbeb..af066d8ff156 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
@@ -56,10 +56,25 @@ struct bnge_vnic_info {
u32 vnic_id;
};
+struct bnge_rss_ctx {
+ struct bnge_vnic_info vnic;
+ u32 index;
+};
+
void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic);
int bnge_hwrm_vnic_rss_cfg(struct bnge_net *bn,
struct bnge_vnic_info *vnic);
int bnge_setup_vnic(struct bnge_net *bn, struct bnge_vnic_info *vnic);
void bnge_set_dflt_rss_indir_tbl(struct bnge_dev *bd);
int bnge_alloc_rfs_vnic(struct bnge_net *bn);
+int bnge_alloc_vnic_rss_table(struct bnge_net *bn,
+ struct bnge_vnic_info *vnic);
+struct bnge_rss_ctx *bnge_get_rss_ctx_from_index(struct bnge_net *bn, u32 idx);
+void bnge_modify_rss(struct bnge_net *bn, struct ethtool_rxfh_context *ctx,
+ struct bnge_rss_ctx *rss_ctx,
+ const struct ethtool_rxfh_param *rxfh);
+void bnge_del_one_rss_ctx(struct bnge_net *bn, struct bnge_rss_ctx *rss_ctx,
+ bool all);
+void bnge_hwrm_realloc_rss_ctx_vnic(struct bnge_net *bn);
+void bnge_clear_rss_ctxs(struct bnge_net *bn);
#endif /* _BNGE_VNIC_H_ */
--
2.47.1