1c50de4afSAya Levin // SPDX-License-Identifier: GPL-2.0
2c50de4afSAya Levin // Copyright (c) 2019 Mellanox Technologies.
3c50de4afSAya Levin 
4c50de4afSAya Levin #include "health.h"
5c50de4afSAya Levin #include "lib/eq.h"
65f29458bSAya Levin #include "lib/mlx5.h"
7c50de4afSAya Levin 
mlx5e_health_fmsg_named_obj_nest_start(struct devlink_fmsg * fmsg,char * name)8d5cbedd7SAya Levin int mlx5e_health_fmsg_named_obj_nest_start(struct devlink_fmsg *fmsg, char *name)
92d708887SAya Levin {
102d708887SAya Levin 	int err;
112d708887SAya Levin 
122d708887SAya Levin 	err = devlink_fmsg_pair_nest_start(fmsg, name);
132d708887SAya Levin 	if (err)
142d708887SAya Levin 		return err;
152d708887SAya Levin 
162d708887SAya Levin 	err = devlink_fmsg_obj_nest_start(fmsg);
172d708887SAya Levin 	if (err)
182d708887SAya Levin 		return err;
192d708887SAya Levin 
202d708887SAya Levin 	return 0;
212d708887SAya Levin }
222d708887SAya Levin 
mlx5e_health_fmsg_named_obj_nest_end(struct devlink_fmsg * fmsg)23d5cbedd7SAya Levin int mlx5e_health_fmsg_named_obj_nest_end(struct devlink_fmsg *fmsg)
242d708887SAya Levin {
252d708887SAya Levin 	int err;
262d708887SAya Levin 
272d708887SAya Levin 	err = devlink_fmsg_obj_nest_end(fmsg);
282d708887SAya Levin 	if (err)
292d708887SAya Levin 		return err;
302d708887SAya Levin 
312d708887SAya Levin 	err = devlink_fmsg_pair_nest_end(fmsg);
322d708887SAya Levin 	if (err)
332d708887SAya Levin 		return err;
342d708887SAya Levin 
352d708887SAya Levin 	return 0;
362d708887SAya Levin }
372d708887SAya Levin 
mlx5e_health_cq_diag_fmsg(struct mlx5e_cq * cq,struct devlink_fmsg * fmsg)38d5cbedd7SAya Levin int mlx5e_health_cq_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg)
392bf09e60SAya Levin {
402bf09e60SAya Levin 	u32 out[MLX5_ST_SZ_DW(query_cq_out)] = {};
412bf09e60SAya Levin 	u8 hw_status;
422bf09e60SAya Levin 	void *cqc;
432bf09e60SAya Levin 	int err;
442bf09e60SAya Levin 
454d0b7ef9SAya Levin 	err = mlx5_core_query_cq(cq->mdev, &cq->mcq, out);
462bf09e60SAya Levin 	if (err)
472bf09e60SAya Levin 		return err;
482bf09e60SAya Levin 
492bf09e60SAya Levin 	cqc = MLX5_ADDR_OF(query_cq_out, out, cq_context);
502bf09e60SAya Levin 	hw_status = MLX5_GET(cqc, cqc, status);
512bf09e60SAya Levin 
52d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "CQ");
532bf09e60SAya Levin 	if (err)
542bf09e60SAya Levin 		return err;
552bf09e60SAya Levin 
562bf09e60SAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "cqn", cq->mcq.cqn);
572bf09e60SAya Levin 	if (err)
582bf09e60SAya Levin 		return err;
592bf09e60SAya Levin 
602bf09e60SAya Levin 	err = devlink_fmsg_u8_pair_put(fmsg, "HW status", hw_status);
612bf09e60SAya Levin 	if (err)
622bf09e60SAya Levin 		return err;
632bf09e60SAya Levin 
643c9d1699SAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "ci", mlx5_cqwq_get_ci(&cq->wq));
653c9d1699SAya Levin 	if (err)
663c9d1699SAya Levin 		return err;
673c9d1699SAya Levin 
683c9d1699SAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "size", mlx5_cqwq_get_size(&cq->wq));
693c9d1699SAya Levin 	if (err)
703c9d1699SAya Levin 		return err;
713c9d1699SAya Levin 
72d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
732bf09e60SAya Levin 	if (err)
742bf09e60SAya Levin 		return err;
752bf09e60SAya Levin 
762bf09e60SAya Levin 	return 0;
772bf09e60SAya Levin }
782bf09e60SAya Levin 
mlx5e_health_cq_common_diag_fmsg(struct mlx5e_cq * cq,struct devlink_fmsg * fmsg)79d5cbedd7SAya Levin int mlx5e_health_cq_common_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg)
802bf09e60SAya Levin {
812bf09e60SAya Levin 	u8 cq_log_stride;
822bf09e60SAya Levin 	u32 cq_sz;
832bf09e60SAya Levin 	int err;
842bf09e60SAya Levin 
852bf09e60SAya Levin 	cq_sz = mlx5_cqwq_get_size(&cq->wq);
862bf09e60SAya Levin 	cq_log_stride = mlx5_cqwq_get_log_stride_size(&cq->wq);
872bf09e60SAya Levin 
88d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "CQ");
892bf09e60SAya Levin 	if (err)
902bf09e60SAya Levin 		return err;
912bf09e60SAya Levin 
922bf09e60SAya Levin 	err = devlink_fmsg_u64_pair_put(fmsg, "stride size", BIT(cq_log_stride));
932bf09e60SAya Levin 	if (err)
942bf09e60SAya Levin 		return err;
952bf09e60SAya Levin 
962bf09e60SAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "size", cq_sz);
972bf09e60SAya Levin 	if (err)
982bf09e60SAya Levin 		return err;
992bf09e60SAya Levin 
100d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
1012bf09e60SAya Levin 	if (err)
1022bf09e60SAya Levin 		return err;
1032bf09e60SAya Levin 
1042bf09e60SAya Levin 	return 0;
1052bf09e60SAya Levin }
1062bf09e60SAya Levin 
mlx5e_health_eq_diag_fmsg(struct mlx5_eq_comp * eq,struct devlink_fmsg * fmsg)10756837c2aSAya Levin int mlx5e_health_eq_diag_fmsg(struct mlx5_eq_comp *eq, struct devlink_fmsg *fmsg)
10856837c2aSAya Levin {
10956837c2aSAya Levin 	int err;
11056837c2aSAya Levin 
11156837c2aSAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "EQ");
11256837c2aSAya Levin 	if (err)
11356837c2aSAya Levin 		return err;
11456837c2aSAya Levin 
11556837c2aSAya Levin 	err = devlink_fmsg_u8_pair_put(fmsg, "eqn", eq->core.eqn);
11656837c2aSAya Levin 	if (err)
11756837c2aSAya Levin 		return err;
11856837c2aSAya Levin 
11956837c2aSAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "irqn", eq->core.irqn);
12056837c2aSAya Levin 	if (err)
12156837c2aSAya Levin 		return err;
12256837c2aSAya Levin 
12356837c2aSAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "vecidx", eq->core.vecidx);
12456837c2aSAya Levin 	if (err)
12556837c2aSAya Levin 		return err;
12656837c2aSAya Levin 
12756837c2aSAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "ci", eq->core.cons_index);
12856837c2aSAya Levin 	if (err)
12956837c2aSAya Levin 		return err;
13056837c2aSAya Levin 
131*26bf3090STariq Toukan 	err = devlink_fmsg_u32_pair_put(fmsg, "size", eq_get_size(&eq->core));
13256837c2aSAya Levin 	if (err)
13356837c2aSAya Levin 		return err;
13456837c2aSAya Levin 
13556837c2aSAya Levin 	return mlx5e_health_fmsg_named_obj_nest_end(fmsg);
13656837c2aSAya Levin }
13756837c2aSAya Levin 
mlx5e_health_create_reporters(struct mlx5e_priv * priv)138b3ea4c4fSEran Ben Elisha void mlx5e_health_create_reporters(struct mlx5e_priv *priv)
13911af6a6dSAya Levin {
140b3ea4c4fSEran Ben Elisha 	mlx5e_reporter_tx_create(priv);
141b3ea4c4fSEran Ben Elisha 	mlx5e_reporter_rx_create(priv);
14211af6a6dSAya Levin }
14311af6a6dSAya Levin 
mlx5e_health_destroy_reporters(struct mlx5e_priv * priv)14411af6a6dSAya Levin void mlx5e_health_destroy_reporters(struct mlx5e_priv *priv)
14511af6a6dSAya Levin {
1469032e719SAya Levin 	mlx5e_reporter_rx_destroy(priv);
14711af6a6dSAya Levin 	mlx5e_reporter_tx_destroy(priv);
14811af6a6dSAya Levin }
14911af6a6dSAya Levin 
mlx5e_health_channels_update(struct mlx5e_priv * priv)15011af6a6dSAya Levin void mlx5e_health_channels_update(struct mlx5e_priv *priv)
15111af6a6dSAya Levin {
15211af6a6dSAya Levin 	if (priv->tx_reporter)
15311af6a6dSAya Levin 		devlink_health_reporter_state_update(priv->tx_reporter,
15411af6a6dSAya Levin 						     DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
1559032e719SAya Levin 	if (priv->rx_reporter)
1569032e719SAya Levin 		devlink_health_reporter_state_update(priv->rx_reporter,
1579032e719SAya Levin 						     DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
15811af6a6dSAya Levin }
15911af6a6dSAya Levin 
mlx5e_health_sq_to_ready(struct mlx5_core_dev * mdev,struct net_device * dev,u32 sqn)1604ad40d8eSEran Ben Elisha int mlx5e_health_sq_to_ready(struct mlx5_core_dev *mdev, struct net_device *dev, u32 sqn)
161c50de4afSAya Levin {
162c50de4afSAya Levin 	struct mlx5e_modify_sq_param msp = {};
163c50de4afSAya Levin 	int err;
164c50de4afSAya Levin 
165c50de4afSAya Levin 	msp.curr_state = MLX5_SQC_STATE_ERR;
166c50de4afSAya Levin 	msp.next_state = MLX5_SQC_STATE_RST;
167c50de4afSAya Levin 
168c50de4afSAya Levin 	err = mlx5e_modify_sq(mdev, sqn, &msp);
169c50de4afSAya Levin 	if (err) {
170c50de4afSAya Levin 		netdev_err(dev, "Failed to move sq 0x%x to reset\n", sqn);
171c50de4afSAya Levin 		return err;
172c50de4afSAya Levin 	}
173c50de4afSAya Levin 
174c50de4afSAya Levin 	memset(&msp, 0, sizeof(msp));
175c50de4afSAya Levin 	msp.curr_state = MLX5_SQC_STATE_RST;
176c50de4afSAya Levin 	msp.next_state = MLX5_SQC_STATE_RDY;
177c50de4afSAya Levin 
178c50de4afSAya Levin 	err = mlx5e_modify_sq(mdev, sqn, &msp);
179c50de4afSAya Levin 	if (err) {
180c50de4afSAya Levin 		netdev_err(dev, "Failed to move sq 0x%x to ready\n", sqn);
181c50de4afSAya Levin 		return err;
182c50de4afSAya Levin 	}
183c50de4afSAya Levin 
184c50de4afSAya Levin 	return 0;
185c50de4afSAya Levin }
186c50de4afSAya Levin 
mlx5e_health_recover_channels(struct mlx5e_priv * priv)187c50de4afSAya Levin int mlx5e_health_recover_channels(struct mlx5e_priv *priv)
188c50de4afSAya Levin {
189c50de4afSAya Levin 	int err = 0;
190c50de4afSAya Levin 
191c50de4afSAya Levin 	rtnl_lock();
192c50de4afSAya Levin 	mutex_lock(&priv->state_lock);
193c50de4afSAya Levin 
194c50de4afSAya Levin 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
195c50de4afSAya Levin 		goto out;
196c50de4afSAya Levin 
197c50de4afSAya Levin 	err = mlx5e_safe_reopen_channels(priv);
198c50de4afSAya Levin 
199c50de4afSAya Levin out:
200c50de4afSAya Levin 	mutex_unlock(&priv->state_lock);
201c50de4afSAya Levin 	rtnl_unlock();
202c50de4afSAya Levin 
203c50de4afSAya Levin 	return err;
204c50de4afSAya Levin }
205c50de4afSAya Levin 
mlx5e_health_channel_eq_recover(struct net_device * dev,struct mlx5_eq_comp * eq,struct mlx5e_ch_stats * stats)206521f31afSAya Levin int mlx5e_health_channel_eq_recover(struct net_device *dev, struct mlx5_eq_comp *eq,
207521f31afSAya Levin 				    struct mlx5e_ch_stats *stats)
208c50de4afSAya Levin {
209c50de4afSAya Levin 	u32 eqe_count;
210c50de4afSAya Levin 
211521f31afSAya Levin 	netdev_err(dev, "EQ 0x%x: Cons = 0x%x, irqn = 0x%x\n",
212c50de4afSAya Levin 		   eq->core.eqn, eq->core.cons_index, eq->core.irqn);
213c50de4afSAya Levin 
214c50de4afSAya Levin 	eqe_count = mlx5_eq_poll_irq_disabled(eq);
215c50de4afSAya Levin 	if (!eqe_count)
216c50de4afSAya Levin 		return -EIO;
217c50de4afSAya Levin 
218521f31afSAya Levin 	netdev_err(dev, "Recovered %d eqes on EQ 0x%x\n",
219c50de4afSAya Levin 		   eqe_count, eq->core.eqn);
220c50de4afSAya Levin 
221521f31afSAya Levin 	stats->eq_rearm++;
222c50de4afSAya Levin 	return 0;
223c50de4afSAya Levin }
224c50de4afSAya Levin 
mlx5e_health_report(struct mlx5e_priv * priv,struct devlink_health_reporter * reporter,char * err_str,struct mlx5e_err_ctx * err_ctx)225c50de4afSAya Levin int mlx5e_health_report(struct mlx5e_priv *priv,
226c50de4afSAya Levin 			struct devlink_health_reporter *reporter, char *err_str,
227c50de4afSAya Levin 			struct mlx5e_err_ctx *err_ctx)
228c50de4afSAya Levin {
229b21aef7eSJoe Perches 	netdev_err(priv->netdev, "%s\n", err_str);
23099cda454SEran Ben Elisha 
23199cda454SEran Ben Elisha 	if (!reporter)
2321ad6c43cSAya Levin 		return err_ctx->recover(err_ctx->ctx);
23399cda454SEran Ben Elisha 
234c50de4afSAya Levin 	return devlink_health_report(reporter, err_str, err_ctx);
235c50de4afSAya Levin }
2365f29458bSAya Levin 
2375f29458bSAya Levin #define MLX5_HEALTH_DEVLINK_MAX_SIZE 1024
mlx5e_health_rsc_fmsg_binary(struct devlink_fmsg * fmsg,const void * value,u32 value_len)2385f29458bSAya Levin static int mlx5e_health_rsc_fmsg_binary(struct devlink_fmsg *fmsg,
2395f29458bSAya Levin 					const void *value, u32 value_len)
2405f29458bSAya Levin 
2415f29458bSAya Levin {
2425f29458bSAya Levin 	u32 data_size;
24319f5b63bSMoshe Tal 	int err = 0;
2445f29458bSAya Levin 	u32 offset;
2455f29458bSAya Levin 
2465f29458bSAya Levin 	for (offset = 0; offset < value_len; offset += data_size) {
2475f29458bSAya Levin 		data_size = value_len - offset;
2485f29458bSAya Levin 		if (data_size > MLX5_HEALTH_DEVLINK_MAX_SIZE)
2495f29458bSAya Levin 			data_size = MLX5_HEALTH_DEVLINK_MAX_SIZE;
2505f29458bSAya Levin 		err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
2515f29458bSAya Levin 		if (err)
2525f29458bSAya Levin 			break;
2535f29458bSAya Levin 	}
2545f29458bSAya Levin 	return err;
2555f29458bSAya Levin }
2565f29458bSAya Levin 
mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv * priv,struct mlx5_rsc_key * key,struct devlink_fmsg * fmsg)2575f29458bSAya Levin int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key,
2585f29458bSAya Levin 			       struct devlink_fmsg *fmsg)
2595f29458bSAya Levin {
2605f29458bSAya Levin 	struct mlx5_core_dev *mdev = priv->mdev;
2615f29458bSAya Levin 	struct mlx5_rsc_dump_cmd *cmd;
2625f29458bSAya Levin 	struct page *page;
2635f29458bSAya Levin 	int cmd_err, err;
2645f29458bSAya Levin 	int end_err;
2655f29458bSAya Levin 	int size;
2665f29458bSAya Levin 
2675f29458bSAya Levin 	if (IS_ERR_OR_NULL(mdev->rsc_dump))
2685f29458bSAya Levin 		return -EOPNOTSUPP;
2695f29458bSAya Levin 
2705f29458bSAya Levin 	page = alloc_page(GFP_KERNEL);
2715f29458bSAya Levin 	if (!page)
2725f29458bSAya Levin 		return -ENOMEM;
2735f29458bSAya Levin 
2745f29458bSAya Levin 	err = devlink_fmsg_binary_pair_nest_start(fmsg, "data");
2755f29458bSAya Levin 	if (err)
276258ed19fSPan Bian 		goto free_page;
2775f29458bSAya Levin 
2785f29458bSAya Levin 	cmd = mlx5_rsc_dump_cmd_create(mdev, key);
2795f29458bSAya Levin 	if (IS_ERR(cmd)) {
2805f29458bSAya Levin 		err = PTR_ERR(cmd);
2815f29458bSAya Levin 		goto free_page;
2825f29458bSAya Levin 	}
2835f29458bSAya Levin 
2845f29458bSAya Levin 	do {
2855f29458bSAya Levin 		cmd_err = mlx5_rsc_dump_next(mdev, cmd, page, &size);
2865f29458bSAya Levin 		if (cmd_err < 0) {
2875f29458bSAya Levin 			err = cmd_err;
2885f29458bSAya Levin 			goto destroy_cmd;
2895f29458bSAya Levin 		}
2905f29458bSAya Levin 
2915f29458bSAya Levin 		err = mlx5e_health_rsc_fmsg_binary(fmsg, page_address(page), size);
2925f29458bSAya Levin 		if (err)
2935f29458bSAya Levin 			goto destroy_cmd;
2945f29458bSAya Levin 
2955f29458bSAya Levin 	} while (cmd_err > 0);
2965f29458bSAya Levin 
2975f29458bSAya Levin destroy_cmd:
2985f29458bSAya Levin 	mlx5_rsc_dump_cmd_destroy(cmd);
2995f29458bSAya Levin 	end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
3005f29458bSAya Levin 	if (end_err)
3015f29458bSAya Levin 		err = end_err;
3025f29458bSAya Levin free_page:
3035f29458bSAya Levin 	__free_page(page);
3045f29458bSAya Levin 	return err;
3055f29458bSAya Levin }
3065f29458bSAya Levin 
mlx5e_health_queue_dump(struct mlx5e_priv * priv,struct devlink_fmsg * fmsg,int queue_idx,char * lbl)3075f29458bSAya Levin int mlx5e_health_queue_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
3085f29458bSAya Levin 			    int queue_idx, char *lbl)
3095f29458bSAya Levin {
3105f29458bSAya Levin 	struct mlx5_rsc_key key = {};
3115f29458bSAya Levin 	int err;
3125f29458bSAya Levin 
3135f29458bSAya Levin 	key.rsc = MLX5_SGMT_TYPE_FULL_QPC;
3145f29458bSAya Levin 	key.index1 = queue_idx;
3155f29458bSAya Levin 	key.size = PAGE_SIZE;
3165f29458bSAya Levin 	key.num_of_obj1 = 1;
3175f29458bSAya Levin 
3185f29458bSAya Levin 	err = devlink_fmsg_obj_nest_start(fmsg);
3195f29458bSAya Levin 	if (err)
3205f29458bSAya Levin 		return err;
3215f29458bSAya Levin 
322d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, lbl);
3235f29458bSAya Levin 	if (err)
3245f29458bSAya Levin 		return err;
3255f29458bSAya Levin 
3265f29458bSAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "index", queue_idx);
3275f29458bSAya Levin 	if (err)
3285f29458bSAya Levin 		return err;
3295f29458bSAya Levin 
3305f29458bSAya Levin 	err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
3315f29458bSAya Levin 	if (err)
3325f29458bSAya Levin 		return err;
3335f29458bSAya Levin 
334d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
3355f29458bSAya Levin 	if (err)
3365f29458bSAya Levin 		return err;
3375f29458bSAya Levin 
3385f29458bSAya Levin 	return devlink_fmsg_obj_nest_end(fmsg);
3395f29458bSAya Levin }
340