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 
mlx5dr_dbg_tbl_add(struct mlx5dr_table * tbl)57 void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl)
58 {
59 	mutex_lock(&tbl->dmn->dump_info.dbg_mutex);
60 	list_add_tail(&tbl->dbg_node, &tbl->dmn->dbg_tbl_list);
61 	mutex_unlock(&tbl->dmn->dump_info.dbg_mutex);
62 }
63 
mlx5dr_dbg_tbl_del(struct mlx5dr_table * tbl)64 void mlx5dr_dbg_tbl_del(struct mlx5dr_table *tbl)
65 {
66 	mutex_lock(&tbl->dmn->dump_info.dbg_mutex);
67 	list_del(&tbl->dbg_node);
68 	mutex_unlock(&tbl->dmn->dump_info.dbg_mutex);
69 }
70 
mlx5dr_dbg_rule_add(struct mlx5dr_rule * rule)71 void mlx5dr_dbg_rule_add(struct mlx5dr_rule *rule)
72 {
73 	struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn;
74 
75 	mutex_lock(&dmn->dump_info.dbg_mutex);
76 	list_add_tail(&rule->dbg_node, &rule->matcher->dbg_rule_list);
77 	mutex_unlock(&dmn->dump_info.dbg_mutex);
78 }
79 
mlx5dr_dbg_rule_del(struct mlx5dr_rule * rule)80 void mlx5dr_dbg_rule_del(struct mlx5dr_rule *rule)
81 {
82 	struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn;
83 
84 	mutex_lock(&dmn->dump_info.dbg_mutex);
85 	list_del(&rule->dbg_node);
86 	mutex_unlock(&dmn->dump_info.dbg_mutex);
87 }
88 
dr_dump_icm_to_idx(u64 icm_addr)89 static u64 dr_dump_icm_to_idx(u64 icm_addr)
90 {
91 	return (icm_addr >> 6) & 0xffffffff;
92 }
93 
94 #define DR_HEX_SIZE 256
95 
96 static void
dr_dump_hex_print(char hex[DR_HEX_SIZE],char * src,u32 size)97 dr_dump_hex_print(char hex[DR_HEX_SIZE], char *src, u32 size)
98 {
99 	if (WARN_ON_ONCE(DR_HEX_SIZE < 2 * size + 1))
100 		size = DR_HEX_SIZE / 2 - 1; /* truncate */
101 
102 	bin2hex(hex, src, size);
103 	hex[2 * size] = 0; /* NULL-terminate */
104 }
105 
106 static int
dr_dump_rule_action_mem(struct seq_file * file,const u64 rule_id,struct mlx5dr_rule_action_member * action_mem)107 dr_dump_rule_action_mem(struct seq_file *file, const u64 rule_id,
108 			struct mlx5dr_rule_action_member *action_mem)
109 {
110 	struct mlx5dr_action *action = action_mem->action;
111 	const u64 action_id = DR_DBG_PTR_TO_ID(action);
112 	u64 hit_tbl_ptr, miss_tbl_ptr;
113 	u32 hit_tbl_id, miss_tbl_id;
114 
115 	switch (action->action_type) {
116 	case DR_ACTION_TYP_DROP:
117 		seq_printf(file, "%d,0x%llx,0x%llx\n",
118 			   DR_DUMP_REC_TYPE_ACTION_DROP, action_id, rule_id);
119 		break;
120 	case DR_ACTION_TYP_FT:
121 		if (action->dest_tbl->is_fw_tbl)
122 			seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x\n",
123 				   DR_DUMP_REC_TYPE_ACTION_FT, action_id,
124 				   rule_id, action->dest_tbl->fw_tbl.id,
125 				   -1);
126 		else
127 			seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%llx\n",
128 				   DR_DUMP_REC_TYPE_ACTION_FT, action_id,
129 				   rule_id, action->dest_tbl->tbl->table_id,
130 				   DR_DBG_PTR_TO_ID(action->dest_tbl->tbl));
131 
132 		break;
133 	case DR_ACTION_TYP_CTR:
134 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
135 			   DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id,
136 			   action->ctr->ctr_id + action->ctr->offset);
137 		break;
138 	case DR_ACTION_TYP_TAG:
139 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
140 			   DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id,
141 			   action->flow_tag->flow_tag);
142 		break;
143 	case DR_ACTION_TYP_MODIFY_HDR:
144 	{
145 		struct mlx5dr_ptrn_obj *ptrn = action->rewrite->ptrn;
146 		struct mlx5dr_arg_obj *arg = action->rewrite->arg;
147 		u8 *rewrite_data = action->rewrite->data;
148 		bool ptrn_arg;
149 		int i;
150 
151 		ptrn_arg = !action->rewrite->single_action_opt && ptrn && arg;
152 
153 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x,%d,0x%x,0x%x,0x%x",
154 			   DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id,
155 			   rule_id, action->rewrite->index,
156 			   action->rewrite->single_action_opt,
157 			   ptrn_arg ? action->rewrite->num_of_actions : 0,
158 			   ptrn_arg ? ptrn->index : 0,
159 			   ptrn_arg ? mlx5dr_arg_get_obj_id(arg) : 0);
160 
161 		if (ptrn_arg) {
162 			for (i = 0; i < action->rewrite->num_of_actions; i++) {
163 				seq_printf(file, ",0x%016llx",
164 					   be64_to_cpu(((__be64 *)rewrite_data)[i]));
165 			}
166 		}
167 
168 		seq_puts(file, "\n");
169 		break;
170 	}
171 	case DR_ACTION_TYP_VPORT:
172 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
173 			   DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id,
174 			   action->vport->caps->num);
175 		break;
176 	case DR_ACTION_TYP_TNL_L2_TO_L2:
177 		seq_printf(file, "%d,0x%llx,0x%llx\n",
178 			   DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id,
179 			   rule_id);
180 		break;
181 	case DR_ACTION_TYP_TNL_L3_TO_L2:
182 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
183 			   DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id,
184 			   rule_id,
185 			   (action->rewrite->ptrn && action->rewrite->arg) ?
186 			   mlx5dr_arg_get_obj_id(action->rewrite->arg) :
187 			   action->rewrite->index);
188 		break;
189 	case DR_ACTION_TYP_L2_TO_TNL_L2:
190 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
191 			   DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id,
192 			   rule_id, action->reformat->id);
193 		break;
194 	case DR_ACTION_TYP_L2_TO_TNL_L3:
195 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
196 			   DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id,
197 			   rule_id, action->reformat->id);
198 		break;
199 	case DR_ACTION_TYP_POP_VLAN:
200 		seq_printf(file, "%d,0x%llx,0x%llx\n",
201 			   DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id,
202 			   rule_id);
203 		break;
204 	case DR_ACTION_TYP_PUSH_VLAN:
205 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x\n",
206 			   DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id,
207 			   rule_id, action->push_vlan->vlan_hdr);
208 		break;
209 	case DR_ACTION_TYP_INSERT_HDR:
210 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n",
211 			   DR_DUMP_REC_TYPE_ACTION_INSERT_HDR, action_id,
212 			   rule_id, action->reformat->id,
213 			   action->reformat->param_0,
214 			   action->reformat->param_1);
215 		break;
216 	case DR_ACTION_TYP_REMOVE_HDR:
217 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n",
218 			   DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR, action_id,
219 			   rule_id, action->reformat->id,
220 			   action->reformat->param_0,
221 			   action->reformat->param_1);
222 		break;
223 	case DR_ACTION_TYP_SAMPLER:
224 		seq_printf(file,
225 			   "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x,0x%llx,0x%llx\n",
226 			   DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id, rule_id,
227 			   0, 0, action->sampler->sampler_id,
228 			   action->sampler->rx_icm_addr,
229 			   action->sampler->tx_icm_addr);
230 		break;
231 	case DR_ACTION_TYP_RANGE:
232 		if (action->range->hit_tbl_action->dest_tbl->is_fw_tbl) {
233 			hit_tbl_id = action->range->hit_tbl_action->dest_tbl->fw_tbl.id;
234 			hit_tbl_ptr = 0;
235 		} else {
236 			hit_tbl_id = action->range->hit_tbl_action->dest_tbl->tbl->table_id;
237 			hit_tbl_ptr =
238 				DR_DBG_PTR_TO_ID(action->range->hit_tbl_action->dest_tbl->tbl);
239 		}
240 
241 		if (action->range->miss_tbl_action->dest_tbl->is_fw_tbl) {
242 			miss_tbl_id = action->range->miss_tbl_action->dest_tbl->fw_tbl.id;
243 			miss_tbl_ptr = 0;
244 		} else {
245 			miss_tbl_id = action->range->miss_tbl_action->dest_tbl->tbl->table_id;
246 			miss_tbl_ptr =
247 				DR_DBG_PTR_TO_ID(action->range->miss_tbl_action->dest_tbl->tbl);
248 		}
249 
250 		seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%llx,0x%x,0x%llx,0x%x\n",
251 			   DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE, action_id, rule_id,
252 			   hit_tbl_id, hit_tbl_ptr, miss_tbl_id, miss_tbl_ptr,
253 			   action->range->definer_id);
254 		break;
255 	default:
256 		return 0;
257 	}
258 
259 	return 0;
260 }
261 
262 static int
dr_dump_rule_mem(struct seq_file * file,struct mlx5dr_ste * ste,bool is_rx,const u64 rule_id,u8 format_ver)263 dr_dump_rule_mem(struct seq_file *file, struct mlx5dr_ste *ste,
264 		 bool is_rx, const u64 rule_id, u8 format_ver)
265 {
266 	char hw_ste_dump[DR_HEX_SIZE];
267 	u32 mem_rec_type;
268 
269 	if (format_ver == MLX5_STEERING_FORMAT_CONNECTX_5) {
270 		mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 :
271 				       DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0;
272 	} else {
273 		mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 :
274 				       DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1;
275 	}
276 
277 	dr_dump_hex_print(hw_ste_dump, (char *)mlx5dr_ste_get_hw_ste(ste),
278 			  DR_STE_SIZE_REDUCED);
279 
280 	seq_printf(file, "%d,0x%llx,0x%llx,%s\n", mem_rec_type,
281 		   dr_dump_icm_to_idx(mlx5dr_ste_get_icm_addr(ste)), rule_id,
282 		   hw_ste_dump);
283 
284 	return 0;
285 }
286 
287 static int
dr_dump_rule_rx_tx(struct seq_file * file,struct mlx5dr_rule_rx_tx * rule_rx_tx,bool is_rx,const u64 rule_id,u8 format_ver)288 dr_dump_rule_rx_tx(struct seq_file *file, struct mlx5dr_rule_rx_tx *rule_rx_tx,
289 		   bool is_rx, const u64 rule_id, u8 format_ver)
290 {
291 	struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES];
292 	struct mlx5dr_ste *curr_ste = rule_rx_tx->last_rule_ste;
293 	int ret, i;
294 
295 	if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i))
296 		return 0;
297 
298 	while (i--) {
299 		ret = dr_dump_rule_mem(file, ste_arr[i], is_rx, rule_id,
300 				       format_ver);
301 		if (ret < 0)
302 			return ret;
303 	}
304 
305 	return 0;
306 }
307 
dr_dump_rule(struct seq_file * file,struct mlx5dr_rule * rule)308 static int dr_dump_rule(struct seq_file *file, struct mlx5dr_rule *rule)
309 {
310 	struct mlx5dr_rule_action_member *action_mem;
311 	const u64 rule_id = DR_DBG_PTR_TO_ID(rule);
312 	struct mlx5dr_rule_rx_tx *rx = &rule->rx;
313 	struct mlx5dr_rule_rx_tx *tx = &rule->tx;
314 	u8 format_ver;
315 	int ret;
316 
317 	format_ver = rule->matcher->tbl->dmn->info.caps.sw_format_ver;
318 
319 	seq_printf(file, "%d,0x%llx,0x%llx\n", DR_DUMP_REC_TYPE_RULE, rule_id,
320 		   DR_DBG_PTR_TO_ID(rule->matcher));
321 
322 	if (rx->nic_matcher) {
323 		ret = dr_dump_rule_rx_tx(file, rx, true, rule_id, format_ver);
324 		if (ret < 0)
325 			return ret;
326 	}
327 
328 	if (tx->nic_matcher) {
329 		ret = dr_dump_rule_rx_tx(file, tx, false, rule_id, format_ver);
330 		if (ret < 0)
331 			return ret;
332 	}
333 
334 	list_for_each_entry(action_mem, &rule->rule_actions_list, list) {
335 		ret = dr_dump_rule_action_mem(file, rule_id, action_mem);
336 		if (ret < 0)
337 			return ret;
338 	}
339 
340 	return 0;
341 }
342 
343 static int
dr_dump_matcher_mask(struct seq_file * file,struct mlx5dr_match_param * mask,u8 criteria,const u64 matcher_id)344 dr_dump_matcher_mask(struct seq_file *file, struct mlx5dr_match_param *mask,
345 		     u8 criteria, const u64 matcher_id)
346 {
347 	char dump[DR_HEX_SIZE];
348 
349 	seq_printf(file, "%d,0x%llx,", DR_DUMP_REC_TYPE_MATCHER_MASK,
350 		   matcher_id);
351 
352 	if (criteria & DR_MATCHER_CRITERIA_OUTER) {
353 		dr_dump_hex_print(dump, (char *)&mask->outer, sizeof(mask->outer));
354 		seq_printf(file, "%s,", dump);
355 	} else {
356 		seq_puts(file, ",");
357 	}
358 
359 	if (criteria & DR_MATCHER_CRITERIA_INNER) {
360 		dr_dump_hex_print(dump, (char *)&mask->inner, sizeof(mask->inner));
361 		seq_printf(file, "%s,", dump);
362 	} else {
363 		seq_puts(file, ",");
364 	}
365 
366 	if (criteria & DR_MATCHER_CRITERIA_MISC) {
367 		dr_dump_hex_print(dump, (char *)&mask->misc, sizeof(mask->misc));
368 		seq_printf(file, "%s,", dump);
369 	} else {
370 		seq_puts(file, ",");
371 	}
372 
373 	if (criteria & DR_MATCHER_CRITERIA_MISC2) {
374 		dr_dump_hex_print(dump, (char *)&mask->misc2, sizeof(mask->misc2));
375 		seq_printf(file, "%s,", dump);
376 	} else {
377 		seq_puts(file, ",");
378 	}
379 
380 	if (criteria & DR_MATCHER_CRITERIA_MISC3) {
381 		dr_dump_hex_print(dump, (char *)&mask->misc3, sizeof(mask->misc3));
382 		seq_printf(file, "%s\n", dump);
383 	} else {
384 		seq_puts(file, ",\n");
385 	}
386 
387 	return 0;
388 }
389 
390 static int
dr_dump_matcher_builder(struct seq_file * file,struct mlx5dr_ste_build * builder,u32 index,bool is_rx,const u64 matcher_id)391 dr_dump_matcher_builder(struct seq_file *file, struct mlx5dr_ste_build *builder,
392 			u32 index, bool is_rx, const u64 matcher_id)
393 {
394 	seq_printf(file, "%d,0x%llx,%d,%d,0x%x\n",
395 		   DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index, is_rx,
396 		   builder->lu_type);
397 
398 	return 0;
399 }
400 
401 static int
dr_dump_matcher_rx_tx(struct seq_file * file,bool is_rx,struct mlx5dr_matcher_rx_tx * matcher_rx_tx,const u64 matcher_id)402 dr_dump_matcher_rx_tx(struct seq_file *file, bool is_rx,
403 		      struct mlx5dr_matcher_rx_tx *matcher_rx_tx,
404 		      const u64 matcher_id)
405 {
406 	enum dr_dump_rec_type rec_type;
407 	u64 s_icm_addr, e_icm_addr;
408 	int i, ret;
409 
410 	rec_type = is_rx ? DR_DUMP_REC_TYPE_MATCHER_RX :
411 			   DR_DUMP_REC_TYPE_MATCHER_TX;
412 
413 	s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->s_htbl->chunk);
414 	e_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->e_anchor->chunk);
415 	seq_printf(file, "%d,0x%llx,0x%llx,%d,0x%llx,0x%llx\n",
416 		   rec_type, DR_DBG_PTR_TO_ID(matcher_rx_tx),
417 		   matcher_id, matcher_rx_tx->num_of_builders,
418 		   dr_dump_icm_to_idx(s_icm_addr),
419 		   dr_dump_icm_to_idx(e_icm_addr));
420 
421 	for (i = 0; i < matcher_rx_tx->num_of_builders; i++) {
422 		ret = dr_dump_matcher_builder(file,
423 					      &matcher_rx_tx->ste_builder[i],
424 					      i, is_rx, matcher_id);
425 		if (ret < 0)
426 			return ret;
427 	}
428 
429 	return 0;
430 }
431 
432 static int
dr_dump_matcher(struct seq_file * file,struct mlx5dr_matcher * matcher)433 dr_dump_matcher(struct seq_file *file, struct mlx5dr_matcher *matcher)
434 {
435 	struct mlx5dr_matcher_rx_tx *rx = &matcher->rx;
436 	struct mlx5dr_matcher_rx_tx *tx = &matcher->tx;
437 	u64 matcher_id;
438 	int ret;
439 
440 	matcher_id = DR_DBG_PTR_TO_ID(matcher);
441 
442 	seq_printf(file, "%d,0x%llx,0x%llx,%d\n", DR_DUMP_REC_TYPE_MATCHER,
443 		   matcher_id, DR_DBG_PTR_TO_ID(matcher->tbl), matcher->prio);
444 
445 	ret = dr_dump_matcher_mask(file, &matcher->mask,
446 				   matcher->match_criteria, matcher_id);
447 	if (ret < 0)
448 		return ret;
449 
450 	if (rx->nic_tbl) {
451 		ret = dr_dump_matcher_rx_tx(file, true, rx, matcher_id);
452 		if (ret < 0)
453 			return ret;
454 	}
455 
456 	if (tx->nic_tbl) {
457 		ret = dr_dump_matcher_rx_tx(file, false, tx, matcher_id);
458 		if (ret < 0)
459 			return ret;
460 	}
461 
462 	return 0;
463 }
464 
465 static int
dr_dump_matcher_all(struct seq_file * file,struct mlx5dr_matcher * matcher)466 dr_dump_matcher_all(struct seq_file *file, struct mlx5dr_matcher *matcher)
467 {
468 	struct mlx5dr_rule *rule;
469 	int ret;
470 
471 	ret = dr_dump_matcher(file, matcher);
472 	if (ret < 0)
473 		return ret;
474 
475 	list_for_each_entry(rule, &matcher->dbg_rule_list, dbg_node) {
476 		ret = dr_dump_rule(file, rule);
477 		if (ret < 0)
478 			return ret;
479 	}
480 
481 	return 0;
482 }
483 
484 static int
dr_dump_table_rx_tx(struct seq_file * file,bool is_rx,struct mlx5dr_table_rx_tx * table_rx_tx,const u64 table_id)485 dr_dump_table_rx_tx(struct seq_file *file, bool is_rx,
486 		    struct mlx5dr_table_rx_tx *table_rx_tx,
487 		    const u64 table_id)
488 {
489 	enum dr_dump_rec_type rec_type;
490 	u64 s_icm_addr;
491 
492 	rec_type = is_rx ? DR_DUMP_REC_TYPE_TABLE_RX :
493 			   DR_DUMP_REC_TYPE_TABLE_TX;
494 
495 	s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(table_rx_tx->s_anchor->chunk);
496 	seq_printf(file, "%d,0x%llx,0x%llx\n", rec_type, table_id,
497 		   dr_dump_icm_to_idx(s_icm_addr));
498 
499 	return 0;
500 }
501 
dr_dump_table(struct seq_file * file,struct mlx5dr_table * table)502 static int dr_dump_table(struct seq_file *file, struct mlx5dr_table *table)
503 {
504 	struct mlx5dr_table_rx_tx *rx = &table->rx;
505 	struct mlx5dr_table_rx_tx *tx = &table->tx;
506 	int ret;
507 
508 	seq_printf(file, "%d,0x%llx,0x%llx,%d,%d\n", DR_DUMP_REC_TYPE_TABLE,
509 		   DR_DBG_PTR_TO_ID(table), DR_DBG_PTR_TO_ID(table->dmn),
510 		   table->table_type, table->level);
511 
512 	if (rx->nic_dmn) {
513 		ret = dr_dump_table_rx_tx(file, true, rx,
514 					  DR_DBG_PTR_TO_ID(table));
515 		if (ret < 0)
516 			return ret;
517 	}
518 
519 	if (tx->nic_dmn) {
520 		ret = dr_dump_table_rx_tx(file, false, tx,
521 					  DR_DBG_PTR_TO_ID(table));
522 		if (ret < 0)
523 			return ret;
524 	}
525 	return 0;
526 }
527 
dr_dump_table_all(struct seq_file * file,struct mlx5dr_table * tbl)528 static int dr_dump_table_all(struct seq_file *file, struct mlx5dr_table *tbl)
529 {
530 	struct mlx5dr_matcher *matcher;
531 	int ret;
532 
533 	ret = dr_dump_table(file, tbl);
534 	if (ret < 0)
535 		return ret;
536 
537 	list_for_each_entry(matcher, &tbl->matcher_list, list_node) {
538 		ret = dr_dump_matcher_all(file, matcher);
539 		if (ret < 0)
540 			return ret;
541 	}
542 	return 0;
543 }
544 
545 static int
dr_dump_send_ring(struct seq_file * file,struct mlx5dr_send_ring * ring,const u64 domain_id)546 dr_dump_send_ring(struct seq_file *file, struct mlx5dr_send_ring *ring,
547 		  const u64 domain_id)
548 {
549 	seq_printf(file, "%d,0x%llx,0x%llx,0x%x,0x%x\n",
550 		   DR_DUMP_REC_TYPE_DOMAIN_SEND_RING, DR_DBG_PTR_TO_ID(ring),
551 		   domain_id, ring->cq->mcq.cqn, ring->qp->qpn);
552 	return 0;
553 }
554 
555 static int
dr_dump_domain_info_flex_parser(struct seq_file * file,const char * flex_parser_name,const u8 flex_parser_value,const u64 domain_id)556 dr_dump_domain_info_flex_parser(struct seq_file *file,
557 				const char *flex_parser_name,
558 				const u8 flex_parser_value,
559 				const u64 domain_id)
560 {
561 	seq_printf(file, "%d,0x%llx,%s,0x%x\n",
562 		   DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id,
563 		   flex_parser_name, flex_parser_value);
564 	return 0;
565 }
566 
567 static int
dr_dump_domain_info_caps(struct seq_file * file,struct mlx5dr_cmd_caps * caps,const u64 domain_id)568 dr_dump_domain_info_caps(struct seq_file *file, struct mlx5dr_cmd_caps *caps,
569 			 const u64 domain_id)
570 {
571 	struct mlx5dr_cmd_vport_cap *vport_caps;
572 	unsigned long i, vports_num;
573 
574 	xa_for_each(&caps->vports.vports_caps_xa, vports_num, vport_caps)
575 		; /* count the number of vports in xarray */
576 
577 	seq_printf(file, "%d,0x%llx,0x%x,0x%llx,0x%llx,0x%x,%lu,%d\n",
578 		   DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi,
579 		   caps->nic_rx_drop_address, caps->nic_tx_drop_address,
580 		   caps->flex_protocols, vports_num, caps->eswitch_manager);
581 
582 	xa_for_each(&caps->vports.vports_caps_xa, i, vport_caps) {
583 		vport_caps = xa_load(&caps->vports.vports_caps_xa, i);
584 
585 		seq_printf(file, "%d,0x%llx,%lu,0x%x,0x%llx,0x%llx\n",
586 			   DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT, domain_id, i,
587 			   vport_caps->vport_gvmi, vport_caps->icm_address_rx,
588 			   vport_caps->icm_address_tx);
589 	}
590 	return 0;
591 }
592 
593 static int
dr_dump_domain_info(struct seq_file * file,struct mlx5dr_domain_info * info,const u64 domain_id)594 dr_dump_domain_info(struct seq_file *file, struct mlx5dr_domain_info *info,
595 		    const u64 domain_id)
596 {
597 	int ret;
598 
599 	ret = dr_dump_domain_info_caps(file, &info->caps, domain_id);
600 	if (ret < 0)
601 		return ret;
602 
603 	ret = dr_dump_domain_info_flex_parser(file, "icmp_dw0",
604 					      info->caps.flex_parser_id_icmp_dw0,
605 					      domain_id);
606 	if (ret < 0)
607 		return ret;
608 
609 	ret = dr_dump_domain_info_flex_parser(file, "icmp_dw1",
610 					      info->caps.flex_parser_id_icmp_dw1,
611 					      domain_id);
612 	if (ret < 0)
613 		return ret;
614 
615 	ret = dr_dump_domain_info_flex_parser(file, "icmpv6_dw0",
616 					      info->caps.flex_parser_id_icmpv6_dw0,
617 					      domain_id);
618 	if (ret < 0)
619 		return ret;
620 
621 	ret = dr_dump_domain_info_flex_parser(file, "icmpv6_dw1",
622 					      info->caps.flex_parser_id_icmpv6_dw1,
623 					      domain_id);
624 	if (ret < 0)
625 		return ret;
626 
627 	return 0;
628 }
629 
630 static int
dr_dump_domain(struct seq_file * file,struct mlx5dr_domain * dmn)631 dr_dump_domain(struct seq_file *file, struct mlx5dr_domain *dmn)
632 {
633 	u64 domain_id = DR_DBG_PTR_TO_ID(dmn);
634 	int ret;
635 
636 	seq_printf(file, "%d,0x%llx,%d,0%x,%d,%u.%u.%u,%s,%d,%u,%u,%u\n",
637 		   DR_DUMP_REC_TYPE_DOMAIN,
638 		   domain_id, dmn->type, dmn->info.caps.gvmi,
639 		   dmn->info.supp_sw_steering,
640 		   /* package version */
641 		   LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL,
642 		   LINUX_VERSION_SUBLEVEL,
643 		   pci_name(dmn->mdev->pdev),
644 		   0, /* domain flags */
645 		   dmn->num_buddies[DR_ICM_TYPE_STE],
646 		   dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION],
647 		   dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN]);
648 
649 	ret = dr_dump_domain_info(file, &dmn->info, domain_id);
650 	if (ret < 0)
651 		return ret;
652 
653 	if (dmn->info.supp_sw_steering) {
654 		ret = dr_dump_send_ring(file, dmn->send_ring, domain_id);
655 		if (ret < 0)
656 			return ret;
657 	}
658 
659 	return 0;
660 }
661 
dr_dump_domain_all(struct seq_file * file,struct mlx5dr_domain * dmn)662 static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn)
663 {
664 	struct mlx5dr_table *tbl;
665 	int ret;
666 
667 	mutex_lock(&dmn->dump_info.dbg_mutex);
668 	mlx5dr_domain_lock(dmn);
669 
670 	ret = dr_dump_domain(file, dmn);
671 	if (ret < 0)
672 		goto unlock_mutex;
673 
674 	list_for_each_entry(tbl, &dmn->dbg_tbl_list, dbg_node) {
675 		ret = dr_dump_table_all(file, tbl);
676 		if (ret < 0)
677 			break;
678 	}
679 
680 unlock_mutex:
681 	mlx5dr_domain_unlock(dmn);
682 	mutex_unlock(&dmn->dump_info.dbg_mutex);
683 	return ret;
684 }
685 
dr_dump_show(struct seq_file * file,void * priv)686 static int dr_dump_show(struct seq_file *file, void *priv)
687 {
688 	return dr_dump_domain_all(file, file->private);
689 }
690 DEFINE_SHOW_ATTRIBUTE(dr_dump);
691 
mlx5dr_dbg_init_dump(struct mlx5dr_domain * dmn)692 void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn)
693 {
694 	struct mlx5_core_dev *dev = dmn->mdev;
695 	char file_name[128];
696 
697 	if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) {
698 		mlx5_core_warn(dev,
699 			       "Steering dump is not supported for NIC RX/TX domains\n");
700 		return;
701 	}
702 
703 	dmn->dump_info.steering_debugfs =
704 		debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev));
705 	dmn->dump_info.fdb_debugfs =
706 		debugfs_create_dir("fdb", dmn->dump_info.steering_debugfs);
707 
708 	sprintf(file_name, "dmn_%p", dmn);
709 	debugfs_create_file(file_name, 0444, dmn->dump_info.fdb_debugfs,
710 			    dmn, &dr_dump_fops);
711 
712 	INIT_LIST_HEAD(&dmn->dbg_tbl_list);
713 	mutex_init(&dmn->dump_info.dbg_mutex);
714 }
715 
mlx5dr_dbg_uninit_dump(struct mlx5dr_domain * dmn)716 void mlx5dr_dbg_uninit_dump(struct mlx5dr_domain *dmn)
717 {
718 	debugfs_remove_recursive(dmn->dump_info.steering_debugfs);
719 	mutex_destroy(&dmn->dump_info.dbg_mutex);
720 }
721