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 
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 
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 
38d5cbedd7SAya Levin int mlx5e_health_cq_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg)
392bf09e60SAya Levin {
402bf09e60SAya Levin 	struct mlx5e_priv *priv = cq->channel->priv;
412bf09e60SAya Levin 	u32 out[MLX5_ST_SZ_DW(query_cq_out)] = {};
422bf09e60SAya Levin 	u8 hw_status;
432bf09e60SAya Levin 	void *cqc;
442bf09e60SAya Levin 	int err;
452bf09e60SAya Levin 
46d1f62050SLeon Romanovsky 	err = mlx5_core_query_cq(priv->mdev, &cq->mcq, out);
472bf09e60SAya Levin 	if (err)
482bf09e60SAya Levin 		return err;
492bf09e60SAya Levin 
502bf09e60SAya Levin 	cqc = MLX5_ADDR_OF(query_cq_out, out, cq_context);
512bf09e60SAya Levin 	hw_status = MLX5_GET(cqc, cqc, status);
522bf09e60SAya Levin 
53d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "CQ");
542bf09e60SAya Levin 	if (err)
552bf09e60SAya Levin 		return err;
562bf09e60SAya Levin 
572bf09e60SAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "cqn", cq->mcq.cqn);
582bf09e60SAya Levin 	if (err)
592bf09e60SAya Levin 		return err;
602bf09e60SAya Levin 
612bf09e60SAya Levin 	err = devlink_fmsg_u8_pair_put(fmsg, "HW status", hw_status);
622bf09e60SAya Levin 	if (err)
632bf09e60SAya Levin 		return err;
642bf09e60SAya Levin 
65d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
662bf09e60SAya Levin 	if (err)
672bf09e60SAya Levin 		return err;
682bf09e60SAya Levin 
692bf09e60SAya Levin 	return 0;
702bf09e60SAya Levin }
712bf09e60SAya Levin 
72d5cbedd7SAya Levin int mlx5e_health_cq_common_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg)
732bf09e60SAya Levin {
742bf09e60SAya Levin 	u8 cq_log_stride;
752bf09e60SAya Levin 	u32 cq_sz;
762bf09e60SAya Levin 	int err;
772bf09e60SAya Levin 
782bf09e60SAya Levin 	cq_sz = mlx5_cqwq_get_size(&cq->wq);
792bf09e60SAya Levin 	cq_log_stride = mlx5_cqwq_get_log_stride_size(&cq->wq);
802bf09e60SAya Levin 
81d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, "CQ");
822bf09e60SAya Levin 	if (err)
832bf09e60SAya Levin 		return err;
842bf09e60SAya Levin 
852bf09e60SAya Levin 	err = devlink_fmsg_u64_pair_put(fmsg, "stride size", BIT(cq_log_stride));
862bf09e60SAya Levin 	if (err)
872bf09e60SAya Levin 		return err;
882bf09e60SAya Levin 
892bf09e60SAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "size", cq_sz);
902bf09e60SAya Levin 	if (err)
912bf09e60SAya Levin 		return err;
922bf09e60SAya Levin 
93d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
942bf09e60SAya Levin 	if (err)
952bf09e60SAya Levin 		return err;
962bf09e60SAya Levin 
972bf09e60SAya Levin 	return 0;
982bf09e60SAya Levin }
992bf09e60SAya Levin 
100b3ea4c4fSEran Ben Elisha void mlx5e_health_create_reporters(struct mlx5e_priv *priv)
10111af6a6dSAya Levin {
102b3ea4c4fSEran Ben Elisha 	mlx5e_reporter_tx_create(priv);
103b3ea4c4fSEran Ben Elisha 	mlx5e_reporter_rx_create(priv);
10411af6a6dSAya Levin }
10511af6a6dSAya Levin 
10611af6a6dSAya Levin void mlx5e_health_destroy_reporters(struct mlx5e_priv *priv)
10711af6a6dSAya Levin {
1089032e719SAya Levin 	mlx5e_reporter_rx_destroy(priv);
10911af6a6dSAya Levin 	mlx5e_reporter_tx_destroy(priv);
11011af6a6dSAya Levin }
11111af6a6dSAya Levin 
11211af6a6dSAya Levin void mlx5e_health_channels_update(struct mlx5e_priv *priv)
11311af6a6dSAya Levin {
11411af6a6dSAya Levin 	if (priv->tx_reporter)
11511af6a6dSAya Levin 		devlink_health_reporter_state_update(priv->tx_reporter,
11611af6a6dSAya Levin 						     DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
1179032e719SAya Levin 	if (priv->rx_reporter)
1189032e719SAya Levin 		devlink_health_reporter_state_update(priv->rx_reporter,
1199032e719SAya Levin 						     DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
12011af6a6dSAya Levin }
12111af6a6dSAya Levin 
122c50de4afSAya Levin int mlx5e_health_sq_to_ready(struct mlx5e_channel *channel, u32 sqn)
123c50de4afSAya Levin {
124c50de4afSAya Levin 	struct mlx5_core_dev *mdev = channel->mdev;
125c50de4afSAya Levin 	struct net_device *dev = channel->netdev;
126c50de4afSAya Levin 	struct mlx5e_modify_sq_param msp = {};
127c50de4afSAya Levin 	int err;
128c50de4afSAya Levin 
129c50de4afSAya Levin 	msp.curr_state = MLX5_SQC_STATE_ERR;
130c50de4afSAya Levin 	msp.next_state = MLX5_SQC_STATE_RST;
131c50de4afSAya Levin 
132c50de4afSAya Levin 	err = mlx5e_modify_sq(mdev, sqn, &msp);
133c50de4afSAya Levin 	if (err) {
134c50de4afSAya Levin 		netdev_err(dev, "Failed to move sq 0x%x to reset\n", sqn);
135c50de4afSAya Levin 		return err;
136c50de4afSAya Levin 	}
137c50de4afSAya Levin 
138c50de4afSAya Levin 	memset(&msp, 0, sizeof(msp));
139c50de4afSAya Levin 	msp.curr_state = MLX5_SQC_STATE_RST;
140c50de4afSAya Levin 	msp.next_state = MLX5_SQC_STATE_RDY;
141c50de4afSAya Levin 
142c50de4afSAya Levin 	err = mlx5e_modify_sq(mdev, sqn, &msp);
143c50de4afSAya Levin 	if (err) {
144c50de4afSAya Levin 		netdev_err(dev, "Failed to move sq 0x%x to ready\n", sqn);
145c50de4afSAya Levin 		return err;
146c50de4afSAya Levin 	}
147c50de4afSAya Levin 
148c50de4afSAya Levin 	return 0;
149c50de4afSAya Levin }
150c50de4afSAya Levin 
151c50de4afSAya Levin int mlx5e_health_recover_channels(struct mlx5e_priv *priv)
152c50de4afSAya Levin {
153c50de4afSAya Levin 	int err = 0;
154c50de4afSAya Levin 
155c50de4afSAya Levin 	rtnl_lock();
156c50de4afSAya Levin 	mutex_lock(&priv->state_lock);
157c50de4afSAya Levin 
158c50de4afSAya Levin 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
159c50de4afSAya Levin 		goto out;
160c50de4afSAya Levin 
161c50de4afSAya Levin 	err = mlx5e_safe_reopen_channels(priv);
162c50de4afSAya Levin 
163c50de4afSAya Levin out:
164c50de4afSAya Levin 	mutex_unlock(&priv->state_lock);
165c50de4afSAya Levin 	rtnl_unlock();
166c50de4afSAya Levin 
167c50de4afSAya Levin 	return err;
168c50de4afSAya Levin }
169c50de4afSAya Levin 
170c50de4afSAya Levin int mlx5e_health_channel_eq_recover(struct mlx5_eq_comp *eq, struct mlx5e_channel *channel)
171c50de4afSAya Levin {
172c50de4afSAya Levin 	u32 eqe_count;
173c50de4afSAya Levin 
174c50de4afSAya Levin 	netdev_err(channel->netdev, "EQ 0x%x: Cons = 0x%x, irqn = 0x%x\n",
175c50de4afSAya Levin 		   eq->core.eqn, eq->core.cons_index, eq->core.irqn);
176c50de4afSAya Levin 
177c50de4afSAya Levin 	eqe_count = mlx5_eq_poll_irq_disabled(eq);
178c50de4afSAya Levin 	if (!eqe_count)
179c50de4afSAya Levin 		return -EIO;
180c50de4afSAya Levin 
181c50de4afSAya Levin 	netdev_err(channel->netdev, "Recovered %d eqes on EQ 0x%x\n",
182c50de4afSAya Levin 		   eqe_count, eq->core.eqn);
183c50de4afSAya Levin 
184c50de4afSAya Levin 	channel->stats->eq_rearm++;
185c50de4afSAya Levin 	return 0;
186c50de4afSAya Levin }
187c50de4afSAya Levin 
188c50de4afSAya Levin int mlx5e_health_report(struct mlx5e_priv *priv,
189c50de4afSAya Levin 			struct devlink_health_reporter *reporter, char *err_str,
190c50de4afSAya Levin 			struct mlx5e_err_ctx *err_ctx)
191c50de4afSAya Levin {
192b21aef7eSJoe Perches 	netdev_err(priv->netdev, "%s\n", err_str);
19399cda454SEran Ben Elisha 
19499cda454SEran Ben Elisha 	if (!reporter)
1951ad6c43cSAya Levin 		return err_ctx->recover(err_ctx->ctx);
19699cda454SEran Ben Elisha 
197c50de4afSAya Levin 	return devlink_health_report(reporter, err_str, err_ctx);
198c50de4afSAya Levin }
1995f29458bSAya Levin 
2005f29458bSAya Levin #define MLX5_HEALTH_DEVLINK_MAX_SIZE 1024
2015f29458bSAya Levin static int mlx5e_health_rsc_fmsg_binary(struct devlink_fmsg *fmsg,
2025f29458bSAya Levin 					const void *value, u32 value_len)
2035f29458bSAya Levin 
2045f29458bSAya Levin {
2055f29458bSAya Levin 	u32 data_size;
2065f29458bSAya Levin 	u32 offset;
2075f29458bSAya Levin 	int err;
2085f29458bSAya Levin 
2095f29458bSAya Levin 	for (offset = 0; offset < value_len; offset += data_size) {
2105f29458bSAya Levin 		data_size = value_len - offset;
2115f29458bSAya Levin 		if (data_size > MLX5_HEALTH_DEVLINK_MAX_SIZE)
2125f29458bSAya Levin 			data_size = MLX5_HEALTH_DEVLINK_MAX_SIZE;
2135f29458bSAya Levin 		err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
2145f29458bSAya Levin 		if (err)
2155f29458bSAya Levin 			break;
2165f29458bSAya Levin 	}
2175f29458bSAya Levin 	return err;
2185f29458bSAya Levin }
2195f29458bSAya Levin 
2205f29458bSAya Levin int mlx5e_health_rsc_fmsg_dump(struct mlx5e_priv *priv, struct mlx5_rsc_key *key,
2215f29458bSAya Levin 			       struct devlink_fmsg *fmsg)
2225f29458bSAya Levin {
2235f29458bSAya Levin 	struct mlx5_core_dev *mdev = priv->mdev;
2245f29458bSAya Levin 	struct mlx5_rsc_dump_cmd *cmd;
2255f29458bSAya Levin 	struct page *page;
2265f29458bSAya Levin 	int cmd_err, err;
2275f29458bSAya Levin 	int end_err;
2285f29458bSAya Levin 	int size;
2295f29458bSAya Levin 
2305f29458bSAya Levin 	if (IS_ERR_OR_NULL(mdev->rsc_dump))
2315f29458bSAya Levin 		return -EOPNOTSUPP;
2325f29458bSAya Levin 
2335f29458bSAya Levin 	page = alloc_page(GFP_KERNEL);
2345f29458bSAya Levin 	if (!page)
2355f29458bSAya Levin 		return -ENOMEM;
2365f29458bSAya Levin 
2375f29458bSAya Levin 	err = devlink_fmsg_binary_pair_nest_start(fmsg, "data");
2385f29458bSAya Levin 	if (err)
2395f29458bSAya Levin 		return err;
2405f29458bSAya Levin 
2415f29458bSAya Levin 	cmd = mlx5_rsc_dump_cmd_create(mdev, key);
2425f29458bSAya Levin 	if (IS_ERR(cmd)) {
2435f29458bSAya Levin 		err = PTR_ERR(cmd);
2445f29458bSAya Levin 		goto free_page;
2455f29458bSAya Levin 	}
2465f29458bSAya Levin 
2475f29458bSAya Levin 	do {
2485f29458bSAya Levin 		cmd_err = mlx5_rsc_dump_next(mdev, cmd, page, &size);
2495f29458bSAya Levin 		if (cmd_err < 0) {
2505f29458bSAya Levin 			err = cmd_err;
2515f29458bSAya Levin 			goto destroy_cmd;
2525f29458bSAya Levin 		}
2535f29458bSAya Levin 
2545f29458bSAya Levin 		err = mlx5e_health_rsc_fmsg_binary(fmsg, page_address(page), size);
2555f29458bSAya Levin 		if (err)
2565f29458bSAya Levin 			goto destroy_cmd;
2575f29458bSAya Levin 
2585f29458bSAya Levin 	} while (cmd_err > 0);
2595f29458bSAya Levin 
2605f29458bSAya Levin destroy_cmd:
2615f29458bSAya Levin 	mlx5_rsc_dump_cmd_destroy(cmd);
2625f29458bSAya Levin 	end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
2635f29458bSAya Levin 	if (end_err)
2645f29458bSAya Levin 		err = end_err;
2655f29458bSAya Levin free_page:
2665f29458bSAya Levin 	__free_page(page);
2675f29458bSAya Levin 	return err;
2685f29458bSAya Levin }
2695f29458bSAya Levin 
2705f29458bSAya Levin int mlx5e_health_queue_dump(struct mlx5e_priv *priv, struct devlink_fmsg *fmsg,
2715f29458bSAya Levin 			    int queue_idx, char *lbl)
2725f29458bSAya Levin {
2735f29458bSAya Levin 	struct mlx5_rsc_key key = {};
2745f29458bSAya Levin 	int err;
2755f29458bSAya Levin 
2765f29458bSAya Levin 	key.rsc = MLX5_SGMT_TYPE_FULL_QPC;
2775f29458bSAya Levin 	key.index1 = queue_idx;
2785f29458bSAya Levin 	key.size = PAGE_SIZE;
2795f29458bSAya Levin 	key.num_of_obj1 = 1;
2805f29458bSAya Levin 
2815f29458bSAya Levin 	err = devlink_fmsg_obj_nest_start(fmsg);
2825f29458bSAya Levin 	if (err)
2835f29458bSAya Levin 		return err;
2845f29458bSAya Levin 
285d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_start(fmsg, lbl);
2865f29458bSAya Levin 	if (err)
2875f29458bSAya Levin 		return err;
2885f29458bSAya Levin 
2895f29458bSAya Levin 	err = devlink_fmsg_u32_pair_put(fmsg, "index", queue_idx);
2905f29458bSAya Levin 	if (err)
2915f29458bSAya Levin 		return err;
2925f29458bSAya Levin 
2935f29458bSAya Levin 	err = mlx5e_health_rsc_fmsg_dump(priv, &key, fmsg);
2945f29458bSAya Levin 	if (err)
2955f29458bSAya Levin 		return err;
2965f29458bSAya Levin 
297d5cbedd7SAya Levin 	err = mlx5e_health_fmsg_named_obj_nest_end(fmsg);
2985f29458bSAya Levin 	if (err)
2995f29458bSAya Levin 		return err;
3005f29458bSAya Levin 
3015f29458bSAya Levin 	return devlink_fmsg_obj_nest_end(fmsg);
3025f29458bSAya Levin }
303