[net-next, v3 03/11] bnge: add NTUPLE/ARFS VNIC
From: Vikas Gupta <vikas.gupta@broadcom.com>
Date: 2026-09-17 06:46:19
Also in:
lkml
Subsystem:
broadcom bng_en 800 gigabit ethernet driver, networking drivers, the rest · Maintainers:
Vikas Gupta, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Initialize the second VNIC, which is specifically used for the NTUPLE/ARFS feature. This VNIC helps support the aRFS/NTUPLE functionality. With this change, the total number of VNICs becomes 2. Add bnge_set_dflt_rfs() to configure the default NTUPLE feature state at netdev allocation time. Also, allocate and configure the ARFS VNIC. Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com> Reviewed-by: Dharmender Garg <redacted> --- drivers/net/ethernet/broadcom/bnge/bnge.h | 11 ++- .../ethernet/broadcom/bnge/bnge_hwrm_lib.h | 1 + .../net/ethernet/broadcom/bnge/bnge_netdev.c | 66 +++++++++++++++-- .../net/ethernet/broadcom/bnge/bnge_netdev.h | 1 + .../net/ethernet/broadcom/bnge/bnge_resc.c | 73 ++++++++++++++++++- .../net/ethernet/broadcom/bnge/bnge_resc.h | 1 + .../net/ethernet/broadcom/bnge/bnge_vnic.c | 33 ++++++++- .../net/ethernet/broadcom/bnge/bnge_vnic.h | 7 +- 8 files changed, 181 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethernet/broadcom/bnge/bnge.h
index bde54ba5d50f..fc2f45fa7712 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge.h@@ -63,9 +63,8 @@ enum { BNGE_FW_CAP_THRESHOLD_TEMP_SUPPORTED = BIT_ULL(21), BNGE_FW_CAP_DFLT_VLAN_TPID_PCP = BIT_ULL(22), BNGE_FW_CAP_VNIC_TUNNEL_TPA = BIT_ULL(23), - BNGE_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO = BIT_ULL(24), - BNGE_FW_CAP_CFA_RFS_RING_TBL_IDX_V3 = BIT_ULL(25), - BNGE_FW_CAP_VNIC_RE_FLUSH = BIT_ULL(26), + BNGE_FW_CAP_CFA_RFS_RING_TBL_IDX_V3 = BIT_ULL(24), + BNGE_FW_CAP_VNIC_RE_FLUSH = BIT_ULL(25), }; enum {
@@ -74,6 +73,7 @@ enum { BNGE_EN_STRIP_VLAN = BIT_ULL(2), BNGE_EN_SHARED_CHNL = BIT_ULL(3), BNGE_EN_UDP_GSO_SUPP = BIT_ULL(4), + BNGE_EN_ARFS_CAP = BIT_ULL(5), }; #define BNGE_EN_ROCE (BNGE_EN_ROCE_V1 | BNGE_EN_ROCE_V2)
@@ -218,6 +218,11 @@ static inline bool bnge_is_roce_en(struct bnge_dev *bd) return bd->flags & BNGE_EN_ROCE; } +static inline bool bnge_is_arfs_cap(struct bnge_dev *bd) +{ + return bd->flags & BNGE_EN_ARFS_CAP; +} + static inline bool bnge_is_agg_reqd(struct bnge_dev *bd) { if (bd->netdev) {
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h
index ae03041c36ac..2ae8ec9f33d3 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h@@ -67,4 +67,5 @@ int bnge_hwrm_shutdown_link(struct bnge_dev *bd); int bnge_hwrm_port_qstats(struct bnge_dev *bd, u8 flags); int bnge_hwrm_port_qstats_ext(struct bnge_dev *bd, u8 flags); int bnge_hwrm_func_qstat_ext(struct bnge_dev *bd, struct bnge_stats_mem *stats); +int bnge_hwrm_cfa_adv_flow_mgnt_qcaps(struct bnge_dev *bd); #endif /* _BNGE_HWRM_LIB_H_ */
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
index 9e64b1933c02..bab706cb969f 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c@@ -1149,12 +1149,10 @@ static int bnge_alloc_vnic_attributes(struct bnge_net *bn) static int bnge_alloc_vnics(struct bnge_net *bn) { - int num_vnics; + int num_vnics = 1; - /* Allocate only 1 VNIC for now - * Additional VNICs will be added based on RFS/NTUPLE in future patches - */ - num_vnics = 1; + if (bn->priv_flags & BNGE_NET_EN_NTUPLE) + num_vnics++; bn->vnic_info = kzalloc_objs(struct bnge_vnic_info, num_vnics); if (!bn->vnic_info)
@@ -1320,6 +1318,10 @@ static int bnge_alloc_core(struct bnge_net *bn) bn->vnic_info[BNGE_VNIC_DEFAULT].flags |= BNGE_VNIC_RSS_FLAG | BNGE_VNIC_MCAST_FLAG | BNGE_VNIC_UCAST_FLAG; + if (bn->priv_flags & BNGE_NET_EN_NTUPLE) + bn->vnic_info[BNGE_VNIC_NTUPLE].flags |= BNGE_VNIC_RSS_FLAG | + BNGE_VNIC_NTUPLE_FLAG; + rc = bnge_alloc_vnic_attributes(bn); if (rc) goto err_free_core;
@@ -2546,6 +2548,12 @@ static int bnge_init_chip(struct bnge_net *bn) if (rc) goto err_out; + if (bn->priv_flags & BNGE_NET_EN_NTUPLE) { + rc = bnge_alloc_rfs_vnic(bn); + if (rc) + goto err_out; + } + if (bd->rss_cap & BNGE_RSS_CAP_RSS_HASH_TYPE_DELTA) bnge_hwrm_update_rss_hash_cfg(bn);
@@ -3019,6 +3027,8 @@ static int bnge_close(struct net_device *dev) bnge_hwrm_if_change(bn->bd, false); bn->sp_event = 0; + netdev_update_features(dev); + return 0; }
@@ -3101,6 +3111,36 @@ static const struct netdev_stat_ops bnge_stat_ops = { .get_base_stats = bnge_get_base_stats, }; +static netdev_features_t bnge_fix_features(struct net_device *dev, + netdev_features_t features) +{ + /* NTUPLE can only be changed while the interface is down. */ + if (netif_running(dev)) { + if (dev->features & NETIF_F_NTUPLE) + features |= NETIF_F_NTUPLE; + else + features &= ~NETIF_F_NTUPLE; + } + return features; +} + +static int bnge_set_features(struct net_device *dev, netdev_features_t features) +{ + struct bnge_net *bn = netdev_priv(dev); + u32 flags = bn->priv_flags; + + flags &= ~BNGE_NET_EN_NTUPLE; + if (features & NETIF_F_NTUPLE) + flags |= BNGE_NET_EN_NTUPLE; + + if (flags == bn->priv_flags) + return 0; + + bn->priv_flags = flags; + + return 0; +} + static const struct net_device_ops bnge_netdev_ops = { .ndo_open = bnge_open, .ndo_stop = bnge_close,
@@ -3108,6 +3148,8 @@ static const struct net_device_ops bnge_netdev_ops = { .ndo_get_stats64 = bnge_get_stats64, .ndo_set_rx_mode_async = bnge_set_rx_mode, .ndo_features_check = bnge_features_check, + .ndo_fix_features = bnge_fix_features, + .ndo_set_features = bnge_set_features, }; static void bnge_init_mac_addr(struct bnge_dev *bd)
@@ -3233,6 +3275,18 @@ static void bnge_init_ring_params(struct bnge_net *bn) bn->netdev->cfg->hds_thresh = max(BNGE_DEFAULT_RX_COPYBREAK, rx_size); } +static void bnge_set_dflt_rfs(struct bnge_net *bn) +{ + bn->netdev->hw_features &= ~NETIF_F_NTUPLE; + bn->netdev->features &= ~NETIF_F_NTUPLE; + bn->priv_flags &= ~BNGE_NET_EN_NTUPLE; + if (bnge_is_arfs_cap(bn->bd)) { + bn->netdev->hw_features |= NETIF_F_NTUPLE; + bn->netdev->features |= NETIF_F_NTUPLE; + bn->priv_flags |= BNGE_NET_EN_NTUPLE; + } +} + int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs) { struct net_device *netdev;
@@ -3339,6 +3393,8 @@ int bnge_netdev_alloc(struct bnge_dev *bd, int max_irqs) bnge_set_ring_params(bd); bnge_init_l2_fltr_tbl(bn); + bnge_set_dflt_rfs(bn); + bnge_init_mac_addr(bd); rc = bnge_probe_phy(bn, true);
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
index ee649cc644db..c47a874df4ba 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h@@ -152,6 +152,7 @@ enum { BNGE_NET_EN_GRO = BIT(0), BNGE_NET_EN_LRO = BIT(1), BNGE_NET_EN_JUMBO = BIT(2), + BNGE_NET_EN_NTUPLE = BIT(3), }; #define BNGE_NET_EN_TPA (BNGE_NET_EN_GRO | BNGE_NET_EN_LRO)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
index 69a894b52485..4c0cde30992c 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c@@ -178,6 +178,16 @@ static int bnge_adjust_rings(struct bnge_dev *bd, u16 *rx, return bnge_fix_rings_count(rx, tx, max_nq, sh); } +static unsigned int bnge_get_max_func_rss_ctxs(struct bnge_dev *bd) +{ + return bd->hw_resc.max_rsscos_ctxs; +} + +static unsigned int bnge_get_max_func_vnics(struct bnge_dev *bd) +{ + return bd->hw_resc.max_vnics; +} + int bnge_cal_nr_rss_ctxs(u16 rx_rings) { if (!rx_rings)
@@ -190,11 +200,24 @@ int bnge_cal_nr_rss_ctxs(u16 rx_rings) static u16 bnge_get_total_rss_ctxs(struct bnge_dev *bd, struct bnge_hw_rings *hwr) { - return bnge_cal_nr_rss_ctxs(hwr->grp); + u16 rss_ctx = bnge_cal_nr_rss_ctxs(hwr->grp); + + rss_ctx *= hwr->vnic; + + return rss_ctx; } static u16 bnge_get_total_vnics(struct bnge_dev *bd) { + if (bd->netdev) { + struct bnge_net *bn = netdev_priv(bd->netdev); + + if (bn->priv_flags & BNGE_NET_EN_NTUPLE) + return 2; + } else if (bnge_is_arfs_cap(bd)) { + return 2; + } + return 1; }
@@ -563,6 +586,51 @@ static int bnge_alloc_rss_indir_tbl(struct bnge_dev *bd) return 0; } +/* If runtime conditions support RFS */ +bool bnge_arfs_capable(struct bnge_dev *bd, bool new_rss_ctx) +{ + struct bnge_hw_rings hwr = {}; + int max_vnics, max_rss_ctxs; + + hwr.grp = bd->rx_nr_rings; + hwr.vnic = bnge_get_total_vnics(bd); + + if (!bnge_is_arfs_cap(bd)) + hwr.vnic++; + + if (new_rss_ctx) + hwr.vnic++; + hwr.rss_ctx = bnge_get_total_rss_ctxs(bd, &hwr); + max_vnics = bnge_get_max_func_vnics(bd); + max_rss_ctxs = bnge_get_max_func_rss_ctxs(bd); + + if (hwr.vnic > max_vnics || hwr.rss_ctx > max_rss_ctxs) { + if (bd->rx_nr_rings > 1) + dev_warn(bd->dev, + "Not enough resources to support NTUPLE filters\n"); + return false; + } + + /* Do not reduce VNIC and RSS ctx reservations. There is a FW + * issue that will mess up the default VNIC if we reduce the + * reservations. + */ + if (hwr.vnic <= bd->hw_resc.resv_vnics && + hwr.rss_ctx <= bd->hw_resc.resv_rsscos_ctxs) + return true; + + bnge_hwrm_reserve_rings(bd, &hwr); + if (hwr.vnic <= bd->hw_resc.resv_vnics && + hwr.rss_ctx <= bd->hw_resc.resv_rsscos_ctxs) + return true; + + dev_warn(bd->dev, "Unable to reserve resources to support NTUPLE filters\n"); + hwr.vnic = 1; + hwr.rss_ctx = 0; + bnge_hwrm_reserve_rings(bd, &hwr); + return false; +} + int bnge_net_init_dflt_config(struct bnge_dev *bd) { struct bnge_hw_resc *hw_resc;
@@ -576,6 +644,9 @@ int bnge_net_init_dflt_config(struct bnge_dev *bd) if (rc) goto err_free_tbl; + if (bnge_arfs_capable(bd, false)) + bd->flags |= BNGE_EN_ARFS_CAP; + hw_resc = &bd->hw_resc; bd->max_fltr = hw_resc->max_rx_em_flows + hw_resc->max_rx_wm_flows + BNGE_L2_FLTR_MAX_FLTR;
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_resc.h b/drivers/net/ethernet/broadcom/bnge/bnge_resc.h
index b62a634669f6..1e55fbe6985b 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_resc.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_resc.h@@ -75,6 +75,7 @@ void bnge_aux_init_dflt_config(struct bnge_dev *bd); u32 bnge_get_rxfh_indir_size(struct bnge_dev *bd); int bnge_cal_nr_rss_ctxs(u16 rx_rings); bool bnge_aux_has_enough_resources(struct bnge_dev *bd); +bool bnge_arfs_capable(struct bnge_dev *bd, bool new_rss_ctx); static inline u32 bnge_adjust_pow_two(u32 total_ent, u16 ent_per_blk)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c
index 80b4ad77c659..779780ab53d2 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.c@@ -42,7 +42,11 @@ void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic) for (i = 0; i < tbl_size; i++) { u16 ring_id, j; - j = bd->rss_indir_tbl[i]; + if (vnic->flags & BNGE_VNIC_NTUPLE_FLAG) + j = ethtool_rxfh_indir_default(i, bd->rx_nr_rings); + else + j = bd->rss_indir_tbl[i]; + rxr = &bn->rx_ring[j]; ring_id = rxr->rx_ring_struct.fw_ring_id;
@@ -98,3 +102,30 @@ int bnge_setup_vnic(struct bnge_net *bn, struct bnge_vnic_info *vnic) } return rc; } + +static int bnge_alloc_and_setup_vnic(struct bnge_net *bn, + struct bnge_vnic_info *vnic, + u16 rx_rings) +{ + int rc; + + rc = bnge_hwrm_vnic_alloc(bn->bd, vnic, rx_rings); + if (rc) { + netdev_err(bn->netdev, "hwrm vnic %u alloc failure rc: %d\n", + vnic->vnic_id, rc); + return rc; + } + + /* If bnge_setup_vnic() fails, the VNIC allocated above is not freed + * here; the caller (bnge_open_core) unwinds via its err_out path, + */ + return bnge_setup_vnic(bn, vnic); +} + +int bnge_alloc_rfs_vnic(struct bnge_net *bn) +{ + struct bnge_vnic_info *vnic; + + vnic = &bn->vnic_info[BNGE_VNIC_NTUPLE]; + return bnge_alloc_and_setup_vnic(bn, vnic, bn->bd->rx_nr_rings); +}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
index 30281e26f39f..93c6d736cbeb 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_vnic.h@@ -21,13 +21,15 @@ struct bnge_l2_filter; #define BNGE_MAX_UC_ADDRS 4 enum { - BNGE_VNIC_DEFAULT = 0 + BNGE_VNIC_DEFAULT = 0, + BNGE_VNIC_NTUPLE = 1 }; enum { BNGE_VNIC_RSS_FLAG = BIT(0), BNGE_VNIC_MCAST_FLAG = BIT(1), - BNGE_VNIC_UCAST_FLAG = BIT(2) + BNGE_VNIC_UCAST_FLAG = BIT(2), + BNGE_VNIC_NTUPLE_FLAG = BIT(3) }; struct bnge_vnic_info {
@@ -59,4 +61,5 @@ 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); #endif /* _BNGE_VNIC_H_ */
--
2.52.0