From: Bryan Cochrane <bcochrane@google.com>
To: Michael Chan <michael.chan@broadcom.com>,
Pavan Chebbi <pavan.chebbi@broadcom.com>,
netdev@vger.kernel.org
Cc: Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Stanislav Fomichev <sdf@fomichev.me>, Joe Damato <joe@dama.to>,
linux-kernel@vger.kernel.org,
Bryan Cochrane <bcochrane@google.com>,
stable@vger.kernel.org
Subject: [PATCH net v2] bnxt_en: Take RTNL before netif_close() when aborting FW reset
Date: Mon, 2 Nov 2026 20:22:09 -0800 [thread overview]
Message-ID: <20261103042210.2984373-1-bcochrane@google.com> (raw)
netif_close() must be called with RTNL held in addition to the netdev
instance lock: __dev_close_many() asserts it, and the NETDEV_GOING_DOWN
and NETDEV_DOWN notifier chains it runs rely on it for serialization.
Commit 004b5008016a ("eth: bnxt: remove most dependencies on RTNL")
replaced rtnl_lock() with netdev_lock() in bnxt_fw_reset_task() and
bnxt_fw_reset(). That is sufficient for the paths that only tear the
NIC down internally with __bnxt_close_nic(), but the abort paths close
the netdev via bnxt_fw_reset_abort() -> netif_close(), and the error
path in bnxt_fw_reset() calls netif_close() directly. Those now run
without RTNL and trigger a WARN_ONCE() cascade when a firmware reset is
aborted:
RTNL: assertion failed at net/core/dev.c (1740)
WARNING: net/core/dev.c:1740 at __dev_close_many+0x1be/0x1f0
Workqueue: bnxt_pf_wq bnxt_fw_reset_task [bnxt_en]
Call Trace:
netif_close_many+0xb5/0x190
netif_close+0xa2/0xd0
bnxt_fw_reset_task.cold+0x8d/0x213 [bnxt_en]
process_one_work+0x19d/0x3a0
worker_thread+0x1af/0x320
kthread+0xe3/0x120
followed by the same assertion from call_netdevice_notifiers_info(),
fib_rules_event(), inetdev_event(), rtnl_fill_ifinfo(),
devlink_compat_phys_port_name_get() and ip_mc_down().
This was observed on a machine in real use with a BCM57504 (4 PFs,
FW 236.1.153.0) running v7.1.6: the firmware crashed, announced a
"Fatal firmware reset event" and then failed to come back within the
advertised max wait, so bnxt_fw_reset_task() aborted the reset on all
ports:
bnxt_en 0000:c1:00.1 eno16905np1: Firmware reset aborted
bnxt_en 0000:c1:00.1 eno16905np1: fw_health_status 0x448100
Take RTNL (before the netdev instance lock, matching the OPENING state
which already uses rtnl_trylock()) in the fw_reset_abort path of
bnxt_fw_reset_task() and route the POLL_VF abort through that same
path.
In bnxt_fw_reset() only the error path that closes the device after
bnxt_get_registered_vfs() fails needs RTNL: drop the instance lock,
take RTNL and the instance lock, then clear BNXT_STATE_IN_FW_RESET and
close. The normal reset flow, which may run on many VFs at the same
time, keeps running without RTNL. BNXT_STATE_IN_FW_RESET stays set
across the lock switch, so a concurrent close marks the reset aborted
as it does today and a concurrent recovery request backs off.
The bug was found by inspecting the kernel log of the affected machine
and the driver source; the fix was prepared with the help of an AI
coding assistant (Gemini based) and reviewed by the submitter. It is
build tested (allmodconfig with W=1, plus the same change on top of
v7.1.6 built as a module for the affected BCM57504 host). The aborted
reset path itself only runs when the firmware fails to return from a
reset, which could not be reproduced on demand.
Fixes: 004b5008016a ("eth: bnxt: remove most dependencies on RTNL")
Cc: stable@vger.kernel.org
Signed-off-by: Bryan Cochrane <bcochrane@google.com>
---
v2:
- Keep bnxt_lock_sp() in bnxt_fw_reset() and take RTNL only on the
bnxt_get_registered_vfs() error path, so that the normal FW reset
flow does not add RTNL contention when many VFs recover at the same
time (Michael Chan).
- Dropped Stanislav's Acked-by because of the change above.
v1: https://lore.kernel.org/netdev/20261029032832.1511180-1-bcochrane@google.com/
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 33c4cacc8ffe..1ea1e8266eab 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -14860,9 +14860,16 @@ void bnxt_fw_reset(struct bnxt *bp)
if (n < 0) {
netdev_err(bp->dev, "Firmware reset aborted, rc = %d\n",
n);
+ /* netif_close() requires RTNL, which must be taken
+ * before the netdev instance lock.
+ */
+ netdev_unlock(bp->dev);
+ rtnl_lock();
+ netdev_lock(bp->dev);
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
netif_close(bp->dev);
- goto fw_reset_exit;
+ bnxt_rtnl_unlock_sp(bp);
+ return;
} else if (n > 0) {
u16 vf_tmo_dsecs = n * 10;
@@ -15547,9 +15554,8 @@ static void bnxt_fw_reset_task(struct work_struct *work)
bp->fw_reset_timestamp = jiffies;
netdev_lock(bp->dev);
if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) {
- bnxt_fw_reset_abort(bp, rc);
netdev_unlock(bp->dev);
- goto ulp_start;
+ goto fw_reset_abort;
}
bnxt_fw_reset_close(bp);
if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) {
@@ -15682,9 +15688,11 @@ static void bnxt_fw_reset_task(struct work_struct *work)
netdev_err(bp->dev, "fw_health_status 0x%x\n", sts);
}
fw_reset_abort:
+ rtnl_lock();
netdev_lock(bp->dev);
bnxt_fw_reset_abort(bp, rc);
netdev_unlock(bp->dev);
+ rtnl_unlock();
ulp_start:
if (!rc)
bnxt_ulp_start(bp);
base-commit: c3e67bd82b9b9b1a5118f09a429ccefe2aab0741
--
2.56.0.385.gac671c819a-goog
next reply other threads:[~2026-11-03 4:22 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 4:22 Bryan Cochrane [this message]
2026-11-03 18:26 ` [PATCH net v2] bnxt_en: Take RTNL before netif_close() when aborting FW reset Michael Chan
2026-11-03 20:10 ` Stanislav Fomichev
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=20261103042210.2984373-1-bcochrane@google.com \
--to=bcochrane@google.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=joe@dama.to \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.chan@broadcom.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pavan.chebbi@broadcom.com \
--cc=sdf@fomichev.me \
--cc=stable@vger.kernel.org \
/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