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