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 	int ret;
146 
147 	netdev_err(sq->channel->netdev, "EQ 0x%x: Cons = 0x%x, irqn = 0x%x\n",
148 		   eq->core.eqn, eq->core.cons_index, eq->core.irqn);
149 
150 	eqe_count = mlx5_eq_poll_irq_disabled(eq);
151 	ret = eqe_count ? true : false;
152 	if (!eqe_count) {
153 		clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
154 		return ret;
155 	}
156 
157 	netdev_err(sq->channel->netdev, "Recover %d eqes on EQ 0x%x\n",
158 		   eqe_count, eq->core.eqn);
159 	sq->channel->stats->eq_rearm++;
160 	return ret;
161 }
162 
163 int mlx5e_tx_reporter_timeout(struct mlx5e_txqsq *sq)
164 {
165 	char err_str[MLX5E_TX_REPORTER_PER_SQ_MAX_LEN];
166 	struct mlx5e_tx_err_ctx err_ctx;
167 
168 	err_ctx.sq       = sq;
169 	err_ctx.recover  = mlx5e_tx_reporter_timeout_recover;
170 	sprintf(err_str,
171 		"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",
172 		sq->channel->ix, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc,
173 		jiffies_to_usecs(jiffies - sq->txq->trans_start));
174 
175 	return mlx5_tx_health_report(sq->channel->priv->tx_reporter, err_str,
176 				     &err_ctx);
177 }
178 
179 /* state lock cannot be grabbed within this function.
180  * It can cause a dead lock or a read-after-free.
181  */
182 int mlx5e_tx_reporter_recover_from_ctx(struct mlx5e_tx_err_ctx *err_ctx)
183 {
184 	return err_ctx->recover(err_ctx->sq);
185 }
186 
187 static int mlx5e_tx_reporter_recover_all(struct mlx5e_priv *priv)
188 {
189 	int err;
190 
191 	rtnl_lock();
192 	mutex_lock(&priv->state_lock);
193 	mlx5e_close_locked(priv->netdev);
194 	err = mlx5e_open_locked(priv->netdev);
195 	mutex_unlock(&priv->state_lock);
196 	rtnl_unlock();
197 
198 	return err;
199 }
200 
201 static int mlx5e_tx_reporter_recover(struct devlink_health_reporter *reporter,
202 				     void *context)
203 {
204 	struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
205 	struct mlx5e_tx_err_ctx *err_ctx = context;
206 
207 	return err_ctx ? mlx5e_tx_reporter_recover_from_ctx(err_ctx) :
208 			 mlx5e_tx_reporter_recover_all(priv);
209 }
210 
211 static int
212 mlx5e_tx_reporter_build_diagnose_output(struct devlink_fmsg *fmsg,
213 					u32 sqn, u8 state, bool stopped)
214 {
215 	int err;
216 
217 	err = devlink_fmsg_obj_nest_start(fmsg);
218 	if (err)
219 		return err;
220 
221 	err = devlink_fmsg_u32_pair_put(fmsg, "sqn", sqn);
222 	if (err)
223 		return err;
224 
225 	err = devlink_fmsg_u8_pair_put(fmsg, "HW state", state);
226 	if (err)
227 		return err;
228 
229 	err = devlink_fmsg_bool_pair_put(fmsg, "stopped", stopped);
230 	if (err)
231 		return err;
232 
233 	err = devlink_fmsg_obj_nest_end(fmsg);
234 	if (err)
235 		return err;
236 
237 	return 0;
238 }
239 
240 static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter,
241 				      struct devlink_fmsg *fmsg)
242 {
243 	struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
244 	int i, err = 0;
245 
246 	mutex_lock(&priv->state_lock);
247 
248 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
249 		goto unlock;
250 
251 	err = devlink_fmsg_arr_pair_nest_start(fmsg, "SQs");
252 	if (err)
253 		goto unlock;
254 
255 	for (i = 0; i < priv->channels.num * priv->channels.params.num_tc;
256 	     i++) {
257 		struct mlx5e_txqsq *sq = priv->txq2sq[i];
258 		u8 state;
259 
260 		err = mlx5_core_query_sq_state(priv->mdev, sq->sqn, &state);
261 		if (err)
262 			break;
263 
264 		err = mlx5e_tx_reporter_build_diagnose_output(fmsg, sq->sqn,
265 							      state,
266 							      netif_xmit_stopped(sq->txq));
267 		if (err)
268 			break;
269 	}
270 	err = devlink_fmsg_arr_pair_nest_end(fmsg);
271 	if (err)
272 		goto unlock;
273 
274 unlock:
275 	mutex_unlock(&priv->state_lock);
276 	return err;
277 }
278 
279 static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {
280 		.name = "tx",
281 		.recover = mlx5e_tx_reporter_recover,
282 		.diagnose = mlx5e_tx_reporter_diagnose,
283 };
284 
285 #define MLX5_REPORTER_TX_GRACEFUL_PERIOD 500
286 
287 int mlx5e_tx_reporter_create(struct mlx5e_priv *priv)
288 {
289 	struct mlx5_core_dev *mdev = priv->mdev;
290 	struct devlink *devlink = priv_to_devlink(mdev);
291 
292 	priv->tx_reporter =
293 		devlink_health_reporter_create(devlink, &mlx5_tx_reporter_ops,
294 					       MLX5_REPORTER_TX_GRACEFUL_PERIOD,
295 					       true, priv);
296 	if (IS_ERR(priv->tx_reporter))
297 		netdev_warn(priv->netdev,
298 			    "Failed to create tx reporter, err = %ld\n",
299 			    PTR_ERR(priv->tx_reporter));
300 	return PTR_ERR_OR_ZERO(priv->tx_reporter);
301 }
302 
303 void mlx5e_tx_reporter_destroy(struct mlx5e_priv *priv)
304 {
305 	if (IS_ERR_OR_NULL(priv->tx_reporter))
306 		return;
307 
308 	devlink_health_reporter_destroy(priv->tx_reporter);
309 }
310