xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
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 void
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 	devlink_fmsg_obj_nest_start(fmsg);
897 	devlink_fmsg_u64_pair_put(fmsg, "timestamp", trace_data->timestamp);
898 	devlink_fmsg_bool_pair_put(fmsg, "lost", trace_data->lost);
899 	devlink_fmsg_u8_pair_put(fmsg, "event_id", trace_data->event_id);
900 	devlink_fmsg_string_pair_put(fmsg, "msg", trace_data->msg);
901 	devlink_fmsg_obj_nest_end(fmsg);
902 }
903 
mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer * tracer,struct devlink_fmsg * fmsg)904 int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
905 					    struct devlink_fmsg *fmsg)
906 {
907 	struct mlx5_fw_trace_data *straces = tracer->st_arr.straces;
908 	u32 index, start_index, end_index;
909 	u32 saved_traces_index;
910 
911 	if (!straces[0].timestamp)
912 		return -ENOMSG;
913 
914 	mutex_lock(&tracer->st_arr.lock);
915 	saved_traces_index = tracer->st_arr.saved_traces_index;
916 	if (straces[saved_traces_index].timestamp)
917 		start_index = saved_traces_index;
918 	else
919 		start_index = 0;
920 	end_index = (saved_traces_index - 1) & (SAVED_TRACES_NUM - 1);
921 
922 	devlink_fmsg_arr_pair_nest_start(fmsg, "dump fw traces");
923 	index = start_index;
924 	while (index != end_index) {
925 		mlx5_devlink_fmsg_fill_trace(fmsg, &straces[index]);
926 
927 		index = (index + 1) & (SAVED_TRACES_NUM - 1);
928 	}
929 
930 	devlink_fmsg_arr_pair_nest_end(fmsg);
931 	mutex_unlock(&tracer->st_arr.lock);
932 
933 	return 0;
934 }
935 
mlx5_fw_tracer_update_db(struct work_struct * work)936 static void mlx5_fw_tracer_update_db(struct work_struct *work)
937 {
938 	struct mlx5_fw_tracer *tracer =
939 			container_of(work, struct mlx5_fw_tracer, update_db_work);
940 
941 	mlx5_fw_tracer_reload(tracer);
942 }
943 
944 /* Create software resources (Buffers, etc ..) */
mlx5_fw_tracer_create(struct mlx5_core_dev * dev)945 struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
946 {
947 	struct mlx5_fw_tracer *tracer = NULL;
948 	int err;
949 
950 	if (!MLX5_CAP_MCAM_REG(dev, tracer_registers)) {
951 		mlx5_core_dbg(dev, "FWTracer: Tracer capability not present\n");
952 		return NULL;
953 	}
954 
955 	tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
956 	if (!tracer)
957 		return ERR_PTR(-ENOMEM);
958 
959 	tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
960 	if (!tracer->work_queue) {
961 		err = -ENOMEM;
962 		goto free_tracer;
963 	}
964 
965 	tracer->dev = dev;
966 
967 	INIT_LIST_HEAD(&tracer->ready_strings_list);
968 	INIT_WORK(&tracer->ownership_change_work, mlx5_fw_tracer_ownership_change);
969 	INIT_WORK(&tracer->read_fw_strings_work, mlx5_tracer_read_strings_db);
970 	INIT_WORK(&tracer->handle_traces_work, mlx5_fw_tracer_handle_traces);
971 	INIT_WORK(&tracer->update_db_work, mlx5_fw_tracer_update_db);
972 	mutex_init(&tracer->state_lock);
973 
974 
975 	err = mlx5_query_mtrc_caps(tracer);
976 	if (err) {
977 		mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err);
978 		goto destroy_workqueue;
979 	}
980 
981 	err = mlx5_fw_tracer_create_log_buf(tracer);
982 	if (err) {
983 		mlx5_core_warn(dev, "FWTracer: Create log buffer failed %d\n", err);
984 		goto destroy_workqueue;
985 	}
986 
987 	err = mlx5_fw_tracer_allocate_strings_db(tracer);
988 	if (err) {
989 		mlx5_core_warn(dev, "FWTracer: Allocate strings database failed %d\n", err);
990 		goto free_log_buf;
991 	}
992 
993 	mlx5_fw_tracer_init_saved_traces_array(tracer);
994 	mlx5_core_dbg(dev, "FWTracer: Tracer created\n");
995 
996 	return tracer;
997 
998 free_log_buf:
999 	mlx5_fw_tracer_destroy_log_buf(tracer);
1000 destroy_workqueue:
1001 	tracer->dev = NULL;
1002 	destroy_workqueue(tracer->work_queue);
1003 free_tracer:
1004 	kvfree(tracer);
1005 	return ERR_PTR(err);
1006 }
1007 
1008 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
1009 
1010 /* Create HW resources + start tracer */
mlx5_fw_tracer_init(struct mlx5_fw_tracer * tracer)1011 int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
1012 {
1013 	struct mlx5_core_dev *dev;
1014 	int err;
1015 
1016 	if (IS_ERR_OR_NULL(tracer))
1017 		return 0;
1018 
1019 	if (!tracer->str_db.loaded)
1020 		queue_work(tracer->work_queue, &tracer->read_fw_strings_work);
1021 
1022 	mutex_lock(&tracer->state_lock);
1023 	if (test_and_set_bit(MLX5_TRACER_STATE_UP, &tracer->state))
1024 		goto unlock;
1025 
1026 	dev = tracer->dev;
1027 
1028 	err = mlx5_core_alloc_pd(dev, &tracer->buff.pdn);
1029 	if (err) {
1030 		mlx5_core_warn(dev, "FWTracer: Failed to allocate PD %d\n", err);
1031 		goto err_cancel_work;
1032 	}
1033 
1034 	err = mlx5_fw_tracer_create_mkey(tracer);
1035 	if (err) {
1036 		mlx5_core_warn(dev, "FWTracer: Failed to create mkey %d\n", err);
1037 		goto err_dealloc_pd;
1038 	}
1039 
1040 	MLX5_NB_INIT(&tracer->nb, fw_tracer_event, DEVICE_TRACER);
1041 	mlx5_eq_notifier_register(dev, &tracer->nb);
1042 
1043 	err = mlx5_fw_tracer_start(tracer);
1044 	if (err) {
1045 		mlx5_core_warn(dev, "FWTracer: Failed to start tracer %d\n", err);
1046 		goto err_notifier_unregister;
1047 	}
1048 unlock:
1049 	mutex_unlock(&tracer->state_lock);
1050 	return 0;
1051 
1052 err_notifier_unregister:
1053 	mlx5_eq_notifier_unregister(dev, &tracer->nb);
1054 	mlx5_core_destroy_mkey(dev, tracer->buff.mkey);
1055 err_dealloc_pd:
1056 	mlx5_core_dealloc_pd(dev, tracer->buff.pdn);
1057 err_cancel_work:
1058 	cancel_work_sync(&tracer->read_fw_strings_work);
1059 	mutex_unlock(&tracer->state_lock);
1060 	return err;
1061 }
1062 
1063 /* Stop tracer + Cleanup HW resources */
mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer * tracer)1064 void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
1065 {
1066 	if (IS_ERR_OR_NULL(tracer))
1067 		return;
1068 
1069 	mutex_lock(&tracer->state_lock);
1070 	if (!test_and_clear_bit(MLX5_TRACER_STATE_UP, &tracer->state))
1071 		goto unlock;
1072 
1073 	mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
1074 		      tracer->owner);
1075 	mlx5_eq_notifier_unregister(tracer->dev, &tracer->nb);
1076 	cancel_work_sync(&tracer->ownership_change_work);
1077 	cancel_work_sync(&tracer->handle_traces_work);
1078 	/* It is valid to get here from update_db_work. Hence, don't wait for
1079 	 * update_db_work to finished.
1080 	 */
1081 	cancel_work(&tracer->update_db_work);
1082 
1083 	if (tracer->owner)
1084 		mlx5_fw_tracer_ownership_release(tracer);
1085 
1086 	mlx5_core_destroy_mkey(tracer->dev, tracer->buff.mkey);
1087 	mlx5_core_dealloc_pd(tracer->dev, tracer->buff.pdn);
1088 unlock:
1089 	mutex_unlock(&tracer->state_lock);
1090 }
1091 
1092 /* Free software resources (Buffers, etc ..) */
mlx5_fw_tracer_destroy(struct mlx5_fw_tracer * tracer)1093 void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
1094 {
1095 	if (IS_ERR_OR_NULL(tracer))
1096 		return;
1097 
1098 	mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
1099 
1100 	cancel_work_sync(&tracer->read_fw_strings_work);
1101 	mlx5_fw_tracer_clean_ready_list(tracer);
1102 	mlx5_fw_tracer_clean_print_hash(tracer);
1103 	mlx5_fw_tracer_clean_saved_traces_array(tracer);
1104 	mlx5_fw_tracer_free_strings_db(tracer);
1105 	mlx5_fw_tracer_destroy_log_buf(tracer);
1106 	mutex_destroy(&tracer->state_lock);
1107 	destroy_workqueue(tracer->work_queue);
1108 	kvfree(tracer);
1109 }
1110 
mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer * tracer)1111 static int mlx5_fw_tracer_recreate_strings_db(struct mlx5_fw_tracer *tracer)
1112 {
1113 	struct mlx5_core_dev *dev;
1114 	int err;
1115 
1116 	if (test_and_set_bit(MLX5_TRACER_RECREATE_DB, &tracer->state))
1117 		return 0;
1118 	cancel_work_sync(&tracer->read_fw_strings_work);
1119 	mlx5_fw_tracer_clean_ready_list(tracer);
1120 	mlx5_fw_tracer_clean_print_hash(tracer);
1121 	mlx5_fw_tracer_clean_saved_traces_array(tracer);
1122 	mlx5_fw_tracer_free_strings_db(tracer);
1123 
1124 	dev = tracer->dev;
1125 	err = mlx5_query_mtrc_caps(tracer);
1126 	if (err) {
1127 		mlx5_core_dbg(dev, "FWTracer: Failed to query capabilities %d\n", err);
1128 		goto out;
1129 	}
1130 
1131 	err = mlx5_fw_tracer_allocate_strings_db(tracer);
1132 	if (err) {
1133 		mlx5_core_warn(dev, "FWTracer: Allocate strings DB failed %d\n", err);
1134 		goto out;
1135 	}
1136 	mlx5_fw_tracer_init_saved_traces_array(tracer);
1137 out:
1138 	clear_bit(MLX5_TRACER_RECREATE_DB, &tracer->state);
1139 	return err;
1140 }
1141 
mlx5_fw_tracer_reload(struct mlx5_fw_tracer * tracer)1142 int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
1143 {
1144 	struct mlx5_core_dev *dev;
1145 	int err;
1146 
1147 	if (IS_ERR_OR_NULL(tracer))
1148 		return 0;
1149 
1150 	dev = tracer->dev;
1151 	mlx5_fw_tracer_cleanup(tracer);
1152 	err = mlx5_fw_tracer_recreate_strings_db(tracer);
1153 	if (err) {
1154 		mlx5_core_warn(dev, "Failed to recreate FW tracer strings DB\n");
1155 		return err;
1156 	}
1157 	err = mlx5_fw_tracer_init(tracer);
1158 	if (err) {
1159 		mlx5_core_warn(dev, "Failed to re-initialize FW tracer\n");
1160 		return err;
1161 	}
1162 
1163 	return 0;
1164 }
1165 
fw_tracer_event(struct notifier_block * nb,unsigned long action,void * data)1166 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data)
1167 {
1168 	struct mlx5_fw_tracer *tracer = mlx5_nb_cof(nb, struct mlx5_fw_tracer, nb);
1169 	struct mlx5_core_dev *dev = tracer->dev;
1170 	struct mlx5_eqe *eqe = data;
1171 
1172 	switch (eqe->sub_type) {
1173 	case MLX5_TRACER_SUBTYPE_OWNERSHIP_CHANGE:
1174 		queue_work(tracer->work_queue, &tracer->ownership_change_work);
1175 		break;
1176 	case MLX5_TRACER_SUBTYPE_TRACES_AVAILABLE:
1177 		queue_work(tracer->work_queue, &tracer->handle_traces_work);
1178 		break;
1179 	case MLX5_TRACER_SUBTYPE_STRINGS_DB_UPDATE:
1180 		queue_work(tracer->work_queue, &tracer->update_db_work);
1181 		break;
1182 	default:
1183 		mlx5_core_dbg(dev, "FWTracer: Event with unrecognized subtype: sub_type %d\n",
1184 			      eqe->sub_type);
1185 	}
1186 
1187 	return NOTIFY_OK;
1188 }
1189 
1190 EXPORT_TRACEPOINT_SYMBOL(mlx5_fw);
1191