Skip to content

Commit aba2527

Browse files
Eran Ben Elishadavem330
authored andcommitted
net/mlx5e: Add TX reporter support
Add mlx5e tx reporter to devlink health reporters. This reporter will be responsible for diagnosing, reporting and recovering of TX errors. This patch declares the TX reporter operations and allocate it using the devlink health API. Currently, this reporter supports reporting and recovering from send error CQE only. In addition, it adds diagnose information for the open SQs. For a local SQ recover (due to driver error report), in case of SQ recover failure, the recover operation will be considered as a failure. For a full TX recover, an attempt to close and open the channels will be done. If this one passed successfully, it will be considered as a successful recover. The SQ recover from error CQE flow is not a new feature in the driver, this patch re-organize the functions and adapt them for the devlink health API. For this purpose, move code from en_main.c to a new file named reporter_tx.c. Signed-off-by: Eran Ben Elisha <[email protected]> Reviewed-by: Saeed Mahameed <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 12bd0dc commit aba2527

File tree

6 files changed

+367
-125
lines changed

6 files changed

+367
-125
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
2222
#
2323
mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
2424
en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o \
25-
en_selftest.o en/port.o en/monitor_stats.o
25+
en_selftest.o en/port.o en/monitor_stats.o en/reporter_tx.o
2626

2727
#
2828
# Netdev extra

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -388,10 +388,7 @@ struct mlx5e_txqsq {
388388
struct mlx5e_channel *channel;
389389
int txq_ix;
390390
u32 rate_limit;
391-
struct mlx5e_txqsq_recover {
392-
struct work_struct recover_work;
393-
u64 last_recover;
394-
} recover;
391+
struct work_struct recover_work;
395392
} ____cacheline_aligned_in_smp;
396393

