ASoC: Merge up v6.6-rc7
[linux-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / diag / fw_tracer.c
CommitLineData
f53aaa31
FD
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 */
70dd6fdb 32#define CREATE_TRACE_POINTS
720a936d 33#include "lib/eq.h"
f53aaa31 34#include "fw_tracer.h"
70dd6fdb 35#include "fw_tracer_tracepoint.h"
f53aaa31
FD
36
37static 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);
db561fed 67 tracer->str_db.loaded = false;
f53aaa31
FD
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
81static 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
94static 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
116static 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
48967ffd
FD
125static int mlx5_fw_tracer_create_log_buf(struct mlx5_fw_tracer *tracer)
126{
127 struct mlx5_core_dev *dev = tracer->dev;
7be3412a 128 struct device *ddev;
48967ffd
FD
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
7be3412a 146 ddev = mlx5_core_dma_dev(dev);
48967ffd
FD
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
158free_pages:
159 free_pages((unsigned long)tracer->buff.log_buf, get_order(tracer->buff.size));
160
161 return err;
162}
163
164static void mlx5_fw_tracer_destroy_log_buf(struct mlx5_fw_tracer *tracer)
165{
166 struct mlx5_core_dev *dev = tracer->dev;
7be3412a 167 struct device *ddev;
48967ffd
FD
168
169 if (!tracer->buff.log_buf)
170 return;
171
7be3412a 172 ddev = mlx5_core_dma_dev(dev);
48967ffd
FD
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
e9cad2ce
SM
177static 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));
5edc4c72 194 mtt = (__be64 *)MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
e9cad2ce
SM
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
48967ffd
FD
219static 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
230static 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++) {
b0118ced
SD
237 if (!string_db_size_out[i])
238 continue;
48967ffd
FD
239 tracer->str_db.buffer[i] = kzalloc(string_db_size_out[i], GFP_KERNEL);
240 if (!tracer->str_db.buffer[i])
241 goto free_strings_db;
242 }
243
244 return 0;
245
246free_strings_db:
247 mlx5_fw_tracer_free_strings_db(tracer);
248 return -ENOMEM;
249}
250
fd1483fe
MS
251static void
252mlx5_fw_tracer_init_saved_traces_array(struct mlx5_fw_tracer *tracer)
253{
254 tracer->st_arr.saved_traces_index = 0;
255 mutex_init(&tracer->st_arr.lock);
256}
257
258static void
259mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer *tracer)
260{
261 mutex_destroy(&tracer->st_arr.lock);
262}
263
48967ffd
FD
264static void mlx5_tracer_read_strings_db(struct work_struct *work)
265{
266 struct mlx5_fw_tracer *tracer = container_of(work, struct mlx5_fw_tracer,
267 read_fw_strings_work);
268 u32 num_of_reads, num_string_db = tracer->str_db.num_string_db;
269 struct mlx5_core_dev *dev = tracer->dev;
270 u32 in[MLX5_ST_SZ_DW(mtrc_cap)] = {0};
271 u32 leftovers, offset;
272 int err = 0, i, j;
273 u32 *out, outlen;
274 void *out_value;
275
276 outlen = MLX5_ST_SZ_BYTES(mtrc_stdb) + STRINGS_DB_READ_SIZE_BYTES;
277 out = kzalloc(outlen, GFP_KERNEL);
278 if (!out) {
279 err = -ENOMEM;
280 goto out;
281 }
282
283 for (i = 0; i < num_string_db; i++) {
b0118ced
SD
284 if (!tracer->str_db.size_out[i])
285 continue;
48967ffd
FD
286 offset = 0;
287 MLX5_SET(mtrc_stdb, in, string_db_index, i);
288 num_of_reads = tracer->str_db.size_out[i] /
289 STRINGS_DB_READ_SIZE_BYTES;
290 leftovers = (tracer->str_db.size_out[i] %
291 STRINGS_DB_READ_SIZE_BYTES) /
292 STRINGS_DB_LEFTOVER_SIZE_BYTES;
293
294 MLX5_SET(mtrc_stdb, in, read_size, STRINGS_DB_READ_SIZE_BYTES);
295 for (j = 0; j < num_of_reads; j++) {
296 MLX5_SET(mtrc_stdb, in, start_offset, offset);
297
298 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
299 outlen, MLX5_REG_MTRC_STDB,
300 0, 1);
301 if (err) {
302 mlx5_core_dbg(dev, "FWTracer: Failed to read strings DB %d\n",
303 err);
304 goto out_free;
305 }
306
307 out_value = MLX5_ADDR_OF(mtrc_stdb, out, string_db_data);
308 memcpy(tracer->str_db.buffer[i] + offset, out_value,
309 STRINGS_DB_READ_SIZE_BYTES);
310 offset += STRINGS_DB_READ_SIZE_BYTES;
311 }
312
313 /* Strings database is aligned to 64, need to read leftovers*/
314 MLX5_SET(mtrc_stdb, in, read_size,
315 STRINGS_DB_LEFTOVER_SIZE_BYTES);
316 for (j = 0; j < leftovers; j++) {
317 MLX5_SET(mtrc_stdb, in, start_offset, offset);
318
319 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
320 outlen, MLX5_REG_MTRC_STDB,
321 0, 1);
322 if (err) {
323 mlx5_core_dbg(dev, "FWTracer: Failed to read strings DB %d\n",
324 err);
325 goto out_free;
326 }
327
328 out_value = MLX5_ADDR_OF(mtrc_stdb, out, string_db_data);
329 memcpy(tracer->str_db.buffer[i] + offset, out_value,
330 STRINGS_DB_LEFTOVER_SIZE_BYTES);
331 offset += STRINGS_DB_LEFTOVER_SIZE_BYTES;
332 }
333 }
334
335 tracer->str_db.loaded = true;
336
337out_free:
338 kfree(out);
339out:
340 return;
341}
342
c71ad41c 343static void mlx5_fw_tracer_arm(struct mlx5_core_dev *dev)
f53aaa31 344{
c71ad41c
FD
345 u32 out[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0};
346 u32 in[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0};
f53aaa31
FD
347 int err;
348
c71ad41c
FD
349 MLX5_SET(mtrc_ctrl, in, arm_event, 1);
350
351 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
352 MLX5_REG_MTRC_CTRL, 0, 1);
353 if (err)
354 mlx5_core_warn(dev, "FWTracer: Failed to arm tracer event %d\n", err);
355}
356
70dd6fdb
FD
357static const char *VAL_PARM = "%llx";
358static const char *REPLACE_64_VAL_PARM = "%x%x";
359static const char *PARAM_CHAR = "%";
360
361static int mlx5_tracer_message_hash(u32 message_id)
362{
363 return jhash_1word(message_id, 0) & (MESSAGE_HASH_SIZE - 1);
364}
365
366static struct tracer_string_format *mlx5_tracer_message_insert(struct mlx5_fw_tracer *tracer,
367 struct tracer_event *tracer_event)
368{
369 struct hlist_head *head =
370 &tracer->hash[mlx5_tracer_message_hash(tracer_event->string_event.tmsn)];
371 struct tracer_string_format *cur_string;
372
373 cur_string = kzalloc(sizeof(*cur_string), GFP_KERNEL);
374 if (!cur_string)
375 return NULL;
376
377 hlist_add_head(&cur_string->hlist, head);
378
379 return cur_string;
380}
381
382static struct tracer_string_format *mlx5_tracer_get_string(struct mlx5_fw_tracer *tracer,
383 struct tracer_event *tracer_event)
384{
385 struct tracer_string_format *cur_string;
386 u32 str_ptr, offset;
387 int i;
388
389 str_ptr = tracer_event->string_event.string_param;
390
391 for (i = 0; i < tracer->str_db.num_string_db; i++) {
b0118ced
SD
392 if (!tracer->str_db.size_out[i])
393 continue;
70dd6fdb
FD
394 if (str_ptr > tracer->str_db.base_address_out[i] &&
395 str_ptr < tracer->str_db.base_address_out[i] +
396 tracer->str_db.size_out[i]) {
397 offset = str_ptr - tracer->str_db.base_address_out[i];
398 /* add it to the hash */
399 cur_string = mlx5_tracer_message_insert(tracer, tracer_event);
400 if (!cur_string)
401 return NULL;
402 cur_string->string = (char *)(tracer->str_db.buffer[i] +
403 offset);
404 return cur_string;
405 }
406 }
407
408 return NULL;
409}
410
411static void mlx5_tracer_clean_message(struct tracer_string_format *str_frmt)
412{
413 hlist_del(&str_frmt->hlist);
414 kfree(str_frmt);
415}
416
417static int mlx5_tracer_get_num_of_params(char *str)
418{
419 char *substr, *pstr = str;
420 int num_of_params = 0;
421
422 /* replace %llx with %x%x */
423 substr = strstr(pstr, VAL_PARM);
424 while (substr) {
425 memcpy(substr, REPLACE_64_VAL_PARM, 4);
426 pstr = substr;
427 substr = strstr(pstr, VAL_PARM);
428 }
429
430 /* count all the % characters */
431 substr = strstr(str, PARAM_CHAR);
432 while (substr) {
433 num_of_params += 1;
434 str = substr + 1;
435 substr = strstr(str, PARAM_CHAR);
436 }
437
438 return num_of_params;
439}
440
441static struct tracer_string_format *mlx5_tracer_message_find(struct hlist_head *head,
442 u8 event_id, u32 tmsn)
443{
444 struct tracer_string_format *message;
445
446 hlist_for_each_entry(message, head, hlist)
447 if (message->event_id == event_id && message->tmsn == tmsn)
448 return message;
449
450 return NULL;
451}
452
453static struct tracer_string_format *mlx5_tracer_message_get(struct mlx5_fw_tracer *tracer,
454 struct tracer_event *tracer_event)
455{
456 struct hlist_head *head =
457 &tracer->hash[mlx5_tracer_message_hash(tracer_event->string_event.tmsn)];
458
459 return mlx5_tracer_message_find(head, tracer_event->event_id, tracer_event->string_event.tmsn);
460}
461
c71ad41c
FD
462static void poll_trace(struct mlx5_fw_tracer *tracer,
463 struct tracer_event *tracer_event, u64 *trace)
464{
465 u32 timestamp_low, timestamp_mid, timestamp_high, urts;
466
467 tracer_event->event_id = MLX5_GET(tracer_event, trace, event_id);
468 tracer_event->lost_event = MLX5_GET(tracer_event, trace, lost);
f7133135 469 tracer_event->out = trace;
c71ad41c
FD
470
471 switch (tracer_event->event_id) {
472 case TRACER_EVENT_TYPE_TIMESTAMP:
473 tracer_event->type = TRACER_EVENT_TYPE_TIMESTAMP;
474 urts = MLX5_GET(tracer_timestamp_event, trace, urts);
475 if (tracer->trc_ver == 0)
476 tracer_event->timestamp_event.unreliable = !!(urts >> 2);
477 else
478 tracer_event->timestamp_event.unreliable = !!(urts & 1);
479
480 timestamp_low = MLX5_GET(tracer_timestamp_event,
481 trace, timestamp7_0);
482 timestamp_mid = MLX5_GET(tracer_timestamp_event,
483 trace, timestamp39_8);
484 timestamp_high = MLX5_GET(tracer_timestamp_event,
485 trace, timestamp52_40);
486
487 tracer_event->timestamp_event.timestamp =
488 ((u64)timestamp_high << 40) |
489 ((u64)timestamp_mid << 8) |
490 (u64)timestamp_low;
491 break;
492 default:
341a80de 493 if (tracer_event->event_id >= tracer->str_db.first_string_trace &&
c71ad41c
FD
494 tracer_event->event_id <= tracer->str_db.first_string_trace +
495 tracer->str_db.num_string_trace) {
496 tracer_event->type = TRACER_EVENT_TYPE_STRING;
497 tracer_event->string_event.timestamp =
498 MLX5_GET(tracer_string_event, trace, timestamp);
499 tracer_event->string_event.string_param =
500 MLX5_GET(tracer_string_event, trace, string_param);
501 tracer_event->string_event.tmsn =
502 MLX5_GET(tracer_string_event, trace, tmsn);
503 tracer_event->string_event.tdsn =
504 MLX5_GET(tracer_string_event, trace, tdsn);
505 } else {
506 tracer_event->type = TRACER_EVENT_TYPE_UNRECOGNIZED;
507 }
508 break;
509 }
510}
511
512static u64 get_block_timestamp(struct mlx5_fw_tracer *tracer, u64 *ts_event)
513{
514 struct tracer_event tracer_event;
515 u8 event_id;
516
517 event_id = MLX5_GET(tracer_event, ts_event, event_id);
518
519 if (event_id == TRACER_EVENT_TYPE_TIMESTAMP)
520 poll_trace(tracer, &tracer_event, ts_event);
521 else
522 tracer_event.timestamp_event.timestamp = 0;
523
524 return tracer_event.timestamp_event.timestamp;
525}
526
70dd6fdb
FD
527static void mlx5_fw_tracer_clean_print_hash(struct mlx5_fw_tracer *tracer)
528{
529 struct tracer_string_format *str_frmt;
530 struct hlist_node *n;
531 int i;
532
533 for (i = 0; i < MESSAGE_HASH_SIZE; i++) {
534 hlist_for_each_entry_safe(str_frmt, n, &tracer->hash[i], hlist)
535 mlx5_tracer_clean_message(str_frmt);
536 }
537}
538
539static void mlx5_fw_tracer_clean_ready_list(struct mlx5_fw_tracer *tracer)
540{
541 struct tracer_string_format *str_frmt, *tmp_str;
542
543 list_for_each_entry_safe(str_frmt, tmp_str, &tracer->ready_strings_list,
544 list)
545 list_del(&str_frmt->list);
546}
547
fd1483fe
MS
548static void mlx5_fw_tracer_save_trace(struct mlx5_fw_tracer *tracer,
549 u64 timestamp, bool lost,
550 u8 event_id, char *msg)
551{
552 struct mlx5_fw_trace_data *trace_data;
553
554 mutex_lock(&tracer->st_arr.lock);
555 trace_data = &tracer->st_arr.straces[tracer->st_arr.saved_traces_index];
556 trace_data->timestamp = timestamp;
557 trace_data->lost = lost;
558 trace_data->event_id = event_id;
bb487d29 559 strscpy_pad(trace_data->msg, msg, TRACE_STR_MSG);
fd1483fe
MS
560
561 tracer->st_arr.saved_traces_index =
562 (tracer->st_arr.saved_traces_index + 1) & (SAVED_TRACES_NUM - 1);
563 mutex_unlock(&tracer->st_arr.lock);
564}
565
fa355bb1
SM
566static noinline
567void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,
568 struct mlx5_core_dev *dev,
569 u64 trace_timestamp)
70dd6fdb
FD
570{
571 char tmp[512];
572
573 snprintf(tmp, sizeof(tmp), str_frmt->string,
574 str_frmt->params[0],
575 str_frmt->params[1],
576 str_frmt->params[2],
577 str_frmt->params[3],
578 str_frmt->params[4],
579 str_frmt->params[5],
580 str_frmt->params[6]);
581
582 trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost,
583 str_frmt->event_id, tmp);
584
fd1483fe
MS
585 mlx5_fw_tracer_save_trace(dev->tracer, trace_timestamp,
586 str_frmt->lost, str_frmt->event_id, tmp);
587
70dd6fdb
FD
588 /* remove it from hash */
589 mlx5_tracer_clean_message(str_frmt);
590}
591
f7133135
SD
592static int mlx5_tracer_handle_raw_string(struct mlx5_fw_tracer *tracer,
593 struct tracer_event *tracer_event)
594{
595 struct tracer_string_format *cur_string;
596
597 cur_string = mlx5_tracer_message_insert(tracer, tracer_event);
598 if (!cur_string)
599 return -1;
600
601 cur_string->event_id = tracer_event->event_id;
602 cur_string->timestamp = tracer_event->string_event.timestamp;
603 cur_string->lost = tracer_event->lost_event;
604 cur_string->string = "0x%08x%08x";
605 cur_string->num_of_params = 2;
606 cur_string->params[0] = upper_32_bits(*tracer_event->out);
607 cur_string->params[1] = lower_32_bits(*tracer_event->out);
608 list_add_tail(&cur_string->list, &tracer->ready_strings_list);
609 return 0;
610}
611
70dd6fdb
FD
612static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer,
613 struct tracer_event *tracer_event)
614{
615 struct tracer_string_format *cur_string;
616
617 if (tracer_event->string_event.tdsn == 0) {
618 cur_string = mlx5_tracer_get_string(tracer, tracer_event);
619 if (!cur_string)
f7133135 620 return mlx5_tracer_handle_raw_string(tracer, tracer_event);
70dd6fdb
FD
621
622 cur_string->num_of_params = mlx5_tracer_get_num_of_params(cur_string->string);
623 cur_string->last_param_num = 0;
624 cur_string->event_id = tracer_event->event_id;
625 cur_string->tmsn = tracer_event->string_event.tmsn;
626 cur_string->timestamp = tracer_event->string_event.timestamp;
627 cur_string->lost = tracer_event->lost_event;
628 if (cur_string->num_of_params == 0) /* trace with no params */
629 list_add_tail(&cur_string->list, &tracer->ready_strings_list);
630 } else {
631 cur_string = mlx5_tracer_message_get(tracer, tracer_event);
632 if (!cur_string) {
988c2352 633 pr_debug("%s Got string event for unknown string tmsn: %d\n",
70dd6fdb 634 __func__, tracer_event->string_event.tmsn);
f7133135 635 return mlx5_tracer_handle_raw_string(tracer, tracer_event);
70dd6fdb
FD
636 }
637 cur_string->last_param_num += 1;
638 if (cur_string->last_param_num > TRACER_MAX_PARAMS) {
639 pr_debug("%s Number of params exceeds the max (%d)\n",
640 __func__, TRACER_MAX_PARAMS);
641 list_add_tail(&cur_string->list, &tracer->ready_strings_list);
642 return 0;
643 }
644 /* keep the new parameter */
645 cur_string->params[cur_string->last_param_num - 1] =
646 tracer_event->string_event.string_param;
647 if (cur_string->last_param_num == cur_string->num_of_params)
648 list_add_tail(&cur_string->list, &tracer->ready_strings_list);
649 }
650
651 return 0;
652}
653
654static void mlx5_tracer_handle_timestamp_trace(struct mlx5_fw_tracer *tracer,
655 struct tracer_event *tracer_event)
656{
657 struct tracer_timestamp_event timestamp_event =
658 tracer_event->timestamp_event;
659 struct tracer_string_format *str_frmt, *tmp_str;
660 struct mlx5_core_dev *dev = tracer->dev;
661 u64 trace_timestamp;
662
663 list_for_each_entry_safe(str_frmt, tmp_str, &tracer->ready_strings_list, list) {
664 list_del(&str_frmt->list);
665 if (str_frmt->timestamp < (timestamp_event.timestamp & MASK_6_0))
666 trace_timestamp = (timestamp_event.timestamp & MASK_52_7) |
667 (str_frmt->timestamp & MASK_6_0);
668 else
61db3d7b 669 trace_timestamp = ((timestamp_event.timestamp - 1) & MASK_52_7) |
70dd6fdb
FD
670 (str_frmt->timestamp & MASK_6_0);
671
672 mlx5_tracer_print_trace(str_frmt, dev, trace_timestamp);
673 }
674}
675
676static int mlx5_tracer_handle_trace(struct mlx5_fw_tracer *tracer,
677 struct tracer_event *tracer_event)
678{
679 if (tracer_event->type == TRACER_EVENT_TYPE_STRING) {
680 mlx5_tracer_handle_string_trace(tracer, tracer_event);
681 } else if (tracer_event->type == TRACER_EVENT_TYPE_TIMESTAMP) {
682 if (!tracer_event->timestamp_event.unreliable)
683 mlx5_tracer_handle_timestamp_trace(tracer, tracer_event);
684 } else {
685 pr_debug("%s Got unrecognised type %d for parsing, exiting..\n",
686 __func__, tracer_event->type);
687 }
688 return 0;
689}
690
c71ad41c
FD
691static void mlx5_fw_tracer_handle_traces(struct work_struct *work)
692{
693 struct mlx5_fw_tracer *tracer =
694 container_of(work, struct mlx5_fw_tracer, handle_traces_work);
695 u64 block_timestamp, last_block_timestamp, tmp_trace_block[TRACES_PER_BLOCK];
696 u32 block_count, start_offset, prev_start_offset, prev_consumer_index;
697 u32 trace_event_size = MLX5_ST_SZ_BYTES(tracer_event);
3101d1fc 698 struct mlx5_core_dev *dev = tracer->dev;
c71ad41c 699 struct tracer_event tracer_event;
c71ad41c
FD
700 int i;
701
3101d1fc 702 mlx5_core_dbg(dev, "FWTracer: Handle Trace event, owner=(%d)\n", tracer->owner);
c71ad41c 703 if (!tracer->owner)
f53aaa31 704 return;
c71ad41c 705
8bf94e64
FD
706 if (unlikely(!tracer->str_db.loaded))
707 goto arm;
708
c71ad41c
FD
709 block_count = tracer->buff.size / TRACER_BLOCK_SIZE_BYTE;
710 start_offset = tracer->buff.consumer_index * TRACER_BLOCK_SIZE_BYTE;
711
39797f1c 712 /* Copy the block to local buffer to avoid HW override while being processed */
c71ad41c
FD
713 memcpy(tmp_trace_block, tracer->buff.log_buf + start_offset,
714 TRACER_BLOCK_SIZE_BYTE);
715
716 block_timestamp =
717 get_block_timestamp(tracer, &tmp_trace_block[TRACES_PER_BLOCK - 1]);
718
719 while (block_timestamp > tracer->last_timestamp) {
6533380d 720 /* Check block override if it's not the first block */
c71ad41c
FD
721 if (!tracer->last_timestamp) {
722 u64 *ts_event;
723 /* To avoid block override be the HW in case of buffer
724 * wraparound, the time stamp of the previous block
725 * should be compared to the last timestamp handled
726 * by the driver.
727 */
728 prev_consumer_index =
729 (tracer->buff.consumer_index - 1) & (block_count - 1);
730 prev_start_offset = prev_consumer_index * TRACER_BLOCK_SIZE_BYTE;
731
732 ts_event = tracer->buff.log_buf + prev_start_offset +
733 (TRACES_PER_BLOCK - 1) * trace_event_size;
734 last_block_timestamp = get_block_timestamp(tracer, ts_event);
735 /* If previous timestamp different from last stored
736 * timestamp then there is a good chance that the
737 * current buffer is overwritten and therefore should
738 * not be parsed.
739 */
740 if (tracer->last_timestamp != last_block_timestamp) {
741 mlx5_core_warn(dev, "FWTracer: Events were lost\n");
742 tracer->last_timestamp = block_timestamp;
743 tracer->buff.consumer_index =
744 (tracer->buff.consumer_index + 1) & (block_count - 1);
745 break;
746 }
747 }
748
749 /* Parse events */
70dd6fdb 750 for (i = 0; i < TRACES_PER_BLOCK ; i++) {
c71ad41c 751 poll_trace(tracer, &tracer_event, &tmp_trace_block[i]);
70dd6fdb
FD
752 mlx5_tracer_handle_trace(tracer, &tracer_event);
753 }
c71ad41c
FD
754
755 tracer->buff.consumer_index =
756 (tracer->buff.consumer_index + 1) & (block_count - 1);
757
758 tracer->last_timestamp = block_timestamp;
759 start_offset = tracer->buff.consumer_index * TRACER_BLOCK_SIZE_BYTE;
760 memcpy(tmp_trace_block, tracer->buff.log_buf + start_offset,
761 TRACER_BLOCK_SIZE_BYTE);
762 block_timestamp = get_block_timestamp(tracer,
763 &tmp_trace_block[TRACES_PER_BLOCK - 1]);
f53aaa31
FD
764 }
765
8bf94e64 766arm:
c71ad41c
FD
767 mlx5_fw_tracer_arm(dev);
768}
769
770static int mlx5_fw_tracer_set_mtrc_conf(struct mlx5_fw_tracer *tracer)
771{
772 struct mlx5_core_dev *dev = tracer->dev;
773 u32 out[MLX5_ST_SZ_DW(mtrc_conf)] = {0};
774 u32 in[MLX5_ST_SZ_DW(mtrc_conf)] = {0};
775 int err;
776
777 MLX5_SET(mtrc_conf, in, trace_mode, TRACE_TO_MEMORY);
778 MLX5_SET(mtrc_conf, in, log_trace_buffer_size,
779 ilog2(TRACER_BUFFER_PAGE_NUM));
83fec3f1 780 MLX5_SET(mtrc_conf, in, trace_mkey, tracer->buff.mkey);
c71ad41c
FD
781
782 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
783 MLX5_REG_MTRC_CONF, 0, 1);
784 if (err)
785 mlx5_core_warn(dev, "FWTracer: Failed to set tracer configurations %d\n", err);
786
184e1e44 787 tracer->buff.consumer_index = 0;
c71ad41c
FD
788 return err;
789}
790
791static int mlx5_fw_tracer_set_mtrc_ctrl(struct mlx5_fw_tracer *tracer, u8 status, u8 arm)
792{
793 struct mlx5_core_dev *dev = tracer->dev;
794 u32 out[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0};
795 u32 in[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0};
796 int err;
797
798 MLX5_SET(mtrc_ctrl, in, modify_field_select, TRACE_STATUS);
799 MLX5_SET(mtrc_ctrl, in, trace_status, status);
800 MLX5_SET(mtrc_ctrl, in, arm_event, arm);
801
802 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
803 MLX5_REG_MTRC_CTRL, 0, 1);
804
805 if (!err && status)
806 tracer->last_timestamp = 0;
807
808 return err;
809}
810
811static int mlx5_fw_tracer_start(struct mlx5_fw_tracer *tracer)
812{
813 struct mlx5_core_dev *dev = tracer->dev;
814 int err;
815
f53aaa31
FD
816 err = mlx5_fw_tracer_ownership_acquire(tracer);
817 if (err) {
818 mlx5_core_dbg(dev, "FWTracer: Ownership was not granted %d\n", err);
c71ad41c
FD
819 /* Don't fail since ownership can be acquired on a later FW event */
820 return 0;
821 }
822
823 err = mlx5_fw_tracer_set_mtrc_conf(tracer);
824 if (err) {
825 mlx5_core_warn(dev, "FWTracer: Failed to set tracer configuration %d\n", err);
826 goto release_ownership;
827 }
828
829 /* enable tracer & trace events */
830 err = mlx5_fw_tracer_set_mtrc_ctrl(tracer, 1, 1);
831 if (err) {
832 mlx5_core_warn(dev, "FWTracer: Failed to enable tracer %d\n", err);
833 goto release_ownership;
834 }
835
3101d1fc 836 mlx5_core_dbg(dev, "FWTracer: Ownership granted and active\n");
c71ad41c
FD
837 return 0;
838
839release_ownership:
840 mlx5_fw_tracer_ownership_release(tracer);
841 return err;
842}
843
844static void mlx5_fw_tracer_ownership_change(struct work_struct *work)
845{
846 struct mlx5_fw_tracer *tracer =
847 container_of(work, struct mlx5_fw_tracer, ownership_change_work);
848
3101d1fc 849 mlx5_core_dbg(tracer->dev, "FWTracer: ownership changed, current=(%d)\n", tracer->owner);
c71ad41c 850 if (tracer->owner) {
92fd3963 851 mlx5_fw_tracer_ownership_acquire(tracer);
f53aaa31
FD
852 return;
853 }
c71ad41c
FD
854
855 mlx5_fw_tracer_start(tracer);
f53aaa31
FD
856}
857
fd1483fe
MS
858static int mlx5_fw_tracer_set_core_dump_reg(struct mlx5_core_dev *dev,
859 u32 *in, int size_in)
860{
861 u32 out[MLX5_ST_SZ_DW(core_dump_reg)] = {};
862
863 if (!MLX5_CAP_DEBUG(dev, core_dump_general) &&
864 !MLX5_CAP_DEBUG(dev, core_dump_qp))
865 return -EOPNOTSUPP;
866
867 return mlx5_core_access_reg(dev, in, size_in, out, sizeof(out),
868 MLX5_REG_CORE_DUMP, 0, 1);
869}
870
871int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev)
872{
873 struct mlx5_fw_tracer *tracer = dev->tracer;
874 u32 in[MLX5_ST_SZ_DW(core_dump_reg)] = {};
875 int err;
876
877 if (!MLX5_CAP_DEBUG(dev, core_dump_general) || !tracer)
878 return -EOPNOTSUPP;
879 if (!tracer->owner)
880 return -EPERM;
881
882 MLX5_SET(core_dump_reg, in, core_dump_type, 0x0);
883
884 err = mlx5_fw_tracer_set_core_dump_reg(dev, in, sizeof(in));
885 if (err)
886 return err;
887 queue_work(tracer->work_queue, &tracer->handle_traces_work);
888 flush_workqueue(tracer->work_queue);
889 return 0;
890}
891
892static int
893mlx5_devlink_fmsg_fill_trace(struct devlink_fmsg *fmsg,
894 struct mlx5_fw_trace_data *trace_data)
895{
896 int err;
897
898 err = devlink_fmsg_obj_nest_start(fmsg);
899 if (err)
900 return err;
901
902 err = devlink_fmsg_u64_pair_put(fmsg, "timestamp", trace_data->timestamp);
903 if (err)
904 return err;
905
906 err = devlink_fmsg_bool_pair_put(fmsg, "lost", trace_data->lost);
907 if (err)
908 return err;
909
910 err = devlink_fmsg_u8_pair_put(fmsg, "event_id", trace_data->event_id);
911 if (err)
912 return err;
913
914 err = devlink_fmsg_string_pair_put(fmsg, "msg", trace_data->msg);
915 if (err)
916 return err;
917
918 err = devlink_fmsg_obj_nest_end(fmsg);
919 if (err)
920 return err;
921 return 0;
922}
923
924int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
925 struct devlink_fmsg *fmsg)
926{
927 struct mlx5_fw_trace_data *straces = tracer->st_arr.straces;
928 u32 index, start_index, end_index;
929 u32 saved_traces_index;
930 int err;
931
932 if (!straces[0].timestamp)
933 return -ENOMSG;
934
935 mutex_lock(&tracer->st_arr.lock);
936 saved_traces_index = tracer->st_arr.saved_traces_index;
937 if (straces[saved_traces_index].timestamp)
938 start_index = saved_traces_index;
939 else
940 start_index = 0;
941 end_index = (saved_traces_index - 1) & (SAVED_TRACES_NUM - 1);
942
943 err = devlink_fmsg_arr_pair_nest_start(fmsg, "dump fw traces");
944 if (err)
945 goto unlock;
946 index = start_index;
947 while (index != end_index) {
948 err = mlx5_devlink_fmsg_fill_trace(fmsg, &straces[index]);
949 if (err)
950 goto unlock;
951
952 index = (index + 1) & (SAVED_TRACES_NUM - 1);
953 }
954
955 err = devlink_fmsg_arr_pair_nest_end(fmsg);
956unlock:
957 mutex_unlock(&tracer->st_arr.lock);
958 return err;
959}
960
7dfcd110
SD
961static void mlx5_fw_tracer_update_db(struct work_struct *work)
962{
963 struct mlx5_fw_tracer *tracer =
964 container_of(work, struct mlx5_fw_tracer, update_db_work);
965
966 mlx5_fw_tracer_reload(tracer);
967}
968
c71ad41c 969/* Create software resources (Buffers, etc ..) */
f53aaa31
FD
970struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
971{
972 struct mlx5_fw_tracer *tracer = NULL;
973 int err;
974
975 if (!MLX5_CAP_MCAM_REG(dev, tracer_registers)) {
976 mlx5_core_dbg(dev, "FWTracer: Tracer capability not present\n");
977 return NULL;
978 }
979
a019b361 980 tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
f53aaa31
FD
981 if (!tracer)
982 return ERR_PTR(-ENOMEM);
983
984 tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
985 if (!tracer->work_queue) {
986 err = -ENOMEM;
987 goto free_tracer;
988 }
989
990 tracer->dev = dev;
991
70dd6fdb 992 INIT_LIST_HEAD(&tracer->ready_strings_list);
f53aaa31 993 INIT_WORK(&tracer->ownership_change_work, mlx5_fw_tracer_ownership_change);
48967ffd 994 INIT_WORK(&tracer->read_fw_strings_work, mlx5_tracer_read_strings_db);
c71ad41c 995 INIT_WORK(&tracer->handle_traces_work, mlx5_fw_tracer_handle_traces);
7dfcd110
SD
996 INIT_WORK(&tracer->update_db_work, mlx5_fw_tracer_update_db);
997 mutex_init(&tracer->state_lock);
c71ad41c 998
f53aaa31
FD
999
1000 err = mlx5_query_mtrc_caps(tracer);
1001 if (err) {
1002 mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err);
1003 goto destroy_workqueue;
1004 }
1005
48967ffd
FD
1006 err = mlx5_fw_tracer_create_log_buf(tracer);
1007 if (err) {
1008 mlx5_core_warn(dev, "FWTracer: Create log buffer failed %d\n", err);
1009 goto destroy_workqueue;
1010 }
1011
1012 err = mlx5_fw_tracer_allocate_strings_db(tracer);
1013 if (err) {
1014 mlx5_core_warn(dev, "FWTracer: Allocate strings database failed %d\n", err);
1015 goto free_log_buf;
1016 }
f53aaa31 1017
fd1483fe 1018 mlx5_fw_tracer_init_saved_traces_array(tracer);
3101d1fc
SM
1019 mlx5_core_dbg(dev, "FWTracer: Tracer created\n");
1020
f53aaa31
FD
1021 return tracer;
1022
48967ffd
FD
1023free_log_buf:
1024 mlx5_fw_tracer_destroy_log_buf(tracer);
f53aaa31
FD
1025destroy_workqueue:
1026 tracer->dev = NULL;
1027 destroy_workqueue(tracer->work_queue);
1028free_tracer:
a019b361 1029 kvfree(tracer);
f53aaa31
FD
1030 return ERR_PTR(err);
1031}
1032
720a936d
SM
1033static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
1034
1035/* Create HW resources + start tracer */
48967ffd 1036int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
f53aaa31 1037{
48967ffd
FD
1038 struct mlx5_core_dev *dev;
1039 int err;
1040
1041 if (IS_ERR_OR_NULL(tracer))
1042 return 0;
1043
48967ffd
FD
1044 if (!tracer->str_db.loaded)
1045 queue_work(tracer->work_queue, &tracer->read_fw_strings_work);
1046
7dfcd110
SD
1047 mutex_lock(&tracer->state_lock);
1048 if (test_and_set_bit(MLX5_TRACER_STATE_UP, &tracer->state))
1049 goto unlock;
1050
1051 dev = tracer->dev;
1052
e9cad2ce 1053 err = mlx5_core_alloc_pd(dev, &tracer->buff.pdn);
48967ffd 1054 if (err) {
e9cad2ce 1055 mlx5_core_warn(dev, "FWTracer: Failed to allocate PD %d\n", err);
dfe6fd72 1056 goto err_cancel_work;
48967ffd
FD
1057 }
1058
e9cad2ce
SM
1059 err = mlx5_fw_tracer_create_mkey(tracer);
1060 if (err) {
1061 mlx5_core_warn(dev, "FWTracer: Failed to create mkey %d\n", err);
1062 goto err_dealloc_pd;
1063 }
1064
720a936d
SM
1065 MLX5_NB_INIT(&tracer->nb, fw_tracer_event, DEVICE_TRACER);
1066 mlx5_eq_notifier_register(dev, &tracer->nb);
1067
bd37c288
AL
1068 err = mlx5_fw_tracer_start(tracer);
1069 if (err) {
1070 mlx5_core_warn(dev, "FWTracer: Failed to start tracer %d\n", err);
1071 goto err_notifier_unregister;
1072 }
7dfcd110
SD
1073unlock:
1074 mutex_unlock(&tracer->state_lock);
48967ffd 1075 return 0;
c71ad41c 1076
bd37c288
AL
1077err_notifier_unregister:
1078 mlx5_eq_notifier_unregister(dev, &tracer->nb);
83fec3f1 1079 mlx5_core_destroy_mkey(dev, tracer->buff.mkey);
e9cad2ce
SM
1080err_dealloc_pd:
1081 mlx5_core_dealloc_pd(dev, tracer->buff.pdn);
dfe6fd72 1082err_cancel_work:
bd37c288 1083 cancel_work_sync(&tracer->read_fw_strings_work);
7dfcd110 1084 mutex_unlock(&tracer->state_lock);
e9cad2ce 1085 return err;
48967ffd
FD
1086}
1087
720a936d 1088/* Stop tracer + Cleanup HW resources */
48967ffd
FD
1089void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
1090{
1091 if (IS_ERR_OR_NULL(tracer))
f53aaa31
FD
1092 return;
1093
7dfcd110
SD
1094 mutex_lock(&tracer->state_lock);
1095 if (!test_and_clear_bit(MLX5_TRACER_STATE_UP, &tracer->state))
1096 goto unlock;
1097
3101d1fc
SM
1098 mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
1099 tracer->owner);
720a936d 1100 mlx5_eq_notifier_unregister(tracer->dev, &tracer->nb);
f53aaa31 1101 cancel_work_sync(&tracer->ownership_change_work);
c71ad41c 1102 cancel_work_sync(&tracer->handle_traces_work);
7dfcd110
SD
1103 /* It is valid to get here from update_db_work. Hence, don't wait for
1104 * update_db_work to finished.
1105 */
1106 cancel_work(&tracer->update_db_work);
f53aaa31
FD
1107
1108 if (tracer->owner)
1109 mlx5_fw_tracer_ownership_release(tracer);
e9cad2ce 1110
83fec3f1 1111 mlx5_core_destroy_mkey(tracer->dev, tracer->buff.mkey);
e9cad2ce 1112 mlx5_core_dealloc_pd(tracer->dev, tracer->buff.pdn);
7dfcd110
SD
1113unlock:
1114 mutex_unlock(&tracer->state_lock);
48967ffd 1115}
f53aaa31 1116
c71ad41c 1117/* Free software resources (Buffers, etc ..) */
48967ffd
FD
1118void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
1119{
1120 if (IS_ERR_OR_NULL(tracer))
1121 return;
1122
3101d1fc
SM
1123 mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
1124
48967ffd 1125 cancel_work_sync(&tracer->read_fw_strings_work);
70dd6fdb
FD
1126 mlx5_fw_tracer_clean_ready_list(tracer);
1127 mlx5_fw_tracer_clean_print_hash(tracer);
fd1483fe 1128 mlx5_fw_tracer_clean_saved_traces_array(tracer);
48967ffd
FD
1129 mlx5_fw_tracer_free_strings_db(tracer);
1130 mlx5_fw_tracer_destroy_log_buf(tracer);
7dfcd110 1131 mutex_destroy(&tracer->state_lock);
f53aaa31 1132 destroy_workqueue(tracer->work_queue);
a019b361 1133 kvfree(tracer);
f53aaa31 1134}
48967ffd 1135
2d693567
MS
1136static int mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer *tracer)
1137{
1138 struct mlx5_core_dev *dev;
1139 int err;
1140
7dfcd110
SD
1141 if (test_and_set_bit(MLX5_TRACER_RECREATE_DB, &tracer->state))
1142 return 0;
2d693567
MS
1143 cancel_work_sync(&tracer->read_fw_strings_work);
1144 mlx5_fw_tracer_clean_ready_list(tracer);
1145 mlx5_fw_tracer_clean_print_hash(tracer);
1146 mlx5_fw_tracer_clean_saved_traces_array(tracer);
1147 mlx5_fw_tracer_free_strings_db(tracer);
1148
1149 dev = tracer->dev;
1150 err = mlx5_query_mtrc_caps(tracer);
1151 if (err) {
1152 mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err);
7dfcd110 1153 goto out;
2d693567
MS
1154 }
1155
1156 err = mlx5_fw_tracer_allocate_strings_db(tracer);
1157 if (err) {
1158 mlx5_core_warn(dev, "FWTracer: Allocate strings DB failed %d\n", err);
7dfcd110 1159 goto out;
2d693567
MS
1160 }
1161 mlx5_fw_tracer_init_saved_traces_array(tracer);
7dfcd110
SD
1162out:
1163 clear_bit(MLX5_TRACER_RECREATE_DB, &tracer->state);
1164 return err;
2d693567
MS
1165}
1166
1167int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
1168{
1169 struct mlx5_core_dev *dev;
1170 int err;
1171
1172 if (IS_ERR_OR_NULL(tracer))
7e615b99 1173 return 0;
2d693567
MS
1174
1175 dev = tracer->dev;
1176 mlx5_fw_tracer_cleanup(tracer);
1177 err = mlx5_fw_tracer_recreate_strings_db(tracer);
1178 if (err) {
1179 mlx5_core_warn(dev, "Failed to recreate FW tracer strings DB\n");
1180 return err;
1181 }
1182 err = mlx5_fw_tracer_init(tracer);
1183 if (err) {
1184 mlx5_core_warn(dev, "Failed to re-initialize FW tracer\n");
1185 return err;
1186 }
1187
1188 return 0;
1189}
1190
720a936d 1191static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data)
c71ad41c 1192{
720a936d
SM
1193 struct mlx5_fw_tracer *tracer = mlx5_nb_cof(nb, struct mlx5_fw_tracer, nb);
1194 struct mlx5_core_dev *dev = tracer->dev;
1195 struct mlx5_eqe *eqe = data;
c71ad41c
FD
1196
1197 switch (eqe->sub_type) {
1198 case MLX5_TRACER_SUBTYPE_OWNERSHIP_CHANGE:
7ad67a20 1199 queue_work(tracer->work_queue, &tracer->ownership_change_work);
c71ad41c
FD
1200 break;
1201 case MLX5_TRACER_SUBTYPE_TRACES_AVAILABLE:
8bf94e64 1202 queue_work(tracer->work_queue, &tracer->handle_traces_work);
c71ad41c 1203 break;
7dfcd110
SD
1204 case MLX5_TRACER_SUBTYPE_STRINGS_DB_UPDATE:
1205 queue_work(tracer->work_queue, &tracer->update_db_work);
1206 break;
c71ad41c
FD
1207 default:
1208 mlx5_core_dbg(dev, "FWTracer: Event with unrecognized subtype: sub_type %d\n",
1209 eqe->sub_type);
1210 }
720a936d
SM
1211
1212 return NOTIFY_OK;
c71ad41c
FD
1213}
1214
48967ffd 1215EXPORT_TRACEPOINT_SYMBOL(mlx5_fw);