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