xref: /linux/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c (revision e7ef461784945e95bb5f137383298cd2d4122a9e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Arm Statistical Profiling Extensions (SPE) support
4  * Copyright (c) 2017-2018, Arm Ltd.
5  */
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <endian.h>
10 #include <byteswap.h>
11 #include <linux/bitmap.h>
12 #include <linux/bitops.h>
13 #include <stdarg.h>
14 #include <linux/kernel.h>
15 #include <linux/unaligned.h>
16 
17 #include "arm-spe-pkt-decoder.h"
18 
19 #include "../../arm64/include/asm/cputype.h"
20 
21 static const char * const arm_spe_packet_name[] = {
22 	[ARM_SPE_PAD]		= "PAD",
23 	[ARM_SPE_END]		= "END",
24 	[ARM_SPE_TIMESTAMP]	= "TS",
25 	[ARM_SPE_ADDRESS]	= "ADDR",
26 	[ARM_SPE_COUNTER]	= "LAT",
27 	[ARM_SPE_CONTEXT]	= "CONTEXT",
28 	[ARM_SPE_OP_TYPE]	= "OP-TYPE",
29 	[ARM_SPE_EVENTS]	= "EVENTS",
30 	[ARM_SPE_DATA_SOURCE]	= "DATA-SOURCE",
31 };
32 
33 const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
34 {
35 	return arm_spe_packet_name[type];
36 }
37 
38 /*
39  * Extracts the field "sz" from header bits and converts to bytes:
40  *   00 : byte (1)
41  *   01 : halfword (2)
42  *   10 : word (4)
43  *   11 : doubleword (8)
44  */
45 static unsigned int arm_spe_payload_len(unsigned char hdr)
46 {
47 	return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
48 }
49 
50 static int arm_spe_get_payload(const unsigned char *buf, size_t len,
51 			       unsigned char ext_hdr,
52 			       struct arm_spe_pkt *packet)
53 {
54 	size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
55 
56 	if (len < 1 + ext_hdr + payload_len)
57 		return ARM_SPE_NEED_MORE_BYTES;
58 
59 	buf += 1 + ext_hdr;
60 
61 	switch (payload_len) {
62 	case 1: packet->payload = *(uint8_t *)buf; break;
63 	case 2: packet->payload = get_unaligned_le16(buf); break;
64 	case 4: packet->payload = get_unaligned_le32(buf); break;
65 	case 8: packet->payload = get_unaligned_le64(buf); break;
66 	default: return ARM_SPE_BAD_PACKET;
67 	}
68 
69 	return 1 + ext_hdr + payload_len;
70 }
71 
72 static int arm_spe_get_pad(struct arm_spe_pkt *packet)
73 {
74 	packet->type = ARM_SPE_PAD;
75 	return 1;
76 }
77 
78 static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
79 				 struct arm_spe_pkt *packet)
80 {
81 	unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
82 
83 	if (len < alignment)
84 		return ARM_SPE_NEED_MORE_BYTES;
85 
86 	packet->type = ARM_SPE_PAD;
87 	return alignment - (((uintptr_t)buf) & (alignment - 1));
88 }
89 
90 static int arm_spe_get_end(struct arm_spe_pkt *packet)
91 {
92 	packet->type = ARM_SPE_END;
93 	return 1;
94 }
95 
96 static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
97 				 struct arm_spe_pkt *packet)
98 {
99 	packet->type = ARM_SPE_TIMESTAMP;
100 	return arm_spe_get_payload(buf, len, 0, packet);
101 }
102 
103 static int arm_spe_get_events(const unsigned char *buf, size_t len,
104 			      struct arm_spe_pkt *packet)
105 {
106 	packet->type = ARM_SPE_EVENTS;
107 
108 	/* we use index to identify Events with a less number of
109 	 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
110 	 * LLC-REFILL, and REMOTE-ACCESS events are identified if
111 	 * index > 1.
112 	 */
113 	packet->index = arm_spe_payload_len(buf[0]);
114 
115 	return arm_spe_get_payload(buf, len, 0, packet);
116 }
117 
118 static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
119 				   struct arm_spe_pkt *packet)
120 {
121 	packet->type = ARM_SPE_DATA_SOURCE;
122 	return arm_spe_get_payload(buf, len, 0, packet);
123 }
124 
125 static int arm_spe_get_context(const unsigned char *buf, size_t len,
126 			       struct arm_spe_pkt *packet)
127 {
128 	packet->type = ARM_SPE_CONTEXT;
129 	packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
130 	return arm_spe_get_payload(buf, len, 0, packet);
131 }
132 
133 static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
134 			       struct arm_spe_pkt *packet)
135 {
136 	packet->type = ARM_SPE_OP_TYPE;
137 	packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]);
138 	return arm_spe_get_payload(buf, len, 0, packet);
139 }
140 
141 static int arm_spe_get_counter(const unsigned char *buf, size_t len,
142 			       const unsigned char ext_hdr, struct arm_spe_pkt *packet)
143 {
144 	packet->type = ARM_SPE_COUNTER;
145 
146 	if (ext_hdr)
147 		packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
148 	else
149 		packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
150 
151 	return arm_spe_get_payload(buf, len, ext_hdr, packet);
152 }
153 
154 static int arm_spe_get_addr(const unsigned char *buf, size_t len,
155 			    const unsigned char ext_hdr, struct arm_spe_pkt *packet)
156 {
157 	packet->type = ARM_SPE_ADDRESS;
158 
159 	if (ext_hdr)
160 		packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
161 	else
162 		packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
163 
164 	return arm_spe_get_payload(buf, len, ext_hdr, packet);
165 }
166 
167 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
168 				 struct arm_spe_pkt *packet)
169 {
170 	unsigned int hdr;
171 	unsigned char ext_hdr = 0;
172 
173 	memset(packet, 0, sizeof(struct arm_spe_pkt));
174 
175 	if (!len)
176 		return ARM_SPE_NEED_MORE_BYTES;
177 
178 	hdr = buf[0];
179 
180 	if (hdr == SPE_HEADER0_PAD)
181 		return arm_spe_get_pad(packet);
182 
183 	if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
184 		return arm_spe_get_end(packet);
185 
186 	if (hdr == SPE_HEADER0_TIMESTAMP)
187 		return arm_spe_get_timestamp(buf, len, packet);
188 
189 	if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
190 		return arm_spe_get_events(buf, len, packet);
191 
192 	if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
193 		return arm_spe_get_data_source(buf, len, packet);
194 
195 	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
196 		return arm_spe_get_context(buf, len, packet);
197 
198 	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
199 		return arm_spe_get_op_type(buf, len, packet);
200 
201 	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
202 		/* 16-bit extended format header */
203 		if (len == 1)
204 			return ARM_SPE_BAD_PACKET;
205 
206 		ext_hdr = 1;
207 		hdr = buf[1];
208 		if (hdr == SPE_HEADER1_ALIGNMENT)
209 			return arm_spe_get_alignment(buf, len, packet);
210 	}
211 
212 	/*
213 	 * The short format header's byte 0 or the extended format header's
214 	 * byte 1 has been assigned to 'hdr', which uses the same encoding for
215 	 * address packet and counter packet, so don't need to distinguish if
216 	 * it's short format or extended format and handle in once.
217 	 */
218 	if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
219 		return arm_spe_get_addr(buf, len, ext_hdr, packet);
220 
221 	if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
222 		return arm_spe_get_counter(buf, len, ext_hdr, packet);
223 
224 	return ARM_SPE_BAD_PACKET;
225 }
226 
227 int arm_spe_get_packet(const unsigned char *buf, size_t len,
228 		       struct arm_spe_pkt *packet, u64 midr)
229 {
230 	int ret;
231 
232 	ret = arm_spe_do_get_packet(buf, len, packet);
233 	packet->midr = midr;
234 	/* put multiple consecutive PADs on the same line, up to
235 	 * the fixed-width output format of 16 bytes per line.
236 	 */
237 	if (ret > 0 && packet->type == ARM_SPE_PAD) {
238 		while (ret < 16 && len > (size_t)ret && !buf[ret])
239 			ret += 1;
240 	}
241 	return ret;
242 }
243 
244 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
245 				  const char *fmt, ...)
246 {
247 	va_list ap;
248 	int ret;
249 
250 	/* Bail out if any error occurred */
251 	if (err && *err)
252 		return *err;
253 
254 	va_start(ap, fmt);
255 	ret = vsnprintf(*buf_p, *blen, fmt, ap);
256 	va_end(ap);
257 
258 	if (ret < 0) {
259 		if (err && !*err)
260 			*err = ret;
261 
262 	/*
263 	 * A return value of *blen or more means that the output was
264 	 * truncated and the buffer is overrun.
265 	 */
266 	} else if ((size_t)ret >= *blen) {
267 		(*buf_p)[*blen - 1] = '\0';
268 
269 		/*
270 		 * Set *err to 'ret' to avoid overflow if tries to
271 		 * fill this buffer sequentially.
272 		 */
273 		if (err && !*err)
274 			*err = ret;
275 	} else {
276 		*buf_p += ret;
277 		*blen -= ret;
278 	}
279 
280 	return ret;
281 }
282 
283 struct ev_string {
284 	u8 event;
285 	const char *desc;
286 };
287 
288 static const struct ev_string common_ev_strings[] = {
289 	{ .event = EV_EXCEPTION_GEN, .desc = "EXCEPTION-GEN" },
290 	{ .event = EV_RETIRED, .desc = "RETIRED" },
291 	{ .event = EV_L1D_ACCESS, .desc = "L1D-ACCESS" },
292 	{ .event = EV_L1D_REFILL, .desc = "L1D-REFILL" },
293 	{ .event = EV_TLB_ACCESS, .desc = "TLB-ACCESS" },
294 	{ .event = EV_TLB_WALK, .desc = "TLB-REFILL" },
295 	{ .event = EV_NOT_TAKEN, .desc = "NOT-TAKEN" },
296 	{ .event = EV_MISPRED, .desc = "MISPRED" },
297 	{ .event = EV_LLC_ACCESS, .desc = "LLC-ACCESS" },
298 	{ .event = EV_LLC_MISS, .desc = "LLC-REFILL" },
299 	{ .event = EV_REMOTE_ACCESS, .desc = "REMOTE-ACCESS" },
300 	{ .event = EV_ALIGNMENT, .desc = "ALIGNMENT" },
301 	{ .event = EV_TRANSACTIONAL, .desc = "TXN" },
302 	{ .event = EV_PARTIAL_PREDICATE, .desc = "SVE-PARTIAL-PRED" },
303 	{ .event = EV_EMPTY_PREDICATE, .desc = "SVE-EMPTY-PRED" },
304 	{ .event = EV_L2D_ACCESS, .desc = "L2D-ACCESS" },
305 	{ .event = EV_L2D_MISS, .desc = "L2D-MISS" },
306 	{ .event = EV_CACHE_DATA_MODIFIED, .desc = "HITM" },
307 	{ .event = EV_RECENTLY_FETCHED, .desc = "LFB" },
308 	{ .event = EV_DATA_SNOOPED, .desc = "SNOOPED" },
309 	{ .event = EV_STREAMING_SVE_MODE, .desc = "STREAMING-SVE" },
310 	{ .event = EV_SMCU, .desc = "SMCU" },
311 	{ .event = 0, .desc = NULL },
312 };
313 
314 static const struct ev_string n1_event_strings[] = {
315 	{ .event = 12, .desc = "LATE-PREFETCH" },
316 	{ .event = 0, .desc = NULL },
317 };
318 
319 static u64 print_event_list(int *err, char **buf, size_t *buf_len,
320 			    const struct ev_string *ev_strings, u64 payload)
321 {
322 	for (const struct ev_string *ev = ev_strings; ev->desc != NULL; ev++) {
323 		if (payload & BIT_ULL(ev->event))
324 			arm_spe_pkt_out_string(err, buf, buf_len, " %s", ev->desc);
325 		payload &= ~BIT_ULL(ev->event);
326 	}
327 	return payload;
328 }
329 
330 struct event_print_handle {
331 	const struct midr_range *midr_ranges;
332 	const struct ev_string *ev_strings;
333 };
334 
335 #define EV_PRINT(range, strings)			\
336 	{					\
337 		.midr_ranges = range,		\
338 		.ev_strings = strings,	\
339 	}
340 
341 static const struct midr_range n1_event_encoding_cpus[] = {
342 	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
343 	{},
344 };
345 
346 static const struct event_print_handle event_print_handles[] = {
347 	EV_PRINT(n1_event_encoding_cpus, n1_event_strings),
348 };
349 
350 static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
351 				  char *buf, size_t buf_len)
352 {
353 	u64 payload = packet->payload;
354 	int err = 0;
355 
356 	arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
357 	payload = print_event_list(&err, &buf, &buf_len, common_ev_strings,
358 				   payload);
359 
360 	/* Try to decode IMPDEF bits for known CPUs */
361 	for (unsigned int i = 0; i < ARRAY_SIZE(event_print_handles); i++) {
362 		if (is_midr_in_range_list(packet->midr,
363 					  event_print_handles[i].midr_ranges))
364 			payload = print_event_list(&err, &buf, &buf_len,
365 						   event_print_handles[i].ev_strings,
366 						   payload);
367 	}
368 
369 	/*
370 	 * Print remaining IMPDEF bits that weren't printed above as raw
371 	 * "IMPDEF:1,2,3,4" etc.
372 	 */
373 	if (payload) {
374 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " IMPDEF:");
375 		for (int i = 0; i < 64; i++) {
376 			const char *sep = payload & (payload - 1) ? "," : "";
377 
378 			if (payload & BIT_ULL(i)) {
379 				arm_spe_pkt_out_string(&err, &buf, &buf_len, "%d%s", i,
380 						sep);
381 				payload &= ~BIT_ULL(i);
382 			}
383 		}
384 	}
385 
386 	return err;
387 }
388 
389 static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
390 				    char *buf, size_t buf_len)
391 {
392 	u64 payload = packet->payload;
393 	int err = 0;
394 
395 	switch (packet->index) {
396 	case SPE_OP_PKT_HDR_CLASS_OTHER:
397 		if (SPE_OP_PKT_OTHER_SUBCLASS_SVE(payload)) {
398 			arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER");
399 
400 			/* SVE effective vector length */
401 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
402 					       SPE_OP_PKG_SVE_EVL(payload));
403 
404 			if (payload & SPE_OP_PKT_SVE_FP)
405 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
406 			if (payload & SPE_OP_PKT_SVE_PRED)
407 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
408 		} else if (SPE_OP_PKT_OTHER_SUBCLASS_SME(payload)) {
409 			arm_spe_pkt_out_string(&err, &buf, &buf_len, "SME-OTHER");
410 
411 			/* SME effective vector length or tile size */
412 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " ETS %d",
413 					       SPE_OP_PKG_SME_ETS(payload));
414 
415 			if (payload & SPE_OP_PKT_OTHER_FP)
416 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
417 		} else if (SPE_OP_PKT_OTHER_SUBCLASS_OTHER(payload)) {
418 			arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER");
419 			if (payload & SPE_OP_PKT_OTHER_ASE)
420 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " ASE");
421 			if (payload & SPE_OP_PKT_OTHER_FP)
422 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
423 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s",
424 					       payload & SPE_OP_PKT_COND ?
425 					       "COND-SELECT" : "INSN-OTHER");
426 		}
427 		break;
428 	case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
429 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
430 				       payload & 0x1 ? "ST" : "LD");
431 
432 		if (SPE_OP_PKT_LDST_SUBCLASS_EXTENDED(payload)) {
433 			if (payload & SPE_OP_PKT_AT)
434 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
435 			if (payload & SPE_OP_PKT_EXCL)
436 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
437 			if (payload & SPE_OP_PKT_AR)
438 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
439 		} else if (SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP(payload)) {
440 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
441 		} else if (SPE_OP_PKT_LDST_SUBCLASS_GP_REG(payload)) {
442 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG");
443 		} else if (SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG(payload)) {
444 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG");
445 		} else if (SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG(payload)) {
446 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG");
447 		} else if (SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG(payload)) {
448 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MTE-TAG");
449 		} else if (SPE_OP_PKT_LDST_SUBCLASS_MEMCPY(payload)) {
450 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMCPY");
451 		} else if (SPE_OP_PKT_LDST_SUBCLASS_MEMSET(payload)) {
452 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMSET");
453 		} else if (SPE_OP_PKT_LDST_SUBCLASS_SVE_SME_REG(payload)) {
454 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-SME-REG");
455 
456 			/* SVE effective vector length */
457 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
458 					       SPE_OP_PKG_SVE_EVL(payload));
459 
460 			if (payload & SPE_OP_PKT_SVE_PRED)
461 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
462 			if (payload & SPE_OP_PKT_SVE_SG)
463 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
464 		} else if (SPE_OP_PKT_LDST_SUBCLASS_GCS(payload)) {
465 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " GCS");
466 			if (payload & SPE_OP_PKT_GCS_COMM)
467 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " COMM");
468 		}
469 		break;
470 	case SPE_OP_PKT_HDR_CLASS_BR_ERET:
471 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
472 
473 		if (payload & SPE_OP_PKT_COND)
474 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
475 		if (payload & SPE_OP_PKT_INDIRECT_BRANCH)
476 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
477 		if (payload & SPE_OP_PKT_GCS)
478 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " GCS");
479 		if (SPE_OP_PKT_CR_BL(payload))
480 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " CR-BL");
481 		if (SPE_OP_PKT_CR_RET(payload))
482 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " CR-RET");
483 		if (SPE_OP_PKT_CR_NON_BL_RET(payload))
484 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " CR-NON-BL-RET");
485 		break;
486 	default:
487 		/* Unknown index */
488 		err = -1;
489 		break;
490 	}
491 
492 	return err;
493 }
494 
495 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
496 				 char *buf, size_t buf_len)
497 {
498 	int ns, el, idx = packet->index;
499 	int ch, pat;
500 	u64 payload = packet->payload;
501 	int err = 0;
502 	static const char *idx_name[] = {"PC", "TGT", "VA", "PA", "PBT"};
503 
504 	switch (idx) {
505 	case SPE_ADDR_PKT_HDR_INDEX_INS:
506 	case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
507 	case SPE_ADDR_PKT_HDR_INDEX_PREV_BRANCH:
508 		ns = !!SPE_ADDR_PKT_GET_NS(payload);
509 		el = SPE_ADDR_PKT_GET_EL(payload);
510 		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
511 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
512 				"%s 0x%llx el%d ns=%d",
513 				idx_name[idx], payload, el, ns);
514 		break;
515 	case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
516 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
517 				       "VA 0x%llx", payload);
518 		break;
519 	case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
520 		ns = !!SPE_ADDR_PKT_GET_NS(payload);
521 		ch = !!SPE_ADDR_PKT_GET_CH(payload);
522 		pat = SPE_ADDR_PKT_GET_PAT(payload);
523 		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
524 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
525 				       "PA 0x%llx ns=%d ch=%d pat=%x",
526 				       payload, ns, ch, pat);
527 		break;
528 	default:
529 		/* Unknown index */
530 		err = -1;
531 		break;
532 	}
533 
534 	return err;
535 }
536 
537 static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
538 				    char *buf, size_t buf_len)
539 {
540 	u64 payload = packet->payload;
541 	const char *name = arm_spe_pkt_name(packet->type);
542 	int err = 0;
543 
544 	arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
545 			       (unsigned short)payload);
546 
547 	switch (packet->index) {
548 	case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
549 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
550 		break;
551 	case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
552 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
553 		break;
554 	case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
555 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
556 		break;
557 	default:
558 		break;
559 	}
560 
561 	return err;
562 }
563 
564 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
565 		     size_t buf_len)
566 {
567 	int idx = packet->index;
568 	unsigned long long payload = packet->payload;
569 	const char *name = arm_spe_pkt_name(packet->type);
570 	char *buf_orig = buf;
571 	size_t blen = buf_len;
572 	int err = 0;
573 
574 	switch (packet->type) {
575 	case ARM_SPE_BAD:
576 	case ARM_SPE_PAD:
577 	case ARM_SPE_END:
578 		arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
579 		break;
580 	case ARM_SPE_EVENTS:
581 		err = arm_spe_pkt_desc_event(packet, buf, buf_len);
582 		break;
583 	case ARM_SPE_OP_TYPE:
584 		err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
585 		break;
586 	case ARM_SPE_DATA_SOURCE:
587 	case ARM_SPE_TIMESTAMP:
588 		arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
589 		break;
590 	case ARM_SPE_ADDRESS:
591 		err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
592 		break;
593 	case ARM_SPE_CONTEXT:
594 		arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
595 				       name, (unsigned long)payload, idx + 1);
596 		break;
597 	case ARM_SPE_COUNTER:
598 		err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
599 		break;
600 	default:
601 		/* Unknown packet type */
602 		err = -1;
603 		break;
604 	}
605 
606 	/* Output raw data if detect any error */
607 	if (err) {
608 		err = 0;
609 		arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
610 				       name, payload, packet->index);
611 	}
612 
613 	return err;
614 }
615