1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (c) 2019 Mellanox Technologies. */
3 
4 #include <net/devlink.h>
5 #include "reporter.h"
6 #include "lib/eq.h"
7 
8 #define MLX5E_TX_REPORTER_PER_SQ_MAX_LEN 256
9 
10 struct mlx5e_tx_err_ctx {
11 	int (*recover)(struct mlx5e_txqsq *sq);
12 	struct mlx5e_txqsq *sq;
13 };
14 
15 static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
16 {
17 	unsigned long exp_time = jiffies + msecs_to_jiffies(2000);
18 
19 	while (time_before(jiffies, exp_time)) {
20 		if (sq->cc == sq->pc)
21 			return 0;
22 
23 		msleep(20);
24 	}
25 
26 	netdev_err(sq->channel->netdev,
27 		   "Wait for SQ 0x%x flush timeout (sq cc = 0x%x, sq pc = 0x%x)\n",
28 		   sq->sqn, sq->cc, sq->pc);
29 
30 	return -ETIMEDOUT;
31 }
32 
33 static void mlx5e_reset_txqsq_cc_pc(struct mlx5e_txqsq *sq)
34 {
35 	WARN_ONCE(sq->cc != sq->pc,
36 		  "SQ 0x%x: cc (0x%x) != pc (0x%x)\n",
37 		  sq->sqn, sq->cc, sq->pc);
38 	sq->cc = 0;
39 	sq->dma_fifo_cc = 0;
40 	sq->pc = 0;
41 }
42 
43 static int mlx5e_sq_to_ready(struct mlx5e_txqsq *sq, int curr_state)
44 {
45 	struct mlx5_core_dev *mdev = sq->channel->mdev;
46 	struct net_device *dev = sq->channel->netdev;
47 	struct mlx5e_modify_sq_param msp = {0};
48 	int err;
49 
50 	msp.curr_state = curr_state;
51 	msp.next_state = MLX5_SQC_STATE_RST;
52 
53 	err = mlx5e_modify_sq(mdev, sq->sqn, &msp);
54 	if (err) {
55 		netdev_err(dev, "Failed to move sq 0x%x to reset\n", sq->sqn);
56 		return err;
57 	}
58 
59 	memset(&msp, 0, sizeof(msp));
60 	msp.curr_state = MLX5_SQC_STATE_RST;
61 	msp.next_state = MLX5_SQC_STATE_RDY;
62 
63 	err = mlx5e_modify_sq(mdev, sq->sqn, &msp);
64 	if (err) {
65 		netdev_err(dev, "Failed to move sq 0x%x to ready\n", sq->sqn);
66 		return err;
67 	}
68 
69 	return 0;
70 }
71 
72 static int mlx5e_tx_reporter_err_cqe_recover(struct mlx5e_txqsq *sq)
73 {
74 	struct mlx5_core_dev *mdev = sq->channel->mdev;
75 	struct net_device *dev = sq->channel->netdev;
76 	u8 state;
77 	int err;
78 
79 	if (!test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state))
80 		return 0;
81 
82 	err = mlx5_core_query_sq_state(mdev, sq->sqn, &state);
83 	if (err) {
84 		netdev_err(dev, "Failed to query SQ 0x%x state. err = %d\n",
85 			   sq->sqn, err);
86 		return err;
87 	}
88 
89 	if (state != MLX5_SQC_STATE_ERR) {
90 		netdev_err(dev, "SQ 0x%x not in ERROR state\n", sq->sqn);
91 		return -EINVAL;
92 	}
93 
94 	mlx5e_tx_disable_queue(sq->txq);
95 
96 	err = mlx5e_wait_for_sq_flush(sq);
97 	if (err)
98 		return err;
99 
100 	/* At this point, no new packets will arrive from the stack as TXQ is
101 	 * marked with QUEUE_STATE_DRV_XOFF. In addition, NAPI cleared all
102 	 * pending WQEs. SQ can safely reset the SQ.
103 	 */
104 
105 	err = mlx5e_sq_to_ready(sq, state);
106 	if (err)
107 		return err;
108 
109 	mlx5e_reset_txqsq_cc_pc(sq);
110 	sq->stats->recover++;
111 	mlx5e_activate_txqsq(sq);
112 
113 	return 0;
114 }
115 
116 static int mlx5_tx_health_report(struct devlink_health_reporter *tx_reporter,
117 				 char *err_str,
118 				 struct mlx5e_tx_err_ctx *err_ctx)
119 {
120 	if (IS_ERR_OR_NULL(tx_reporter)) {
121 		netdev_err(err_ctx->sq->channel->netdev, err_str);
122 		return err_ctx->recover(err_ctx->sq);
123 	}
124 
125 	return devlink_health_report(tx_reporter, err_str, err_ctx);
126 }
127 
128 void mlx5e_tx_reporter_err_cqe(struct mlx5e_txqsq *sq)
129 {
130 	char err_str[MLX5E_TX_REPORTER_PER_SQ_MAX_LEN];
131 	struct mlx5e_tx_err_ctx err_ctx = {0};
132 
133 	err_ctx.sq       = sq;
134 	err_ctx.recover  = mlx5e_tx_reporter_err_cqe_recover;
135 	sprintf(err_str, "ERR CQE on SQ: 0x%x", sq->sqn);
136 
137 	mlx5_tx_health_report(sq->channel->priv->tx_reporter, err_str,
138 			      &err_ctx);
139 }
140 
141 static int mlx5e_tx_reporter_timeout_recover(struct mlx5e_txqsq *sq)
142 {
143 	struct mlx5_eq_comp *eq = sq->cq.mcq.eq;
144 	u32 eqe_count;
145 
146 	netdev_err(sq->channel->netdev, "EQ 0x%x: Cons = 0x%x, irqn = 0x%x\n",
147 		   eq->core.eqn, eq->core.cons_index, eq->core.irqn);
148 
149 	eqe_count = mlx5_eq_poll_irq_disabled(eq);
150 	if (!eqe_count) {
151 		clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
152 		return -EIO;
153 	}
154 
155 	netdev_err(sq->channel->netdev, "Recover %d eqes on EQ 0x%x\n",
156 		   eqe_count, eq->core.eqn);
157 	sq->channel->stats->eq_rearm++;
158 	return 0;
159 }
160 
161 int mlx5e_tx_reporter_timeout(struct mlx5e_txqsq *sq)
162 {
163 	char err_str[MLX5E_TX_REPORTER_PER_SQ_MAX_LEN];
164 	struct mlx5e_tx_err_ctx err_ctx;
165 
166 	err_ctx.sq       = sq;
167 	err_ctx.recover  = mlx5e_tx_reporter_timeout_recover;
168 	sprintf(err_str,
169 		"TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x, usecs since last trans: %u\n",
170 		sq->channel->ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc,
171 		jiffies_to_usecs(jiffies - sq->txq->trans_start));
172 
173 	return mlx5_tx_health_report(sq->channel->priv->tx_reporter, err_str,
174 				     &err_ctx);
175 }
176 
177 /* state lock cannot be grabbed within this function.
178  * It can cause a dead lock or a read-after-free.
179  */
180 static int mlx5e_tx_reporter_recover_from_ctx(struct mlx5e_tx_err_ctx *err_ctx)
181 {
182 	return err_ctx->recover(err_ctx->sq);
183 }
184 
185 static int mlx5e_tx_reporter_recover_all(struct mlx5e_priv *priv)
186 {
187 	int err = 0;
188 
189 	rtnl_lock();
190 	mutex_lock(&priv->state_lock);
191 
192 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
193 		goto out;
194 
195 	err = mlx5e_safe_reopen_channels(priv);
196 
197 out:
198 	mutex_unlock(&priv->state_lock);
199 	rtnl_unlock();
200 
201 	return err;
202 }
203 
204 static int mlx5e_tx_reporter_recover(struct devlink_health_reporter *reporter,
205 				     void *context)
206 {
207 	struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
208 	struct mlx5e_tx_err_ctx *err_ctx = context;
209 
210 	return err_ctx ? mlx5e_tx_reporter_recover_from_ctx(err_ctx) :
211 			 mlx5e_tx_reporter_recover_all(priv);
212 }
213 
214 static int
215 mlx5e_tx_reporter_build_diagnose_output(struct devlink_fmsg *fmsg,
216 					u32 sqn, u8 state, bool stopped)
217 {
218 	int err;
219 
220 	err = devlink_fmsg_obj_nest_start(fmsg);
221 	if (err)
222 		return err;
223 
224 	err = devlink_fmsg_u32_pair_put(fmsg, "sqn", sqn);
225 	if (err)
226 		return err;
227 
228 	err = devlink_fmsg_u8_pair_put(fmsg, "HW state", state);
229 	if (err)
230 		return err;
231 
232 	err = devlink_fmsg_bool_pair_put(fmsg, "stopped", stopped);
233 	if (err)
234 		return err;
235 
236 	err = devlink_fmsg_obj_nest_end(fmsg);
237 	if (err)
238 		return err;
239 
240 	return 0;
241 }
242 
243 static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter,
244 				      struct devlink_fmsg *fmsg)
245 {
246 	struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
247 	int i, err = 0;
248 
249 	mutex_lock(&priv->state_lock);
250 
251 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
252 		goto unlock;
253 
254 	err = devlink_fmsg_arr_pair_nest_start(fmsg, "SQs");
255 	if (err)
256 		goto unlock;
257 
258 	for (i = 0; i < priv->channels.num * priv->channels.params.num_tc;
259 	     i++) {
260 		struct mlx5e_txqsq *sq = priv->txq2sq[i];
261 		u8 state;
262 
263 		err = mlx5_core_query_sq_state(priv->mdev, sq->sqn, &state);
264 		if (err)
265 			goto unlock;
266 
267 		err = mlx5e_tx_reporter_build_diagnose_output(fmsg, sq->sqn,
268 							      state,
269 							      netif_xmit_stopped(sq->txq));
270 		if (err)
271 			goto unlock;
272 	}
273 	err = devlink_fmsg_arr_pair_nest_end(fmsg);
274 	if (err)
275 		goto unlock;
276 
277 unlock:
278 	mutex_unlock(&priv->state_lock);
279 	return err;
280 }
281 
282 static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {
283 		.name = "tx",
284 		.recover = mlx5e_tx_reporter_recover,
285 		.diagnose = mlx5e_tx_reporter_diagnose,
286 };
287 
288 #define MLX5_REPORTER_TX_GRACEFUL_PERIOD 500
289 
290 int mlx5e_tx_reporter_create(struct mlx5e_priv *priv)
291 {
292 	struct mlx5_core_dev *mdev = priv->mdev;
293 	struct devlink *devlink = priv_to_devlink(mdev);
294 
295 	priv->tx_reporter =
296 		devlink_health_reporter_create(devlink, &mlx5_tx_reporter_ops,
297 					       MLX5_REPORTER_TX_GRACEFUL_PERIOD,
298 					       true, priv);
299 	if (IS_ERR(priv->tx_reporter))
300 		netdev_warn(priv->netdev,
301 			    "Failed to create tx reporter, err = %ld\n",
302 			    PTR_ERR(priv->tx_reporter));
303 	return IS_ERR_OR_NULL(priv->tx_reporter);
304 }
305 
306 void mlx5e_tx_reporter_destroy(struct mlx5e_priv *priv)
307 {
308 	if (IS_ERR_OR_NULL(priv->tx_reporter))
309 		return;
310 
311 	devlink_health_reporter_destroy(priv->tx_reporter);
312 }
313