FAILED: patch "[PATCH] bnxt_en: Handle buffer allocation failure in" failed to apply to 6.18-stable tree
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 961e2a17c5e3559b3f8654d2daabdd25a42e770a
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091648-flakily-icing-f492@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 961e2a17c5e3559b3f8654d2daabdd25a42e770a Mon Sep 17 00:00:00 2001
From: Joe Damato <[email protected]>
Date: Tue, 1 Sep 2026 18:56:47 -0700
Subject: [PATCH] bnxt_en: Handle buffer allocation failure in
bnxt_rx_ring_reset()
bnxt_rx_ring_reset() frees the ring buffers and then reallocates them, ignoring the result.
bnxt_alloc_one_rx_ring() can fail in bnxt_alloc_one_tpa_info_data(), which returns -ENOMEM on the first failed allocation and leaves the remaining rxr->rx_tpa[] entries zeroed.
The error isn't propagated up, so the loop in bnxt_rx_ring_reset continues and at the end the code re-enables TPA with partially unallocated rx_tpa array.
This means that when the agg_id from hardware is mapped to a SW index in rxr->rx_tpa[], an uninitialized slot can be chosen which would hand a zero DMA address to the device.
Fix this by falling back to a global reset, which is what the existing code already does when other functions fail, but unlike the other failure cases this particular failure has to return because TPA can't be re-enabled since the allocation failed.
drivers/net/ethernet/broadcom/bnxt/bnxt.c +8 -1
@@ -14628,7 +14628,14 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) rxr->rx_sw_agg_prod =0 ; rxr->rx_next_cons =0 ; rxr->bnapi->in_reset = false; -bnxt_alloc_one_rx_ring (bp, i); + rc =bnxt_alloc_one_rx_ring (bp, i); +if (rc) { +netdev_warn (bp->dev,"RX ring reset failed to allocate buffers, rc = %d, falling back to global reset\n" , + rc); +bnxt_reset_task (bp, true); +bnxt_rtnl_unlock_sp (bp); +return ; + } cpr = &rxr->bnapi->cp_ring; cpr->sw_stats->rx.rx_resets++;if (bp->flags &BNXT_FLAG_AGG_RINGS )
Sasha Levin
maintainerPATCH 1/3 fwctl/bnxt_en: Move common definitions to include/linux/bnxt/
From: Pavan Chebbi <[email protected]>
[ Upstream commit 7be18a1fa00eab5283b35c13e26c6b76fcaab9ce ]
We have common definitions that are now going to be used by more than one component outside of bnxt (bnxt_re and fwctl)
Move bnxt_ulp.h to include/linux/bnxt/ as ulp.h.
Stable-dep-of: 961e2a17c5e3 ("bnxt_en: Handle buffer allocation failure in bnxt_rx_ring_reset()")
--- drivers/infiniband/hw/bnxt_re/debugfs.c | 2 +- drivers/infiniband/hw/bnxt_re/main.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.h | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 2 +- .../broadcom/bnxt/bnxt_ulp.h => include/linux/bnxt/ulp.h | 0 10 files changed, 9 insertions(+), 9 deletions(-) rename drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h => include/linux/bnxt/ulp.h (100%)
drivers/infiniband/hw/bnxt_re/debugfs.c +1 -1
@@ -10,8 +10,8 @@#include <linux/pci.h> #include <linux/seq_file.h> #include <rdma/ib_addr.h> +#include <linux/bnxt/ulp.h> -#include "bnxt_ulp.h" #include "roce_hsi.h" #include "qplib_res.h" #include "qplib_sp.h"
drivers/infiniband/hw/bnxt_re/main.c +1 -1
@@ -55,8 +55,8 @@#include <rdma/ib_umem.h> #include <rdma/ib_addr.h> #include <linux/hashtable.h> +#include <linux/bnxt/ulp.h> -#include "bnxt_ulp.h" #include "roce_hsi.h" #include "qplib_res.h" #include "qplib_sp.h"
drivers/infiniband/hw/bnxt_re/qplib_fp.c +1 -1
@@ -46,6 +46,7 @@#include <linux/delay.h> #include <linux/prefetch.h> #include <linux/if_ether.h> +#include <linux/bnxt/ulp.h> #include <rdma/ib_mad.h> #include "roce_hsi.h"
@@ -55,7 +56,6 @@#include "qplib_sp.h" #include "qplib_fp.h" #include <rdma/ib_addr.h> -#include "bnxt_ulp.h" #include "bnxt_re.h" #include "ib_verbs.h"
drivers/infiniband/hw/bnxt_re/qplib_res.h +1 -1
@@ -39,7 +39,7 @@#ifndef __BNXT_QPLIB_RES_H__#define __BNXT_QPLIB_RES_H__ -#include "bnxt_ulp.h" +#include <linux/bnxt/ulp.h> extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;
drivers/net/ethernet/broadcom/bnxt/bnxt.c +1 -1
@@ -59,10 +59,10 @@#include <net/netdev_rx_queue.h> #include <linux/pci-tph.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" #include "bnxt_sriov.h" #include "bnxt_ethtool.h" #include "bnxt_dcb.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +1 -1
@@ -13,12 +13,12 @@#include <net/devlink.h> #include <net/netdev_lock.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" #include "bnxt_vfr.h" #include "bnxt_devlink.h" #include "bnxt_ethtool.h" -#include "bnxt_ulp.h" #include "bnxt_ptp.h" #include "bnxt_coredump.h" #include "bnxt_nvm_defs.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +1 -1
@@ -27,9 +27,9 @@#include <net/netdev_queues.h> #include <net/netlink.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" #include "bnxt_xdp.h" #include "bnxt_ptp.h" #include "bnxt_ethtool.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +1 -1
@@ -17,9 +17,9 @@#include <linux/etherdevice.h> #include <net/dcbnl.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" #include "bnxt_sriov.h" #include "bnxt_vfr.h" #include "bnxt_ethtool.h"
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +1 -1
@@ -22,10 +22,10 @@#include <linux/auxiliary_bus.h> #include <net/netdev_lock.h> #include <linux/bnxt/hsi.h> +#include <linux/bnxt/ulp.h> #include "bnxt.h" #include "bnxt_hwrm.h" -#include "bnxt_ulp.h" static DEFINE_IDA (bnxt_aux_dev_ids);
include/linux/bnxt/ulp.h renamed from drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +0 -0
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 Reapply "bnxt_en: bring back rtnl_lock() in the bnxt_open() path"
From: Jakub Kicinski <[email protected]>
[ Upstream commit b6197b386677ae5268d4702e23849d9ad53051ad ]
This reverts commit 850d9248d2eac662f869c766a598c877690c74e5. This reapplies commit 325eb217e41f ("bnxt_en: bring back rtnl_lock() in the bnxt_open() path").
Breno reports a lockdep warning in bnxt. During FW reset the driver may end up calling netif_set_real_num_tx_queues() (if queue count changes), so calls to bnxt_open() still require rtnl_lock.
net/sched/sch_generic.c:1416 suspicious rcu_dereference_protected() usage!
dev_qdisc_change_real_num_tx+0x54/0xe0 netif_set_real_num_tx_queues+0x4ed/0xa80 __bnxt_open_nic+0x9cb/0x3490 bnxt_open+0x1cb/0x370 bnxt_fw_reset_task+0x80d/0x1e80 process_scheduled_works+0x9c1/0x13b0
The reverted commit was just an optimization / experiment so let's go back to taking the lock.
Stable adaptation for dependency of 961e2a17c5e3559b3f8654d2daabdd25a42e770a:
Keep this branch's two-argument bnxt_ulp_start() calls, including error notifications, and release RTNL before invoking them.
Reuse and rename the existing service-task lock/unlock helpers to add RTNL coverage without adding functions. Inline their original netdev-only operations in bnxt_fw_exception() and bnxt_fw_reset() so those paths keep their existing locking and BNXT_STATE_IN_SP_TASK ordering. The RX reset path then provides the bnxt_rtnl_unlock_sp() required by the target's buffer-allocation failure handling.
Stable-dep-of: 961e2a17c5e3 ("bnxt_en: Handle buffer allocation failure in bnxt_rx_ring_reset()")
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 44 ++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +28 -16
@@ -14271,31 +14271,32 @@ static void bnxt_timer(struct timer_list *t)mod_timer (&bp->timer, jiffies + bp->current_interval); } -static void bnxt_lock_sp (struct bnxt *bp) +static void bnxt_rtnl_lock_sp (struct bnxt *bp) {/* We are called from bnxt_sp_task which has BNXT_STATE_IN_SP_TASK * set. If the device is being closed, bnxt_close() may be holding -* netdev instance lock and waiting for BNXT_STATE_IN_SP_TASK to clear. -* So we must clear BNXT_STATE_IN_SP_TASK before holding netdev -* instance lock. +* RTNL and the netdev instance lock while waiting for +* BNXT_STATE_IN_SP_TASK to clear. Clear it before taking either lock. */ clear_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +rtnl_lock ();netdev_lock (bp->dev); } -static void bnxt_unlock_sp (struct bnxt *bp) +static void bnxt_rtnl_unlock_sp (struct bnxt *bp) {set_bit (BNXT_STATE_IN_SP_TASK , &bp->state);netdev_unlock (bp->dev); +rtnl_unlock (); }/* Only called from bnxt_sp_task() */ static void bnxt_reset (struct bnxt *bp,bool silent) { -bnxt_lock_sp (bp); +bnxt_rtnl_lock_sp (bp);if (test_bit (BNXT_STATE_OPEN , &bp->state))bnxt_reset_task (bp, silent); -bnxt_unlock_sp (bp); +bnxt_rtnl_unlock_sp (bp); }/* Only called from bnxt_sp_task() */
@@ -14303,9 +14304,9 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) {int i; -bnxt_lock_sp (bp); +bnxt_rtnl_lock_sp (bp);if (!test_bit (BNXT_STATE_OPEN , &bp->state)) { -bnxt_unlock_sp (bp); +bnxt_rtnl_unlock_sp (bp);return ; }/* Disable and flush TPA before resetting the RX ring */
@@ -14344,7 +14345,7 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) }if (bp->flags &BNXT_FLAG_TPA )bnxt_set_tpa (bp, true); -bnxt_unlock_sp (bp); +bnxt_rtnl_unlock_sp (bp); }static void bnxt_fw_fatal_close (struct bnxt *bp)
@@ -14443,9 +14444,11 @@ void bnxt_fw_exception(struct bnxt *bp)netdev_warn (bp->dev,"Detected firmware fatal condition, initiating reset\n" );set_bit (BNXT_STATE_FW_FATAL_COND , &bp->state);bnxt_ulp_stop (bp); -bnxt_lock_sp (bp); +clear_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_lock (bp->dev);bnxt_force_fw_reset (bp); -bnxt_unlock_sp (bp); +set_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_unlock (bp->dev); }/* Returns the number of registered VFs, or 1 if VF configuration is pending, or
@@ -14475,7 +14478,8 @@ static int bnxt_get_registered_vfs(struct bnxt *bp)void bnxt_fw_reset (struct bnxt *bp) {bnxt_ulp_stop (bp); -bnxt_lock_sp (bp); +clear_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_lock (bp->dev);if (test_bit (BNXT_STATE_OPEN , &bp->state) && !test_bit (BNXT_STATE_IN_FW_RESET , &bp->state)) {struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
@@ -14521,7 +14525,8 @@ void bnxt_fw_reset(struct bnxt *bp)bnxt_queue_fw_reset_work (bp, tmo); } fw_reset_exit: -bnxt_unlock_sp (bp); +set_bit (BNXT_STATE_IN_SP_TASK , &bp->state); +netdev_unlock (bp->dev); }static void bnxt_chk_missed_irq (struct bnxt *bp)
@@ -15257,15 +15262,17 @@ static void bnxt_fw_reset_task(struct work_struct *work) bp->fw_reset_state =BNXT_FW_RESET_STATE_OPENING ; fallthrough;case BNXT_FW_RESET_STATE_OPENING : -while (!netdev_trylock (bp->dev)) { +while (!rtnl_trylock ()) {bnxt_queue_fw_reset_work (bp,HZ /10 );return ; } +netdev_lock (bp->dev); rc =bnxt_open (bp->dev);if (rc) {netdev_err (bp->dev,"bnxt_open() failed during FW reset\n" );bnxt_fw_reset_abort (bp, rc);netdev_unlock (bp->dev); +rtnl_unlock (); goto ulp_start; }
@@ -15285,6 +15292,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)bnxt_dl_health_fw_status_update (bp, true); }netdev_unlock (bp->dev); +rtnl_unlock ();bnxt_ulp_start (bp,0 );bnxt_reenable_sriov (bp);netdev_lock (bp->dev);
@@ -16273,7 +16281,7 @@ static int bnxt_queue_start(struct net_device *dev, rc);napi_enable_locked (&bnapi->napi);bnxt_db_nq_arm (bp, &cpr->cp_db, cpr->cp_raw_cons); -bnxt_reset_task (bp, true); +netif_close (dev);return rc; }
@@ -17101,6 +17109,7 @@ static int bnxt_resume(struct device *device)struct bnxt *bp =netdev_priv (dev);int rc =0 ; +rtnl_lock ();netdev_lock (dev); rc =pci_enable_device (bp->pdev);if (rc) {
@@ -17145,6 +17154,7 @@ static int bnxt_resume(struct device *device) resume_exit:netdev_unlock (bp->dev); +rtnl_unlock ();bnxt_ulp_start (bp, rc);if (!rc)bnxt_reenable_sriov (bp);
@@ -17310,6 +17320,7 @@ static void bnxt_io_resume(struct pci_dev *pdev)int err;netdev_info (bp->dev,"PCI Slot Resume\n" ); +rtnl_lock ();netdev_lock (netdev); err =bnxt_hwrm_func_qcaps (bp);
@@ -17327,6 +17338,7 @@ static void bnxt_io_resume(struct pci_dev *pdev)netif_device_attach (netdev);netdev_unlock (netdev); +rtnl_unlock ();bnxt_ulp_start (bp, err);if (!err)bnxt_reenable_sriov (bp);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 bnxt_en: Handle buffer allocation failure in bnxt_rx_ring_reset()
In reply to Sasha LevinFrom: Joe Damato <[email protected]>
[ Upstream commit 961e2a17c5e3559b3f8654d2daabdd25a42e770a ]
bnxt_rx_ring_reset() frees the ring buffers and then reallocates them, ignoring the result.
bnxt_alloc_one_rx_ring() can fail in bnxt_alloc_one_tpa_info_data(), which returns -ENOMEM on the first failed allocation and leaves the remaining rxr->rx_tpa[] entries zeroed.
The error isn't propagated up, so the loop in bnxt_rx_ring_reset continues and at the end the code re-enables TPA with partially unallocated rx_tpa array.
This means that when the agg_id from hardware is mapped to a SW index in rxr->rx_tpa[], an uninitialized slot can be chosen which would hand a zero DMA address to the device.
Fix this by falling back to a global reset, which is what the existing code already does when other functions fail, but unlike the other failure cases this particular failure has to return because TPA can't be re-enabled since the allocation failed.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +8 -1
@@ -14336,7 +14336,14 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) rxr->rx_sw_agg_prod =0 ; rxr->rx_next_cons =0 ; rxr->bnapi->in_reset = false; -bnxt_alloc_one_rx_ring (bp, i); + rc =bnxt_alloc_one_rx_ring (bp, i); +if (rc) { +netdev_warn (bp->dev,"RX ring reset failed to allocate buffers, rc = %d, falling back to global reset\n" , + rc); +bnxt_reset_task (bp, true); +bnxt_rtnl_unlock_sp (bp); +return ; + } cpr = &rxr->bnapi->cp_ring; cpr->sw_stats->rx.rx_resets++;if (bp->flags &BNXT_FLAG_AGG_RINGS )
Signature · 1 line
2.53.0