From: Simon Horman <horms@kernel.org>
To: vikas.gupta@broadcom.com
Cc: Simon Horman <horms@kernel.org>,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, andrew+netdev@lunn.ch, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, bhargava.marreddy@broadcom.com,
rahul-rg.gupta@broadcom.com, vsrama-krishna.nemani@broadcom.com,
rajashekar.hudumula@broadcom.com, dharmender.garg@broadcom.com,
ajit.khaparde@broadcom.com
Subject: Re: [PATCH net] bnge: add missing ndo_set_features
Date: Wed, 26 Aug 2026 13:30:20 +0100 [thread overview]
Message-ID: <20260826123020.350008-1-horms@kernel.org> (raw)
In-Reply-To: <20260824085028.1174150-1-vikas.gupta@broadcom.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824085028.1174150-1-vikas.gupta@broadcom.com?part=1
---
bnge: add missing ndo_set_features
This adds a bnge_set_features() callback so that toggling LRO/GRO_HW via
ethtool -K actually reprograms the TPA engine. On a running interface it
recomputes bn->priv_flags, then tears down and re-opens the datapath with
bnge_close_core() followed by bnge_set_ring_params() and bnge_open_core().
A few questions about the reconfiguration sequence below.
> diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
> index a4288f0258f87..0973cc25a3ec4 100644
> --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
> +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
> @@ -3267,6 +3267,33 @@ static const struct netdev_stat_ops bnge_stat_ops = {
> .get_base_stats = bnge_get_base_stats,
> };
>
> +static int bnge_set_features(struct net_device *dev, netdev_features_t features)
> +{
> + struct bnge_net *bn = netdev_priv(dev);
> + struct bnge_dev *bd = bn->bd;
> + u32 flags = bn->priv_flags;
> +
> + flags &= ~BNGE_NET_EN_TPA;
> + if (features & NETIF_F_GRO_HW)
> + flags |= BNGE_NET_EN_GRO;
> + else if (features & NETIF_F_LRO)
> + flags |= BNGE_NET_EN_LRO;
> +
> + if (flags == bn->priv_flags)
> + return 0;
> +
> + bn->priv_flags = flags;
^^^^^^^^^^^^^^^^^^^^^
[Severity: Medium]
Is it safe to publish the new TPA mode here, before the datapath has been
quiesced? At this point NAPI is still running; bnge_disable_napi() is only
reached later, inside bnge_close_core().
The RX completion path reads the same word from softirq context with no
lock:
drivers/net/ethernet/broadcom/bnge/bnge_txrx.c:bnge_tpa_end() {
...
#ifdef CONFIG_INET
if (bn->priv_flags & BNGE_NET_EN_GRO)
skb = bnge_gro_skb(bn, tpa_info, tpa_end, tpa_end1, skb);
#endif
...
}
So an aggregation that was started (TPA_START) while the VNIC was still
programmed for the old mode can be completed using the new flag value, and
bnge_gro_func() will then derive skb_set_network_header()/
skb_set_transport_header() offsets from TPA_START metadata that was produced
under the previous configuration.
bnxt_reinit_features() orders this the other way round - it closes first and
publishes afterwards:
drivers/net/ethernet/broadcom/bnxt/bnxt.c:bnxt_reinit_features() {
bnxt_close_nic(bp, irq_re_init, link_re_init);
bp->flags = flags;
if (update_tpa)
bnxt_set_ring_params(bp);
return bnxt_open_nic(bp, irq_re_init, link_re_init);
}
Would moving the bn->priv_flags store below bnge_close_core() be preferable?
> +
> + if (!netif_running(dev)) {
> + bnge_set_ring_params(bd);
> + return 0;
> + }
> +
> + bnge_close_core(bn);
> + bnge_set_ring_params(bd);
> + return bnge_open_core(bn);
^^^^^^^^^^^^^^^^^^^^^^^
[Severity: High]
Can a failing bnge_open_core() here leave the netdev running over a freed
datapath?
Every error exit in bnge_open_core() frees the core and tells firmware the
interface went down:
drivers/net/ethernet/broadcom/bnge/bnge_netdev.c:bnge_open_core() {
...
err_free_irq:
bnge_free_irq(bn);
err_del_napi:
bnge_del_napi(bn);
bnge_free_core(bn);
err_if_change:
bnge_hwrm_if_change(bd, false);
return rc;
}
bnge_free_core() NULLs bn->vnic_info (via bnge_free_vnics()), bn->grp_info,
bn->tx_ring, bn->rx_ring and bn->bnapi.
The core does not close the device when ndo_set_features returns an error:
net/core/dev.c:__netdev_update_features() {
...
if (unlikely(err < 0)) {
netdev_err(dev,
"set_features() failed (%d); wanted %pNF, left %pNF\n",
err, &features, &dev->features);
return -1;
}
...
}
So netif_running() stays true, and the next teardown re-enters
bnge_close_core() on that freed state. bnge_close_core() has no guard, and
bnge_shutdown_nic()->bnge_hwrm_resource_free()->bnge_clear_vnic()->
bnge_hwrm_clear_vnic_filter() starts with:
struct bnge_vnic_info *vnic = &bn->vnic_info[BNGE_VNIC_DEFAULT];
int i;
for (i = 0; i < vnic->uc_filter_count; i++) {
which reads through a NULL bn->vnic_info. bnge_save_ring_stats()
(bn->bnapi[i]), bnge_del_napi() (bn->bnapi[i]) and bnge_free_tx_skbs()
(&bn->tx_ring[i], then txr->tx_buf_ring, unlike
bnge_free_rx_ring_pair_bufs()/bnge_tx_disable() which do test for NULL) are
on the same path.
Two easy second-teardown triggers: ip link set ethX down -> bnge_close(),
which calls bnge_close_core() unconditionally, and simply repeating
ethtool -K, since bnge_set_features() only gates on netif_running().
bnxt_open_nic() forces the device closed in this situation:
drivers/net/ethernet/broadcom/bnxt/bnxt.c:bnxt_open_nic() {
...
if (rc) {
netdev_err(bp->dev, "nic open fail (rc: %x)\n", rc);
netif_close(bp->dev);
}
...
}
Should bnge_set_features() do the same on a failed re-open?
[Severity: Medium]
Related to the above: on that failure bn->priv_flags keeps the new value and
bnge_set_ring_params() has already recomputed rx_agg_ring_size /
rx_buf_size / cp_ring_size for it, while __netdev_update_features() leaves
dev->features at the old value.
If the user then repeats the same ethtool -K command, the recomputed flags
now equal bn->priv_flags, so:
if (flags == bn->priv_flags)
return 0;
returns success without touching hardware, and the core commits
dev->features. Isn't that the same "dev->features no longer reflects the
actual hardware state" mismatch the commit message sets out to fix?
bnxt_set_features() restores the private flag word when the hardware step
fails:
drivers/net/ethernet/broadcom/bnxt/bnxt.c:bnxt_set_features() {
...
rc = bnxt_set_tpa(bp, (flags & BNXT_FLAG_TPA) ? true : false);
if (rc)
bp->flags = old_flags;
...
}
[Severity: Medium]
Does this pairing produce an unbalanced FUNC_DRV_IF_CHANGE handshake?
bnge_open_core() starts with bnge_hwrm_if_change(bd, true), but the matching
DOWN notification lives only in ndo_stop:
drivers/net/ethernet/broadcom/bnge/bnge_netdev.c:bnge_close() {
bnge_close_core(bn);
bnge_hwrm_shutdown_link(bn->bd);
bnge_hwrm_if_change(bn->bd, false);
}
bnge_close_core() does not issue it, so every ethtool -K toggle on a running
interface sends a second UP with no intervening DOWN.
bnge_hwrm_if_change() also discards the response:
if (up)
req->flags = cpu_to_le32(FUNC_DRV_IF_CHANGE_REQ_FLAGS_UP);
return bnge_hwrm_req_send(bd, req);
so any resource-change or hot-FW-reset indication firmware returns on that
extra UP is lost, and bnge_reserve_rings() runs immediately afterwards on
the driver's existing reservation bookkeeping.
bnxt keeps the handshake at the ndo_open/ndo_stop level only -
bnxt_reinit_features() calls bnxt_close_nic()/bnxt_open_nic() and never
bnxt_hwrm_if_change(). Would it make sense to keep bnge_hwrm_if_change()
out of the reinit path here as well?
> +}
> +
> static const struct net_device_ops bnge_netdev_ops = {
> .ndo_open = bnge_open,
> .ndo_stop = bnge_close,
[ ... ]
prev parent reply other threads:[~2026-08-26 12:30 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 8:50 [PATCH net] bnge: add missing ndo_set_features Vikas Gupta
2026-08-26 12:30 ` Simon Horman [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260826123020.350008-1-horms@kernel.org \
--to=horms@kernel.org \
--cc=ajit.khaparde@broadcom.com \
--cc=andrew+netdev@lunn.ch \
--cc=bhargava.marreddy@broadcom.com \
--cc=davem@davemloft.net \
--cc=dharmender.garg@broadcom.com \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rahul-rg.gupta@broadcom.com \
--cc=rajashekar.hudumula@broadcom.com \
--cc=vikas.gupta@broadcom.com \
--cc=vsrama-krishna.nemani@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox