mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 11:06:41 -05:00
Merge branch 'expose-burst-period-for-devlink-health-reporter'
Mark Bloch says: ==================== Expose burst period for devlink health reporter Shahar writes: -------------------------------------------------------------------------- Currently, the devlink health reporter initiates the grace period immediately after recovering an error, which blocks further recovery attempts until the grace period concludes. Since additional errors are not generally expected during this short interval, any new error reported during the grace period is not only rejected but also causes the reporter to enter an error state that requires manual intervention. This approach poses a problem in scenarios where a single root cause triggers multiple related errors in quick succession - for example, a PCI issue affecting multiple hardware queues. Because these errors are closely related and occur rapidly, it is more effective to handle them together rather than handling only the first one reported and blocking any subsequent recovery attempts. Furthermore, setting the reporter to an error state in this context can be misleading, as these multiple errors are manifestations of a single underlying issue, making it unlike the general case where additional errors are not expected during the grace period. To resolve this, introduce a configurable burst period attribute to the devlink health reporter. This period starts when the first error is recovered and lasts for a user-defined duration. Once this error burst period expires, the grace period begins. After the grace period ends, a new reported error will start the same flow again. Timeline summary: ----|--------|------------------------------/----------------------/-- error is error is burst period grace period reported recovered (recoveries allowed) (recoveries blocked) With burst period, create a time window during which recovery attempts are permitted, allowing all reported errors to be handled sequentially before the grace period starts. Once the grace period begins, it prevents any further error recoveries until it ends. When burst period is set to 0, current behavior is preserved. Design alternatives considered: 1. Recover all queues upon any error: A brute-force approach that recovers all queues on any error. While simple, it is overly aggressive and disrupts unaffected queues unnecessarily. Also, because this is handled entirely within the driver, it leads to a driver-specific implementation rather than a generic one. 2. Per-queue reporter: This design would isolate recovery handling per SQ or RQ, effectively removing interdependencies between queues. While conceptually clean, it introduces significant scalability challenges as the number of queues grows, as well as synchronization challenges across multiple reporters. 3. Error aggregation with delayed handling: Errors arriving during the grace period are saved and processed after it ends. While addressing the issue of related errors whose recovery is aborted as grace period started, this adds complexity due to synchronization needs and contradicts the assumption that no errors should occur during a healthy system’s grace period. Also, this breaks the important role of grace period in preventing an infinite loop of immediate error detection following recovery. In such cases we want to stop. 4. Allowing a fixed burst of errors before starting grace period: Allows a set number of recoveries before the grace period begins. However, it also requires limiting the error reporting window. To keep the design simple, the burst threshold becomes redundant. The burst period design was chosen for its simplicity and precision in addressing the problem at hand. It effectively captures the temporal correlation of related errors and aligns with the original intent of the grace period as a stabilization window where further errors are unexpected, and if they do occur, they indicate an abnormal system state. v3: https://lore.kernel.org/1755111349-416632-1-git-send-email-tariqt@nvidia.com v2: https://lore.kernel.org/1753390134-345154-1-git-send-email-tariqt@nvidia.com v1: https://lore.kernel.org/1752768442-264413-1-git-send-email-tariqt@nvidia.com ==================== Link: https://patch.msgid.link/20250824084354.533182-1-mbloch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -853,6 +853,10 @@ attribute-sets:
|
||||
type: nest
|
||||
multi-attr: true
|
||||
nested-attributes: dl-rate-tc-bws
|
||||
-
|
||||
name: health-reporter-burst-period
|
||||
type: u64
|
||||
doc: Time (in msec) for recoveries before starting the grace period.
|
||||
-
|
||||
name: dl-dev-stats
|
||||
subset-of: devlink
|
||||
@@ -1216,6 +1220,8 @@ attribute-sets:
|
||||
name: health-reporter-dump-ts-ns
|
||||
-
|
||||
name: health-reporter-auto-dump
|
||||
-
|
||||
name: health-reporter-burst-period
|
||||
|
||||
-
|
||||
name: dl-attr-stats
|
||||
@@ -1961,6 +1967,7 @@ operations:
|
||||
- health-reporter-graceful-period
|
||||
- health-reporter-auto-recover
|
||||
- health-reporter-auto-dump
|
||||
- health-reporter-burst-period
|
||||
|
||||
-
|
||||
name: health-reporter-recover
|
||||
|
||||
@@ -50,7 +50,7 @@ Once an error is reported, devlink health will perform the following actions:
|
||||
* Auto recovery attempt is being done. Depends on:
|
||||
|
||||
- Auto-recovery configuration
|
||||
- Grace period vs. time passed since last recover
|
||||
- Grace period (and burst period) vs. time passed since last recover
|
||||
|
||||
Devlink formatted message
|
||||
=========================
|
||||
|
||||
@@ -280,7 +280,7 @@ static int pdsc_init_pf(struct pdsc *pdsc)
|
||||
goto err_out_del_dev;
|
||||
}
|
||||
|
||||
hr = devl_health_reporter_create(dl, &pdsc_fw_reporter_ops, 0, pdsc);
|
||||
hr = devl_health_reporter_create(dl, &pdsc_fw_reporter_ops, pdsc);
|
||||
if (IS_ERR(hr)) {
|
||||
devl_unlock(dl);
|
||||
dev_warn(pdsc->dev, "Failed to create fw reporter: %pe\n", hr);
|
||||
|
||||
@@ -220,7 +220,7 @@ __bnxt_dl_reporter_create(struct bnxt *bp,
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
reporter = devlink_health_reporter_create(bp->dl, ops, 0, bp);
|
||||
reporter = devlink_health_reporter_create(bp->dl, ops, bp);
|
||||
if (IS_ERR(reporter)) {
|
||||
netdev_warn(bp->dev, "Failed to create %s health reporter, rc = %ld\n",
|
||||
ops->name, PTR_ERR(reporter));
|
||||
|
||||
@@ -443,8 +443,9 @@ int hinic_health_reporters_create(struct hinic_devlink_priv *priv)
|
||||
struct devlink *devlink = priv_to_devlink(priv);
|
||||
|
||||
priv->hw_fault_reporter =
|
||||
devlink_health_reporter_create(devlink, &hinic_hw_fault_reporter_ops,
|
||||
0, priv);
|
||||
devlink_health_reporter_create(devlink,
|
||||
&hinic_hw_fault_reporter_ops,
|
||||
priv);
|
||||
if (IS_ERR(priv->hw_fault_reporter)) {
|
||||
dev_warn(&priv->hwdev->hwif->pdev->dev, "Failed to create hw fault reporter, err: %ld\n",
|
||||
PTR_ERR(priv->hw_fault_reporter));
|
||||
@@ -452,8 +453,9 @@ int hinic_health_reporters_create(struct hinic_devlink_priv *priv)
|
||||
}
|
||||
|
||||
priv->fw_fault_reporter =
|
||||
devlink_health_reporter_create(devlink, &hinic_fw_fault_reporter_ops,
|
||||
0, priv);
|
||||
devlink_health_reporter_create(devlink,
|
||||
&hinic_fw_fault_reporter_ops,
|
||||
priv);
|
||||
if (IS_ERR(priv->fw_fault_reporter)) {
|
||||
dev_warn(&priv->hwdev->hwif->pdev->dev, "Failed to create fw fault reporter, err: %ld\n",
|
||||
PTR_ERR(priv->fw_fault_reporter));
|
||||
|
||||
@@ -450,9 +450,8 @@ ice_init_devlink_rep(struct ice_pf *pf,
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(pf);
|
||||
struct devlink_health_reporter *rep;
|
||||
const u64 graceful_period = 0;
|
||||
|
||||
rep = devl_health_reporter_create(devlink, ops, graceful_period, pf);
|
||||
rep = devl_health_reporter_create(devlink, ops, pf);
|
||||
if (IS_ERR(rep)) {
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
|
||||
|
||||
@@ -505,7 +505,9 @@ static int rvu_nix_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
|
||||
rvu_reporters->nix_event_ctx = nix_event_context;
|
||||
rvu_reporters->rvu_hw_nix_intr_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_nix_intr_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_nix_intr_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_nix_intr_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_nix_intr reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_nix_intr_reporter));
|
||||
@@ -513,7 +515,9 @@ static int rvu_nix_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
}
|
||||
|
||||
rvu_reporters->rvu_hw_nix_gen_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_nix_gen_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_nix_gen_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_nix_gen_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_nix_gen reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_nix_gen_reporter));
|
||||
@@ -521,7 +525,9 @@ static int rvu_nix_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
}
|
||||
|
||||
rvu_reporters->rvu_hw_nix_err_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_nix_err_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_nix_err_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_nix_err_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_nix_err reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_nix_err_reporter));
|
||||
@@ -529,7 +535,9 @@ static int rvu_nix_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
}
|
||||
|
||||
rvu_reporters->rvu_hw_nix_ras_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_nix_ras_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_nix_ras_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_nix_ras_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_nix_ras reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_nix_ras_reporter));
|
||||
@@ -1051,7 +1059,9 @@ static int rvu_npa_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
|
||||
rvu_reporters->npa_event_ctx = npa_event_context;
|
||||
rvu_reporters->rvu_hw_npa_intr_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_intr_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_npa_intr_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_npa_intr_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_npa_intr reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_npa_intr_reporter));
|
||||
@@ -1059,7 +1069,9 @@ static int rvu_npa_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
}
|
||||
|
||||
rvu_reporters->rvu_hw_npa_gen_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_gen_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_npa_gen_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_npa_gen_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_npa_gen reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_npa_gen_reporter));
|
||||
@@ -1067,7 +1079,9 @@ static int rvu_npa_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
}
|
||||
|
||||
rvu_reporters->rvu_hw_npa_err_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_err_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_npa_err_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_npa_err_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_npa_err reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_npa_err_reporter));
|
||||
@@ -1075,7 +1089,9 @@ static int rvu_npa_register_reporters(struct rvu_devlink *rvu_dl)
|
||||
}
|
||||
|
||||
rvu_reporters->rvu_hw_npa_ras_reporter =
|
||||
devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_ras_reporter_ops, 0, rvu);
|
||||
devlink_health_reporter_create(rvu_dl->dl,
|
||||
&rvu_hw_npa_ras_reporter_ops,
|
||||
rvu);
|
||||
if (IS_ERR(rvu_reporters->rvu_hw_npa_ras_reporter)) {
|
||||
dev_warn(rvu->dev, "Failed to create hw_npa_ras reporter, err=%ld\n",
|
||||
PTR_ERR(rvu_reporters->rvu_hw_npa_ras_reporter));
|
||||
|
||||
@@ -135,7 +135,7 @@ void mlx5_reporter_vnic_create(struct mlx5_core_dev *dev)
|
||||
health->vnic_reporter =
|
||||
devlink_health_reporter_create(devlink,
|
||||
&mlx5_reporter_vnic_ops,
|
||||
0, dev);
|
||||
dev);
|
||||
if (IS_ERR(health->vnic_reporter))
|
||||
mlx5_core_warn(dev,
|
||||
"Failed to create vnic reporter, err = %ld\n",
|
||||
|
||||
@@ -651,22 +651,26 @@ void mlx5e_reporter_icosq_resume_recovery(struct mlx5e_channel *c)
|
||||
mutex_unlock(&c->icosq_recovery_lock);
|
||||
}
|
||||
|
||||
#define MLX5E_REPORTER_RX_GRACEFUL_PERIOD 500
|
||||
#define MLX5E_REPORTER_RX_BURST_PERIOD 500
|
||||
|
||||
static const struct devlink_health_reporter_ops mlx5_rx_reporter_ops = {
|
||||
.name = "rx",
|
||||
.recover = mlx5e_rx_reporter_recover,
|
||||
.diagnose = mlx5e_rx_reporter_diagnose,
|
||||
.dump = mlx5e_rx_reporter_dump,
|
||||
.default_graceful_period = MLX5E_REPORTER_RX_GRACEFUL_PERIOD,
|
||||
.default_burst_period = MLX5E_REPORTER_RX_BURST_PERIOD,
|
||||
};
|
||||
|
||||
#define MLX5E_REPORTER_RX_GRACEFUL_PERIOD 500
|
||||
|
||||
void mlx5e_reporter_rx_create(struct mlx5e_priv *priv)
|
||||
{
|
||||
struct devlink_port *port = priv->netdev->devlink_port;
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
reporter = devlink_port_health_reporter_create(priv->netdev->devlink_port,
|
||||
reporter = devlink_port_health_reporter_create(port,
|
||||
&mlx5_rx_reporter_ops,
|
||||
MLX5E_REPORTER_RX_GRACEFUL_PERIOD, priv);
|
||||
priv);
|
||||
if (IS_ERR(reporter)) {
|
||||
netdev_warn(priv->netdev, "Failed to create rx reporter, err = %ld\n",
|
||||
PTR_ERR(reporter));
|
||||
|
||||
@@ -539,22 +539,26 @@ void mlx5e_reporter_tx_ptpsq_unhealthy(struct mlx5e_ptpsq *ptpsq)
|
||||
mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx);
|
||||
}
|
||||
|
||||
#define MLX5E_REPORTER_TX_GRACEFUL_PERIOD 500
|
||||
#define MLX5E_REPORTER_TX_BURST_PERIOD 500
|
||||
|
||||
static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {
|
||||
.name = "tx",
|
||||
.recover = mlx5e_tx_reporter_recover,
|
||||
.diagnose = mlx5e_tx_reporter_diagnose,
|
||||
.dump = mlx5e_tx_reporter_dump,
|
||||
.default_graceful_period = MLX5E_REPORTER_TX_GRACEFUL_PERIOD,
|
||||
.default_burst_period = MLX5E_REPORTER_TX_BURST_PERIOD,
|
||||
};
|
||||
|
||||
#define MLX5_REPORTER_TX_GRACEFUL_PERIOD 500
|
||||
|
||||
void mlx5e_reporter_tx_create(struct mlx5e_priv *priv)
|
||||
{
|
||||
struct devlink_port *port = priv->netdev->devlink_port;
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
reporter = devlink_port_health_reporter_create(priv->netdev->devlink_port,
|
||||
reporter = devlink_port_health_reporter_create(port,
|
||||
&mlx5_tx_reporter_ops,
|
||||
MLX5_REPORTER_TX_GRACEFUL_PERIOD, priv);
|
||||
priv);
|
||||
if (IS_ERR(reporter)) {
|
||||
netdev_warn(priv->netdev,
|
||||
"Failed to create tx reporter, err = %ld\n",
|
||||
|
||||
@@ -1447,7 +1447,7 @@ static void mlx5e_rep_vnic_reporter_create(struct mlx5e_priv *priv,
|
||||
|
||||
reporter = devl_port_health_reporter_create(dl_port,
|
||||
&mlx5_rep_vnic_reporter_ops,
|
||||
0, rpriv);
|
||||
rpriv);
|
||||
if (IS_ERR(reporter)) {
|
||||
mlx5_core_err(priv->mdev,
|
||||
"Failed to create representor vnic reporter, err = %ld\n",
|
||||
|
||||
@@ -669,54 +669,61 @@ static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
#define MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD 180000
|
||||
#define MLX5_FW_REPORTER_PF_GRACEFUL_PERIOD 60000
|
||||
#define MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD 30000
|
||||
#define MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD \
|
||||
MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD
|
||||
|
||||
static
|
||||
const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ecpf_ops = {
|
||||
.name = "fw_fatal",
|
||||
.recover = mlx5_fw_fatal_reporter_recover,
|
||||
.dump = mlx5_fw_fatal_reporter_dump,
|
||||
.default_graceful_period =
|
||||
MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD,
|
||||
};
|
||||
|
||||
static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_pf_ops = {
|
||||
.name = "fw_fatal",
|
||||
.recover = mlx5_fw_fatal_reporter_recover,
|
||||
.dump = mlx5_fw_fatal_reporter_dump,
|
||||
.default_graceful_period = MLX5_FW_REPORTER_PF_GRACEFUL_PERIOD,
|
||||
};
|
||||
|
||||
static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = {
|
||||
.name = "fw_fatal",
|
||||
.recover = mlx5_fw_fatal_reporter_recover,
|
||||
.default_graceful_period =
|
||||
MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD,
|
||||
};
|
||||
|
||||
#define MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD 180000
|
||||
#define MLX5_FW_REPORTER_PF_GRACEFUL_PERIOD 60000
|
||||
#define MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD 30000
|
||||
#define MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD
|
||||
|
||||
void mlx5_fw_reporters_create(struct mlx5_core_dev *dev)
|
||||
{
|
||||
const struct devlink_health_reporter_ops *fw_fatal_ops;
|
||||
struct mlx5_core_health *health = &dev->priv.health;
|
||||
const struct devlink_health_reporter_ops *fw_ops;
|
||||
struct devlink *devlink = priv_to_devlink(dev);
|
||||
u64 grace_period;
|
||||
|
||||
fw_fatal_ops = &mlx5_fw_fatal_reporter_pf_ops;
|
||||
fw_ops = &mlx5_fw_reporter_pf_ops;
|
||||
if (mlx5_core_is_ecpf(dev)) {
|
||||
grace_period = MLX5_FW_REPORTER_ECPF_GRACEFUL_PERIOD;
|
||||
fw_fatal_ops = &mlx5_fw_fatal_reporter_ecpf_ops;
|
||||
} else if (mlx5_core_is_pf(dev)) {
|
||||
grace_period = MLX5_FW_REPORTER_PF_GRACEFUL_PERIOD;
|
||||
fw_fatal_ops = &mlx5_fw_fatal_reporter_pf_ops;
|
||||
} else {
|
||||
/* VF or SF */
|
||||
grace_period = MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD;
|
||||
fw_fatal_ops = &mlx5_fw_fatal_reporter_ops;
|
||||
fw_ops = &mlx5_fw_reporter_ops;
|
||||
}
|
||||
|
||||
health->fw_reporter =
|
||||
devl_health_reporter_create(devlink, fw_ops, 0, dev);
|
||||
health->fw_reporter = devl_health_reporter_create(devlink, fw_ops, dev);
|
||||
if (IS_ERR(health->fw_reporter))
|
||||
mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n",
|
||||
PTR_ERR(health->fw_reporter));
|
||||
|
||||
health->fw_fatal_reporter =
|
||||
devl_health_reporter_create(devlink,
|
||||
fw_fatal_ops,
|
||||
grace_period,
|
||||
dev);
|
||||
health->fw_fatal_reporter = devl_health_reporter_create(devlink,
|
||||
fw_fatal_ops,
|
||||
dev);
|
||||
if (IS_ERR(health->fw_fatal_reporter))
|
||||
mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n",
|
||||
PTR_ERR(health->fw_fatal_reporter));
|
||||
|
||||
@@ -2043,7 +2043,7 @@ static int mlxsw_core_health_init(struct mlxsw_core *mlxsw_core)
|
||||
return 0;
|
||||
|
||||
fw_fatal = devl_health_reporter_create(devlink, &mlxsw_core_health_fw_fatal_ops,
|
||||
0, mlxsw_core);
|
||||
mlxsw_core);
|
||||
if (IS_ERR(fw_fatal)) {
|
||||
dev_err(mlxsw_core->bus_info->dev, "Failed to create fw fatal reporter");
|
||||
return PTR_ERR(fw_fatal);
|
||||
|
||||
@@ -87,20 +87,21 @@ qed_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define QED_REPORTER_FW_GRACEFUL_PERIOD 0
|
||||
|
||||
static const struct devlink_health_reporter_ops qed_fw_fatal_reporter_ops = {
|
||||
.name = "fw_fatal",
|
||||
.recover = qed_fw_fatal_reporter_recover,
|
||||
.dump = qed_fw_fatal_reporter_dump,
|
||||
.default_graceful_period = QED_REPORTER_FW_GRACEFUL_PERIOD,
|
||||
};
|
||||
|
||||
#define QED_REPORTER_FW_GRACEFUL_PERIOD 0
|
||||
|
||||
void qed_fw_reporters_create(struct devlink *devlink)
|
||||
{
|
||||
struct qed_devlink *dl = devlink_priv(devlink);
|
||||
|
||||
dl->fw_reporter = devlink_health_reporter_create(devlink, &qed_fw_fatal_reporter_ops,
|
||||
QED_REPORTER_FW_GRACEFUL_PERIOD, dl);
|
||||
dl->fw_reporter = devlink_health_reporter_create(devlink,
|
||||
&qed_fw_fatal_reporter_ops, dl);
|
||||
if (IS_ERR(dl->fw_reporter)) {
|
||||
DP_NOTICE(dl->cdev, "Failed to create fw reporter, err = %ld\n",
|
||||
PTR_ERR(dl->fw_reporter));
|
||||
|
||||
@@ -183,14 +183,14 @@ int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
|
||||
health->empty_reporter =
|
||||
devl_health_reporter_create(devlink,
|
||||
&nsim_dev_empty_reporter_ops,
|
||||
0, health);
|
||||
health);
|
||||
if (IS_ERR(health->empty_reporter))
|
||||
return PTR_ERR(health->empty_reporter);
|
||||
|
||||
health->dummy_reporter =
|
||||
devl_health_reporter_create(devlink,
|
||||
&nsim_dev_dummy_reporter_ops,
|
||||
0, health);
|
||||
health);
|
||||
if (IS_ERR(health->dummy_reporter)) {
|
||||
err = PTR_ERR(health->dummy_reporter);
|
||||
goto err_empty_reporter_destroy;
|
||||
|
||||
@@ -746,6 +746,10 @@ enum devlink_health_reporter_state {
|
||||
* if priv_ctx is NULL, run a full dump
|
||||
* @diagnose: callback to diagnose the current status
|
||||
* @test: callback to trigger a test event
|
||||
* @default_graceful_period: default min time (in msec)
|
||||
* between recovery attempts
|
||||
* @default_burst_period: default time (in msec) for
|
||||
* error recoveries before starting the grace period
|
||||
*/
|
||||
|
||||
struct devlink_health_reporter_ops {
|
||||
@@ -760,6 +764,8 @@ struct devlink_health_reporter_ops {
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*test)(struct devlink_health_reporter *reporter,
|
||||
struct netlink_ext_ack *extack);
|
||||
u64 default_graceful_period;
|
||||
u64 default_burst_period;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1928,22 +1934,22 @@ void devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
||||
struct devlink_health_reporter *
|
||||
devl_port_health_reporter_create(struct devlink_port *port,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv);
|
||||
void *priv);
|
||||
|
||||
struct devlink_health_reporter *
|
||||
devlink_port_health_reporter_create(struct devlink_port *port,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv);
|
||||
void *priv);
|
||||
|
||||
struct devlink_health_reporter *
|
||||
devl_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv);
|
||||
void *priv);
|
||||
|
||||
struct devlink_health_reporter *
|
||||
devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv);
|
||||
void *priv);
|
||||
|
||||
void
|
||||
devl_health_reporter_destroy(struct devlink_health_reporter *reporter);
|
||||
|
||||
@@ -636,6 +636,8 @@ enum devlink_attr {
|
||||
|
||||
DEVLINK_ATTR_RATE_TC_BWS, /* nested */
|
||||
|
||||
DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD, /* u64 */
|
||||
|
||||
/* Add new attributes above here, update the spec in
|
||||
* Documentation/netlink/specs/devlink.yaml and re-generate
|
||||
* net/devlink/netlink_gen.c.
|
||||
|
||||
@@ -60,6 +60,7 @@ struct devlink_health_reporter {
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink_fmsg *dump_fmsg;
|
||||
u64 graceful_period;
|
||||
u64 burst_period;
|
||||
bool auto_recover;
|
||||
bool auto_dump;
|
||||
u8 health_state;
|
||||
@@ -108,11 +109,14 @@ devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
|
||||
static struct devlink_health_reporter *
|
||||
__devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv)
|
||||
void *priv)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
if (WARN_ON(graceful_period && !ops->recover))
|
||||
if (WARN_ON(ops->default_graceful_period && !ops->recover))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (WARN_ON(ops->default_burst_period && !ops->default_graceful_period))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
|
||||
@@ -122,7 +126,8 @@ __devlink_health_reporter_create(struct devlink *devlink,
|
||||
reporter->priv = priv;
|
||||
reporter->ops = ops;
|
||||
reporter->devlink = devlink;
|
||||
reporter->graceful_period = graceful_period;
|
||||
reporter->graceful_period = ops->default_graceful_period;
|
||||
reporter->burst_period = ops->default_burst_period;
|
||||
reporter->auto_recover = !!ops->recover;
|
||||
reporter->auto_dump = !!ops->dump;
|
||||
return reporter;
|
||||
@@ -134,13 +139,12 @@ __devlink_health_reporter_create(struct devlink *devlink,
|
||||
*
|
||||
* @port: devlink_port to which health reports will relate
|
||||
* @ops: devlink health reporter ops
|
||||
* @graceful_period: min time (in msec) between recovery attempts
|
||||
* @priv: driver priv pointer
|
||||
*/
|
||||
struct devlink_health_reporter *
|
||||
devl_port_health_reporter_create(struct devlink_port *port,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv)
|
||||
void *priv)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
@@ -150,8 +154,7 @@ devl_port_health_reporter_create(struct devlink_port *port,
|
||||
ops->name))
|
||||
return ERR_PTR(-EEXIST);
|
||||
|
||||
reporter = __devlink_health_reporter_create(port->devlink, ops,
|
||||
graceful_period, priv);
|
||||
reporter = __devlink_health_reporter_create(port->devlink, ops, priv);
|
||||
if (IS_ERR(reporter))
|
||||
return reporter;
|
||||
|
||||
@@ -164,14 +167,13 @@ EXPORT_SYMBOL_GPL(devl_port_health_reporter_create);
|
||||
struct devlink_health_reporter *
|
||||
devlink_port_health_reporter_create(struct devlink_port *port,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv)
|
||||
void *priv)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
struct devlink *devlink = port->devlink;
|
||||
|
||||
devl_lock(devlink);
|
||||
reporter = devl_port_health_reporter_create(port, ops,
|
||||
graceful_period, priv);
|
||||
reporter = devl_port_health_reporter_create(port, ops, priv);
|
||||
devl_unlock(devlink);
|
||||
return reporter;
|
||||
}
|
||||
@@ -182,13 +184,12 @@ EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
|
||||
*
|
||||
* @devlink: devlink instance which the health reports will relate
|
||||
* @ops: devlink health reporter ops
|
||||
* @graceful_period: min time (in msec) between recovery attempts
|
||||
* @priv: driver priv pointer
|
||||
*/
|
||||
struct devlink_health_reporter *
|
||||
devl_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv)
|
||||
void *priv)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
@@ -197,8 +198,7 @@ devl_health_reporter_create(struct devlink *devlink,
|
||||
if (devlink_health_reporter_find_by_name(devlink, ops->name))
|
||||
return ERR_PTR(-EEXIST);
|
||||
|
||||
reporter = __devlink_health_reporter_create(devlink, ops,
|
||||
graceful_period, priv);
|
||||
reporter = __devlink_health_reporter_create(devlink, ops, priv);
|
||||
if (IS_ERR(reporter))
|
||||
return reporter;
|
||||
|
||||
@@ -210,13 +210,12 @@ EXPORT_SYMBOL_GPL(devl_health_reporter_create);
|
||||
struct devlink_health_reporter *
|
||||
devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
u64 graceful_period, void *priv)
|
||||
void *priv)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
|
||||
devl_lock(devlink);
|
||||
reporter = devl_health_reporter_create(devlink, ops,
|
||||
graceful_period, priv);
|
||||
reporter = devl_health_reporter_create(devlink, ops, priv);
|
||||
devl_unlock(devlink);
|
||||
return reporter;
|
||||
}
|
||||
@@ -297,6 +296,10 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
|
||||
devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
|
||||
reporter->graceful_period))
|
||||
goto reporter_nest_cancel;
|
||||
if (reporter->ops->recover &&
|
||||
devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD,
|
||||
reporter->burst_period))
|
||||
goto reporter_nest_cancel;
|
||||
if (reporter->ops->recover &&
|
||||
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
|
||||
reporter->auto_recover))
|
||||
@@ -462,16 +465,33 @@ int devlink_nl_health_reporter_set_doit(struct sk_buff *skb,
|
||||
|
||||
if (!reporter->ops->recover &&
|
||||
(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
|
||||
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
|
||||
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] ||
|
||||
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD]))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!reporter->ops->dump &&
|
||||
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
|
||||
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) {
|
||||
reporter->graceful_period =
|
||||
nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
|
||||
if (!reporter->graceful_period)
|
||||
reporter->burst_period = 0;
|
||||
}
|
||||
|
||||
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD]) {
|
||||
u64 burst_period =
|
||||
nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD]);
|
||||
|
||||
if (!reporter->graceful_period && burst_period) {
|
||||
NL_SET_ERR_MSG_MOD(info->extack,
|
||||
"Cannot set burst period without a grace period.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reporter->burst_period = burst_period;
|
||||
}
|
||||
|
||||
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
|
||||
reporter->auto_recover =
|
||||
@@ -514,11 +534,25 @@ static void devlink_recover_notify(struct devlink_health_reporter *reporter,
|
||||
devlink_nl_notify_send_desc(devlink, msg, &desc);
|
||||
}
|
||||
|
||||
static bool
|
||||
devlink_health_reporter_in_burst(struct devlink_health_reporter *reporter)
|
||||
{
|
||||
unsigned long burst_threshold = reporter->last_recovery_ts +
|
||||
msecs_to_jiffies(reporter->burst_period);
|
||||
|
||||
return time_is_after_jiffies(burst_threshold);
|
||||
}
|
||||
|
||||
void
|
||||
devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
|
||||
{
|
||||
reporter->recovery_count++;
|
||||
reporter->last_recovery_ts = jiffies;
|
||||
if (!devlink_health_reporter_in_burst(reporter))
|
||||
/* When burst period is set, last_recovery_ts marks the first
|
||||
* recovery within the burst period, not necessarily the last
|
||||
* one.
|
||||
*/
|
||||
reporter->last_recovery_ts = jiffies;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
|
||||
|
||||
@@ -592,12 +626,37 @@ static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool
|
||||
devlink_health_recover_abort(struct devlink_health_reporter *reporter,
|
||||
enum devlink_health_reporter_state prev_state)
|
||||
{
|
||||
unsigned long recover_ts_threshold;
|
||||
|
||||
if (!reporter->auto_recover)
|
||||
return false;
|
||||
|
||||
/* abort if the previous error wasn't recovered */
|
||||
if (prev_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
|
||||
return true;
|
||||
|
||||
if (devlink_health_reporter_in_burst(reporter))
|
||||
return false;
|
||||
|
||||
recover_ts_threshold = reporter->last_recovery_ts +
|
||||
msecs_to_jiffies(reporter->burst_period) +
|
||||
msecs_to_jiffies(reporter->graceful_period);
|
||||
if (reporter->last_recovery_ts && reporter->recovery_count &&
|
||||
time_is_after_jiffies(recover_ts_threshold))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int devlink_health_report(struct devlink_health_reporter *reporter,
|
||||
const char *msg, void *priv_ctx)
|
||||
{
|
||||
enum devlink_health_reporter_state prev_health_state;
|
||||
struct devlink *devlink = reporter->devlink;
|
||||
unsigned long recover_ts_threshold;
|
||||
int ret;
|
||||
|
||||
/* write a log message of the current error */
|
||||
@@ -608,13 +667,7 @@ int devlink_health_report(struct devlink_health_reporter *reporter,
|
||||
reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
|
||||
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
|
||||
|
||||
/* abort if the previous error wasn't recovered */
|
||||
recover_ts_threshold = reporter->last_recovery_ts +
|
||||
msecs_to_jiffies(reporter->graceful_period);
|
||||
if (reporter->auto_recover &&
|
||||
(prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
|
||||
(reporter->last_recovery_ts && reporter->recovery_count &&
|
||||
time_is_after_jiffies(recover_ts_threshold)))) {
|
||||
if (devlink_health_recover_abort(reporter, prev_health_state)) {
|
||||
trace_devlink_health_recover_aborted(devlink,
|
||||
reporter->ops->name,
|
||||
reporter->health_state,
|
||||
|
||||
@@ -389,7 +389,7 @@ static const struct nla_policy devlink_health_reporter_get_dump_nl_policy[DEVLIN
|
||||
};
|
||||
|
||||
/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */
|
||||
static const struct nla_policy devlink_health_reporter_set_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP + 1] = {
|
||||
static const struct nla_policy devlink_health_reporter_set_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD + 1] = {
|
||||
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
|
||||
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
|
||||
[DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, },
|
||||
@@ -397,6 +397,7 @@ static const struct nla_policy devlink_health_reporter_set_nl_policy[DEVLINK_ATT
|
||||
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64, },
|
||||
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8, },
|
||||
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8, },
|
||||
[DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD] = { .type = NLA_U64, },
|
||||
};
|
||||
|
||||
/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */
|
||||
@@ -1032,7 +1033,7 @@ const struct genl_split_ops devlink_nl_ops[74] = {
|
||||
.doit = devlink_nl_health_reporter_set_doit,
|
||||
.post_doit = devlink_nl_post_doit,
|
||||
.policy = devlink_health_reporter_set_nl_policy,
|
||||
.maxattr = DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
|
||||
.maxattr = DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user