xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c (revision 3e7759b94a0fcfdd6771caa64a37dda7ce825874)
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  		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
mlx5_fw_tracer_init_saved_traces_array(struct mlx5_fw_tracer * tracer)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
mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer * tracer)259  mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer *tracer)
260  {
261  	mutex_destroy(&tracer->st_arr.lock);
262  }
263  
mlx5_tracer_read_strings_db(struct work_struct * work)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  
mlx5_fw_tracer_arm(struct mlx5_core_dev * dev)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  
mlx5_tracer_message_hash(u32 message_id)361  static int mlx5_tracer_message_hash(u32 message_id)
362  {
363  	return jhash_1word(message_id, 0) & (MESSAGE_HASH_SIZE - 1);
364  }
365  
mlx5_tracer_message_insert(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
mlx5_tracer_get_string(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
mlx5_tracer_clean_message(struct tracer_string_format * str_frmt)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  
mlx5_tracer_get_num_of_params(char * str)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  
mlx5_tracer_message_find(struct hlist_head * head,u8 event_id,u32 tmsn)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  
mlx5_tracer_message_get(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
poll_trace(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event,u64 * trace)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  
get_block_timestamp(struct mlx5_fw_tracer * tracer,u64 * ts_event)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  
mlx5_fw_tracer_clean_print_hash(struct mlx5_fw_tracer * tracer)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  
mlx5_fw_tracer_clean_ready_list(struct mlx5_fw_tracer * tracer)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  
mlx5_fw_tracer_save_trace(struct mlx5_fw_tracer * tracer,u64 timestamp,bool lost,u8 event_id,char * msg)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
mlx5_tracer_print_trace(struct tracer_string_format * str_frmt,struct mlx5_core_dev * dev,u64 trace_timestamp)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  
mlx5_tracer_handle_raw_string(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
mlx5_tracer_handle_timestamp_trace(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
mlx5_tracer_handle_trace(struct mlx5_fw_tracer * tracer,struct tracer_event * tracer_event)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  
mlx5_fw_tracer_handle_traces(struct work_struct * work)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  
mlx5_fw_tracer_set_mtrc_conf(struct mlx5_fw_tracer * tracer)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  
mlx5_fw_tracer_set_mtrc_ctrl(struct mlx5_fw_tracer * tracer,u8 status,u8 arm)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  
mlx5_fw_tracer_start(struct mlx5_fw_tracer * tracer)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  
mlx5_fw_tracer_ownership_change(struct work_struct * work)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  		mlx5_fw_tracer_ownership_acquire(tracer);
852  		return;
853  	}
854  
855  	mlx5_fw_tracer_start(tracer);
856  }
857  
mlx5_fw_tracer_set_core_dump_reg(struct mlx5_core_dev * dev,u32 * in,int size_in)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  
mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev * dev)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
mlx5_devlink_fmsg_fill_trace(struct devlink_fmsg * fmsg,struct mlx5_fw_trace_data * trace_data)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  
mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer * tracer,struct devlink_fmsg * fmsg)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  
mlx5_fw_tracer_update_db(struct work_struct * work)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 ..) */
mlx5_fw_tracer_create(struct mlx5_core_dev * dev)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 */
mlx5_fw_tracer_init(struct mlx5_fw_tracer * 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 */
mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer * tracer)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 ..) */
mlx5_fw_tracer_destroy(struct mlx5_fw_tracer * tracer)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  
mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer * tracer)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  
mlx5_fw_tracer_reload(struct mlx5_fw_tracer * tracer)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  
fw_tracer_event(struct notifier_block * nb,unsigned long action,void * data)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);
1216