diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-08-04 20:00:22 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-08-04 20:00:22 -0700 |
| commit | a23b36233d4103def55dc8cf65698106d0bd1e62 (patch) | |
| tree | bfbda158c11c17a83389a556274399ddb2f977d3 | |
| parent | b16bab325801c7be004222cad0ae296aa5982e79 (diff) | |
| parent | 1b1e855e4306e227b610c5c2c7d475281a912f29 (diff) | |
| download | linux-a23b36233d4103def55dc8cf65698106d0bd1e62.tar.gz linux-a23b36233d4103def55dc8cf65698106d0bd1e62.zip | |
Merge branch 'bnge-add-more-functionality'
Vikas Gupta says:
====================
bnge: add more functionality
This patch series adds a few functionality for bnge driver:
Patch 1-2: Implements ndo_set_rx_mode_async().
Patch 3: Adds a dedicated HWRM (Hardware Resource Management) command
sequence to handle explicit interface down and up transitions cleanly.
====================
Link: https://patch.msgid.link/20260731163712.3463362-1-vikas.gupta@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnge/bnge_netdev.c | 132 | ||||
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnge/bnge_netdev.h | 6 |
2 files changed, 112 insertions, 26 deletions
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c index 6f7ef506d4e1..c2e865f8d9c4 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -20,6 +20,7 @@ #include <net/page_pool/helpers.h> #include "bnge.h" +#include "bnge_hwrm.h" #include "bnge_hwrm_lib.h" #include "bnge_ethtool.h" #include "bnge_rmem.h" @@ -2144,16 +2145,16 @@ err_del_l2_filter: return rc; } -static bool bnge_mc_list_updated(struct bnge_net *bn, u32 *rx_mask) +static bool bnge_mc_list_updated(struct bnge_net *bn, u32 *rx_mask, + const struct netdev_hw_addr_list *mc) { struct bnge_vnic_info *vnic = &bn->vnic_info[BNGE_VNIC_DEFAULT]; - struct net_device *dev = bn->netdev; struct netdev_hw_addr *ha; int mc_count = 0, off = 0; bool update = false; u8 *haddr; - netdev_for_each_mc_addr(ha, dev) { + netdev_hw_addr_list_for_each(ha, mc) { if (mc_count >= BNGE_MAX_MC_ADDRS) { *rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST; vnic->mc_list_count = 0; @@ -2177,17 +2178,17 @@ static bool bnge_mc_list_updated(struct bnge_net *bn, u32 *rx_mask) return update; } -static bool bnge_uc_list_updated(struct bnge_net *bn) +static bool bnge_uc_list_updated(struct bnge_net *bn, + const struct netdev_hw_addr_list *uc) { struct bnge_vnic_info *vnic = &bn->vnic_info[BNGE_VNIC_DEFAULT]; - struct net_device *dev = bn->netdev; struct netdev_hw_addr *ha; int off = 0; - if (netdev_uc_count(dev) != (vnic->uc_filter_count - 1)) + if (netdev_hw_addr_list_count(uc) != (vnic->uc_filter_count - 1)) return true; - netdev_for_each_uc_addr(ha, dev) { + netdev_hw_addr_list_for_each(ha, uc) { if (!ether_addr_equal(ha->addr, vnic->uc_list + off)) return true; @@ -2201,18 +2202,14 @@ static bool bnge_promisc_ok(struct bnge_net *bn) return true; } -static int bnge_cfg_def_vnic(struct bnge_net *bn) +static int bnge_cfg_rx_mode(struct bnge_net *bn, struct netdev_hw_addr_list *uc, + bool uc_update, bool snapshot) { struct bnge_vnic_info *vnic = &bn->vnic_info[BNGE_VNIC_DEFAULT]; struct net_device *dev = bn->netdev; struct bnge_dev *bd = bn->bd; struct netdev_hw_addr *ha; int i, off = 0, rc; - bool uc_update; - - netif_addr_lock_bh(dev); - uc_update = bnge_uc_list_updated(bn); - netif_addr_unlock_bh(dev); if (!uc_update) goto skip_uc; @@ -2226,22 +2223,28 @@ static int bnge_cfg_def_vnic(struct bnge_net *bn) vnic->uc_filter_count = 1; - netif_addr_lock_bh(dev); - if (netdev_uc_count(dev) > (BNGE_MAX_UC_ADDRS - 1)) { + if (!snapshot) + netif_addr_lock_bh(dev); + if (netdev_hw_addr_list_count(uc) > (BNGE_MAX_UC_ADDRS - 1)) { vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS; } else { - netdev_for_each_uc_addr(ha, dev) { + netdev_hw_addr_list_for_each(ha, uc) { memcpy(vnic->uc_list + off, ha->addr, ETH_ALEN); off += ETH_ALEN; vnic->uc_filter_count++; } } - netif_addr_unlock_bh(dev); + if (!snapshot) + netif_addr_unlock_bh(dev); for (i = 1, off = 0; i < vnic->uc_filter_count; i++, off += ETH_ALEN) { rc = bnge_hwrm_set_vnic_filter(bn, 0, i, vnic->uc_list + off); if (rc) { - netdev_err(dev, "HWRM vnic filter failure rc: %d\n", rc); + if (rc == -EAGAIN) + netdev_warn(dev, "FW busy while setting vnic filter, will retry\n"); + else + netdev_err(dev, "HWRM vnic filter failure rc: %d\n", + rc); vnic->uc_filter_count = i; return rc; } @@ -2260,13 +2263,58 @@ skip_uc: vnic->mc_list_count = 0; rc = bnge_hwrm_cfa_l2_set_rx_mask(bd, vnic); } - if (rc) - netdev_err(dev, "HWRM cfa l2 rx mask failure rc: %d\n", - rc); + if (rc) { + if (rc == -EAGAIN) { + netdev_warn(dev, "FW busy while setting l2 rx mask in CFA, will retry\n"); + vnic->rx_mask &= ~BNGE_RX_MASK_CFG_FLAGS; + } else { + netdev_err(dev, "HWRM CFA L2 rx mask failure rc: %d\n", + rc); + } + } return rc; } +static int bnge_set_rx_mode(struct net_device *dev, + struct netdev_hw_addr_list *uc, + struct netdev_hw_addr_list *mc) +{ + struct bnge_net *bn = netdev_priv(dev); + struct bnge_vnic_info *vnic; + bool mc_update = false; + bool uc_update; + u32 mask; + + if (!test_bit(BNGE_STATE_OPEN, &bn->bd->state)) + return 0; + + vnic = &bn->vnic_info[BNGE_VNIC_DEFAULT]; + mask = vnic->rx_mask; + mask &= ~BNGE_RX_MASK_CFG_FLAGS; + + if (dev->flags & IFF_PROMISC) + mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS; + + uc_update = bnge_uc_list_updated(bn, uc); + + if (dev->flags & IFF_BROADCAST) + mask |= CFA_L2_SET_RX_MASK_REQ_MASK_BCAST; + if (dev->flags & IFF_ALLMULTI) { + mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST; + vnic->mc_list_count = 0; + } else if (dev->flags & IFF_MULTICAST) { + mc_update = bnge_mc_list_updated(bn, &mask, mc); + } + + if (mask != vnic->rx_mask || uc_update || mc_update) { + vnic->rx_mask = mask; + return bnge_cfg_rx_mode(bn, uc, uc_update, true); + } + + return 0; +} + static void bnge_disable_int(struct bnge_net *bn) { struct bnge_dev *bd = bn->bd; @@ -2695,13 +2743,17 @@ static int bnge_init_chip(struct bnge_net *bn) } else if (bn->netdev->flags & IFF_MULTICAST) { u32 mask = 0; - bnge_mc_list_updated(bn, &mask); + bnge_mc_list_updated(bn, &mask, &bn->netdev->mc); vnic->rx_mask |= mask; } - rc = bnge_cfg_def_vnic(bn); - if (rc) + rc = bnge_cfg_rx_mode(bn, &bn->netdev->uc, true, false); + if (rc == -EAGAIN) { + netif_rx_mode_schedule_retry(bn->netdev); + rc = 0; + } else if (rc) { goto err_out; + } return 0; err_out: @@ -2813,6 +2865,24 @@ static void bnge_tx_enable(struct bnge_net *bn) netif_carrier_on(bn->netdev); } +static int bnge_hwrm_if_change(struct bnge_dev *bd, bool up) +{ + struct hwrm_func_drv_if_change_input *req; + int rc; + + if (!(bd->fw_cap & BNGE_FW_CAP_IF_CHANGE)) + return 0; + + rc = bnge_hwrm_req_init(bd, req, HWRM_FUNC_DRV_IF_CHANGE); + if (rc) + return rc; + + if (up) + req->flags = cpu_to_le32(FUNC_DRV_IF_CHANGE_REQ_FLAGS_UP); + + return bnge_hwrm_req_send(bd, req); +} + static int bnge_open_core(struct bnge_net *bn) { struct bnge_dev *bd = bn->bd; @@ -2820,16 +2890,22 @@ static int bnge_open_core(struct bnge_net *bn) netif_carrier_off(bn->netdev); + rc = bnge_hwrm_if_change(bd, true); + if (rc) { + netdev_err(bn->netdev, "bnge_hwrm_if_change err: %d\n", rc); + return rc; + } + rc = bnge_reserve_rings(bd); if (rc) { netdev_err(bn->netdev, "bnge_reserve_rings err: %d\n", rc); - return rc; + goto err_if_change; } rc = bnge_alloc_core(bn); if (rc) { netdev_err(bn->netdev, "bnge_alloc_core err: %d\n", rc); - return rc; + goto err_if_change; } bnge_init_napi(bn); @@ -2876,6 +2952,8 @@ err_free_irq: err_del_napi: bnge_del_napi(bn); bnge_free_core(bn); +err_if_change: + bnge_hwrm_if_change(bd, false); return rc; } @@ -3106,6 +3184,7 @@ static int bnge_close(struct net_device *dev) bnge_close_core(bn); bnge_hwrm_shutdown_link(bn->bd); + bnge_hwrm_if_change(bn->bd, false); bn->sp_event = 0; return 0; @@ -3195,6 +3274,7 @@ static const struct net_device_ops bnge_netdev_ops = { .ndo_stop = bnge_close, .ndo_start_xmit = bnge_start_xmit, .ndo_get_stats64 = bnge_get_stats64, + .ndo_set_rx_mode_async = bnge_set_rx_mode, .ndo_features_check = bnge_features_check, }; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h index d177919c2e11..476b5bab96fe 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h @@ -561,6 +561,12 @@ struct bnge_napi { #define BNGE_VNIC_DEFAULT 0 #define BNGE_MAX_UC_ADDRS 4 +#define BNGE_RX_MASK_CFG_FLAGS \ + (CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS | \ + CFA_L2_SET_RX_MASK_REQ_MASK_MCAST | \ + CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST | \ + CFA_L2_SET_RX_MASK_REQ_MASK_BCAST) + struct bnge_vnic_info { u16 fw_vnic_id; #define BNGE_MAX_CTX_PER_VNIC 8 |
