powerpc/mm: Avoid calling arch_enter/leave_lazy_mmu() in set_ptes
[platform/kernel/linux-starfive.git] / 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
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
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
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
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
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
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
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
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
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                 if (!string_db_size_out[i])
238                         continue;
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
246 free_strings_db:
247         mlx5_fw_tracer_free_strings_db(tracer);
248         return -ENOMEM;
249 }
250
251 static void
252 mlx5_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
258 static void
259 mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer *tracer)
260 {
261         mutex_destroy(&tracer->st_arr.lock);
262 }
263
264 static 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++) {
284                 if (!tracer->str_db.size_out[i])
285                         continue;
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
337 out_free:
338         kfree(out);
339 out:
340         return;
341 }
342
343 static void mlx5_fw_tracer_arm(struct mlx5_core_dev *dev)
344 {
345         u32 out[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0};
346         u32 in[MLX5_ST_SZ_DW(mtrc_ctrl)] = {0};
347         int err;
348
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
357 static const char *VAL_PARM             = "%llx";
358 static const char *REPLACE_64_VAL_PARM  = "%x%x";
359 static const char *PARAM_CHAR           = "%";
360
361 static int mlx5_tracer_message_hash(u32 message_id)
362 {
363         return jhash_1word(message_id, 0) & (MESSAGE_HASH_SIZE - 1);
364 }
365
366 static 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
382 static 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++) {
392                 if (!tracer->str_db.size_out[i])
393                         continue;
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
411 static void mlx5_tracer_clean_message(struct tracer_string_format *str_frmt)
412 {
413         hlist_del(&str_frmt->hlist);
414         kfree(str_frmt);
415 }
416
417 static 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
441 static 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
453 static 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
462 static 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);
469         tracer_event->out = trace;
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:
493                 if (tracer_event->event_id >= tracer->str_db.first_string_trace &&
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
512 static 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
527 static 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
539 static 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
548 static 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;
559         strscpy_pad(trace_data->msg, msg, TRACE_STR_MSG);
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
566 static noinline
567 void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,
568                              struct mlx5_core_dev *dev,
569                              u64 trace_timestamp)
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
585         mlx5_fw_tracer_save_trace(dev->tracer, trace_timestamp,
586                                   str_frmt->lost, str_frmt->event_id, tmp);
587
588         /* remove it from hash */
589         mlx5_tracer_clean_message(str_frmt);
590 }
591
592 static 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
612 static 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)
620                         return mlx5_tracer_handle_raw_string(tracer, tracer_event);
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) {
633                         pr_debug("%s Got string event for unknown string tmsn: %d\n",
634                                  __func__, tracer_event->string_event.tmsn);
635                         return mlx5_tracer_handle_raw_string(tracer, tracer_event);
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
654 static 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
669                         trace_timestamp = ((timestamp_event.timestamp - 1) & MASK_52_7) |
670                                           (str_frmt->timestamp & MASK_6_0);
671
672                 mlx5_tracer_print_trace(str_frmt, dev, trace_timestamp);
673         }
674 }
675
676 static 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
691 static 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);
698         struct mlx5_core_dev *dev = tracer->dev;
699         struct tracer_event tracer_event;
700         int i;
701
702         mlx5_core_dbg(dev, "FWTracer: Handle Trace event, owner=(%d)\n", tracer->owner);
703         if (!tracer->owner)
704                 return;
705
706         if (unlikely(!tracer->str_db.loaded))
707                 goto arm;
708
709         block_count = tracer->buff.size / TRACER_BLOCK_SIZE_BYTE;
710         start_offset = tracer->buff.consumer_index * TRACER_BLOCK_SIZE_BYTE;
711
712         /* Copy the block to local buffer to avoid HW override while being processed */
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) {
720                 /* Check block override if it's not the first block */
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 */
750                 for (i = 0; i < TRACES_PER_BLOCK ; i++) {
751                         poll_trace(tracer, &tracer_event, &tmp_trace_block[i]);
752                         mlx5_tracer_handle_trace(tracer, &tracer_event);
753                 }
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]);
764         }
765
766 arm:
767         mlx5_fw_tracer_arm(dev);
768 }
769
770 static 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));
780         MLX5_SET(mtrc_conf, in, trace_mkey, tracer->buff.mkey);
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
787         tracer->buff.consumer_index = 0;
788         return err;
789 }
790
791 static 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
811 static int mlx5_fw_tracer_start(struct mlx5_fw_tracer *tracer)
812 {
813         struct mlx5_core_dev *dev = tracer->dev;
814         int err;
815
816         err = mlx5_fw_tracer_ownership_acquire(tracer);
817         if (err) {
818                 mlx5_core_dbg(dev, "FWTracer: Ownership was not granted %d\n", err);
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
836         mlx5_core_dbg(dev, "FWTracer: Ownership granted and active\n");
837         return 0;
838
839 release_ownership:
840         mlx5_fw_tracer_ownership_release(tracer);
841         return err;
842 }
843
844 static 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
849         mlx5_core_dbg(tracer->dev, "FWTracer: ownership changed, current=(%d)\n", tracer->owner);
850         if (tracer->owner) {
851                 tracer->owner = false;
852                 return;
853         }
854
855         mlx5_fw_tracer_start(tracer);
856 }
857
858 static 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
871 int 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
892 static int
893 mlx5_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
924 int 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);
956 unlock:
957         mutex_unlock(&tracer->st_arr.lock);
958         return err;
959 }
960
961 static 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
969 /* Create software resources (Buffers, etc ..) */
970 struct 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
980         tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
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
992         INIT_LIST_HEAD(&tracer->ready_strings_list);
993         INIT_WORK(&tracer->ownership_change_work, mlx5_fw_tracer_ownership_change);
994         INIT_WORK(&tracer->read_fw_strings_work, mlx5_tracer_read_strings_db);
995         INIT_WORK(&tracer->handle_traces_work, mlx5_fw_tracer_handle_traces);
996         INIT_WORK(&tracer->update_db_work, mlx5_fw_tracer_update_db);
997         mutex_init(&tracer->state_lock);
998
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
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         }
1017
1018         mlx5_fw_tracer_init_saved_traces_array(tracer);
1019         mlx5_core_dbg(dev, "FWTracer: Tracer created\n");
1020
1021         return tracer;
1022
1023 free_log_buf:
1024         mlx5_fw_tracer_destroy_log_buf(tracer);
1025 destroy_workqueue:
1026         tracer->dev = NULL;
1027         destroy_workqueue(tracer->work_queue);
1028 free_tracer:
1029         kvfree(tracer);
1030         return ERR_PTR(err);
1031 }
1032
1033 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
1034
1035 /* Create HW resources + start tracer */
1036 int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
1037 {
1038         struct mlx5_core_dev *dev;
1039         int err;
1040
1041         if (IS_ERR_OR_NULL(tracer))
1042                 return 0;
1043
1044         if (!tracer->str_db.loaded)
1045                 queue_work(tracer->work_queue, &tracer->read_fw_strings_work);
1046
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
1053         err = mlx5_core_alloc_pd(dev, &tracer->buff.pdn);
1054         if (err) {
1055                 mlx5_core_warn(dev, "FWTracer: Failed to allocate PD %d\n", err);
1056                 goto err_cancel_work;
1057         }
1058
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
1065         MLX5_NB_INIT(&tracer->nb, fw_tracer_event, DEVICE_TRACER);
1066         mlx5_eq_notifier_register(dev, &tracer->nb);
1067
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         }
1073 unlock:
1074         mutex_unlock(&tracer->state_lock);
1075         return 0;
1076
1077 err_notifier_unregister:
1078         mlx5_eq_notifier_unregister(dev, &tracer->nb);
1079         mlx5_core_destroy_mkey(dev, tracer->buff.mkey);
1080 err_dealloc_pd:
1081         mlx5_core_dealloc_pd(dev, tracer->buff.pdn);
1082 err_cancel_work:
1083         cancel_work_sync(&tracer->read_fw_strings_work);
1084         mutex_unlock(&tracer->state_lock);
1085         return err;
1086 }
1087
1088 /* Stop tracer + Cleanup HW resources */
1089 void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
1090 {
1091         if (IS_ERR_OR_NULL(tracer))
1092                 return;
1093
1094         mutex_lock(&tracer->state_lock);
1095         if (!test_and_clear_bit(MLX5_TRACER_STATE_UP, &tracer->state))
1096                 goto unlock;
1097
1098         mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
1099                       tracer->owner);
1100         mlx5_eq_notifier_unregister(tracer->dev, &tracer->nb);
1101         cancel_work_sync(&tracer->ownership_change_work);
1102         cancel_work_sync(&tracer->handle_traces_work);
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);
1107
1108         if (tracer->owner)
1109                 mlx5_fw_tracer_ownership_release(tracer);
1110
1111         mlx5_core_destroy_mkey(tracer->dev, tracer->buff.mkey);
1112         mlx5_core_dealloc_pd(tracer->dev, tracer->buff.pdn);
1113 unlock:
1114         mutex_unlock(&tracer->state_lock);
1115 }
1116
1117 /* Free software resources (Buffers, etc ..) */
1118 void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
1119 {
1120         if (IS_ERR_OR_NULL(tracer))
1121                 return;
1122
1123         mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
1124
1125         cancel_work_sync(&tracer->read_fw_strings_work);
1126         mlx5_fw_tracer_clean_ready_list(tracer);
1127         mlx5_fw_tracer_clean_print_hash(tracer);
1128         mlx5_fw_tracer_clean_saved_traces_array(tracer);
1129         mlx5_fw_tracer_free_strings_db(tracer);
1130         mlx5_fw_tracer_destroy_log_buf(tracer);
1131         mutex_destroy(&tracer->state_lock);
1132         destroy_workqueue(tracer->work_queue);
1133         kvfree(tracer);
1134 }
1135
1136 static int mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer *tracer)
1137 {
1138         struct mlx5_core_dev *dev;
1139         int err;
1140
1141         if (test_and_set_bit(MLX5_TRACER_RECREATE_DB, &tracer->state))
1142                 return 0;
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);
1153                 goto out;
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);
1159                 goto out;
1160         }
1161         mlx5_fw_tracer_init_saved_traces_array(tracer);
1162 out:
1163         clear_bit(MLX5_TRACER_RECREATE_DB, &tracer->state);
1164         return err;
1165 }
1166
1167 int 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))
1173                 return 0;
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
1191 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data)
1192 {
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;
1196
1197         switch (eqe->sub_type) {
1198         case MLX5_TRACER_SUBTYPE_OWNERSHIP_CHANGE:
1199                 queue_work(tracer->work_queue, &tracer->ownership_change_work);
1200                 break;
1201         case MLX5_TRACER_SUBTYPE_TRACES_AVAILABLE:
1202                 queue_work(tracer->work_queue, &tracer->handle_traces_work);
1203                 break;
1204         case MLX5_TRACER_SUBTYPE_STRINGS_DB_UPDATE:
1205                 queue_work(tracer->work_queue, &tracer->update_db_work);
1206                 break;
1207         default:
1208                 mlx5_core_dbg(dev, "FWTracer: Event with unrecognized subtype: sub_type %d\n",
1209                               eqe->sub_type);
1210         }
1211
1212         return NOTIFY_OK;
1213 }
1214
1215 EXPORT_TRACEPOINT_SYMBOL(mlx5_fw);