397394
struct mlx5e_dma_info {
@@ -682,6 +679,13 @@ struct mlx5e_rss_params {
682679
u8 hfunc;
683680
};
684681

682+
struct mlx5e_modify_sq_param {
683+
int curr_state;
684+
int next_state;
685+
int rl_update;
686+
int rl_index;
687+
};
688+
685689
struct mlx5e_priv {
686690
/* priv data path fields - start */
687691
struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC];
@@ -737,6 +741,7 @@ struct mlx5e_priv {
737741
#ifdef CONFIG_MLX5_EN_TLS
738742
struct mlx5e_tls *tls;
739743
#endif
744+
struct devlink_health_reporter *tx_reporter;
740745
};
741746

742747
struct mlx5e_profile {
@@ -866,6 +871,11 @@ void mlx5e_set_rq_type(struct mlx5_core_dev *mdev, struct mlx5e_params *params);
866871
void mlx5e_init_rq_type_params(struct mlx5_core_dev *mdev,
867872
struct mlx5e_params *params);
868873

874+
int mlx5e_modify_sq(struct mlx5_core_dev *mdev, u32 sqn,
875+
struct mlx5e_modify_sq_param *p);
876+
void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq);
877+
void mlx5e_tx_disable_queue(struct netdev_queue *txq);
878+
869879
static inline bool mlx5e_tunnel_inner_ft_supported(struct mlx5_core_dev *mdev)
870880
{
871881
return (MLX5_CAP_ETH(mdev, tunnel_stateless_gre) &&
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2018 Mellanox Technologies. */
3+
4+
#ifndef __MLX5E_EN_REPORTER_H
5+
#define __MLX5E_EN_REPORTER_H
6+
7+
#include <linux/mlx5/driver.h>
8+
#include "en.h"
9+
10+
int mlx5e_tx_reporter_create(struct mlx5e_priv *priv);
11+
void mlx5e_tx_reporter_destroy(struct mlx5e_priv *priv);
12+
void mlx5e_tx_reporter_err_cqe(struct mlx5e_txqsq *sq);
13+
14+
#endif
Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2018 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_RQC_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+
void mlx5e_tx_reporter_err_cqe(struct mlx5e_txqsq *sq)
117+
{
118+
char err_str[MLX5E_TX_REPORTER_PER_SQ_MAX_LEN];
119+
struct mlx5e_tx_err_ctx err_ctx = {0};
120+
121+
err_ctx.sq = sq;
122+
err_ctx.recover = mlx5e_tx_reporter_err_cqe_recover;
123+
sprintf(err_str, "ERR CQE on SQ: 0x%x", sq->sqn);
124+
125+
devlink_health_report(sq->channel->priv->tx_reporter, err_str,
126+
&err_ctx);
127+
}
128+
129+
/* state lock cannot be grabbed within this function.
130+
* It can cause a dead lock or a read-after-free.
131+
*/
132+
int mlx5e_tx_reporter_recover_from_ctx(struct mlx5e_tx_err_ctx *err_ctx)
133+
{
134+
return err_ctx->recover(err_ctx->sq);
135+
}
136+
137+
static int mlx5e_tx_reporter_recover_all(struct mlx5e_priv *priv)
138+
{
139+
int err;
140+
141+
mutex_lock(&priv->state_lock);
142+
mlx5e_close_locked(priv->netdev);
143+
err = mlx5e_open_locked(priv->netdev);
144+
mutex_unlock(&priv->state_lock);
145+
146+
return err;
147+
}
148+
149+
static int mlx5e_tx_reporter_recover(struct devlink_health_reporter *reporter,
150+
void *context)
151+
{
152+
struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
153+
struct mlx5e_tx_err_ctx *err_ctx = context;
154+
155+
return err_ctx ? mlx5e_tx_reporter_recover_from_ctx(err_ctx) :
156+
mlx5e_tx_reporter_recover_all(priv);
157+
}
158+
159+
static int
160+
mlx5e_tx_reporter_build_diagnose_output(struct devlink_health_buffer *buffer,
161+
u32 sqn, u8 state, u8 stopped)
162+
{
163+
int err, i;
164+
int nest = 0;
165+
char name[20];
166+
167+
err = devlink_health_buffer_nest_start(buffer,
168+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT);
169+
if (err)
170+
goto buffer_error;
171+
nest++;
172+
173+
err = devlink_health_buffer_nest_start(buffer,
174+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR);
175+
if (err)
176+
goto buffer_error;
177+
nest++;
178+
179+
sprintf(name, "SQ 0x%x", sqn);
180+
err = devlink_health_buffer_put_object_name(buffer, name);
181+
if (err)
182+
goto buffer_error;
183+
184+
err = devlink_health_buffer_nest_start(buffer,
185+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE);
186+
if (err)
187+
goto buffer_error;
188+
nest++;
189+
190+
err = devlink_health_buffer_nest_start(buffer,
191+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT);
192+
if (err)
193+
goto buffer_error;
194+
nest++;
195+
196+
err = devlink_health_buffer_nest_start(buffer,
197+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR);
198+
if (err)
199+
goto buffer_error;
200+
nest++;
201+
202+
err = devlink_health_buffer_put_object_name(buffer, "HW state");
203+
if (err)
204+
goto buffer_error;
205+
206+
err = devlink_health_buffer_nest_start(buffer,
207+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE);
208+
if (err)
209+
goto buffer_error;
210+
nest++;
211+
212+
err = devlink_health_buffer_put_value_u8(buffer, state);
213+
if (err)
214+
goto buffer_error;
215+
216+
devlink_health_buffer_nest_end(buffer); /* DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE */
217+
nest--;
218+
219+
devlink_health_buffer_nest_end(buffer); /* DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR */
220+
nest--;
221+
222+
err = devlink_health_buffer_nest_start(buffer,
223+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR);
224+
if (err)
225+
goto buffer_error;
226+
nest++;
227+
228+
err = devlink_health_buffer_put_object_name(buffer, "stopped");
229+
if (err)
230+
goto buffer_error;
231+
232+
err = devlink_health_buffer_nest_start(buffer,
233+
DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE);
234+
if (err)
235+
goto buffer_error;
236+
nest++;
237+
238+
err = devlink_health_buffer_put_value_u8(buffer, stopped);
239+
if (err)
240+
goto buffer_error;
241+
242+
for (i = 0; i < nest; i++)
243+
devlink_health_buffer_nest_end(buffer);
244+
245+
return 0;
246+
247+
buffer_error:
248+
for (i = 0; i < nest; i++)
249+
devlink_health_buffer_nest_cancel(buffer);
250+
return err;
251+
}
252+
253+
static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter,
254+
struct devlink_health_buffer **buffers_array,
255+
unsigned int buffer_size,
256+
unsigned int num_buffers)
257+
{
258+
struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter);
259+
unsigned int buff = 0;
260+
int i = 0, err = 0;
261+
262+
if (buffer_size < MLX5E_TX_REPORTER_PER_SQ_MAX_LEN)
263+
return -ENOMEM;
264+
265+
mutex_lock(&priv->state_lock);
266+
267+
if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
268+
mutex_unlock(&priv->state_lock);
269+
return 0;
270+
}
271+
272+
while (i < priv->channels.num * priv->channels.params.num_tc) {
273+
struct mlx5e_txqsq *sq = priv->txq2sq[i];
274+
u8 state;
275+
276+
err = mlx5_core_query_sq_state(priv->mdev, sq->sqn, &state);
277+
if (err)
278+
break;
279+
280+
err = mlx5e_tx_reporter_build_diagnose_output(buffers_array[buff],
281+
sq->sqn, state,
282+
netif_xmit_stopped(sq->txq));
283+
if (err) {
284+
if (++buff == num_buffers)
285+
break;
286+
} else {
287+
i++;
288+
}
289+
}
290+
291+
mutex_unlock(&priv->state_lock);
292+
return err;
293+
}
294+
295+
static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {
296+
.name = "TX",
297+
.recover = mlx5e_tx_reporter_recover,
298+
.diagnose_size = MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC *
299+
MLX5E_TX_REPORTER_PER_SQ_MAX_LEN,
300+
.diagnose = mlx5e_tx_reporter_diagnose,
301+
.dump_size = 0,
302+
.dump = NULL,
303+
};
304+
305+
#define MLX5_REPORTER_TX_GRACEFUL_PERIOD 500
306+
int mlx5e_tx_reporter_create(struct mlx5e_priv *priv)
307+
{
308+
struct mlx5_core_dev *mdev = priv->mdev;
309+
struct devlink *devlink = priv_to_devlink(mdev);
310+
311+
priv->tx_reporter =
312+
devlink_health_reporter_create(devlink, &mlx5_tx_reporter_ops,
313+
MLX5_REPORTER_TX_GRACEFUL_PERIOD,
314+
true, priv);
315+
return PTR_ERR_OR_ZERO(priv->tx_reporter);
316+
}
317+
318+
void mlx5e_tx_reporter_destroy(struct mlx5e_priv *priv)
319+
{
320+
devlink_health_reporter_destroy(priv->tx_reporter);
321+
}

0 commit comments

Comments
 (0)