1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
3
4 #include <linux/debugfs.h>
5 #include <linux/kernel.h>
6 #include <linux/seq_file.h>
7 #include <linux/version.h>
8 #include "internal.h"
9
10 static int
hws_debug_dump_matcher_template_definer(struct seq_file * f,void * parent_obj,struct mlx5hws_definer * definer,enum mlx5hws_debug_res_type type)11 hws_debug_dump_matcher_template_definer(struct seq_file *f,
12 void *parent_obj,
13 struct mlx5hws_definer *definer,
14 enum mlx5hws_debug_res_type type)
15 {
16 int i;
17
18 if (!definer)
19 return 0;
20
21 seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,",
22 type,
23 HWS_PTR_TO_ID(definer),
24 HWS_PTR_TO_ID(parent_obj),
25 definer->obj_id,
26 definer->type);
27
28 for (i = 0; i < DW_SELECTORS; i++)
29 seq_printf(f, "0x%x%s", definer->dw_selector[i],
30 (i == DW_SELECTORS - 1) ? "," : "-");
31
32 for (i = 0; i < BYTE_SELECTORS; i++)
33 seq_printf(f, "0x%x%s", definer->byte_selector[i],
34 (i == BYTE_SELECTORS - 1) ? "," : "-");
35
36 for (i = 0; i < MLX5HWS_JUMBO_TAG_SZ; i++)
37 seq_printf(f, "%02x", definer->mask.jumbo[i]);
38
39 seq_puts(f, "\n");
40
41 return 0;
42 }
43
44 static int
hws_debug_dump_matcher_match_template(struct seq_file * f,struct mlx5hws_matcher * matcher)45 hws_debug_dump_matcher_match_template(struct seq_file *f, struct mlx5hws_matcher *matcher)
46 {
47 enum mlx5hws_debug_res_type type;
48 int i, ret;
49
50 for (i = 0; i < matcher->num_of_mt; i++) {
51 struct mlx5hws_match_template *mt = &matcher->mt[i];
52
53 seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d\n",
54 MLX5HWS_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE,
55 HWS_PTR_TO_ID(mt),
56 HWS_PTR_TO_ID(matcher),
57 mt->fc_sz,
58 0, 0);
59
60 type = MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_MATCH_DEFINER;
61 ret = hws_debug_dump_matcher_template_definer(f, mt, mt->definer, type);
62 if (ret)
63 return ret;
64 }
65
66 return 0;
67 }
68
69 static int
hws_debug_dump_matcher_action_template(struct seq_file * f,struct mlx5hws_matcher * matcher)70 hws_debug_dump_matcher_action_template(struct seq_file *f, struct mlx5hws_matcher *matcher)
71 {
72 enum mlx5hws_action_type action_type;
73 int i, j;
74
75 for (i = 0; i < matcher->num_of_at; i++) {
76 struct mlx5hws_action_template *at = &matcher->at[i];
77
78 seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d",
79 MLX5HWS_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE,
80 HWS_PTR_TO_ID(at),
81 HWS_PTR_TO_ID(matcher),
82 at->only_term,
83 at->num_of_action_stes,
84 at->num_actions);
85
86 for (j = 0; j < at->num_actions; j++) {
87 action_type = at->action_type_arr[j];
88 seq_printf(f, ",%s", mlx5hws_action_type_to_str(action_type));
89 }
90
91 seq_puts(f, "\n");
92 }
93
94 return 0;
95 }
96
97 static int
hws_debug_dump_matcher_attr(struct seq_file * f,struct mlx5hws_matcher * matcher)98 hws_debug_dump_matcher_attr(struct seq_file *f, struct mlx5hws_matcher *matcher)
99 {
100 struct mlx5hws_matcher_attr *attr = &matcher->attr;
101
102 seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,-1,-1,%d,%d\n",
103 MLX5HWS_DEBUG_RES_TYPE_MATCHER_ATTR,
104 HWS_PTR_TO_ID(matcher),
105 attr->priority,
106 attr->mode,
107 attr->size[MLX5HWS_MATCHER_SIZE_TYPE_RX].table.sz_row_log,
108 attr->size[MLX5HWS_MATCHER_SIZE_TYPE_RX].table.sz_col_log,
109 attr->optimize_using_rule_idx,
110 attr->optimize_flow_src,
111 attr->insert_mode,
112 attr->distribute_mode,
113 attr->size[MLX5HWS_MATCHER_SIZE_TYPE_TX].table.sz_row_log,
114 attr->size[MLX5HWS_MATCHER_SIZE_TYPE_TX].table.sz_col_log);
115
116 return 0;
117 }
118
hws_debug_dump_matcher(struct seq_file * f,struct mlx5hws_matcher * matcher)119 static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *matcher)
120 {
121 enum mlx5hws_table_type tbl_type = matcher->tbl->type;
122 struct mlx5hws_cmd_ft_query_attr ft_attr = {0};
123 u64 icm_addr_0 = 0;
124 u64 icm_addr_1 = 0;
125 u32 ste_0_id = -1;
126 u32 ste_1_id = -1;
127 int ret;
128
129 seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,0x%llx",
130 MLX5HWS_DEBUG_RES_TYPE_MATCHER,
131 HWS_PTR_TO_ID(matcher),
132 HWS_PTR_TO_ID(matcher->tbl),
133 matcher->num_of_mt,
134 matcher->end_ft_id,
135 matcher->col_matcher ? HWS_PTR_TO_ID(matcher->col_matcher) : 0);
136
137 ste_0_id = matcher->match_ste.ste_0_base;
138 if (tbl_type == MLX5HWS_TABLE_TYPE_FDB)
139 ste_1_id = matcher->match_ste.ste_1_base;
140
141 seq_printf(f, ",%d,%d,%d,%d",
142 matcher->match_ste.rtc_0_id,
143 (int)ste_0_id,
144 matcher->match_ste.rtc_1_id,
145 (int)ste_1_id);
146
147 ft_attr.type = matcher->tbl->fw_ft_type;
148 ret = mlx5hws_cmd_flow_table_query(matcher->tbl->ctx->mdev,
149 matcher->end_ft_id,
150 &ft_attr,
151 &icm_addr_0,
152 &icm_addr_1);
153 if (ret)
154 return ret;
155
156 seq_printf(f, ",-1,-1,-1,-1,0,0x%llx,0x%llx\n",
157 mlx5hws_debug_icm_to_idx(icm_addr_0),
158 mlx5hws_debug_icm_to_idx(icm_addr_1));
159
160 ret = hws_debug_dump_matcher_attr(f, matcher);
161 if (ret)
162 return ret;
163
164 ret = hws_debug_dump_matcher_match_template(f, matcher);
165 if (ret)
166 return ret;
167
168 ret = hws_debug_dump_matcher_action_template(f, matcher);
169 if (ret)
170 return ret;
171
172 return 0;
173 }
174
hws_debug_dump_table(struct seq_file * f,struct mlx5hws_table * tbl)175 static int hws_debug_dump_table(struct seq_file *f, struct mlx5hws_table *tbl)
176 {
177 struct mlx5hws_cmd_ft_query_attr ft_attr = {0};
178 struct mlx5hws_matcher *matcher;
179 u64 local_icm_addr_0 = 0;
180 u64 local_icm_addr_1 = 0;
181 u64 icm_addr_0 = 0;
182 u64 icm_addr_1 = 0;
183 int ret;
184
185 seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d,%d,%d",
186 MLX5HWS_DEBUG_RES_TYPE_TABLE,
187 HWS_PTR_TO_ID(tbl),
188 HWS_PTR_TO_ID(tbl->ctx),
189 tbl->ft_id,
190 MLX5HWS_TABLE_TYPE_BASE + tbl->type,
191 tbl->fw_ft_type,
192 tbl->level,
193 0);
194
195 ft_attr.type = tbl->fw_ft_type;
196 ret = mlx5hws_cmd_flow_table_query(tbl->ctx->mdev,
197 tbl->ft_id,
198 &ft_attr,
199 &icm_addr_0,
200 &icm_addr_1);
201 if (ret)
202 return ret;
203
204 seq_printf(f, ",0x%llx,0x%llx,0x%llx,0x%llx,0x%llx\n",
205 mlx5hws_debug_icm_to_idx(icm_addr_0),
206 mlx5hws_debug_icm_to_idx(icm_addr_1),
207 mlx5hws_debug_icm_to_idx(local_icm_addr_0),
208 mlx5hws_debug_icm_to_idx(local_icm_addr_1),
209 HWS_PTR_TO_ID(tbl->default_miss.miss_tbl));
210
211 list_for_each_entry(matcher, &tbl->matchers_list, list_node) {
212 ret = hws_debug_dump_matcher(f, matcher);
213 if (ret)
214 return ret;
215 }
216
217 return 0;
218 }
219
220 static int
hws_debug_dump_context_send_engine(struct seq_file * f,struct mlx5hws_context * ctx)221 hws_debug_dump_context_send_engine(struct seq_file *f, struct mlx5hws_context *ctx)
222 {
223 struct mlx5hws_send_engine *send_queue;
224 struct mlx5hws_send_ring *send_ring;
225 struct mlx5hws_send_ring_cq *cq;
226 struct mlx5hws_send_ring_sq *sq;
227 int i;
228
229 for (i = 0; i < (int)ctx->queues; i++) {
230 send_queue = &ctx->send_queue[i];
231 seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
232 MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE,
233 HWS_PTR_TO_ID(ctx),
234 i,
235 send_queue->used_entries,
236 send_queue->num_entries,
237 1, /* one send ring per queue */
238 send_queue->num_entries,
239 send_queue->err,
240 send_queue->completed.ci,
241 send_queue->completed.pi,
242 send_queue->completed.mask);
243
244 send_ring = &send_queue->send_ring;
245 cq = &send_ring->send_cq;
246 sq = &send_ring->send_sq;
247
248 seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
249 MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_RING,
250 HWS_PTR_TO_ID(ctx),
251 0, /* one send ring per send queue */
252 i,
253 cq->mcq.cqn,
254 0,
255 0,
256 0,
257 0,
258 0,
259 0,
260 cq->mcq.cqe_sz,
261 sq->sqn,
262 0,
263 0,
264 0);
265 }
266
267 return 0;
268 }
269
hws_debug_dump_context_caps(struct seq_file * f,struct mlx5hws_context * ctx)270 static int hws_debug_dump_context_caps(struct seq_file *f, struct mlx5hws_context *ctx)
271 {
272 struct mlx5hws_cmd_query_caps *caps = ctx->caps;
273
274 seq_printf(f, "%d,0x%llx,%s,%d,%d,%d,%d,",
275 MLX5HWS_DEBUG_RES_TYPE_CONTEXT_CAPS,
276 HWS_PTR_TO_ID(ctx),
277 caps->fw_ver,
278 caps->wqe_based_update,
279 caps->ste_format,
280 caps->ste_alloc_log_max,
281 caps->log_header_modify_argument_max_alloc);
282
283 seq_printf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s\n",
284 caps->flex_protocols,
285 caps->rtc_reparse_mode,
286 caps->rtc_index_mode,
287 caps->ste_alloc_log_gran,
288 caps->stc_alloc_log_max,
289 caps->stc_alloc_log_gran,
290 caps->rtc_log_depth_max,
291 caps->format_select_gtpu_dw_0,
292 caps->format_select_gtpu_dw_1,
293 caps->format_select_gtpu_dw_2,
294 caps->format_select_gtpu_ext_dw_0,
295 caps->nic_ft.max_level,
296 caps->nic_ft.reparse,
297 caps->fdb_ft.max_level,
298 caps->fdb_ft.reparse,
299 caps->log_header_modify_argument_granularity,
300 caps->linear_match_definer,
301 "regc_3");
302
303 return 0;
304 }
305
hws_debug_dump_context_attr(struct seq_file * f,struct mlx5hws_context * ctx)306 static int hws_debug_dump_context_attr(struct seq_file *f, struct mlx5hws_context *ctx)
307 {
308 seq_printf(f, "%u,0x%llx,%d,%zu,%d,%s,%d,%d\n",
309 MLX5HWS_DEBUG_RES_TYPE_CONTEXT_ATTR,
310 HWS_PTR_TO_ID(ctx),
311 ctx->pd_num,
312 ctx->queues,
313 ctx->send_queue->num_entries,
314 "None", /* no shared gvmi */
315 ctx->caps->vhca_id,
316 0xffff); /* no shared gvmi */
317
318 return 0;
319 }
320
hws_debug_dump_context_info(struct seq_file * f,struct mlx5hws_context * ctx)321 static int hws_debug_dump_context_info(struct seq_file *f, struct mlx5hws_context *ctx)
322 {
323 struct mlx5_core_dev *dev = ctx->mdev;
324 int ret;
325
326 seq_printf(f, "%d,0x%llx,%d,%s,%s.KERNEL_%u_%u_%u\n",
327 MLX5HWS_DEBUG_RES_TYPE_CONTEXT,
328 HWS_PTR_TO_ID(ctx),
329 ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT,
330 pci_name(dev->pdev),
331 HWS_DEBUG_FORMAT_VERSION,
332 LINUX_VERSION_MAJOR,
333 LINUX_VERSION_PATCHLEVEL,
334 LINUX_VERSION_SUBLEVEL);
335
336 ret = hws_debug_dump_context_attr(f, ctx);
337 if (ret)
338 return ret;
339
340 ret = hws_debug_dump_context_caps(f, ctx);
341 if (ret)
342 return ret;
343
344 return 0;
345 }
346
hws_debug_dump_context_stc_resource(struct seq_file * f,struct mlx5hws_context * ctx,struct mlx5hws_pool_resource * resource)347 static int hws_debug_dump_context_stc_resource(struct seq_file *f,
348 struct mlx5hws_context *ctx,
349 struct mlx5hws_pool_resource *resource)
350 {
351 u32 tbl_type = MLX5HWS_TABLE_TYPE_BASE + MLX5HWS_TABLE_TYPE_FDB;
352
353 seq_printf(f, "%d,0x%llx,%u,%u\n",
354 MLX5HWS_DEBUG_RES_TYPE_CONTEXT_STC,
355 HWS_PTR_TO_ID(ctx),
356 tbl_type,
357 resource->base_id);
358
359 return 0;
360 }
361
hws_debug_dump_context_stc(struct seq_file * f,struct mlx5hws_context * ctx)362 static int hws_debug_dump_context_stc(struct seq_file *f, struct mlx5hws_context *ctx)
363 {
364 struct mlx5hws_pool *stc_pool = ctx->stc_pool;
365 int ret;
366
367 if (!stc_pool)
368 return 0;
369
370 if (stc_pool->resource) {
371 ret = hws_debug_dump_context_stc_resource(f, ctx,
372 stc_pool->resource);
373 if (ret)
374 return ret;
375 }
376
377 if (stc_pool->mirror_resource) {
378 struct mlx5hws_pool_resource *res = stc_pool->mirror_resource;
379
380 ret = hws_debug_dump_context_stc_resource(f, ctx, res);
381 if (ret)
382 return ret;
383 }
384
385 return 0;
386 }
387
388 static void
hws_debug_dump_action_ste_table(struct seq_file * f,struct mlx5hws_action_ste_table * action_tbl)389 hws_debug_dump_action_ste_table(struct seq_file *f,
390 struct mlx5hws_action_ste_table *action_tbl)
391 {
392 int ste_0_id = mlx5hws_pool_get_base_id(action_tbl->pool);
393 int ste_1_id = mlx5hws_pool_get_base_mirror_id(action_tbl->pool);
394
395 seq_printf(f, "%d,0x%llx,%d,%d,%d,%d\n",
396 MLX5HWS_DEBUG_RES_TYPE_ACTION_STE_TABLE,
397 HWS_PTR_TO_ID(action_tbl),
398 action_tbl->rtc_0_id, ste_0_id,
399 action_tbl->rtc_1_id, ste_1_id);
400 }
401
hws_debug_dump_action_ste_pool(struct seq_file * f,struct mlx5hws_action_ste_pool * pool)402 static void hws_debug_dump_action_ste_pool(struct seq_file *f,
403 struct mlx5hws_action_ste_pool *pool)
404 {
405 struct mlx5hws_action_ste_table *action_tbl;
406 enum mlx5hws_pool_optimize opt;
407
408 mutex_lock(&pool->lock);
409 for (opt = MLX5HWS_POOL_OPTIMIZE_NONE; opt < MLX5HWS_POOL_OPTIMIZE_MAX;
410 opt++) {
411 list_for_each_entry(action_tbl, &pool->elems[opt].available,
412 list_node) {
413 hws_debug_dump_action_ste_table(f, action_tbl);
414 }
415 }
416 mutex_unlock(&pool->lock);
417 }
418
hws_debug_dump_context(struct seq_file * f,struct mlx5hws_context * ctx)419 static int hws_debug_dump_context(struct seq_file *f, struct mlx5hws_context *ctx)
420 {
421 struct mlx5hws_table *tbl;
422 int ret, i;
423
424 ret = hws_debug_dump_context_info(f, ctx);
425 if (ret)
426 return ret;
427
428 ret = hws_debug_dump_context_send_engine(f, ctx);
429 if (ret)
430 return ret;
431
432 ret = hws_debug_dump_context_stc(f, ctx);
433 if (ret)
434 return ret;
435
436 list_for_each_entry(tbl, &ctx->tbl_list, tbl_list_node) {
437 ret = hws_debug_dump_table(f, tbl);
438 if (ret)
439 return ret;
440 }
441
442 for (i = 0; i < ctx->queues; i++)
443 hws_debug_dump_action_ste_pool(f, &ctx->action_ste_pool[i]);
444
445 return 0;
446 }
447
448 static int
hws_debug_dump(struct seq_file * f,struct mlx5hws_context * ctx)449 hws_debug_dump(struct seq_file *f, struct mlx5hws_context *ctx)
450 {
451 int ret;
452
453 if (!f || !ctx)
454 return -EINVAL;
455
456 mutex_lock(&ctx->ctrl_lock);
457 ret = hws_debug_dump_context(f, ctx);
458 mutex_unlock(&ctx->ctrl_lock);
459
460 return ret;
461 }
462
hws_dump_show(struct seq_file * file,void * priv)463 static int hws_dump_show(struct seq_file *file, void *priv)
464 {
465 return hws_debug_dump(file, file->private);
466 }
467 DEFINE_SHOW_ATTRIBUTE(hws_dump);
468
mlx5hws_debug_init_dump(struct mlx5hws_context * ctx)469 void mlx5hws_debug_init_dump(struct mlx5hws_context *ctx)
470 {
471 struct mlx5_core_dev *dev = ctx->mdev;
472 char file_name[128];
473
474 ctx->debug_info.steering_debugfs =
475 debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev));
476 ctx->debug_info.fdb_debugfs =
477 debugfs_create_dir("fdb", ctx->debug_info.steering_debugfs);
478
479 sprintf(file_name, "ctx_%p", ctx);
480 debugfs_create_file(file_name, 0444, ctx->debug_info.fdb_debugfs,
481 ctx, &hws_dump_fops);
482 }
483
mlx5hws_debug_uninit_dump(struct mlx5hws_context * ctx)484 void mlx5hws_debug_uninit_dump(struct mlx5hws_context *ctx)
485 {
486 debugfs_remove_recursive(ctx->debug_info.steering_debugfs);
487 }
488