1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Mellanox Technologies.
7 static int mlx5e_query_rq_state(struct mlx5_core_dev
*dev
, u32 rqn
, u8
*state
)
9 int outlen
= MLX5_ST_SZ_BYTES(query_rq_out
);
14 out
= kvzalloc(outlen
, GFP_KERNEL
);
18 err
= mlx5_core_query_rq(dev
, rqn
, out
);
22 rqc
= MLX5_ADDR_OF(query_rq_out
, out
, rq_context
);
23 *state
= MLX5_GET(rqc
, rqc
, state
);
30 static int mlx5e_wait_for_icosq_flush(struct mlx5e_icosq
*icosq
)
32 unsigned long exp_time
= jiffies
+ msecs_to_jiffies(2000);
34 while (time_before(jiffies
, exp_time
)) {
35 if (icosq
->cc
== icosq
->pc
)
41 netdev_err(icosq
->channel
->netdev
,
42 "Wait for ICOSQ 0x%x flush timeout (cc = 0x%x, pc = 0x%x)\n",
43 icosq
->sqn
, icosq
->cc
, icosq
->pc
);
48 static void mlx5e_reset_icosq_cc_pc(struct mlx5e_icosq
*icosq
)
50 WARN_ONCE(icosq
->cc
!= icosq
->pc
, "ICOSQ 0x%x: cc (0x%x) != pc (0x%x)\n",
51 icosq
->sqn
, icosq
->cc
, icosq
->pc
);
56 static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx
)
58 struct mlx5_core_dev
*mdev
;
59 struct mlx5e_icosq
*icosq
;
60 struct net_device
*dev
;
66 rq
= &icosq
->channel
->rq
;
67 mdev
= icosq
->channel
->mdev
;
68 dev
= icosq
->channel
->netdev
;
69 err
= mlx5_core_query_sq_state(mdev
, icosq
->sqn
, &state
);
71 netdev_err(dev
, "Failed to query ICOSQ 0x%x state. err = %d\n",
76 if (state
!= MLX5_SQC_STATE_ERR
)
79 mlx5e_deactivate_rq(rq
);
80 err
= mlx5e_wait_for_icosq_flush(icosq
);
84 mlx5e_deactivate_icosq(icosq
);
86 /* At this point, both the rq and the icosq are disabled */
88 err
= mlx5e_health_sq_to_ready(icosq
->channel
, icosq
->sqn
);
92 mlx5e_reset_icosq_cc_pc(icosq
);
93 mlx5e_free_rx_descs(rq
);
94 clear_bit(MLX5E_SQ_STATE_RECOVERING
, &icosq
->state
);
95 mlx5e_activate_icosq(icosq
);
96 mlx5e_activate_rq(rq
);
101 clear_bit(MLX5E_SQ_STATE_RECOVERING
, &icosq
->state
);
105 void mlx5e_reporter_icosq_cqe_err(struct mlx5e_icosq
*icosq
)
107 struct mlx5e_priv
*priv
= icosq
->channel
->priv
;
108 char err_str
[MLX5E_REPORTER_PER_Q_MAX_LEN
];
109 struct mlx5e_err_ctx err_ctx
= {};
112 err_ctx
.recover
= mlx5e_rx_reporter_err_icosq_cqe_recover
;
113 sprintf(err_str
, "ERR CQE on ICOSQ: 0x%x", icosq
->sqn
);
115 mlx5e_health_report(priv
, priv
->rx_reporter
, err_str
, &err_ctx
);
118 static int mlx5e_rq_to_ready(struct mlx5e_rq
*rq
, int curr_state
)
120 struct net_device
*dev
= rq
->netdev
;
123 err
= mlx5e_modify_rq_state(rq
, curr_state
, MLX5_RQC_STATE_RST
);
125 netdev_err(dev
, "Failed to move rq 0x%x to reset\n", rq
->rqn
);
128 err
= mlx5e_modify_rq_state(rq
, MLX5_RQC_STATE_RST
, MLX5_RQC_STATE_RDY
);
130 netdev_err(dev
, "Failed to move rq 0x%x to ready\n", rq
->rqn
);
137 static int mlx5e_rx_reporter_err_rq_cqe_recover(void *ctx
)
139 struct mlx5_core_dev
*mdev
;
140 struct net_device
*dev
;
148 err
= mlx5e_query_rq_state(mdev
, rq
->rqn
, &state
);
150 netdev_err(dev
, "Failed to query RQ 0x%x state. err = %d\n",
155 if (state
!= MLX5_RQC_STATE_ERR
)
158 mlx5e_deactivate_rq(rq
);
159 mlx5e_free_rx_descs(rq
);
161 err
= mlx5e_rq_to_ready(rq
, MLX5_RQC_STATE_ERR
);
165 clear_bit(MLX5E_RQ_STATE_RECOVERING
, &rq
->state
);
166 mlx5e_activate_rq(rq
);
167 rq
->stats
->recover
++;
170 clear_bit(MLX5E_RQ_STATE_RECOVERING
, &rq
->state
);
174 void mlx5e_reporter_rq_cqe_err(struct mlx5e_rq
*rq
)
176 struct mlx5e_priv
*priv
= rq
->channel
->priv
;
177 char err_str
[MLX5E_REPORTER_PER_Q_MAX_LEN
];
178 struct mlx5e_err_ctx err_ctx
= {};
181 err_ctx
.recover
= mlx5e_rx_reporter_err_rq_cqe_recover
;
182 sprintf(err_str
, "ERR CQE on RQ: 0x%x", rq
->rqn
);
184 mlx5e_health_report(priv
, priv
->rx_reporter
, err_str
, &err_ctx
);
187 static int mlx5e_rx_reporter_timeout_recover(void *ctx
)
189 struct mlx5e_icosq
*icosq
;
190 struct mlx5_eq_comp
*eq
;
195 icosq
= &rq
->channel
->icosq
;
197 err
= mlx5e_health_channel_eq_recover(eq
, rq
->channel
);
199 clear_bit(MLX5E_SQ_STATE_ENABLED
, &icosq
->state
);
204 void mlx5e_reporter_rx_timeout(struct mlx5e_rq
*rq
)
206 struct mlx5e_icosq
*icosq
= &rq
->channel
->icosq
;
207 struct mlx5e_priv
*priv
= rq
->channel
->priv
;
208 char err_str
[MLX5E_REPORTER_PER_Q_MAX_LEN
];
209 struct mlx5e_err_ctx err_ctx
= {};
212 err_ctx
.recover
= mlx5e_rx_reporter_timeout_recover
;
213 sprintf(err_str
, "RX timeout on channel: %d, ICOSQ: 0x%x RQ: 0x%x, CQ: 0x%x\n",
214 icosq
->channel
->ix
, icosq
->sqn
, rq
->rqn
, rq
->cq
.mcq
.cqn
);
216 mlx5e_health_report(priv
, priv
->rx_reporter
, err_str
, &err_ctx
);
219 static int mlx5e_rx_reporter_recover_from_ctx(struct mlx5e_err_ctx
*err_ctx
)
221 return err_ctx
->recover(err_ctx
->ctx
);
224 static int mlx5e_rx_reporter_recover(struct devlink_health_reporter
*reporter
,
226 struct netlink_ext_ack
*extack
)
228 struct mlx5e_priv
*priv
= devlink_health_reporter_priv(reporter
);
229 struct mlx5e_err_ctx
*err_ctx
= context
;
231 return err_ctx
? mlx5e_rx_reporter_recover_from_ctx(err_ctx
) :
232 mlx5e_health_recover_channels(priv
);
235 static int mlx5e_rx_reporter_build_diagnose_output(struct mlx5e_rq
*rq
,
236 struct devlink_fmsg
*fmsg
)
238 struct mlx5e_priv
*priv
= rq
->channel
->priv
;
239 struct mlx5e_params
*params
;
240 struct mlx5e_icosq
*icosq
;
247 params
= &priv
->channels
.params
;
248 icosq
= &rq
->channel
->icosq
;
249 err
= mlx5e_query_rq_state(priv
->mdev
, rq
->rqn
, &hw_state
);
253 err
= mlx5_core_query_sq_state(priv
->mdev
, icosq
->sqn
, &icosq_hw_state
);
257 wqes_sz
= mlx5e_rqwq_get_cur_sz(rq
);
258 wq_head
= params
->rq_wq_type
== MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ
?
259 rq
->mpwqe
.wq
.head
: mlx5_wq_cyc_get_head(&rq
->wqe
.wq
);
261 err
= devlink_fmsg_obj_nest_start(fmsg
);
265 err
= devlink_fmsg_u32_pair_put(fmsg
, "channel ix", rq
->channel
->ix
);
269 err
= devlink_fmsg_u32_pair_put(fmsg
, "rqn", rq
->rqn
);
273 err
= devlink_fmsg_u8_pair_put(fmsg
, "HW state", hw_state
);
277 err
= devlink_fmsg_u8_pair_put(fmsg
, "SW state", rq
->state
);
281 err
= devlink_fmsg_u32_pair_put(fmsg
, "posted WQEs", wqes_sz
);
285 err
= devlink_fmsg_u32_pair_put(fmsg
, "cc", wq_head
);
289 err
= devlink_fmsg_u8_pair_put(fmsg
, "ICOSQ HW state", icosq_hw_state
);
293 err
= mlx5e_reporter_cq_diagnose(&rq
->cq
, fmsg
);
297 err
= devlink_fmsg_obj_nest_end(fmsg
);
304 static int mlx5e_rx_reporter_diagnose(struct devlink_health_reporter
*reporter
,
305 struct devlink_fmsg
*fmsg
,
306 struct netlink_ext_ack
*extack
)
308 struct mlx5e_priv
*priv
= devlink_health_reporter_priv(reporter
);
309 struct mlx5e_params
*params
= &priv
->channels
.params
;
310 struct mlx5e_rq
*generic_rq
;
311 u32 rq_stride
, rq_sz
;
314 mutex_lock(&priv
->state_lock
);
316 if (!test_bit(MLX5E_STATE_OPENED
, &priv
->state
))
319 generic_rq
= &priv
->channels
.c
[0]->rq
;
320 rq_sz
= mlx5e_rqwq_get_size(generic_rq
);
321 rq_stride
= BIT(mlx5e_mpwqe_get_log_stride_size(priv
->mdev
, params
, NULL
));
323 err
= mlx5e_reporter_named_obj_nest_start(fmsg
, "Common config");
327 err
= mlx5e_reporter_named_obj_nest_start(fmsg
, "RQ");
331 err
= devlink_fmsg_u8_pair_put(fmsg
, "type", params
->rq_wq_type
);
335 err
= devlink_fmsg_u64_pair_put(fmsg
, "stride size", rq_stride
);
339 err
= devlink_fmsg_u32_pair_put(fmsg
, "size", rq_sz
);
343 err
= mlx5e_reporter_named_obj_nest_end(fmsg
);
347 err
= mlx5e_reporter_cq_common_diagnose(&generic_rq
->cq
, fmsg
);
351 err
= mlx5e_reporter_named_obj_nest_end(fmsg
);
355 err
= devlink_fmsg_arr_pair_nest_start(fmsg
, "RQs");
359 for (i
= 0; i
< priv
->channels
.num
; i
++) {
360 struct mlx5e_rq
*rq
= &priv
->channels
.c
[i
]->rq
;
362 err
= mlx5e_rx_reporter_build_diagnose_output(rq
, fmsg
);
366 err
= devlink_fmsg_arr_pair_nest_end(fmsg
);
370 mutex_unlock(&priv
->state_lock
);
374 static const struct devlink_health_reporter_ops mlx5_rx_reporter_ops
= {
376 .recover
= mlx5e_rx_reporter_recover
,
377 .diagnose
= mlx5e_rx_reporter_diagnose
,
380 #define MLX5E_REPORTER_RX_GRACEFUL_PERIOD 500
382 int mlx5e_reporter_rx_create(struct mlx5e_priv
*priv
)
384 struct devlink
*devlink
= priv_to_devlink(priv
->mdev
);
385 struct devlink_health_reporter
*reporter
;
387 reporter
= devlink_health_reporter_create(devlink
,
388 &mlx5_rx_reporter_ops
,
389 MLX5E_REPORTER_RX_GRACEFUL_PERIOD
,
391 if (IS_ERR(reporter
)) {
392 netdev_warn(priv
->netdev
, "Failed to create rx reporter, err = %ld\n",
394 return PTR_ERR(reporter
);
396 priv
->rx_reporter
= reporter
;
400 void mlx5e_reporter_rx_destroy(struct mlx5e_priv
*priv
)
402 if (!priv
->rx_reporter
)
405 devlink_health_reporter_destroy(priv
->rx_reporter
);