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