FILE
fw_tracer.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
1/* 2 * Copyright (c) 2018, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32#define CREATE_TRACE_POINTS 33#include "lib/eq.h" 34#include "fw_tracer.h" 35#include "fw_tracer_tracepoint.h" 36#include <linux/ctype.h> 37 38static int mlx5_query_mtrc_caps(struct mlx5_fw_tracer *tracer) 39{ 40 u32 *string_db_base_address_out = tracer->str_db.base_address_out; 41 u32 *string_db_size_out = tracer->str_db.size_out; 42 struct mlx5_core_dev *dev = tracer->dev; 43 u32 out[MLX5_ST_SZ_DW(mtrc_cap)] = {0}; 44 u32 in[MLX5_ST_SZ_DW(mtrc_cap)] = {0}; 45 void *mtrc_cap_sp; 46 int err, i; 47 48 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), 49 MLX5_REG_MTRC_CAP, 0, 0); 50 if (err) { 51 mlx5_core_warn(dev, "FWTracer: Error reading tracer caps %d\n", 52 err); 53 return err; 54 } 55 56 if (!MLX5_GET(mtrc_cap, out, trace_to_memory)) { 57 mlx5_core_dbg(dev, "FWTracer: Device does not support logging traces to memory\n"); 58 return -EOPNOTSUPP; 59 } 60 61 tracer->trc_ver = MLX5_GET(mtrc_cap, out, trc_ver); 62 tracer->str_db.first_string_trace = 63 MLX5_GET(mtrc_cap, out, first_string_trace); 64 tracer->str_db.num_string_trace = 65 MLX5_GET(mtrc_cap, out, num_string_trace); 66 tracer->str_db.num_string_db = MLX5_GET(mtrc_cap, out, num_string_db); 67 tracer->owner = !!MLX5_GET(mtrc_cap, out, trace_owner); 68 tracer->str_db.loaded = false; 69 70 for (i = 0; i < tracer->str_db.num_string_db; i++) { 71 mtrc_cap_sp = MLX5_ADDR_OF(mtrc_cap, out, string_db_param[i]); 72 string_db_base_address_out[i] = MLX5_GET(mtrc_string_db_param, 73 mtrc_cap_sp, 74 string_db_base_address); 75 string_db_size_out[i] = MLX5_GET(mtrc_string_db_param, 76 mtrc_cap_sp, string_db_size); 77 } 78 79 return err; 80} 81 82static int mlx5_set_mtrc_caps_trace_owner(struct mlx5_fw_tracer *tracer, 83 u32 *out, u32 out_size, 84 u8 trace_owner) 85{ 86 struct mlx5_core_dev *dev = tracer->dev; 87 u32 in[MLX5_ST_SZ_DW(mtrc_cap)] = {0}; 88 89 MLX5_SET(mtrc_cap, in, trace_owner, trace_owner); 90 91 return mlx5_core_access_reg(dev, in, sizeof(in), out, out_size, 92 MLX5_REG_MTRC_CAP, 0, 1); 93} 94 95static int mlx5_fw_tracer_ownership_acquire(struct mlx5_fw_tracer *tracer) 96{ 97 struct mlx5_core_dev *dev = tracer->dev; 98 u32 out[MLX5_ST_SZ_DW(mtrc_cap)] = {0}; 99 int err; 100 101 err = mlx5_set_mtrc_caps_trace_owner(tracer, out, sizeof(out), 102 MLX5_FW_TRACER_ACQUIRE_OWNERSHIP); 103 if (err) { 104 mlx5_core_warn(dev, "FWTracer: Acquire tracer ownership failed %d\n", 105 err); 106 return err; 107 } 108 109 tracer->owner = !!MLX5_GET(mtrc_cap, out, trace_owner); 110 111 if (!tracer->owner) 112 return -EBUSY; 113 114 return 0; 115} 116 117static void mlx5_fw_tracer_ownership_release(struct mlx5_fw_tracer *tracer) 118{ 119 u32 out[MLX5_ST_SZ_DW(mtrc_cap)] = {0}; 120 121 mlx5_set_mtrc_caps_trace_owner(tracer, out, sizeof(out), 122 MLX5_FW_TRACER_RELEASE_OWNERSHIP); 123 tracer->owner = false; 124} 125 126static int mlx5_fw_tracer_create_log_buf(struct mlx5_fw_tracer *tracer) 127{ 128 struct mlx5_core_dev *dev = tracer->dev; 129 struct device *ddev; 130 dma_addr_t dma; 131 void *buff; 132 gfp_t gfp; 133 int err; 134 135 tracer->buff.size = TRACE_BUFFER_SIZE_BYTE; 136 137 gfp = GFP_KERNEL | __GFP_ZERO; 138 buff = (void *)__get_free_pages(gfp, 139 get_order(tracer->buff.size)); 140 if (!buff) { 141 err = -ENOMEM; 142 mlx5_core_warn(dev, "FWTracer: Failed to allocate pages, %d\n", err); 143 return err; 144 } 145 tracer->buff.log_buf = buff; 146 147 ddev = mlx5_core_dma_dev(dev); 148 dma = dma_map_single(ddev, buff, tracer->buff.size, DMA_FROM_DEVICE); 149 if (dma_mapping_error(ddev, dma)) { 150 mlx5_core_warn(dev, "FWTracer: Unable to map DMA: %d\n", 151 dma_mapping_error(ddev, dma)); 152 err = -ENOMEM; 153 goto free_pages; 154 } 155 tracer->buff.dma = dma; 156 157 return 0; 158 159free_pages: 160 free_pages((unsigned long)tracer->buff.log_buf, get_order(tracer->buff.size)); 161 162 return err; 163} 164 165static void mlx5_fw_tracer_destroy_log_buf(struct mlx5_fw_tracer *tracer) 166{ 167 struct mlx5_core_dev *dev = tracer->dev; 168 struct device *ddev; 169 170 if (!tracer->buff.log_buf) 171 return; 172 173 ddev = mlx5_core_dma_dev(dev); 174 dma_unmap_single(ddev, tracer->buff.dma, tracer->buff.size, DMA_FROM_DEVICE); 175 free_pages((unsigned long)tracer->buff.log_buf, get_order(tracer->buff.size)); 176} 177 178static int mlx5_fw_tracer_create_mkey(struct mlx5_fw_tracer *tracer) 179{ 180 struct mlx5_core_dev *dev = tracer->dev; 181 int err, inlen, i; 182 __be64 *mtt; 183 void *mkc; 184 u32 *in; 185 186 inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + 187 sizeof(*mtt) * round_up(TRACER_BUFFER_PAGE_NUM, 2); 188 189 in = kvzalloc(inlen, GFP_KERNEL); 190 if (!in) 191 return -ENOMEM; 192 193 MLX5_SET(create_mkey_in, in, translations_octword_actual_size, 194 DIV_ROUND_UP(TRACER_BUFFER_PAGE_NUM, 2)); 195 mtt = (__be64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt); 196 for (i = 0 ; i < TRACER_BUFFER_PAGE_NUM ; i++) 197 mtt[i] = cpu_to_be64(tracer->buff.dma + i * PAGE_SIZE); 198 199 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); 200 MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_MTT); 201 MLX5_SET(mkc, mkc, lr, 1); 202 MLX5_SET(mkc, mkc, lw, 1); 203 MLX5_SET(mkc, mkc, pd, tracer->buff.pdn); 204 MLX5_SET(mkc, mkc, bsf_octword_size, 0); 205 MLX5_SET(mkc, mkc, qpn, 0xffffff); 206 MLX5_SET(mkc, mkc, log_page_size, PAGE_SHIFT); 207 MLX5_SET(mkc, mkc, translations_octword_size, 208 DIV_ROUND_UP(TRACER_BUFFER_PAGE_NUM, 2)); 209 MLX5_SET64(mkc, mkc, start_addr, tracer->buff.dma); 210 MLX5_SET64(mkc, mkc, len, tracer->buff.size); 211 err = mlx5_core_create_mkey(dev, &tracer->buff.mkey, in, inlen); 212 if (err) 213 mlx5_core_warn(dev, "FWTracer: Failed to create mkey, %d\n", err); 214 215 kvfree(in); 216 217 return err; 218} 219 220static void mlx5_fw_tracer_free_strings_db(struct mlx5_fw_tracer *tracer) 221{ 222 u32 num_string_db = tracer->str_db.num_string_db; 223 int i; 224 225 for (i = 0; i < num_string_db; i++) { 226 kfree(tracer->str_db.buffer[i]); 227 tracer->str_db.buffer[i] = NULL; 228 } 229} 230 231static int mlx5_fw_tracer_allocate_strings_db(struct mlx5_fw_tracer *tracer) 232{ 233 u32 *string_db_size_out = tracer->str_db.size_out; 234 u32 num_string_db = tracer->str_db.num_string_db; 235 int i; 236 237 for (i = 0; i < num_string_db; i++) { 238 if (!string_db_size_out[i]) 239 continue; 240 tracer->str_db.buffer[i] = kzalloc(string_db_size_out[i], GFP_KERNEL); 241 if (!tracer->str_db.buffer[i]) 242 goto free_strings_db; 243 } 244 245 return 0; 246 247free_strings_db: 248 mlx5_fw_tracer_free_strings_db(tracer); 249 return -ENOMEM; 250} 251 252static void 253mlx5_fw_tracer_init_saved_traces_array(struct mlx5_fw_tracer *tracer) 254{ 255 tracer->st_arr.saved_traces_index = 0; 256 mutex_init(&tracer->st_arr.lock); 257} 258 259static void 260mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer *tracer) 261{ 262 mutex_destroy(&tracer->st_arr.lock); 263} 264 265static void mlx5_tracer_read_strings_db(struct work_struct *work) 266{ 267 struct mlx5_fw_tracer *tracer = container_of(work, struct mlx5_fw_tracer, 268 read_fw_strings_work); 269 u32 num_of_reads, num_string_db = tracer->str_db.num_string_db; 270 struct mlx5_core_dev *dev = tracer->dev; 271 u32 in[MLX5_ST_SZ_DW(mtrc_cap)] = {0}; 272 u32 leftovers, offset; 273 int err = 0, i, j; 274 u32 *out, outlen; 275 void *out_value; 276 277 outlen = MLX5_ST_SZ_BYTES(mtrc_stdb) + STRINGS_DB_READ_SIZE_BYTES; 278 out = kzalloc(outlen, GFP_KERNEL); 279 if (!out) { 280 err = -ENOMEM; 281 goto out; 282 } 283 284 for (i = 0; i < num_string_db; i++) { 285 if (!tracer->str_db.size_out[i]) 286 continue; 287 offset = 0; 288 MLX5_SET(mtrc_stdb, in, string_db_index, i); 289 num_of_reads = tracer->str_db.size_out[i] / 290 STRINGS_DB_READ_SIZE_BYTES; 291 leftovers = (tracer->str_db.size_out[i] % 292 STRINGS_DB_READ_SIZE_BYTES) / 293 STRINGS_DB_LEFTOVER_SIZE_BYTES; 294 295 MLX5_SET(mtrc_stdb, in, read_size, STRINGS_DB_READ_SIZE_BYTES); 296 for (j = 0; j < num_of_reads; j++) { 297 MLX5_SET(mtrc_stdb, in, start_offset, offset); 298 299 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 300 outlen, MLX5_REG_MTRC_STDB, 301 0, 1); 302 if (err) { 303 mlx5_core_dbg(dev, "FWTracer: Failed to read strings DB %d\n", 304 err); 305 goto out_free; 306 } 307 308 out_value = MLX5_ADDR_OF(mtrc_stdb, out, string_db_data); 309 memcpy(tracer->str_db.buffer[i] + offset, out_value, 310 STRINGS_DB_READ_SIZE_BYTES); 311 offset += STRINGS_DB_READ_SIZE_BYTES; 312 } 313 314 /* Strings database is aligned to 64, need to read leftovers*/ 315 MLX5_SET(mtrc_stdb, in, read_size, 316 STRINGS_DB_LEFTOVER_SIZE_BYTES); 317 for (j = 0; j < leftovers; j++) { 318 MLX5_SET(mtrc_stdb, in, start_offset, offset); 319 320 err = mlx5_core_access_reg(dev, in, sizeof(in), out, 321 outlen, MLX5_REG_MTRC_STDB, 322 0, 1); 323 if (err) { 324 mlx5_core_dbg(dev, "FWTracer: Failed to read strings DB %d\n", 325 err); 326 goto out_free; 327 } 328 329 out_value = MLX5_ADDR_OF(mtrc_stdb, out, string_db_data); 330 memcpy(tracer->str_db.buffer[i] + offset, out_value, 331 STRINGS_DB_LEFTOVER_SIZE_BYTES); 332 offset += STRINGS_DB_LEFTOVER_SIZE_BYTES; 333 } 334 } 335 336 tracer->str_db.loaded = true; 337 338out_free: 339 kfree(out); 340out: 341 return; 342} 343 344static void mlx5_fw_tracer_arm(struct mlx5_core_dev *dev) 345{ 346 u32 out[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0}; 347 u32 in[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0}; 348 int err; 349 350 MLX5_SET(mtrc_ctrl, in, arm_event, 1); 351 352 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), 353 MLX5_REG_MTRC_CTRL, 0, 1); 354 if (err) 355 mlx5_core_warn(dev, "FWTracer: Failed to arm tracer event %d\n", err); 356} 357 358static const char *VAL_PARM = "%llx"; 359static const char *REPLACE_64_VAL_PARM = "%x%x"; 360static const char *PARAM_CHAR = "%"; 361 362static bool mlx5_is_valid_spec(const char *str) 363{ 364 /* Parse format specifiers to find the actual type. 365 * Structure: %[flags][width][.precision][length]type 366 * Skip flags, width, precision & length. 367 */ 368 while (isdigit(*str) || *str == '#' || *str == '.' || *str == 'l') 369 str++; 370 371 /* Check if it's a valid integer/hex specifier or %%: 372 * Valid formats: %x, %d, %i, %u, etc. 373 */ 374 if (*str != 'x' && *str != 'X' && *str != 'd' && *str != 'i' && 375 *str != 'u' && *str != 'c' && *str != '%') 376 return false; 377 378 return true; 379} 380 381static bool mlx5_tracer_validate_params(const char *str) 382{ 383 const char *substr = str; 384 385 if (!str) 386 return false; 387 388 substr = strstr(substr, PARAM_CHAR); 389 while (substr) { 390 if (!mlx5_is_valid_spec(substr + 1)) 391 return false; 392 393 if (*(substr + 1) == '%') 394 substr = strstr(substr + 2, PARAM_CHAR); 395 else 396 substr = strstr(substr + 1, PARAM_CHAR); 397 398 } 399 400 return true; 401} 402 403static int mlx5_tracer_message_hash(u32 message_id) 404{ 405 return jhash_1word(message_id, 0) & (MESSAGE_HASH_SIZE - 1); 406} 407 408static struct tracer_string_format *mlx5_tracer_message_insert(struct mlx5_fw_tracer *tracer, 409 struct tracer_event *tracer_event) 410{ 411 struct hlist_head *head = 412 &tracer->hash[mlx5_tracer_message_hash(tracer_event->string_event.tmsn)]; 413 struct tracer_string_format *cur_string; 414 415 cur_string = kzalloc(sizeof(*cur_string), GFP_KERNEL); 416 if (!cur_string) 417 return NULL; 418 419 hlist_add_head(&cur_string->hlist, head); 420 421 return cur_string; 422} 423 424static struct tracer_string_format *mlx5_tracer_get_string(struct mlx5_fw_tracer *tracer, 425 struct tracer_event *tracer_event) 426{ 427 struct tracer_string_format *cur_string; 428 u32 str_ptr, offset; 429 int i; 430 431 str_ptr = tracer_event->string_event.string_param; 432 433 for (i = 0; i < tracer->str_db.num_string_db; i++) { 434 if (!tracer->str_db.size_out[i]) 435 continue; 436 if (str_ptr > tracer->str_db.base_address_out[i] && 437 str_ptr < tracer->str_db.base_address_out[i] + 438 tracer->str_db.size_out[i]) { 439 offset = str_ptr - tracer->str_db.base_address_out[i]; 440 /* add it to the hash */ 441 cur_string = mlx5_tracer_message_insert(tracer, tracer_event); 442 if (!cur_string) 443 return NULL; 444 cur_string->string = (char *)(tracer->str_db.buffer[i] + 445 offset); 446 return cur_string; 447 } 448 } 449 450 return NULL; 451} 452 453static void mlx5_tracer_clean_message(struct tracer_string_format *str_frmt) 454{ 455 hlist_del(&str_frmt->hlist); 456 kfree(str_frmt); 457} 458 459static int mlx5_tracer_get_num_of_params(char *str) 460{ 461 char *substr, *pstr = str; 462 int num_of_params = 0; 463 464 /* Validate that all parameters are valid before processing */ 465 if (!mlx5_tracer_validate_params(str)) 466 return -EINVAL; 467 468 /* replace %llx with %x%x */ 469 substr = strstr(pstr, VAL_PARM); 470 while (substr) { 471 memcpy(substr, REPLACE_64_VAL_PARM, 4); 472 pstr = substr; 473 substr = strstr(pstr, VAL_PARM); 474 } 475 476 /* count all the % characters, but skip %% (escaped percent) */ 477 substr = strstr(str, PARAM_CHAR); 478 while (substr) { 479 if (*(substr + 1) != '%') { 480 num_of_params += 1; 481 str = substr + 1; 482 } else { 483 str = substr + 2; 484 } 485 substr = strstr(str, PARAM_CHAR); 486 } 487 488 return num_of_params; 489} 490 491static struct tracer_string_format *mlx5_tracer_message_find(struct hlist_head *head, 492 u8 event_id, u32 tmsn) 493{ 494 struct tracer_string_format *message; 495 496 hlist_for_each_entry(message, head, hlist) 497 if (message->event_id == event_id && message->tmsn == tmsn) 498 return message; 499 500 return NULL; 501} 502 503static struct tracer_string_format *mlx5_tracer_message_get(struct mlx5_fw_tracer *tracer, 504 struct tracer_event *tracer_event) 505{ 506 struct hlist_head *head = 507 &tracer->hash[mlx5_tracer_message_hash(tracer_event->string_event.tmsn)]; 508 509 return mlx5_tracer_message_find(head, tracer_event->event_id, tracer_event->string_event.tmsn); 510} 511 512static void poll_trace(struct mlx5_fw_tracer *tracer, 513 struct tracer_event *tracer_event, u64 *trace) 514{ 515 u32 timestamp_low, timestamp_mid, timestamp_high, urts; 516 517 tracer_event->event_id = MLX5_GET(tracer_event, trace, event_id); 518 tracer_event->lost_event = MLX5_GET(tracer_event, trace, lost); 519 tracer_event->out = trace; 520 521 switch (tracer_event->event_id) { 522 case TRACER_EVENT_TYPE_TIMESTAMP: 523 tracer_event->type = TRACER_EVENT_TYPE_TIMESTAMP; 524 urts = MLX5_GET(tracer_timestamp_event, trace, urts); 525 if (tracer->trc_ver == 0) 526 tracer_event->timestamp_event.unreliable = !!(urts >> 2); 527 else 528 tracer_event->timestamp_event.unreliable = !!(urts & 1); 529 530 timestamp_low = MLX5_GET(tracer_timestamp_event, 531 trace, timestamp7_0); 532 timestamp_mid = MLX5_GET(tracer_timestamp_event, 533 trace, timestamp39_8); 534 timestamp_high = MLX5_GET(tracer_timestamp_event, 535 trace, timestamp52_40); 536 537 tracer_event->timestamp_event.timestamp = 538 ((u64)timestamp_high << 40) | 539 ((u64)timestamp_mid << 8) | 540 (u64)timestamp_low; 541 break; 542 default: 543 if (tracer_event->event_id >= tracer->str_db.first_string_trace && 544 tracer_event->event_id <= tracer->str_db.first_string_trace + 545 tracer->str_db.num_string_trace) { 546 tracer_event->type = TRACER_EVENT_TYPE_STRING; 547 tracer_event->string_event.timestamp = 548 MLX5_GET(tracer_string_event, trace, timestamp); 549 tracer_event->string_event.string_param = 550 MLX5_GET(tracer_string_event, trace, string_param); 551 tracer_event->string_event.tmsn = 552 MLX5_GET(tracer_string_event, trace, tmsn); 553 tracer_event->string_event.tdsn = 554 MLX5_GET(tracer_string_event, trace, tdsn); 555 } else { 556 tracer_event->type = TRACER_EVENT_TYPE_UNRECOGNIZED; 557 } 558 break; 559 } 560} 561 562static u64 get_block_timestamp(struct mlx5_fw_tracer *tracer, u64 *ts_event) 563{ 564 struct tracer_event tracer_event; 565 u8 event_id; 566 567 event_id = MLX5_GET(tracer_event, ts_event, event_id); 568 569 if (event_id == TRACER_EVENT_TYPE_TIMESTAMP) 570 poll_trace(tracer, &tracer_event, ts_event); 571 else 572 tracer_event.timestamp_event.timestamp = 0; 573 574 return tracer_event.timestamp_event.timestamp; 575} 576 577static void mlx5_fw_tracer_clean_print_hash(struct mlx5_fw_tracer *tracer) 578{ 579 struct tracer_string_format *str_frmt; 580 struct hlist_node *n; 581 int i; 582 583 for (i = 0; i < MESSAGE_HASH_SIZE; i++) { 584 hlist_for_each_entry_safe(str_frmt, n, &tracer->hash[i], hlist) 585 mlx5_tracer_clean_message(str_frmt); 586 } 587} 588 589static void mlx5_fw_tracer_clean_ready_list(struct mlx5_fw_tracer *tracer) 590{ 591 struct tracer_string_format *str_frmt, *tmp_str; 592 593 list_for_each_entry_safe(str_frmt, tmp_str, &tracer->ready_strings_list, 594 list) 595 list_del(&str_frmt->list); 596} 597 598static void mlx5_fw_tracer_save_trace(struct mlx5_fw_tracer *tracer, 599 u64 timestamp, bool lost, 600 u8 event_id, char *msg) 601{ 602 struct mlx5_fw_trace_data *trace_data; 603 604 mutex_lock(&tracer->st_arr.lock); 605 trace_data = &tracer->st_arr.straces[tracer->st_arr.saved_traces_index]; 606 trace_data->timestamp = timestamp; 607 trace_data->lost = lost; 608 trace_data->event_id = event_id; 609 strscpy_pad(trace_data->msg, msg, TRACE_STR_MSG); 610 611 tracer->st_arr.saved_traces_index = 612 (tracer->st_arr.saved_traces_index + 1) & (SAVED_TRACES_NUM - 1); 613 mutex_unlock(&tracer->st_arr.lock); 614} 615 616static noinline 617void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt, 618 struct mlx5_core_dev *dev, 619 u64 trace_timestamp) 620{ 621 char tmp[512]; 622 623 if (str_frmt->invalid_string) 624 snprintf(tmp, sizeof(tmp), "BAD_FORMAT: %s", str_frmt->string); 625 else 626 snprintf(tmp, sizeof(tmp), str_frmt->string, 627 str_frmt->params[0], 628 str_frmt->params[1], 629 str_frmt->params[2], 630 str_frmt->params[3], 631 str_frmt->params[4], 632 str_frmt->params[5], 633 str_frmt->params[6]); 634 635 trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost, 636 str_frmt->event_id, tmp); 637 638 mlx5_fw_tracer_save_trace(dev->tracer, trace_timestamp, 639 str_frmt->lost, str_frmt->event_id, tmp); 640 641 /* remove it from hash */ 642 mlx5_tracer_clean_message(str_frmt); 643} 644 645static int mlx5_tracer_handle_raw_string(struct mlx5_fw_tracer *tracer, 646 struct tracer_event *tracer_event) 647{ 648 struct tracer_string_format *cur_string; 649 650 cur_string = mlx5_tracer_message_insert(tracer, tracer_event); 651 if (!cur_string) 652 return -1; 653 654 cur_string->event_id = tracer_event->event_id; 655 cur_string->timestamp = tracer_event->string_event.timestamp; 656 cur_string->lost = tracer_event->lost_event; 657 cur_string->string = "0x%08x%08x"; 658 cur_string->num_of_params = 2; 659 cur_string->params[0] = upper_32_bits(*tracer_event->out); 660 cur_string->params[1] = lower_32_bits(*tracer_event->out); 661 list_add_tail(&cur_string->list, &tracer->ready_strings_list); 662 return 0; 663} 664 665static void mlx5_tracer_handle_bad_format_string(struct mlx5_fw_tracer *tracer, 666 struct tracer_string_format *cur_string) 667{ 668 cur_string->invalid_string = true; 669 list_add_tail(&cur_string->list, &tracer->ready_strings_list); 670} 671 672static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer, 673 struct tracer_event *tracer_event) 674{ 675 struct tracer_string_format *cur_string; 676 677 if (tracer_event->string_event.tdsn == 0) { 678 cur_string = mlx5_tracer_get_string(tracer, tracer_event); 679 if (!cur_string) 680 return mlx5_tracer_handle_raw_string(tracer, tracer_event); 681 682 cur_string->event_id = tracer_event->event_id; 683 cur_string->tmsn = tracer_event->string_event.tmsn; 684 cur_string->timestamp = tracer_event->string_event.timestamp; 685 cur_string->lost = tracer_event->lost_event; 686 cur_string->last_param_num = 0; 687 cur_string->num_of_params = mlx5_tracer_get_num_of_params(cur_string->string); 688 if (cur_string->num_of_params < 0) { 689 pr_debug("%s Invalid format string parameters\n", 690 __func__); 691 mlx5_tracer_handle_bad_format_string(tracer, cur_string); 692 return 0; 693 } 694 if (cur_string->num_of_params == 0) /* trace with no params */ 695 list_add_tail(&cur_string->list, &tracer->ready_strings_list); 696 } else { 697 cur_string = mlx5_tracer_message_get(tracer, tracer_event); 698 if (!cur_string) { 699 pr_debug("%s Got string event for unknown string tmsn: %d\n", 700 __func__, tracer_event->string_event.tmsn); 701 return mlx5_tracer_handle_raw_string(tracer, tracer_event); 702 } 703 if (cur_string->num_of_params < 0) { 704 pr_debug("%s string parameter of invalid string, dumping\n", 705 __func__); 706 return 0; 707 } 708 cur_string->last_param_num += 1; 709 if (cur_string->last_param_num > TRACER_MAX_PARAMS) { 710 pr_debug("%s Number of params exceeds the max (%d)\n", 711 __func__, TRACER_MAX_PARAMS); 712 list_add_tail(&cur_string->list, &tracer->ready_strings_list); 713 return 0; 714 } 715 /* keep the new parameter */ 716 cur_string->params[cur_string->last_param_num - 1] = 717 tracer_event->string_event.string_param; 718 if (cur_string->last_param_num == cur_string->num_of_params) 719 list_add_tail(&cur_string->list, &tracer->ready_strings_list); 720 } 721 722 return 0; 723} 724 725static void mlx5_tracer_handle_timestamp_trace(struct mlx5_fw_tracer *tracer, 726 struct tracer_event *tracer_event) 727{ 728 struct tracer_timestamp_event timestamp_event = 729 tracer_event->timestamp_event; 730 struct tracer_string_format *str_frmt, *tmp_str; 731 struct mlx5_core_dev *dev = tracer->dev; 732 u64 trace_timestamp; 733 734 list_for_each_entry_safe(str_frmt, tmp_str, &tracer->ready_strings_list, list) { 735 list_del(&str_frmt->list); 736 if (str_frmt->timestamp < (timestamp_event.timestamp & MASK_6_0)) 737 trace_timestamp = (timestamp_event.timestamp & MASK_52_7) | 738 (str_frmt->timestamp & MASK_6_0); 739 else 740 trace_timestamp = ((timestamp_event.timestamp - 1) & MASK_52_7) | 741 (str_frmt->timestamp & MASK_6_0); 742 743 mlx5_tracer_print_trace(str_frmt, dev, trace_timestamp); 744 } 745} 746 747static int mlx5_tracer_handle_trace(struct mlx5_fw_tracer *tracer, 748 struct tracer_event *tracer_event) 749{ 750 if (tracer_event->type == TRACER_EVENT_TYPE_STRING) { 751 mlx5_tracer_handle_string_trace(tracer, tracer_event); 752 } else if (tracer_event->type == TRACER_EVENT_TYPE_TIMESTAMP) { 753 if (!tracer_event->timestamp_event.unreliable) 754 mlx5_tracer_handle_timestamp_trace(tracer, tracer_event); 755 } else { 756 pr_debug("%s Got unrecognised type %d for parsing, exiting..\n", 757 __func__, tracer_event->type); 758 } 759 return 0; 760} 761 762static void mlx5_fw_tracer_handle_traces(struct work_struct *work) 763{ 764 struct mlx5_fw_tracer *tracer = 765 container_of(work, struct mlx5_fw_tracer, handle_traces_work); 766 u64 block_timestamp, last_block_timestamp, tmp_trace_block[TRACES_PER_BLOCK]; 767 u32 block_count, start_offset, prev_start_offset, prev_consumer_index; 768 u32 trace_event_size = MLX5_ST_SZ_BYTES(tracer_event); 769 struct mlx5_core_dev *dev = tracer->dev; 770 struct tracer_event tracer_event; 771 int i; 772 773 mlx5_core_dbg(dev, "FWTracer: Handle Trace event, owner=(%d)\n", tracer->owner); 774 if (!tracer->owner) 775 return; 776 777 if (unlikely(!tracer->str_db.loaded)) 778 goto arm; 779 780 block_count = tracer->buff.size / TRACER_BLOCK_SIZE_BYTE; 781 start_offset = tracer->buff.consumer_index * TRACER_BLOCK_SIZE_BYTE; 782 783 /* Copy the block to local buffer to avoid HW override while being processed */ 784 memcpy(tmp_trace_block, tracer->buff.log_buf + start_offset, 785 TRACER_BLOCK_SIZE_BYTE); 786 787 block_timestamp = 788 get_block_timestamp(tracer, &tmp_trace_block[TRACES_PER_BLOCK - 1]); 789 790 while (block_timestamp > tracer->last_timestamp) { 791 /* Check block override if it's not the first block */ 792 if (tracer->last_timestamp) { 793 u64 *ts_event; 794 /* To avoid block override be the HW in case of buffer 795 * wraparound, the time stamp of the previous block 796 * should be compared to the last timestamp handled 797 * by the driver. 798 */ 799 prev_consumer_index = 800 (tracer->buff.consumer_index - 1) & (block_count - 1); 801 prev_start_offset = prev_consumer_index * TRACER_BLOCK_SIZE_BYTE; 802 803 ts_event = tracer->buff.log_buf + prev_start_offset + 804 (TRACES_PER_BLOCK - 1) * trace_event_size; 805 last_block_timestamp = get_block_timestamp(tracer, ts_event); 806 /* If previous timestamp different from last stored 807 * timestamp then there is a good chance that the 808 * current buffer is overwritten and therefore should 809 * not be parsed. 810 */ 811 if (tracer->last_timestamp != last_block_timestamp) { 812 mlx5_core_warn(dev, "FWTracer: Events were lost\n"); 813 tracer->last_timestamp = block_timestamp; 814 tracer->buff.consumer_index = 815 (tracer->buff.consumer_index + 1) & (block_count - 1); 816 break; 817 } 818 } 819 820 /* Parse events */ 821 for (i = 0; i < TRACES_PER_BLOCK ; i++) { 822 poll_trace(tracer, &tracer_event, &tmp_trace_block[i]); 823 mlx5_tracer_handle_trace(tracer, &tracer_event); 824 } 825 826 tracer->buff.consumer_index = 827 (tracer->buff.consumer_index + 1) & (block_count - 1); 828 829 tracer->last_timestamp = block_timestamp; 830 start_offset = tracer->buff.consumer_index * TRACER_BLOCK_SIZE_BYTE; 831 memcpy(tmp_trace_block, tracer->buff.log_buf + start_offset, 832 TRACER_BLOCK_SIZE_BYTE); 833 block_timestamp = get_block_timestamp(tracer, 834 &tmp_trace_block[TRACES_PER_BLOCK - 1]); 835 } 836 837arm: 838 mlx5_fw_tracer_arm(dev); 839} 840 841static int mlx5_fw_tracer_set_mtrc_conf(struct mlx5_fw_tracer *tracer) 842{ 843 struct mlx5_core_dev *dev = tracer->dev; 844 u32 out[MLX5_ST_SZ_DW(mtrc_conf)] = {0}; 845 u32 in[MLX5_ST_SZ_DW(mtrc_conf)] = {0}; 846 int err; 847 848 MLX5_SET(mtrc_conf, in, trace_mode, TRACE_TO_MEMORY); 849 MLX5_SET(mtrc_conf, in, log_trace_buffer_size, 850 ilog2(TRACER_BUFFER_PAGE_NUM)); 851 MLX5_SET(mtrc_conf, in, trace_mkey, tracer->buff.mkey); 852 853 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), 854 MLX5_REG_MTRC_CONF, 0, 1); 855 if (err) 856 mlx5_core_warn(dev, "FWTracer: Failed to set tracer configurations %d\n", err); 857 858 tracer->buff.consumer_index = 0; 859 return err; 860} 861 862static int mlx5_fw_tracer_set_mtrc_ctrl(struct mlx5_fw_tracer *tracer, u8 status, u8 arm) 863{ 864 struct mlx5_core_dev *dev = tracer->dev; 865 u32 out[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0}; 866 u32 in[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0}; 867 int err; 868 869 MLX5_SET(mtrc_ctrl, in, modify_field_select, TRACE_STATUS); 870 MLX5_SET(mtrc_ctrl, in, trace_status, status); 871 MLX5_SET(mtrc_ctrl, in, arm_event, arm); 872 873 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), 874 MLX5_REG_MTRC_CTRL, 0, 1); 875 876 if (!err && status) 877 tracer->last_timestamp = 0; 878 879 return err; 880} 881 882static int mlx5_fw_tracer_start(struct mlx5_fw_tracer *tracer) 883{ 884 struct mlx5_core_dev *dev = tracer->dev; 885 int err; 886 887 err = mlx5_fw_tracer_ownership_acquire(tracer); 888 if (err) { 889 mlx5_core_dbg(dev, "FWTracer: Ownership was not granted %d\n", err); 890 /* Don't fail since ownership can be acquired on a later FW event */ 891 return 0; 892 } 893 894 err = mlx5_fw_tracer_set_mtrc_conf(tracer); 895 if (err) { 896 mlx5_core_warn(dev, "FWTracer: Failed to set tracer configuration %d\n", err); 897 goto release_ownership; 898 } 899 900 /* enable tracer & trace events */ 901 err = mlx5_fw_tracer_set_mtrc_ctrl(tracer, 1, 1); 902 if (err) { 903 mlx5_core_warn(dev, "FWTracer: Failed to enable tracer %d\n", err); 904 goto release_ownership; 905 } 906 907 mlx5_core_dbg(dev, "FWTracer: Ownership granted and active\n"); 908 return 0; 909 910release_ownership: 911 mlx5_fw_tracer_ownership_release(tracer); 912 return err; 913} 914 915static void mlx5_fw_tracer_ownership_change(struct work_struct *work) 916{ 917 struct mlx5_fw_tracer *tracer = 918 container_of(work, struct mlx5_fw_tracer, ownership_change_work); 919 920 mlx5_core_dbg(tracer->dev, "FWTracer: ownership changed, current=(%d)\n", tracer->owner); 921 if (tracer->owner) { 922 mlx5_fw_tracer_ownership_acquire(tracer); 923 return; 924 } 925 926 mlx5_fw_tracer_start(tracer); 927} 928 929static int mlx5_fw_tracer_set_core_dump_reg(struct mlx5_core_dev *dev, 930 u32 *in, int size_in) 931{ 932 u32 out[MLX5_ST_SZ_DW(core_dump_reg)] = {}; 933 934 if (!MLX5_CAP_DEBUG(dev, core_dump_general) && 935 !MLX5_CAP_DEBUG(dev, core_dump_qp)) 936 return -EOPNOTSUPP; 937 938 return mlx5_core_access_reg(dev, in, size_in, out, sizeof(out), 939 MLX5_REG_CORE_DUMP, 0, 1); 940} 941 942int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev) 943{ 944 struct mlx5_fw_tracer *tracer = dev->tracer; 945 u32 in[MLX5_ST_SZ_DW(core_dump_reg)] = {}; 946 int err; 947 948 if (!MLX5_CAP_DEBUG(dev, core_dump_general) || !tracer) 949 return -EOPNOTSUPP; 950 if (!tracer->owner) 951 return -EPERM; 952 953 MLX5_SET(core_dump_reg, in, core_dump_type, 0x0); 954 955 err = mlx5_fw_tracer_set_core_dump_reg(dev, in, sizeof(in)); 956 if (err) 957 return err; 958 queue_work(tracer->work_queue, &tracer->handle_traces_work); 959 flush_workqueue(tracer->work_queue); 960 return 0; 961} 962 963static void 964mlx5_devlink_fmsg_fill_trace(struct devlink_fmsg *fmsg, 965 struct mlx5_fw_trace_data *trace_data) 966{ 967 devlink_fmsg_obj_nest_start(fmsg); 968 devlink_fmsg_u64_pair_put(fmsg, "timestamp", trace_data->timestamp); 969 devlink_fmsg_bool_pair_put(fmsg, "lost", trace_data->lost); 970 devlink_fmsg_u8_pair_put(fmsg, "event_id", trace_data->event_id); 971 devlink_fmsg_string_pair_put(fmsg, "msg", trace_data->msg); 972 devlink_fmsg_obj_nest_end(fmsg); 973} 974 975int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer, 976 struct devlink_fmsg *fmsg) 977{ 978 struct mlx5_fw_trace_data *straces = tracer->st_arr.straces; 979 u32 index, start_index, end_index; 980 u32 saved_traces_index; 981 982 if (!straces[0].timestamp) 983 return -ENOMSG; 984 985 mutex_lock(&tracer->st_arr.lock); 986 saved_traces_index = tracer->st_arr.saved_traces_index; 987 if (straces[saved_traces_index].timestamp) 988 start_index = saved_traces_index; 989 else 990 start_index = 0; 991 end_index = (saved_traces_index - 1) & (SAVED_TRACES_NUM - 1); 992 993 devlink_fmsg_arr_pair_nest_start(fmsg, "dump fw traces"); 994 index = start_index; 995 while (index != end_index) { 996 mlx5_devlink_fmsg_fill_trace(fmsg, &straces[index]); 997 998 index = (index + 1) & (SAVED_TRACES_NUM - 1); 999 } 1000 1001 devlink_fmsg_arr_pair_nest_end(fmsg); 1002 mutex_unlock(&tracer->st_arr.lock); 1003 1004 return 0; 1005} 1006 1007static void mlx5_fw_tracer_update_db(struct work_struct *work) 1008{ 1009 struct mlx5_fw_tracer *tracer = 1010 container_of(work, struct mlx5_fw_tracer, update_db_work); 1011 1012 mlx5_fw_tracer_reload(tracer); 1013} 1014 1015/* Create software resources (Buffers, etc ..) */ 1016struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev) 1017{ 1018 struct mlx5_fw_tracer *tracer = NULL; 1019 int err; 1020 1021 if (!MLX5_CAP_MCAM_REG(dev, tracer_registers)) { 1022 mlx5_core_dbg(dev, "FWTracer: Tracer capability not present\n"); 1023 return NULL; 1024 } 1025 1026 tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL); 1027 if (!tracer) 1028 return ERR_PTR(-ENOMEM); 1029 1030 tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer"); 1031 if (!tracer->work_queue) { 1032 err = -ENOMEM; 1033 goto free_tracer; 1034 } 1035 1036 tracer->dev = dev; 1037 1038 INIT_LIST_HEAD(&tracer->ready_strings_list); 1039 INIT_WORK(&tracer->ownership_change_work, mlx5_fw_tracer_ownership_change); 1040 INIT_WORK(&tracer->read_fw_strings_work, mlx5_tracer_read_strings_db); 1041 INIT_WORK(&tracer->handle_traces_work, mlx5_fw_tracer_handle_traces); 1042 INIT_WORK(&tracer->update_db_work, mlx5_fw_tracer_update_db); 1043 mutex_init(&tracer->state_lock); 1044 1045 1046 err = mlx5_query_mtrc_caps(tracer); 1047 if (err) { 1048 mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err); 1049 goto destroy_workqueue; 1050 } 1051 1052 err = mlx5_fw_tracer_create_log_buf(tracer); 1053 if (err) { 1054 mlx5_core_warn(dev, "FWTracer: Create log buffer failed %d\n", err); 1055 goto destroy_workqueue; 1056 } 1057 1058 err = mlx5_fw_tracer_allocate_strings_db(tracer); 1059 if (err) { 1060 mlx5_core_warn(dev, "FWTracer: Allocate strings database failed %d\n", err); 1061 goto free_log_buf; 1062 } 1063 1064 mlx5_fw_tracer_init_saved_traces_array(tracer); 1065 mlx5_core_dbg(dev, "FWTracer: Tracer created\n"); 1066 1067 return tracer; 1068 1069free_log_buf: 1070 mlx5_fw_tracer_destroy_log_buf(tracer); 1071destroy_workqueue: 1072 tracer->dev = NULL; 1073 destroy_workqueue(tracer->work_queue); 1074free_tracer: 1075 kvfree(tracer); 1076 return ERR_PTR(err); 1077} 1078 1079static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data); 1080 1081/* Create HW resources + start tracer */ 1082int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer) 1083{ 1084 struct mlx5_core_dev *dev; 1085 int err; 1086 1087 if (IS_ERR_OR_NULL(tracer)) 1088 return 0; 1089 1090 if (!tracer->str_db.loaded) 1091 queue_work(tracer->work_queue, &tracer->read_fw_strings_work); 1092 1093 mutex_lock(&tracer->state_lock); 1094 if (test_and_set_bit(MLX5_TRACER_STATE_UP, &tracer->state)) 1095 goto unlock; 1096 1097 dev = tracer->dev; 1098 1099 err = mlx5_core_alloc_pd(dev, &tracer->buff.pdn); 1100 if (err) { 1101 mlx5_core_warn(dev, "FWTracer: Failed to allocate PD %d\n", err); 1102 goto err_cancel_work; 1103 } 1104 1105 err = mlx5_fw_tracer_create_mkey(tracer); 1106 if (err) { 1107 mlx5_core_warn(dev, "FWTracer: Failed to create mkey %d\n", err); 1108 goto err_dealloc_pd; 1109 } 1110 1111 MLX5_NB_INIT(&tracer->nb, fw_tracer_event, DEVICE_TRACER); 1112 mlx5_eq_notifier_register(dev, &tracer->nb); 1113 1114 err = mlx5_fw_tracer_start(tracer); 1115 if (err) { 1116 mlx5_core_warn(dev, "FWTracer: Failed to start tracer %d\n", err); 1117 goto err_notifier_unregister; 1118 } 1119unlock: 1120 mutex_unlock(&tracer->state_lock); 1121 return 0; 1122 1123err_notifier_unregister: 1124 mlx5_eq_notifier_unregister(dev, &tracer->nb); 1125 mlx5_core_destroy_mkey(dev, tracer->buff.mkey); 1126err_dealloc_pd: 1127 mlx5_core_dealloc_pd(dev, tracer->buff.pdn); 1128err_cancel_work: 1129 cancel_work_sync(&tracer->read_fw_strings_work); 1130 mutex_unlock(&tracer->state_lock); 1131 return err; 1132} 1133 1134/* Stop tracer + Cleanup HW resources */ 1135void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer) 1136{ 1137 if (IS_ERR_OR_NULL(tracer)) 1138 return; 1139 1140 mutex_lock(&tracer->state_lock); 1141 if (!test_and_clear_bit(MLX5_TRACER_STATE_UP, &tracer->state)) 1142 goto unlock; 1143 1144 mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n", 1145 tracer->owner); 1146 mlx5_eq_notifier_unregister(tracer->dev, &tracer->nb); 1147 cancel_work_sync(&tracer->ownership_change_work); 1148 cancel_work_sync(&tracer->handle_traces_work); 1149 /* It is valid to get here from update_db_work. Hence, don't wait for 1150 * update_db_work to finished. 1151 */ 1152 cancel_work(&tracer->update_db_work); 1153 1154 if (tracer->owner) 1155 mlx5_fw_tracer_ownership_release(tracer); 1156 1157 mlx5_core_destroy_mkey(tracer->dev, tracer->buff.mkey); 1158 mlx5_core_dealloc_pd(tracer->dev, tracer->buff.pdn); 1159unlock: 1160 mutex_unlock(&tracer->state_lock); 1161} 1162 1163/* Free software resources (Buffers, etc ..) */ 1164void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer) 1165{ 1166 if (IS_ERR_OR_NULL(tracer)) 1167 return; 1168 1169 mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n"); 1170 1171 cancel_work_sync(&tracer->read_fw_strings_work); 1172 mlx5_fw_tracer_clean_ready_list(tracer); 1173 mlx5_fw_tracer_clean_print_hash(tracer); 1174 mlx5_fw_tracer_clean_saved_traces_array(tracer); 1175 mlx5_fw_tracer_free_strings_db(tracer); 1176 mlx5_fw_tracer_destroy_log_buf(tracer); 1177 mutex_destroy(&tracer->state_lock); 1178 destroy_workqueue(tracer->work_queue); 1179 kvfree(tracer); 1180} 1181 1182static int mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer *tracer) 1183{ 1184 struct mlx5_core_dev *dev; 1185 int err; 1186 1187 if (test_and_set_bit(MLX5_TRACER_RECREATE_DB, &tracer->state)) 1188 return 0; 1189 cancel_work_sync(&tracer->read_fw_strings_work); 1190 mlx5_fw_tracer_clean_ready_list(tracer); 1191 mlx5_fw_tracer_clean_print_hash(tracer); 1192 mlx5_fw_tracer_clean_saved_traces_array(tracer); 1193 mlx5_fw_tracer_free_strings_db(tracer); 1194 1195 dev = tracer->dev; 1196 err = mlx5_query_mtrc_caps(tracer); 1197 if (err) { 1198 mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err); 1199 goto out; 1200 } 1201 1202 err = mlx5_fw_tracer_allocate_strings_db(tracer); 1203 if (err) { 1204 mlx5_core_warn(dev, "FWTracer: Allocate strings DB failed %d\n", err); 1205 goto out; 1206 } 1207 mlx5_fw_tracer_init_saved_traces_array(tracer); 1208out: 1209 clear_bit(MLX5_TRACER_RECREATE_DB, &tracer->state); 1210 return err; 1211} 1212 1213int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer) 1214{ 1215 struct mlx5_core_dev *dev; 1216 int err; 1217 1218 if (IS_ERR_OR_NULL(tracer)) 1219 return 0; 1220 1221 dev = tracer->dev; 1222 mlx5_fw_tracer_cleanup(tracer); 1223 err = mlx5_fw_tracer_recreate_strings_db(tracer); 1224 if (err) { 1225 mlx5_core_warn(dev, "Failed to recreate FW tracer strings DB\n"); 1226 return err; 1227 } 1228 err = mlx5_fw_tracer_init(tracer); 1229 if (err) { 1230 mlx5_core_warn(dev, "Failed to re-initialize FW tracer\n"); 1231 return err; 1232 } 1233 1234 return 0; 1235} 1236 1237static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data) 1238{ 1239 struct mlx5_fw_tracer *tracer = mlx5_nb_cof(nb, struct mlx5_fw_tracer, nb); 1240 struct mlx5_core_dev *dev = tracer->dev; 1241 struct mlx5_eqe *eqe = data; 1242 1243 switch (eqe->sub_type) { 1244 case MLX5_TRACER_SUBTYPE_OWNERSHIP_CHANGE: 1245 queue_work(tracer->work_queue, &tracer->ownership_change_work); 1246 break; 1247 case MLX5_TRACER_SUBTYPE_TRACES_AVAILABLE: 1248 queue_work(tracer->work_queue, &tracer->handle_traces_work); 1249 break; 1250 case MLX5_TRACER_SUBTYPE_STRINGS_DB_UPDATE: 1251 queue_work(tracer->work_queue, &tracer->update_db_work); 1252 break; 1253 default: 1254 mlx5_core_dbg(dev, "FWTracer: Event with unrecognized subtype: sub_type %d\n", 1255 eqe->sub_type); 1256 } 1257 1258 return NOTIFY_OK; 1259} 1260 1261EXPORT_TRACEPOINT_SYMBOL(mlx5_fw);
~/
Read-only file preview.