Skip to content

Commit a935b59

Browse files
shayshyigregkh
authored andcommitted
net/mlx5: Serialize firmware reset with devlink
[ Upstream commit 367e501 ] The firmware reset mechanism can be triggered by asynchronous events, which may race with other devlink operations like devlink reload or devlink dev eswitch set, potentially leading to inconsistent states. This patch addresses the race by using the devl_lock to serialize the firmware reset against other devlink operations. When a reset is requested, the driver attempts to acquire the lock. If successful, it sets a flag to block devlink reload or eswitch changes, ACKs the reset to firmware and then releases the lock. If the lock is already held by another operation, the driver NACKs the firmware reset request, indicating that the reset cannot proceed. Firmware reset does not keep the devl_lock and instead uses an internal firmware reset bit. This is because firmware resets can be triggered by asynchronous events, and processed in different threads. It is illegal and unsafe to acquire a lock in one thread and attempt to release it in another, as lock ownership is intrinsically thread-specific. This change ensures that firmware resets and other devlink operations are mutually exclusive during the critical reset request phase, preventing race conditions. Fixes: 38b9f90 ("net/mlx5: Handle sync reset request event") Signed-off-by: Shay Drory <shayd@nvidia.com> Reviewed-by: Mateusz Berezecki <mberezecki@nvidia.com> Reviewed-by: Moshe Shemesh <moshe@nvidia.com> Signed-off-by: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/1765284977-1363052-6-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent d173741 commit a935b59

4 files changed

Lines changed: 53 additions & 4 deletions

File tree

drivers/net/ethernet/mellanox/mlx5/core/devlink.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change,
197197
struct pci_dev *pdev = dev->pdev;
198198
int ret = 0;
199199

200+
if (mlx5_fw_reset_in_progress(dev)) {
201+
NL_SET_ERR_MSG_MOD(extack, "Can't reload during firmware reset");
202+
return -EBUSY;
203+
}
204+
200205
if (mlx5_dev_is_lightweight(dev)) {
201206
if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
202207
return -EOPNOTSUPP;

drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "devlink.h"
5353
#include "lag/lag.h"
5454
#include "en/tc/post_meter.h"
55+
#include "fw_reset.h"
5556

5657
/* There are two match-all miss flows, one for unicast dst mac and
5758
* one for multicast.
@@ -3807,6 +3808,11 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
38073808
if (IS_ERR(esw))
38083809
return PTR_ERR(esw);
38093810

3811+
if (mlx5_fw_reset_in_progress(esw->dev)) {
3812+
NL_SET_ERR_MSG_MOD(extack, "Can't change eswitch mode during firmware reset");
3813+
return -EBUSY;
3814+
}
3815+
38103816
if (esw_mode_from_devlink(mode, &mlx5_mode))
38113817
return -EINVAL;
38123818

drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum {
1515
MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS,
1616
MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED,
1717
MLX5_FW_RESET_FLAGS_UNLOAD_EVENT,
18+
MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS,
1819
};
1920

2021
struct mlx5_fw_reset {
@@ -127,6 +128,16 @@ int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_ty
127128
return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL, NULL);
128129
}
129130

131+
bool mlx5_fw_reset_in_progress(struct mlx5_core_dev *dev)
132+
{
133+
struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
134+
135+
if (!fw_reset)
136+
return false;
137+
138+
return test_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags);
139+
}
140+
130141
static int mlx5_fw_reset_get_reset_method(struct mlx5_core_dev *dev,
131142
u8 *reset_method)
132143
{
@@ -242,6 +253,8 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev)
242253
BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE));
243254
devl_unlock(devlink);
244255
}
256+
257+
clear_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags);
245258
}
246259

247260
static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev)
@@ -461,27 +474,48 @@ static void mlx5_sync_reset_request_event(struct work_struct *work)
461474
struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
462475
reset_request_work);
463476
struct mlx5_core_dev *dev = fw_reset->dev;
477+
bool nack_request = false;
478+
struct devlink *devlink;
464479
int err;
465480

466481
err = mlx5_fw_reset_get_reset_method(dev, &fw_reset->reset_method);
467-
if (err)
482+
if (err) {
483+
nack_request = true;
468484
mlx5_core_warn(dev, "Failed reading MFRL, err %d\n", err);
485+
} else if (!mlx5_is_reset_now_capable(dev, fw_reset->reset_method) ||
486+
test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST,
487+
&fw_reset->reset_flags)) {
488+
nack_request = true;
489+
}
469490

470-
if (err || test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) ||
471-
!mlx5_is_reset_now_capable(dev, fw_reset->reset_method)) {
491+
devlink = priv_to_devlink(dev);
492+
/* For external resets, try to acquire devl_lock. Skip if devlink reset is
493+
* pending (lock already held)
494+
*/
495+
if (nack_request ||
496+
(!test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP,
497+
&fw_reset->reset_flags) &&
498+
!devl_trylock(devlink))) {
472499
err = mlx5_fw_reset_set_reset_sync_nack(dev);
473500
mlx5_core_warn(dev, "PCI Sync FW Update Reset Nack %s",
474501
err ? "Failed" : "Sent");
475502
return;
476503
}
504+
477505
if (mlx5_sync_reset_set_reset_requested(dev))
478-
return;
506+
goto unlock;
507+
508+
set_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags);
479509

480510
err = mlx5_fw_reset_set_reset_sync_ack(dev);
481511
if (err)
482512
mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack Failed. Error code: %d\n", err);
483513
else
484514
mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack. Device reset is expected.\n");
515+
516+
unlock:
517+
if (!test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags))
518+
devl_unlock(devlink);
485519
}
486520

487521
static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev, u16 dev_id)
@@ -721,6 +755,8 @@ static void mlx5_sync_reset_abort_event(struct work_struct *work)
721755

722756
if (mlx5_sync_reset_clear_reset_requested(dev, true))
723757
return;
758+
759+
clear_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags);
724760
mlx5_core_warn(dev, "PCI Sync FW Update Reset Aborted.\n");
725761
}
726762

@@ -757,6 +793,7 @@ static void mlx5_sync_reset_timeout_work(struct work_struct *work)
757793

758794
if (mlx5_sync_reset_clear_reset_requested(dev, true))
759795
return;
796+
clear_bit(MLX5_FW_RESET_FLAGS_RESET_IN_PROGRESS, &fw_reset->reset_flags);
760797
mlx5_core_warn(dev, "PCI Sync FW Update Reset Timeout.\n");
761798
}
762799

drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_ty
1010
int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel,
1111
struct netlink_ext_ack *extack);
1212
int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev);
13+
bool mlx5_fw_reset_in_progress(struct mlx5_core_dev *dev);
1314

1415
int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev);
1516
void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked);

0 commit comments

Comments
 (0)