Skip to content

Commit 367e501

Browse files
shayshyiPaolo Abeni
authored andcommitted
net/mlx5: Serialize firmware reset with devlink
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>
1 parent c0289f6 commit 367e501

File tree

4 files changed

+53
-4
lines changed

4 files changed

+53
-4
lines changed

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.
@@ -3991,6 +3992,11 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
39913992
if (IS_ERR(esw))
39923993
return PTR_ERR(esw);
39933994

3995+
if (mlx5_fw_reset_in_progress(esw->dev)) {
3996+
NL_SET_ERR_MSG_MOD(extack, "Can't change eswitch mode during firmware reset");
3997+
return -EBUSY;
3998+
}
3999+
39944000
if (esw_mode_from_devlink(mode, &mlx5_mode))
39954001
return -EINVAL;
39964002

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 {
@@ -128,6 +129,16 @@ int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_ty
128129
return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL, NULL);
129130
}
130131

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

248261
static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev)
@@ -462,27 +475,48 @@ static void mlx5_sync_reset_request_event(struct work_struct *work)
462475
struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
463476
reset_request_work);
464477
struct mlx5_core_dev *dev = fw_reset->dev;
478+
bool nack_request = false;
479+
struct devlink *devlink;
465480
int err;
466481

467482
err = mlx5_fw_reset_get_reset_method(dev, &fw_reset->reset_method);
468-
if (err)
483+
if (err) {
484+
nack_request = true;
469485
mlx5_core_warn(dev, "Failed reading MFRL, err %d\n", err);
486+
} else if (!mlx5_is_reset_now_capable(dev, fw_reset->reset_method) ||
487+
test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST,
488+
&fw_reset->reset_flags)) {
489+
nack_request = true;
490+
}
470491

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

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

488522
static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev, u16 dev_id)
@@ -722,6 +756,8 @@ static void mlx5_sync_reset_abort_event(struct work_struct *work)
722756

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

@@ -758,6 +794,7 @@ static void mlx5_sync_reset_timeout_work(struct work_struct *work)
758794

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

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)