]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c
net/mlx5: fix possible stack overflows
[thirdparty/kernel/stable.git] / drivers / net / ethernet / mellanox / mlx5 / core / steering / dr_dbg.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4 #include <linux/debugfs.h>
5 #include <linux/kernel.h>
6 #include <linux/seq_file.h>
7 #include <linux/version.h>
8 #include "dr_types.h"
9
10 #define DR_DBG_PTR_TO_ID(p) ((u64)(uintptr_t)(p) & 0xFFFFFFFFULL)
11
12 enum dr_dump_rec_type {
13 DR_DUMP_REC_TYPE_DOMAIN = 3000,
14 DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER = 3001,
15 DR_DUMP_REC_TYPE_DOMAIN_INFO_DEV_ATTR = 3002,
16 DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT = 3003,
17 DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS = 3004,
18 DR_DUMP_REC_TYPE_DOMAIN_SEND_RING = 3005,
19
20 DR_DUMP_REC_TYPE_TABLE = 3100,
21 DR_DUMP_REC_TYPE_TABLE_RX = 3101,
22 DR_DUMP_REC_TYPE_TABLE_TX = 3102,
23
24 DR_DUMP_REC_TYPE_MATCHER = 3200,
25 DR_DUMP_REC_TYPE_MATCHER_MASK_DEPRECATED = 3201,
26 DR_DUMP_REC_TYPE_MATCHER_RX = 3202,
27 DR_DUMP_REC_TYPE_MATCHER_TX = 3203,
28 DR_DUMP_REC_TYPE_MATCHER_BUILDER = 3204,
29 DR_DUMP_REC_TYPE_MATCHER_MASK = 3205,
30
31 DR_DUMP_REC_TYPE_RULE = 3300,
32 DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 = 3301,
33 DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0 = 3302,
34 DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 = 3303,
35 DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1 = 3304,
36
37 DR_DUMP_REC_TYPE_ACTION_ENCAP_L2 = 3400,
38 DR_DUMP_REC_TYPE_ACTION_ENCAP_L3 = 3401,
39 DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR = 3402,
40 DR_DUMP_REC_TYPE_ACTION_DROP = 3403,
41 DR_DUMP_REC_TYPE_ACTION_QP = 3404,
42 DR_DUMP_REC_TYPE_ACTION_FT = 3405,
43 DR_DUMP_REC_TYPE_ACTION_CTR = 3406,
44 DR_DUMP_REC_TYPE_ACTION_TAG = 3407,
45 DR_DUMP_REC_TYPE_ACTION_VPORT = 3408,
46 DR_DUMP_REC_TYPE_ACTION_DECAP_L2 = 3409,
47 DR_DUMP_REC_TYPE_ACTION_DECAP_L3 = 3410,
48 DR_DUMP_REC_TYPE_ACTION_DEVX_TIR = 3411,
49 DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN = 3412,
50 DR_DUMP_REC_TYPE_ACTION_POP_VLAN = 3413,
51 DR_DUMP_REC_TYPE_ACTION_SAMPLER = 3415,
52 DR_DUMP_REC_TYPE_ACTION_INSERT_HDR = 3420,
53 DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR = 3421,
54 DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE = 3425,
55 };
56
57 static struct mlx5dr_dbg_dump_buff *
58 mlx5dr_dbg_dump_data_init_new_buff(struct mlx5dr_dbg_dump_data *dump_data)
59 {
60 struct mlx5dr_dbg_dump_buff *new_buff;
61
62 new_buff = kzalloc(sizeof(*new_buff), GFP_KERNEL);
63 if (!new_buff)
64 return NULL;
65
66 new_buff->buff = kvzalloc(MLX5DR_DEBUG_DUMP_BUFF_SIZE, GFP_KERNEL);
67 if (!new_buff->buff) {
68 kfree(new_buff);
69 return NULL;
70 }
71
72 INIT_LIST_HEAD(&new_buff->node);
73 list_add_tail(&new_buff->node, &dump_data->buff_list);
74
75 return new_buff;
76 }
77
78 static struct mlx5dr_dbg_dump_data *
79 mlx5dr_dbg_create_dump_data(void)
80 {
81 struct mlx5dr_dbg_dump_data *dump_data;
82
83 dump_data = kzalloc(sizeof(*dump_data), GFP_KERNEL);
84 if (!dump_data)
85 return NULL;
86
87 INIT_LIST_HEAD(&dump_data->buff_list);
88
89 if (!mlx5dr_dbg_dump_data_init_new_buff(dump_data)) {
90 kfree(dump_data);
91 return NULL;
92 }
93
94 return dump_data;
95 }
96
97 static void
98 mlx5dr_dbg_destroy_dump_data(struct mlx5dr_dbg_dump_data *dump_data)
99 {
100 struct mlx5dr_dbg_dump_buff *dump_buff, *tmp_buff;
101
102 if (!dump_data)
103 return;
104
105 list_for_each_entry_safe(dump_buff, tmp_buff, &dump_data->buff_list, node) {
106 kvfree(dump_buff->buff);
107 list_del(&dump_buff->node);
108 kfree(dump_buff);
109 }
110
111 kfree(dump_data);
112 }
113
114 static int
115 mlx5dr_dbg_dump_data_print(struct seq_file *file, char *str, u32 size)
116 {
117 struct mlx5dr_domain *dmn = file->private;
118 struct mlx5dr_dbg_dump_data *dump_data;
119 struct mlx5dr_dbg_dump_buff *buff;
120 u32 buff_capacity, write_size;
121 int remain_size, ret;
122
123 if (size >= MLX5DR_DEBUG_DUMP_BUFF_SIZE)
124 return -EINVAL;
125
126 dump_data = dmn->dump_info.dump_data;
127 buff = list_last_entry(&dump_data->buff_list,
128 struct mlx5dr_dbg_dump_buff, node);
129
130 buff_capacity = (MLX5DR_DEBUG_DUMP_BUFF_SIZE - 1) - buff->index;
131 remain_size = buff_capacity - size;
132 write_size = (remain_size > 0) ? size : buff_capacity;
133
134 if (likely(write_size)) {
135 ret = snprintf(buff->buff + buff->index, write_size + 1, "%s", str);
136 if (ret < 0)
137 return ret;
138
139 buff->index += write_size;
140 }
141
142 if (remain_size < 0) {
143 remain_size *= -1;
144 buff = mlx5dr_dbg_dump_data_init_new_buff(dump_data);
145 if (!buff)
146 return -ENOMEM;
147
148 ret = snprintf(buff->buff, remain_size + 1, "%s", str + write_size);
149 if (ret < 0)
150 return ret;
151
152 buff->index += remain_size;
153 }
154
155 return 0;
156 }
157
158 void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl)
159 {
160 mutex_lock(&tbl->dmn->dump_info.dbg_mutex);
161 list_add_tail(&tbl->dbg_node, &tbl->dmn->dbg_tbl_list);
162 mutex_unlock(&tbl->dmn->dump_info.dbg_mutex);
163 }
164
165 void mlx5dr_dbg_tbl_del(struct mlx5dr_table *tbl)
166 {
167 mutex_lock(&tbl->dmn->dump_info.dbg_mutex);
168 list_del(&tbl->dbg_node);
169 mutex_unlock(&tbl->dmn->dump_info.dbg_mutex);
170 }
171
172 void mlx5dr_dbg_rule_add(struct mlx5dr_rule *rule)
173 {
174 struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn;
175
176 mutex_lock(&dmn->dump_info.dbg_mutex);
177 list_add_tail(&rule->dbg_node, &rule->matcher->dbg_rule_list);
178 mutex_unlock(&dmn->dump_info.dbg_mutex);
179 }
180
181 void mlx5dr_dbg_rule_del(struct mlx5dr_rule *rule)
182 {
183 struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn;
184
185 mutex_lock(&dmn->dump_info.dbg_mutex);
186 list_del(&rule->dbg_node);
187 mutex_unlock(&dmn->dump_info.dbg_mutex);
188 }
189
190 static u64 dr_dump_icm_to_idx(u64 icm_addr)
191 {
192 return (icm_addr >> 6) & 0xffffffff;
193 }
194
195 #define DR_HEX_SIZE 256
196
197 static void
198 dr_dump_hex_print(char hex[DR_HEX_SIZE], char *src, u32 size)
199 {
200 if (WARN_ON_ONCE(DR_HEX_SIZE < 2 * size + 1))
201 size = DR_HEX_SIZE / 2 - 1; /* truncate */
202
203 bin2hex(hex, src, size);
204 hex[2 * size] = 0; /* NULL-terminate */
205 }
206
207 static int
208 dr_dump_rule_action_mem(struct seq_file *file, char *buff, const u64 rule_id,
209 struct mlx5dr_rule_action_member *action_mem)
210 {
211 struct mlx5dr_action *action = action_mem->action;
212 const u64 action_id = DR_DBG_PTR_TO_ID(action);
213 u64 hit_tbl_ptr, miss_tbl_ptr;
214 u32 hit_tbl_id, miss_tbl_id;
215 int ret;
216
217 switch (action->action_type) {
218 case DR_ACTION_TYP_DROP:
219 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
220 "%d,0x%llx,0x%llx\n",
221 DR_DUMP_REC_TYPE_ACTION_DROP, action_id,
222 rule_id);
223 if (ret < 0)
224 return ret;
225
226 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
227 if (ret)
228 return ret;
229 break;
230 case DR_ACTION_TYP_FT:
231 if (action->dest_tbl->is_fw_tbl)
232 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
233 "%d,0x%llx,0x%llx,0x%x,0x%x\n",
234 DR_DUMP_REC_TYPE_ACTION_FT, action_id,
235 rule_id, action->dest_tbl->fw_tbl.id,
236 -1);
237 else
238 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
239 "%d,0x%llx,0x%llx,0x%x,0x%llx\n",
240 DR_DUMP_REC_TYPE_ACTION_FT, action_id,
241 rule_id, action->dest_tbl->tbl->table_id,
242 DR_DBG_PTR_TO_ID(action->dest_tbl->tbl));
243
244 if (ret < 0)
245 return ret;
246
247 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
248 if (ret)
249 return ret;
250 break;
251 case DR_ACTION_TYP_CTR:
252 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
253 "%d,0x%llx,0x%llx,0x%x\n",
254 DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id,
255 action->ctr->ctr_id + action->ctr->offset);
256 if (ret < 0)
257 return ret;
258
259 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
260 if (ret)
261 return ret;
262 break;
263 case DR_ACTION_TYP_TAG:
264 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
265 "%d,0x%llx,0x%llx,0x%x\n",
266 DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id,
267 action->flow_tag->flow_tag);
268 if (ret < 0)
269 return ret;
270
271 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
272 if (ret)
273 return ret;
274 break;
275 case DR_ACTION_TYP_MODIFY_HDR:
276 {
277 struct mlx5dr_ptrn_obj *ptrn = action->rewrite->ptrn;
278 struct mlx5dr_arg_obj *arg = action->rewrite->arg;
279 u8 *rewrite_data = action->rewrite->data;
280 bool ptrn_arg;
281 int i;
282
283 ptrn_arg = !action->rewrite->single_action_opt && ptrn && arg;
284
285 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
286 "%d,0x%llx,0x%llx,0x%x,%d,0x%x,0x%x,0x%x",
287 DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id,
288 rule_id, action->rewrite->index,
289 action->rewrite->single_action_opt,
290 ptrn_arg ? action->rewrite->num_of_actions : 0,
291 ptrn_arg ? ptrn->index : 0,
292 ptrn_arg ? mlx5dr_arg_get_obj_id(arg) : 0);
293 if (ret < 0)
294 return ret;
295
296 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
297 if (ret)
298 return ret;
299
300 if (ptrn_arg) {
301 for (i = 0; i < action->rewrite->num_of_actions; i++) {
302 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
303 ",0x%016llx",
304 be64_to_cpu(((__be64 *)rewrite_data)[i]));
305 if (ret < 0)
306 return ret;
307
308 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
309 if (ret)
310 return ret;
311 }
312 }
313
314 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "\n");
315 if (ret < 0)
316 return ret;
317 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
318 if (ret)
319 return ret;
320 break;
321 }
322 case DR_ACTION_TYP_VPORT:
323 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
324 "%d,0x%llx,0x%llx,0x%x\n",
325 DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id,
326 action->vport->caps->num);
327 if (ret < 0)
328 return ret;
329
330 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
331 if (ret)
332 return ret;
333 break;
334 case DR_ACTION_TYP_TNL_L2_TO_L2:
335 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
336 "%d,0x%llx,0x%llx\n",
337 DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id,
338 rule_id);
339 if (ret < 0)
340 return ret;
341
342 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
343 if (ret)
344 return ret;
345 break;
346 case DR_ACTION_TYP_TNL_L3_TO_L2:
347 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
348 "%d,0x%llx,0x%llx,0x%x\n",
349 DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id,
350 rule_id,
351 (action->rewrite->ptrn && action->rewrite->arg) ?
352 mlx5dr_arg_get_obj_id(action->rewrite->arg) :
353 action->rewrite->index);
354 if (ret < 0)
355 return ret;
356
357 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
358 if (ret)
359 return ret;
360 break;
361 case DR_ACTION_TYP_L2_TO_TNL_L2:
362 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
363 "%d,0x%llx,0x%llx,0x%x\n",
364 DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id,
365 rule_id, action->reformat->id);
366 if (ret < 0)
367 return ret;
368
369 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
370 if (ret)
371 return ret;
372 break;
373 case DR_ACTION_TYP_L2_TO_TNL_L3:
374 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
375 "%d,0x%llx,0x%llx,0x%x\n",
376 DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id,
377 rule_id, action->reformat->id);
378 if (ret < 0)
379 return ret;
380
381 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
382 if (ret)
383 return ret;
384 break;
385 case DR_ACTION_TYP_POP_VLAN:
386 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
387 "%d,0x%llx,0x%llx\n",
388 DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id,
389 rule_id);
390 if (ret < 0)
391 return ret;
392
393 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
394 if (ret)
395 return ret;
396 break;
397 case DR_ACTION_TYP_PUSH_VLAN:
398 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
399 "%d,0x%llx,0x%llx,0x%x\n",
400 DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id,
401 rule_id, action->push_vlan->vlan_hdr);
402 if (ret < 0)
403 return ret;
404
405 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
406 if (ret)
407 return ret;
408 break;
409 case DR_ACTION_TYP_INSERT_HDR:
410 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
411 "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n",
412 DR_DUMP_REC_TYPE_ACTION_INSERT_HDR, action_id,
413 rule_id, action->reformat->id,
414 action->reformat->param_0,
415 action->reformat->param_1);
416 if (ret < 0)
417 return ret;
418
419 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
420 if (ret)
421 return ret;
422 break;
423 case DR_ACTION_TYP_REMOVE_HDR:
424 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
425 "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n",
426 DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR, action_id,
427 rule_id, action->reformat->id,
428 action->reformat->param_0,
429 action->reformat->param_1);
430 if (ret < 0)
431 return ret;
432
433 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
434 if (ret)
435 return ret;
436 break;
437 case DR_ACTION_TYP_SAMPLER:
438 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
439 "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
440 DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id,
441 rule_id, 0, 0, action->sampler->sampler_id,
442 action->sampler->rx_icm_addr,
443 action->sampler->tx_icm_addr);
444 if (ret < 0)
445 return ret;
446
447 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
448 if (ret)
449 return ret;
450 break;
451 case DR_ACTION_TYP_RANGE:
452 if (action->range->hit_tbl_action->dest_tbl->is_fw_tbl) {
453 hit_tbl_id = action->range->hit_tbl_action->dest_tbl->fw_tbl.id;
454 hit_tbl_ptr = 0;
455 } else {
456 hit_tbl_id = action->range->hit_tbl_action->dest_tbl->tbl->table_id;
457 hit_tbl_ptr =
458 DR_DBG_PTR_TO_ID(action->range->hit_tbl_action->dest_tbl->tbl);
459 }
460
461 if (action->range->miss_tbl_action->dest_tbl->is_fw_tbl) {
462 miss_tbl_id = action->range->miss_tbl_action->dest_tbl->fw_tbl.id;
463 miss_tbl_ptr = 0;
464 } else {
465 miss_tbl_id = action->range->miss_tbl_action->dest_tbl->tbl->table_id;
466 miss_tbl_ptr =
467 DR_DBG_PTR_TO_ID(action->range->miss_tbl_action->dest_tbl->tbl);
468 }
469
470 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
471 "%d,0x%llx,0x%llx,0x%x,0x%llx,0x%x,0x%llx,0x%x\n",
472 DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE, action_id,
473 rule_id, hit_tbl_id, hit_tbl_ptr, miss_tbl_id,
474 miss_tbl_ptr, action->range->definer_id);
475 if (ret < 0)
476 return ret;
477
478 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
479 if (ret)
480 return ret;
481 break;
482 default:
483 return 0;
484 }
485
486 return 0;
487 }
488
489 static int
490 dr_dump_rule_mem(struct seq_file *file, char *buff, struct mlx5dr_ste *ste,
491 bool is_rx, const u64 rule_id, u8 format_ver)
492 {
493 char hw_ste_dump[DR_HEX_SIZE];
494 u32 mem_rec_type;
495 int ret;
496
497 if (format_ver == MLX5_STEERING_FORMAT_CONNECTX_5) {
498 mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 :
499 DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0;
500 } else {
501 mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 :
502 DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1;
503 }
504
505 dr_dump_hex_print(hw_ste_dump, (char *)mlx5dr_ste_get_hw_ste(ste),
506 DR_STE_SIZE_REDUCED);
507
508 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
509 "%d,0x%llx,0x%llx,%s\n", mem_rec_type,
510 dr_dump_icm_to_idx(mlx5dr_ste_get_icm_addr(ste)),
511 rule_id, hw_ste_dump);
512 if (ret < 0)
513 return ret;
514
515 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
516 if (ret)
517 return ret;
518
519 return 0;
520 }
521
522 static int
523 dr_dump_rule_rx_tx(struct seq_file *file, char *buff,
524 struct mlx5dr_rule_rx_tx *rule_rx_tx,
525 bool is_rx, const u64 rule_id, u8 format_ver)
526 {
527 struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES];
528 struct mlx5dr_ste *curr_ste = rule_rx_tx->last_rule_ste;
529 int ret, i;
530
531 if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i))
532 return 0;
533
534 while (i--) {
535 ret = dr_dump_rule_mem(file, buff, ste_arr[i], is_rx, rule_id,
536 format_ver);
537 if (ret < 0)
538 return ret;
539 }
540
541 return 0;
542 }
543
544 static noinline_for_stack int
545 dr_dump_rule(struct seq_file *file, struct mlx5dr_rule *rule)
546 {
547 struct mlx5dr_rule_action_member *action_mem;
548 const u64 rule_id = DR_DBG_PTR_TO_ID(rule);
549 char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH];
550 struct mlx5dr_rule_rx_tx *rx = &rule->rx;
551 struct mlx5dr_rule_rx_tx *tx = &rule->tx;
552 u8 format_ver;
553 int ret;
554
555 format_ver = rule->matcher->tbl->dmn->info.caps.sw_format_ver;
556
557 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
558 "%d,0x%llx,0x%llx\n", DR_DUMP_REC_TYPE_RULE,
559 rule_id, DR_DBG_PTR_TO_ID(rule->matcher));
560 if (ret < 0)
561 return ret;
562
563 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
564 if (ret)
565 return ret;
566
567 if (rx->nic_matcher) {
568 ret = dr_dump_rule_rx_tx(file, buff, rx, true, rule_id, format_ver);
569 if (ret < 0)
570 return ret;
571 }
572
573 if (tx->nic_matcher) {
574 ret = dr_dump_rule_rx_tx(file, buff, tx, false, rule_id, format_ver);
575 if (ret < 0)
576 return ret;
577 }
578
579 list_for_each_entry(action_mem, &rule->rule_actions_list, list) {
580 ret = dr_dump_rule_action_mem(file, buff, rule_id, action_mem);
581 if (ret < 0)
582 return ret;
583 }
584
585 return 0;
586 }
587
588 static int
589 dr_dump_matcher_mask(struct seq_file *file, char *buff,
590 struct mlx5dr_match_param *mask,
591 u8 criteria, const u64 matcher_id)
592 {
593 char dump[DR_HEX_SIZE];
594 int ret;
595
596 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "%d,0x%llx,",
597 DR_DUMP_REC_TYPE_MATCHER_MASK, matcher_id);
598 if (ret < 0)
599 return ret;
600
601 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
602 if (ret)
603 return ret;
604
605 if (criteria & DR_MATCHER_CRITERIA_OUTER) {
606 dr_dump_hex_print(dump, (char *)&mask->outer, sizeof(mask->outer));
607 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
608 "%s,", dump);
609 } else {
610 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",");
611 }
612
613 if (ret < 0)
614 return ret;
615
616 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
617 if (ret)
618 return ret;
619
620 if (criteria & DR_MATCHER_CRITERIA_INNER) {
621 dr_dump_hex_print(dump, (char *)&mask->inner, sizeof(mask->inner));
622 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
623 "%s,", dump);
624 } else {
625 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",");
626 }
627
628 if (ret < 0)
629 return ret;
630
631 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
632 if (ret)
633 return ret;
634
635 if (criteria & DR_MATCHER_CRITERIA_MISC) {
636 dr_dump_hex_print(dump, (char *)&mask->misc, sizeof(mask->misc));
637 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
638 "%s,", dump);
639 } else {
640 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",");
641 }
642
643 if (ret < 0)
644 return ret;
645
646 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
647 if (ret)
648 return ret;
649
650 if (criteria & DR_MATCHER_CRITERIA_MISC2) {
651 dr_dump_hex_print(dump, (char *)&mask->misc2, sizeof(mask->misc2));
652 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
653 "%s,", dump);
654 } else {
655 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",");
656 }
657
658 if (ret < 0)
659 return ret;
660
661 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
662 if (ret)
663 return ret;
664
665 if (criteria & DR_MATCHER_CRITERIA_MISC3) {
666 dr_dump_hex_print(dump, (char *)&mask->misc3, sizeof(mask->misc3));
667 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
668 "%s\n", dump);
669 } else {
670 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",\n");
671 }
672
673 if (ret < 0)
674 return ret;
675
676 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
677 if (ret)
678 return ret;
679
680 return 0;
681 }
682
683 static int
684 dr_dump_matcher_builder(struct seq_file *file, char *buff,
685 struct mlx5dr_ste_build *builder,
686 u32 index, bool is_rx, const u64 matcher_id)
687 {
688 int ret;
689
690 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
691 "%d,0x%llx,%d,%d,0x%x\n",
692 DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index,
693 is_rx, builder->lu_type);
694 if (ret < 0)
695 return ret;
696
697 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
698 if (ret)
699 return ret;
700
701 return 0;
702 }
703
704 static int
705 dr_dump_matcher_rx_tx(struct seq_file *file, char *buff, bool is_rx,
706 struct mlx5dr_matcher_rx_tx *matcher_rx_tx,
707 const u64 matcher_id)
708 {
709 enum dr_dump_rec_type rec_type;
710 u64 s_icm_addr, e_icm_addr;
711 int i, ret;
712
713 rec_type = is_rx ? DR_DUMP_REC_TYPE_MATCHER_RX :
714 DR_DUMP_REC_TYPE_MATCHER_TX;
715
716 s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->s_htbl->chunk);
717 e_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->e_anchor->chunk);
718 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
719 "%d,0x%llx,0x%llx,%d,0x%llx,0x%llx\n",
720 rec_type, DR_DBG_PTR_TO_ID(matcher_rx_tx),
721 matcher_id, matcher_rx_tx->num_of_builders,
722 dr_dump_icm_to_idx(s_icm_addr),
723 dr_dump_icm_to_idx(e_icm_addr));
724
725 if (ret < 0)
726 return ret;
727
728 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
729 if (ret)
730 return ret;
731
732 for (i = 0; i < matcher_rx_tx->num_of_builders; i++) {
733 ret = dr_dump_matcher_builder(file, buff,
734 &matcher_rx_tx->ste_builder[i],
735 i, is_rx, matcher_id);
736 if (ret < 0)
737 return ret;
738 }
739
740 return 0;
741 }
742
743 static noinline_for_stack int
744 dr_dump_matcher(struct seq_file *file, struct mlx5dr_matcher *matcher)
745 {
746 struct mlx5dr_matcher_rx_tx *rx = &matcher->rx;
747 struct mlx5dr_matcher_rx_tx *tx = &matcher->tx;
748 char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH];
749 u64 matcher_id;
750 int ret;
751
752 matcher_id = DR_DBG_PTR_TO_ID(matcher);
753
754 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
755 "%d,0x%llx,0x%llx,%d\n", DR_DUMP_REC_TYPE_MATCHER,
756 matcher_id, DR_DBG_PTR_TO_ID(matcher->tbl),
757 matcher->prio);
758 if (ret < 0)
759 return ret;
760
761 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
762 if (ret)
763 return ret;
764
765 ret = dr_dump_matcher_mask(file, buff, &matcher->mask,
766 matcher->match_criteria, matcher_id);
767 if (ret < 0)
768 return ret;
769
770 if (rx->nic_tbl) {
771 ret = dr_dump_matcher_rx_tx(file, buff, true, rx, matcher_id);
772 if (ret < 0)
773 return ret;
774 }
775
776 if (tx->nic_tbl) {
777 ret = dr_dump_matcher_rx_tx(file, buff, false, tx, matcher_id);
778 if (ret < 0)
779 return ret;
780 }
781
782 return 0;
783 }
784
785 static int
786 dr_dump_matcher_all(struct seq_file *file, struct mlx5dr_matcher *matcher)
787 {
788 struct mlx5dr_rule *rule;
789 int ret;
790
791 ret = dr_dump_matcher(file, matcher);
792 if (ret < 0)
793 return ret;
794
795 list_for_each_entry(rule, &matcher->dbg_rule_list, dbg_node) {
796 ret = dr_dump_rule(file, rule);
797 if (ret < 0)
798 return ret;
799 }
800
801 return 0;
802 }
803
804 static int
805 dr_dump_table_rx_tx(struct seq_file *file, char *buff, bool is_rx,
806 struct mlx5dr_table_rx_tx *table_rx_tx,
807 const u64 table_id)
808 {
809 enum dr_dump_rec_type rec_type;
810 u64 s_icm_addr;
811 int ret;
812
813 rec_type = is_rx ? DR_DUMP_REC_TYPE_TABLE_RX :
814 DR_DUMP_REC_TYPE_TABLE_TX;
815
816 s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(table_rx_tx->s_anchor->chunk);
817 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
818 "%d,0x%llx,0x%llx\n", rec_type, table_id,
819 dr_dump_icm_to_idx(s_icm_addr));
820 if (ret < 0)
821 return ret;
822
823 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
824 if (ret)
825 return ret;
826
827 return 0;
828 }
829
830 static noinline_for_stack int
831 dr_dump_table(struct seq_file *file, struct mlx5dr_table *table)
832 {
833 struct mlx5dr_table_rx_tx *rx = &table->rx;
834 struct mlx5dr_table_rx_tx *tx = &table->tx;
835 char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH];
836 int ret;
837
838 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
839 "%d,0x%llx,0x%llx,%d,%d\n", DR_DUMP_REC_TYPE_TABLE,
840 DR_DBG_PTR_TO_ID(table), DR_DBG_PTR_TO_ID(table->dmn),
841 table->table_type, table->level);
842 if (ret < 0)
843 return ret;
844
845 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
846 if (ret)
847 return ret;
848
849 if (rx->nic_dmn) {
850 ret = dr_dump_table_rx_tx(file, buff, true, rx,
851 DR_DBG_PTR_TO_ID(table));
852 if (ret < 0)
853 return ret;
854 }
855
856 if (tx->nic_dmn) {
857 ret = dr_dump_table_rx_tx(file, buff, false, tx,
858 DR_DBG_PTR_TO_ID(table));
859 if (ret < 0)
860 return ret;
861 }
862 return 0;
863 }
864
865 static int dr_dump_table_all(struct seq_file *file, struct mlx5dr_table *tbl)
866 {
867 struct mlx5dr_matcher *matcher;
868 int ret;
869
870 ret = dr_dump_table(file, tbl);
871 if (ret < 0)
872 return ret;
873
874 list_for_each_entry(matcher, &tbl->matcher_list, list_node) {
875 ret = dr_dump_matcher_all(file, matcher);
876 if (ret < 0)
877 return ret;
878 }
879 return 0;
880 }
881
882 static int
883 dr_dump_send_ring(struct seq_file *file, char *buff,
884 struct mlx5dr_send_ring *ring,
885 const u64 domain_id)
886 {
887 int ret;
888
889 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
890 "%d,0x%llx,0x%llx,0x%x,0x%x\n",
891 DR_DUMP_REC_TYPE_DOMAIN_SEND_RING,
892 DR_DBG_PTR_TO_ID(ring), domain_id,
893 ring->cq->mcq.cqn, ring->qp->qpn);
894 if (ret < 0)
895 return ret;
896
897 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
898 if (ret)
899 return ret;
900
901 return 0;
902 }
903
904 static int
905 dr_dump_domain_info_flex_parser(struct seq_file *file,
906 char *buff,
907 const char *flex_parser_name,
908 const u8 flex_parser_value,
909 const u64 domain_id)
910 {
911 int ret;
912
913 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
914 "%d,0x%llx,%s,0x%x\n",
915 DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id,
916 flex_parser_name, flex_parser_value);
917 if (ret < 0)
918 return ret;
919
920 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
921 if (ret)
922 return ret;
923
924 return 0;
925 }
926
927 static int
928 dr_dump_domain_info_caps(struct seq_file *file, char *buff,
929 struct mlx5dr_cmd_caps *caps,
930 const u64 domain_id)
931 {
932 struct mlx5dr_cmd_vport_cap *vport_caps;
933 unsigned long i, vports_num;
934 int ret;
935
936 xa_for_each(&caps->vports.vports_caps_xa, vports_num, vport_caps)
937 ; /* count the number of vports in xarray */
938
939 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
940 "%d,0x%llx,0x%x,0x%llx,0x%llx,0x%x,%lu,%d\n",
941 DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi,
942 caps->nic_rx_drop_address, caps->nic_tx_drop_address,
943 caps->flex_protocols, vports_num, caps->eswitch_manager);
944 if (ret < 0)
945 return ret;
946
947 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
948 if (ret)
949 return ret;
950
951 xa_for_each(&caps->vports.vports_caps_xa, i, vport_caps) {
952 vport_caps = xa_load(&caps->vports.vports_caps_xa, i);
953
954 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
955 "%d,0x%llx,%lu,0x%x,0x%llx,0x%llx\n",
956 DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT,
957 domain_id, i, vport_caps->vport_gvmi,
958 vport_caps->icm_address_rx,
959 vport_caps->icm_address_tx);
960 if (ret < 0)
961 return ret;
962
963 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
964 if (ret)
965 return ret;
966 }
967 return 0;
968 }
969
970 static int
971 dr_dump_domain_info(struct seq_file *file, char *buff,
972 struct mlx5dr_domain_info *info,
973 const u64 domain_id)
974 {
975 int ret;
976
977 ret = dr_dump_domain_info_caps(file, buff, &info->caps, domain_id);
978 if (ret < 0)
979 return ret;
980
981 ret = dr_dump_domain_info_flex_parser(file, buff, "icmp_dw0",
982 info->caps.flex_parser_id_icmp_dw0,
983 domain_id);
984 if (ret < 0)
985 return ret;
986
987 ret = dr_dump_domain_info_flex_parser(file, buff, "icmp_dw1",
988 info->caps.flex_parser_id_icmp_dw1,
989 domain_id);
990 if (ret < 0)
991 return ret;
992
993 ret = dr_dump_domain_info_flex_parser(file, buff, "icmpv6_dw0",
994 info->caps.flex_parser_id_icmpv6_dw0,
995 domain_id);
996 if (ret < 0)
997 return ret;
998
999 ret = dr_dump_domain_info_flex_parser(file, buff, "icmpv6_dw1",
1000 info->caps.flex_parser_id_icmpv6_dw1,
1001 domain_id);
1002 if (ret < 0)
1003 return ret;
1004
1005 return 0;
1006 }
1007
1008 static noinline_for_stack int
1009 dr_dump_domain(struct seq_file *file, struct mlx5dr_domain *dmn)
1010 {
1011 char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH];
1012 u64 domain_id = DR_DBG_PTR_TO_ID(dmn);
1013 int ret;
1014
1015 ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH,
1016 "%d,0x%llx,%d,0%x,%d,%u.%u.%u,%s,%d,%u,%u,%u\n",
1017 DR_DUMP_REC_TYPE_DOMAIN,
1018 domain_id, dmn->type, dmn->info.caps.gvmi,
1019 dmn->info.supp_sw_steering,
1020 /* package version */
1021 LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL,
1022 LINUX_VERSION_SUBLEVEL,
1023 pci_name(dmn->mdev->pdev),
1024 0, /* domain flags */
1025 dmn->num_buddies[DR_ICM_TYPE_STE],
1026 dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION],
1027 dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN]);
1028 if (ret < 0)
1029 return ret;
1030
1031 ret = mlx5dr_dbg_dump_data_print(file, buff, ret);
1032 if (ret)
1033 return ret;
1034
1035 ret = dr_dump_domain_info(file, buff, &dmn->info, domain_id);
1036 if (ret < 0)
1037 return ret;
1038
1039 if (dmn->info.supp_sw_steering) {
1040 ret = dr_dump_send_ring(file, buff, dmn->send_ring, domain_id);
1041 if (ret < 0)
1042 return ret;
1043 }
1044
1045 return 0;
1046 }
1047
1048 static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn)
1049 {
1050 struct mlx5dr_table *tbl;
1051 int ret;
1052
1053 mutex_lock(&dmn->dump_info.dbg_mutex);
1054 mlx5dr_domain_lock(dmn);
1055
1056 ret = dr_dump_domain(file, dmn);
1057 if (ret < 0)
1058 goto unlock_mutex;
1059
1060 list_for_each_entry(tbl, &dmn->dbg_tbl_list, dbg_node) {
1061 ret = dr_dump_table_all(file, tbl);
1062 if (ret < 0)
1063 break;
1064 }
1065
1066 unlock_mutex:
1067 mlx5dr_domain_unlock(dmn);
1068 mutex_unlock(&dmn->dump_info.dbg_mutex);
1069 return ret;
1070 }
1071
1072 static void *
1073 dr_dump_start(struct seq_file *file, loff_t *pos)
1074 {
1075 struct mlx5dr_domain *dmn = file->private;
1076 struct mlx5dr_dbg_dump_data *dump_data;
1077
1078 if (atomic_read(&dmn->dump_info.state) != MLX5DR_DEBUG_DUMP_STATE_FREE) {
1079 mlx5_core_warn(dmn->mdev, "Dump already in progress\n");
1080 return ERR_PTR(-EBUSY);
1081 }
1082
1083 atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS);
1084 dump_data = dmn->dump_info.dump_data;
1085
1086 if (dump_data) {
1087 return seq_list_start(&dump_data->buff_list, *pos);
1088 } else if (*pos == 0) {
1089 dump_data = mlx5dr_dbg_create_dump_data();
1090 if (!dump_data)
1091 goto exit;
1092
1093 dmn->dump_info.dump_data = dump_data;
1094 if (dr_dump_domain_all(file, dmn)) {
1095 mlx5dr_dbg_destroy_dump_data(dump_data);
1096 dmn->dump_info.dump_data = NULL;
1097 goto exit;
1098 }
1099
1100 return seq_list_start(&dump_data->buff_list, *pos);
1101 }
1102
1103 exit:
1104 atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE);
1105 return NULL;
1106 }
1107
1108 static void *
1109 dr_dump_next(struct seq_file *file, void *v, loff_t *pos)
1110 {
1111 struct mlx5dr_domain *dmn = file->private;
1112 struct mlx5dr_dbg_dump_data *dump_data;
1113
1114 dump_data = dmn->dump_info.dump_data;
1115
1116 return seq_list_next(v, &dump_data->buff_list, pos);
1117 }
1118
1119 static void
1120 dr_dump_stop(struct seq_file *file, void *v)
1121 {
1122 struct mlx5dr_domain *dmn = file->private;
1123 struct mlx5dr_dbg_dump_data *dump_data;
1124
1125 if (v && IS_ERR(v))
1126 return;
1127
1128 if (!v) {
1129 dump_data = dmn->dump_info.dump_data;
1130 if (dump_data) {
1131 mlx5dr_dbg_destroy_dump_data(dump_data);
1132 dmn->dump_info.dump_data = NULL;
1133 }
1134 }
1135
1136 atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE);
1137 }
1138
1139 static int
1140 dr_dump_show(struct seq_file *file, void *v)
1141 {
1142 struct mlx5dr_dbg_dump_buff *entry;
1143
1144 entry = list_entry(v, struct mlx5dr_dbg_dump_buff, node);
1145 seq_printf(file, "%s", entry->buff);
1146
1147 return 0;
1148 }
1149
1150 static const struct seq_operations dr_dump_sops = {
1151 .start = dr_dump_start,
1152 .next = dr_dump_next,
1153 .stop = dr_dump_stop,
1154 .show = dr_dump_show,
1155 };
1156 DEFINE_SEQ_ATTRIBUTE(dr_dump);
1157
1158 void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn)
1159 {
1160 struct mlx5_core_dev *dev = dmn->mdev;
1161 char file_name[128];
1162
1163 if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) {
1164 mlx5_core_warn(dev,
1165 "Steering dump is not supported for NIC RX/TX domains\n");
1166 return;
1167 }
1168
1169 dmn->dump_info.steering_debugfs =
1170 debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev));
1171 dmn->dump_info.fdb_debugfs =
1172 debugfs_create_dir("fdb", dmn->dump_info.steering_debugfs);
1173
1174 sprintf(file_name, "dmn_%p", dmn);
1175 debugfs_create_file(file_name, 0444, dmn->dump_info.fdb_debugfs,
1176 dmn, &dr_dump_fops);
1177
1178 INIT_LIST_HEAD(&dmn->dbg_tbl_list);
1179 mutex_init(&dmn->dump_info.dbg_mutex);
1180 }
1181
1182 void mlx5dr_dbg_uninit_dump(struct mlx5dr_domain *dmn)
1183 {
1184 debugfs_remove_recursive(dmn->dump_info.steering_debugfs);
1185 mutex_destroy(&dmn->dump_info.dbg_mutex);
1186 }