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 12enum 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 57static struct mlx5dr_dbg_dump_buff * 58mlx5dr_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 78static struct mlx5dr_dbg_dump_data * 79mlx5dr_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 97static void 98mlx5dr_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 114static int 115mlx5dr_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 158void 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 165void 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 172void 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 181void 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 190static 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 197static void 198dr_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 207static int 208dr_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 489static int 490dr_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 522static int 523dr_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 544static noinline_for_stack int 545dr_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 588static int 589dr_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 683static int 684dr_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 704static int 705dr_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 743static noinline_for_stack int 744dr_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 785static int 786dr_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 804static int 805dr_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 830static noinline_for_stack int 831dr_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 865static 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 882static int 883dr_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 904static int 905dr_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 927static int 928dr_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 970static int 971dr_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 1008static noinline_for_stack int 1009dr_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 1048static 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 1066unlock_mutex: 1067 mlx5dr_domain_unlock(dmn); 1068 mutex_unlock(&dmn->dump_info.dbg_mutex); 1069 return ret; 1070} 1071 1072static void * 1073dr_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 1103exit: 1104 atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); 1105 return NULL; 1106} 1107 1108static void * 1109dr_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 1119static void 1120dr_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 1139static int 1140dr_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 1150static 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}; 1156DEFINE_SEQ_ATTRIBUTE(dr_dump); 1157 1158void 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 1182void 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} 1187