bnge: add ndo_set_rx_mode_async support

Register bnge_set_rx_mode() as ndo_set_rx_mode_async to handle
unicast, multicast, broadcast, and promiscuous filter updates via
CFA_L2_SET_RX_MASK. The async variant receives pre-snapshotted address
lists from the kernel, allowing the driver to issue sleepable HWRM
firmware commands without holding the addr lock.

Move uc_update detection to the caller so the async path can compute
it directly from the snapshotted UC list before calling
bnge_cfg_rx_mode().

Handle -EAGAIN from bnge_hwrm_set_vnic_filter() and
bnge_hwrm_cfa_l2_set_rx_mask() on the open path by scheduling a retry
via netif_rx_mode_schedule_retry() rather than failing the open.

Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: Dharmender Garg <dharmender.garg@broadcom.com>
Reviewed-by: Rahul Gupta <rahul-rg.gupta@broadcom.com>
Link: https://patch.msgid.link/20260731163712.3463362-3-vikas.gupta@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Vikas Gupta 2026-07-31 22:07:11 +05:30 committed by Jakub Kicinski
parent d5d7b17b3f
commit fbe3647fd4
2 changed files with 62 additions and 11 deletions

View File

@ -2202,18 +2202,13 @@ static bool bnge_promisc_ok(struct bnge_net *bn)
}
static int bnge_cfg_rx_mode(struct bnge_net *bn, struct netdev_hw_addr_list *uc,
bool snapshot)
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, uc);
netif_addr_unlock_bh(dev);
if (!uc_update)
goto skip_uc;
@ -2267,13 +2262,58 @@ static int bnge_cfg_rx_mode(struct bnge_net *bn, struct netdev_hw_addr_list *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;
@ -2706,9 +2746,13 @@ static int bnge_init_chip(struct bnge_net *bn)
vnic->rx_mask |= mask;
}
rc = bnge_cfg_rx_mode(bn, &bn->netdev->uc, false);
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:
@ -3202,6 +3246,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,
};

View File

@ -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