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