14db25f66STan Xiaojun // SPDX-License-Identifier: GPL-2.0
24db25f66STan Xiaojun /*
34db25f66STan Xiaojun  * Arm Statistical Profiling Extensions (SPE) support
44db25f66STan Xiaojun  * Copyright (c) 2017-2018, Arm Ltd.
54db25f66STan Xiaojun  */
64db25f66STan Xiaojun 
74db25f66STan Xiaojun #include <stdio.h>
84db25f66STan Xiaojun #include <string.h>
94db25f66STan Xiaojun #include <endian.h>
104db25f66STan Xiaojun #include <byteswap.h>
11c185f1cdSLeo Yan #include <linux/bitops.h>
1275eeadddSLeo Yan #include <stdarg.h>
134db25f66STan Xiaojun 
144db25f66STan Xiaojun #include "arm-spe-pkt-decoder.h"
154db25f66STan Xiaojun 
164e88118cSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
174db25f66STan Xiaojun #define le16_to_cpu bswap_16
184db25f66STan Xiaojun #define le32_to_cpu bswap_32
194db25f66STan Xiaojun #define le64_to_cpu bswap_64
204db25f66STan Xiaojun #define memcpy_le64(d, s, n) do { \
214db25f66STan Xiaojun 	memcpy((d), (s), (n));    \
224db25f66STan Xiaojun 	*(d) = le64_to_cpu(*(d)); \
234db25f66STan Xiaojun } while (0)
244db25f66STan Xiaojun #else
254db25f66STan Xiaojun #define le16_to_cpu
264db25f66STan Xiaojun #define le32_to_cpu
274db25f66STan Xiaojun #define le64_to_cpu
284db25f66STan Xiaojun #define memcpy_le64 memcpy
294db25f66STan Xiaojun #endif
304db25f66STan Xiaojun 
314db25f66STan Xiaojun static const char * const arm_spe_packet_name[] = {
324db25f66STan Xiaojun 	[ARM_SPE_PAD]		= "PAD",
334db25f66STan Xiaojun 	[ARM_SPE_END]		= "END",
344db25f66STan Xiaojun 	[ARM_SPE_TIMESTAMP]	= "TS",
354db25f66STan Xiaojun 	[ARM_SPE_ADDRESS]	= "ADDR",
364db25f66STan Xiaojun 	[ARM_SPE_COUNTER]	= "LAT",
374db25f66STan Xiaojun 	[ARM_SPE_CONTEXT]	= "CONTEXT",
384db25f66STan Xiaojun 	[ARM_SPE_OP_TYPE]	= "OP-TYPE",
394db25f66STan Xiaojun 	[ARM_SPE_EVENTS]	= "EVENTS",
404db25f66STan Xiaojun 	[ARM_SPE_DATA_SOURCE]	= "DATA-SOURCE",
414db25f66STan Xiaojun };
424db25f66STan Xiaojun 
arm_spe_pkt_name(enum arm_spe_pkt_type type)434db25f66STan Xiaojun const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
444db25f66STan Xiaojun {
454db25f66STan Xiaojun 	return arm_spe_packet_name[type];
464db25f66STan Xiaojun }
474db25f66STan Xiaojun 
48b2ded2e2SLeo Yan /*
49b2ded2e2SLeo Yan  * Extracts the field "sz" from header bits and converts to bytes:
50b2ded2e2SLeo Yan  *   00 : byte (1)
514db25f66STan Xiaojun  *   01 : halfword (2)
524db25f66STan Xiaojun  *   10 : word (4)
534db25f66STan Xiaojun  *   11 : doubleword (8)
544db25f66STan Xiaojun  */
arm_spe_payload_len(unsigned char hdr)55b2ded2e2SLeo Yan static unsigned int arm_spe_payload_len(unsigned char hdr)
564db25f66STan Xiaojun {
57b2ded2e2SLeo Yan 	return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
584db25f66STan Xiaojun }
594db25f66STan Xiaojun 
arm_spe_get_payload(const unsigned char * buf,size_t len,unsigned char ext_hdr,struct arm_spe_pkt * packet)604db25f66STan Xiaojun static int arm_spe_get_payload(const unsigned char *buf, size_t len,
610a04244cSLeo Yan 			       unsigned char ext_hdr,
624db25f66STan Xiaojun 			       struct arm_spe_pkt *packet)
634db25f66STan Xiaojun {
640a04244cSLeo Yan 	size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
654db25f66STan Xiaojun 
660a04244cSLeo Yan 	if (len < 1 + ext_hdr + payload_len)
674db25f66STan Xiaojun 		return ARM_SPE_NEED_MORE_BYTES;
684db25f66STan Xiaojun 
690a04244cSLeo Yan 	buf += 1 + ext_hdr;
704db25f66STan Xiaojun 
714db25f66STan Xiaojun 	switch (payload_len) {
724db25f66STan Xiaojun 	case 1: packet->payload = *(uint8_t *)buf; break;
734db25f66STan Xiaojun 	case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
744db25f66STan Xiaojun 	case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
754db25f66STan Xiaojun 	case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
764db25f66STan Xiaojun 	default: return ARM_SPE_BAD_PACKET;
774db25f66STan Xiaojun 	}
784db25f66STan Xiaojun 
790a04244cSLeo Yan 	return 1 + ext_hdr + payload_len;
804db25f66STan Xiaojun }
814db25f66STan Xiaojun 
arm_spe_get_pad(struct arm_spe_pkt * packet)824db25f66STan Xiaojun static int arm_spe_get_pad(struct arm_spe_pkt *packet)
834db25f66STan Xiaojun {
844db25f66STan Xiaojun 	packet->type = ARM_SPE_PAD;
854db25f66STan Xiaojun 	return 1;
864db25f66STan Xiaojun }
874db25f66STan Xiaojun 
arm_spe_get_alignment(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)884db25f66STan Xiaojun static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
894db25f66STan Xiaojun 				 struct arm_spe_pkt *packet)
904db25f66STan Xiaojun {
914db25f66STan Xiaojun 	unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
924db25f66STan Xiaojun 
934db25f66STan Xiaojun 	if (len < alignment)
944db25f66STan Xiaojun 		return ARM_SPE_NEED_MORE_BYTES;
954db25f66STan Xiaojun 
964db25f66STan Xiaojun 	packet->type = ARM_SPE_PAD;
974db25f66STan Xiaojun 	return alignment - (((uintptr_t)buf) & (alignment - 1));
984db25f66STan Xiaojun }
994db25f66STan Xiaojun 
arm_spe_get_end(struct arm_spe_pkt * packet)1004db25f66STan Xiaojun static int arm_spe_get_end(struct arm_spe_pkt *packet)
1014db25f66STan Xiaojun {
1024db25f66STan Xiaojun 	packet->type = ARM_SPE_END;
1034db25f66STan Xiaojun 	return 1;
1044db25f66STan Xiaojun }
1054db25f66STan Xiaojun 
arm_spe_get_timestamp(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)1064db25f66STan Xiaojun static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
1074db25f66STan Xiaojun 				 struct arm_spe_pkt *packet)
1084db25f66STan Xiaojun {
1094db25f66STan Xiaojun 	packet->type = ARM_SPE_TIMESTAMP;
1100a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, 0, packet);
1114db25f66STan Xiaojun }
1124db25f66STan Xiaojun 
arm_spe_get_events(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)1134db25f66STan Xiaojun static int arm_spe_get_events(const unsigned char *buf, size_t len,
1144db25f66STan Xiaojun 			      struct arm_spe_pkt *packet)
1154db25f66STan Xiaojun {
1164db25f66STan Xiaojun 	packet->type = ARM_SPE_EVENTS;
1174db25f66STan Xiaojun 
1184db25f66STan Xiaojun 	/* we use index to identify Events with a less number of
1194db25f66STan Xiaojun 	 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
120903b6594SLeo Yan 	 * LLC-REFILL, and REMOTE-ACCESS events are identified if
1214db25f66STan Xiaojun 	 * index > 1.
1224db25f66STan Xiaojun 	 */
123b65577baSLeo Yan 	packet->index = arm_spe_payload_len(buf[0]);
1244db25f66STan Xiaojun 
1250a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, 0, packet);
1264db25f66STan Xiaojun }
1274db25f66STan Xiaojun 
arm_spe_get_data_source(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)1284db25f66STan Xiaojun static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
1294db25f66STan Xiaojun 				   struct arm_spe_pkt *packet)
1304db25f66STan Xiaojun {
1314db25f66STan Xiaojun 	packet->type = ARM_SPE_DATA_SOURCE;
1320a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, 0, packet);
1334db25f66STan Xiaojun }
1344db25f66STan Xiaojun 
arm_spe_get_context(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)1354db25f66STan Xiaojun static int arm_spe_get_context(const unsigned char *buf, size_t len,
1364db25f66STan Xiaojun 			       struct arm_spe_pkt *packet)
1374db25f66STan Xiaojun {
1384db25f66STan Xiaojun 	packet->type = ARM_SPE_CONTEXT;
1396550149eSLeo Yan 	packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
1400a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, 0, packet);
1414db25f66STan Xiaojun }
1424db25f66STan Xiaojun 
arm_spe_get_op_type(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)1434db25f66STan Xiaojun static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
1444db25f66STan Xiaojun 			       struct arm_spe_pkt *packet)
1454db25f66STan Xiaojun {
1464db25f66STan Xiaojun 	packet->type = ARM_SPE_OP_TYPE;
147e771218fSLeo Yan 	packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]);
1480a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, 0, packet);
1494db25f66STan Xiaojun }
1504db25f66STan Xiaojun 
arm_spe_get_counter(const unsigned char * buf,size_t len,const unsigned char ext_hdr,struct arm_spe_pkt * packet)1514db25f66STan Xiaojun static int arm_spe_get_counter(const unsigned char *buf, size_t len,
1524db25f66STan Xiaojun 			       const unsigned char ext_hdr, struct arm_spe_pkt *packet)
1534db25f66STan Xiaojun {
1544db25f66STan Xiaojun 	packet->type = ARM_SPE_COUNTER;
155d158aa40SLeo Yan 
1564db25f66STan Xiaojun 	if (ext_hdr)
157d158aa40SLeo Yan 		packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
1584db25f66STan Xiaojun 	else
159d158aa40SLeo Yan 		packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
1604db25f66STan Xiaojun 
1610a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, ext_hdr, packet);
1624db25f66STan Xiaojun }
1634db25f66STan Xiaojun 
arm_spe_get_addr(const unsigned char * buf,size_t len,const unsigned char ext_hdr,struct arm_spe_pkt * packet)1644db25f66STan Xiaojun static int arm_spe_get_addr(const unsigned char *buf, size_t len,
1654db25f66STan Xiaojun 			    const unsigned char ext_hdr, struct arm_spe_pkt *packet)
1664db25f66STan Xiaojun {
1674db25f66STan Xiaojun 	packet->type = ARM_SPE_ADDRESS;
16809935ca7SLeo Yan 
1694db25f66STan Xiaojun 	if (ext_hdr)
17009935ca7SLeo Yan 		packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
1714db25f66STan Xiaojun 	else
17209935ca7SLeo Yan 		packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
1734db25f66STan Xiaojun 
1740a04244cSLeo Yan 	return arm_spe_get_payload(buf, len, ext_hdr, packet);
1754db25f66STan Xiaojun }
1764db25f66STan Xiaojun 
arm_spe_do_get_packet(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)1774db25f66STan Xiaojun static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
1784db25f66STan Xiaojun 				 struct arm_spe_pkt *packet)
1794db25f66STan Xiaojun {
18011695142SLeo Yan 	unsigned int hdr;
18111695142SLeo Yan 	unsigned char ext_hdr = 0;
1824db25f66STan Xiaojun 
1834db25f66STan Xiaojun 	memset(packet, 0, sizeof(struct arm_spe_pkt));
1844db25f66STan Xiaojun 
1854db25f66STan Xiaojun 	if (!len)
1864db25f66STan Xiaojun 		return ARM_SPE_NEED_MORE_BYTES;
1874db25f66STan Xiaojun 
18811695142SLeo Yan 	hdr = buf[0];
18911695142SLeo Yan 
19011695142SLeo Yan 	if (hdr == SPE_HEADER0_PAD)
1914db25f66STan Xiaojun 		return arm_spe_get_pad(packet);
19211695142SLeo Yan 
19311695142SLeo Yan 	if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
1944db25f66STan Xiaojun 		return arm_spe_get_end(packet);
19511695142SLeo Yan 
19611695142SLeo Yan 	if (hdr == SPE_HEADER0_TIMESTAMP)
1974db25f66STan Xiaojun 		return arm_spe_get_timestamp(buf, len, packet);
19811695142SLeo Yan 
19911695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
2004db25f66STan Xiaojun 		return arm_spe_get_events(buf, len, packet);
20111695142SLeo Yan 
20211695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
2034db25f66STan Xiaojun 		return arm_spe_get_data_source(buf, len, packet);
20411695142SLeo Yan 
20511695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
2064db25f66STan Xiaojun 		return arm_spe_get_context(buf, len, packet);
20711695142SLeo Yan 
20811695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
2094db25f66STan Xiaojun 		return arm_spe_get_op_type(buf, len, packet);
21011695142SLeo Yan 
21111695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
21211695142SLeo Yan 		/* 16-bit extended format header */
21392f1e8adSIan Rogers 		if (len == 1)
21492f1e8adSIan Rogers 			return ARM_SPE_BAD_PACKET;
21511695142SLeo Yan 
21692f1e8adSIan Rogers 		ext_hdr = 1;
21711695142SLeo Yan 		hdr = buf[1];
21811695142SLeo Yan 		if (hdr == SPE_HEADER1_ALIGNMENT)
2194db25f66STan Xiaojun 			return arm_spe_get_alignment(buf, len, packet);
2204db25f66STan Xiaojun 	}
2214db25f66STan Xiaojun 
22211695142SLeo Yan 	/*
22311695142SLeo Yan 	 * The short format header's byte 0 or the extended format header's
22411695142SLeo Yan 	 * byte 1 has been assigned to 'hdr', which uses the same encoding for
22511695142SLeo Yan 	 * address packet and counter packet, so don't need to distinguish if
22611695142SLeo Yan 	 * it's short format or extended format and handle in once.
22711695142SLeo Yan 	 */
22811695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
22911695142SLeo Yan 		return arm_spe_get_addr(buf, len, ext_hdr, packet);
23011695142SLeo Yan 
23111695142SLeo Yan 	if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
23211695142SLeo Yan 		return arm_spe_get_counter(buf, len, ext_hdr, packet);
23311695142SLeo Yan 
2344db25f66STan Xiaojun 	return ARM_SPE_BAD_PACKET;
2354db25f66STan Xiaojun }
2364db25f66STan Xiaojun 
arm_spe_get_packet(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)2374db25f66STan Xiaojun int arm_spe_get_packet(const unsigned char *buf, size_t len,
2384db25f66STan Xiaojun 		       struct arm_spe_pkt *packet)
2394db25f66STan Xiaojun {
2404db25f66STan Xiaojun 	int ret;
2414db25f66STan Xiaojun 
2424db25f66STan Xiaojun 	ret = arm_spe_do_get_packet(buf, len, packet);
2434db25f66STan Xiaojun 	/* put multiple consecutive PADs on the same line, up to
2444db25f66STan Xiaojun 	 * the fixed-width output format of 16 bytes per line.
2454db25f66STan Xiaojun 	 */
2464db25f66STan Xiaojun 	if (ret > 0 && packet->type == ARM_SPE_PAD) {
2474db25f66STan Xiaojun 		while (ret < 16 && len > (size_t)ret && !buf[ret])
2484db25f66STan Xiaojun 			ret += 1;
2494db25f66STan Xiaojun 	}
2504db25f66STan Xiaojun 	return ret;
2514db25f66STan Xiaojun }
2524db25f66STan Xiaojun 
arm_spe_pkt_out_string(int * err,char ** buf_p,size_t * blen,const char * fmt,...)25375eeadddSLeo Yan static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
25475eeadddSLeo Yan 				  const char *fmt, ...)
25575eeadddSLeo Yan {
25675eeadddSLeo Yan 	va_list ap;
25775eeadddSLeo Yan 	int ret;
25875eeadddSLeo Yan 
25975eeadddSLeo Yan 	/* Bail out if any error occurred */
26075eeadddSLeo Yan 	if (err && *err)
26175eeadddSLeo Yan 		return *err;
26275eeadddSLeo Yan 
26375eeadddSLeo Yan 	va_start(ap, fmt);
26475eeadddSLeo Yan 	ret = vsnprintf(*buf_p, *blen, fmt, ap);
26575eeadddSLeo Yan 	va_end(ap);
26675eeadddSLeo Yan 
26775eeadddSLeo Yan 	if (ret < 0) {
26875eeadddSLeo Yan 		if (err && !*err)
26975eeadddSLeo Yan 			*err = ret;
27075eeadddSLeo Yan 
27175eeadddSLeo Yan 	/*
27275eeadddSLeo Yan 	 * A return value of *blen or more means that the output was
27375eeadddSLeo Yan 	 * truncated and the buffer is overrun.
27475eeadddSLeo Yan 	 */
27575eeadddSLeo Yan 	} else if ((size_t)ret >= *blen) {
27675eeadddSLeo Yan 		(*buf_p)[*blen - 1] = '\0';
27775eeadddSLeo Yan 
27875eeadddSLeo Yan 		/*
27975eeadddSLeo Yan 		 * Set *err to 'ret' to avoid overflow if tries to
28075eeadddSLeo Yan 		 * fill this buffer sequentially.
28175eeadddSLeo Yan 		 */
28275eeadddSLeo Yan 		if (err && !*err)
28375eeadddSLeo Yan 			*err = ret;
28475eeadddSLeo Yan 	} else {
28575eeadddSLeo Yan 		*buf_p += ret;
28675eeadddSLeo Yan 		*blen -= ret;
28775eeadddSLeo Yan 	}
28875eeadddSLeo Yan 
28975eeadddSLeo Yan 	return ret;
29075eeadddSLeo Yan }
29175eeadddSLeo Yan 
arm_spe_pkt_desc_event(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)292e66f6d75SLeo Yan static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
293e66f6d75SLeo Yan 				  char *buf, size_t buf_len)
294e66f6d75SLeo Yan {
295e66f6d75SLeo Yan 	u64 payload = packet->payload;
296e66f6d75SLeo Yan 	int err = 0;
297e66f6d75SLeo Yan 
298e66f6d75SLeo Yan 	arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
299e66f6d75SLeo Yan 
300889d1a67SLeo Yan 	if (payload & BIT(EV_EXCEPTION_GEN))
301e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
302889d1a67SLeo Yan 	if (payload & BIT(EV_RETIRED))
303e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
304889d1a67SLeo Yan 	if (payload & BIT(EV_L1D_ACCESS))
305e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
306889d1a67SLeo Yan 	if (payload & BIT(EV_L1D_REFILL))
307e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
308889d1a67SLeo Yan 	if (payload & BIT(EV_TLB_ACCESS))
309e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
310889d1a67SLeo Yan 	if (payload & BIT(EV_TLB_WALK))
311e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
312889d1a67SLeo Yan 	if (payload & BIT(EV_NOT_TAKEN))
313e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
314889d1a67SLeo Yan 	if (payload & BIT(EV_MISPRED))
315e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
316889d1a67SLeo Yan 	if (payload & BIT(EV_LLC_ACCESS))
317e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
318889d1a67SLeo Yan 	if (payload & BIT(EV_LLC_MISS))
319e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
320889d1a67SLeo Yan 	if (payload & BIT(EV_REMOTE_ACCESS))
321e66f6d75SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
32205e91e7fSWei Li 	if (payload & BIT(EV_ALIGNMENT))
32305e91e7fSWei Li 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " ALIGNMENT");
32405e91e7fSWei Li 	if (payload & BIT(EV_PARTIAL_PREDICATE))
32505e91e7fSWei Li 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED");
32605e91e7fSWei Li 	if (payload & BIT(EV_EMPTY_PREDICATE))
32705e91e7fSWei Li 		arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED");
328e66f6d75SLeo Yan 
329e66f6d75SLeo Yan 	return err;
330e66f6d75SLeo Yan }
331e66f6d75SLeo Yan 
arm_spe_pkt_desc_op_type(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)3327488ffc4SLeo Yan static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
3337488ffc4SLeo Yan 				    char *buf, size_t buf_len)
3347488ffc4SLeo Yan {
3357488ffc4SLeo Yan 	u64 payload = packet->payload;
3367488ffc4SLeo Yan 	int err = 0;
3377488ffc4SLeo Yan 
3387488ffc4SLeo Yan 	switch (packet->index) {
339e771218fSLeo Yan 	case SPE_OP_PKT_HDR_CLASS_OTHER:
34005e91e7fSWei Li 		if (SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) {
34105e91e7fSWei Li 			arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER");
34205e91e7fSWei Li 
34305e91e7fSWei Li 			/* SVE effective vector length */
34405e91e7fSWei Li 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
34505e91e7fSWei Li 					       SPE_OP_PKG_SVE_EVL(payload));
34605e91e7fSWei Li 
34705e91e7fSWei Li 			if (payload & SPE_OP_PKT_SVE_FP)
34805e91e7fSWei Li 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
34905e91e7fSWei Li 			if (payload & SPE_OP_PKT_SVE_PRED)
35005e91e7fSWei Li 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
35105e91e7fSWei Li 		} else {
35205e91e7fSWei Li 			arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER");
35305e91e7fSWei Li 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s",
35405e91e7fSWei Li 					       payload & SPE_OP_PKT_COND ?
35505e91e7fSWei Li 					       "COND-SELECT" : "INSN-OTHER");
35605e91e7fSWei Li 		}
3577488ffc4SLeo Yan 		break;
358e771218fSLeo Yan 	case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
3597488ffc4SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
3607488ffc4SLeo Yan 				       payload & 0x1 ? "ST" : "LD");
3617488ffc4SLeo Yan 
362e771218fSLeo Yan 		if (SPE_OP_PKT_IS_LDST_ATOMIC(payload)) {
363e771218fSLeo Yan 			if (payload & SPE_OP_PKT_AT)
3647488ffc4SLeo Yan 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
365e771218fSLeo Yan 			if (payload & SPE_OP_PKT_EXCL)
3667488ffc4SLeo Yan 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
367e771218fSLeo Yan 			if (payload & SPE_OP_PKT_AR)
3687488ffc4SLeo Yan 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
3693d829724SLeo Yan 		}
3703d829724SLeo Yan 
3713d829724SLeo Yan 		switch (SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) {
3723d829724SLeo Yan 		case SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP:
3737488ffc4SLeo Yan 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
3743d829724SLeo Yan 			break;
3753d829724SLeo Yan 		case SPE_OP_PKT_LDST_SUBCLASS_GP_REG:
3763d829724SLeo Yan 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG");
3773d829724SLeo Yan 			break;
3783d829724SLeo Yan 		case SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG:
3793d829724SLeo Yan 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG");
3803d829724SLeo Yan 			break;
3813d829724SLeo Yan 		case SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG:
3823d829724SLeo Yan 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG");
3833d829724SLeo Yan 			break;
384*34fb6040SRob Herring 		case SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG:
385*34fb6040SRob Herring 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MTE-TAG");
386*34fb6040SRob Herring 			break;
387*34fb6040SRob Herring 		case SPE_OP_PKT_LDST_SUBCLASS_MEMCPY:
388*34fb6040SRob Herring 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMCPY");
389*34fb6040SRob Herring 			break;
390*34fb6040SRob Herring 		case SPE_OP_PKT_LDST_SUBCLASS_MEMSET:
391*34fb6040SRob Herring 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMSET");
392*34fb6040SRob Herring 			break;
3933d829724SLeo Yan 		default:
3943d829724SLeo Yan 			break;
3957488ffc4SLeo Yan 		}
39605e91e7fSWei Li 
39705e91e7fSWei Li 		if (SPE_OP_PKT_IS_LDST_SVE(payload)) {
39805e91e7fSWei Li 			/* SVE effective vector length */
39905e91e7fSWei Li 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
40005e91e7fSWei Li 					       SPE_OP_PKG_SVE_EVL(payload));
40105e91e7fSWei Li 
40205e91e7fSWei Li 			if (payload & SPE_OP_PKT_SVE_PRED)
40305e91e7fSWei Li 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
40405e91e7fSWei Li 			if (payload & SPE_OP_PKT_SVE_SG)
40505e91e7fSWei Li 				arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
40605e91e7fSWei Li 		}
4077488ffc4SLeo Yan 		break;
408e771218fSLeo Yan 	case SPE_OP_PKT_HDR_CLASS_BR_ERET:
4097488ffc4SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
4107488ffc4SLeo Yan 
411e771218fSLeo Yan 		if (payload & SPE_OP_PKT_COND)
4127488ffc4SLeo Yan 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
413e771218fSLeo Yan 
414e771218fSLeo Yan 		if (SPE_OP_PKT_IS_INDIRECT_BRANCH(payload))
4157488ffc4SLeo Yan 			arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
4167488ffc4SLeo Yan 
4177488ffc4SLeo Yan 		break;
4187488ffc4SLeo Yan 	default:
4197488ffc4SLeo Yan 		/* Unknown index */
4207488ffc4SLeo Yan 		err = -1;
4217488ffc4SLeo Yan 		break;
4227488ffc4SLeo Yan 	}
4237488ffc4SLeo Yan 
4247488ffc4SLeo Yan 	return err;
4257488ffc4SLeo Yan }
4267488ffc4SLeo Yan 
arm_spe_pkt_desc_addr(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)427ab2aa439SLeo Yan static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
428ab2aa439SLeo Yan 				 char *buf, size_t buf_len)
429ab2aa439SLeo Yan {
430ab2aa439SLeo Yan 	int ns, el, idx = packet->index;
4313601e605SAndre Przywara 	int ch, pat;
432ab2aa439SLeo Yan 	u64 payload = packet->payload;
433ab2aa439SLeo Yan 	int err = 0;
4347105311cSRob Herring 	static const char *idx_name[] = {"PC", "TGT", "VA", "PA", "PBT"};
435ab2aa439SLeo Yan 
436ab2aa439SLeo Yan 	switch (idx) {
43709935ca7SLeo Yan 	case SPE_ADDR_PKT_HDR_INDEX_INS:
43809935ca7SLeo Yan 	case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
4397105311cSRob Herring 	case SPE_ADDR_PKT_HDR_INDEX_PREV_BRANCH:
44009935ca7SLeo Yan 		ns = !!SPE_ADDR_PKT_GET_NS(payload);
44109935ca7SLeo Yan 		el = SPE_ADDR_PKT_GET_EL(payload);
44209935ca7SLeo Yan 		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
443ab2aa439SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
444ab2aa439SLeo Yan 				"%s 0x%llx el%d ns=%d",
4457105311cSRob Herring 				idx_name[idx], payload, el, ns);
446ab2aa439SLeo Yan 		break;
44709935ca7SLeo Yan 	case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
448ab2aa439SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
449ab2aa439SLeo Yan 				       "VA 0x%llx", payload);
450ab2aa439SLeo Yan 		break;
45109935ca7SLeo Yan 	case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
45209935ca7SLeo Yan 		ns = !!SPE_ADDR_PKT_GET_NS(payload);
4533601e605SAndre Przywara 		ch = !!SPE_ADDR_PKT_GET_CH(payload);
4543601e605SAndre Przywara 		pat = SPE_ADDR_PKT_GET_PAT(payload);
45509935ca7SLeo Yan 		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
456ab2aa439SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len,
4573601e605SAndre Przywara 				       "PA 0x%llx ns=%d ch=%d pat=%x",
4583601e605SAndre Przywara 				       payload, ns, ch, pat);
459ab2aa439SLeo Yan 		break;
460ab2aa439SLeo Yan 	default:
461ab2aa439SLeo Yan 		/* Unknown index */
462ab2aa439SLeo Yan 		err = -1;
463ab2aa439SLeo Yan 		break;
464ab2aa439SLeo Yan 	}
465ab2aa439SLeo Yan 
466ab2aa439SLeo Yan 	return err;
467ab2aa439SLeo Yan }
468ab2aa439SLeo Yan 
arm_spe_pkt_desc_counter(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)469c52cfe98SLeo Yan static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
470c52cfe98SLeo Yan 				    char *buf, size_t buf_len)
471c52cfe98SLeo Yan {
472c52cfe98SLeo Yan 	u64 payload = packet->payload;
473c52cfe98SLeo Yan 	const char *name = arm_spe_pkt_name(packet->type);
474c52cfe98SLeo Yan 	int err = 0;
475c52cfe98SLeo Yan 
476c52cfe98SLeo Yan 	arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
477c52cfe98SLeo Yan 			       (unsigned short)payload);
478c52cfe98SLeo Yan 
479c52cfe98SLeo Yan 	switch (packet->index) {
480d158aa40SLeo Yan 	case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
481c52cfe98SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
482c52cfe98SLeo Yan 		break;
483d158aa40SLeo Yan 	case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
484c52cfe98SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
485c52cfe98SLeo Yan 		break;
486d158aa40SLeo Yan 	case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
487c52cfe98SLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
488c52cfe98SLeo Yan 		break;
489c52cfe98SLeo Yan 	default:
490c52cfe98SLeo Yan 		break;
491c52cfe98SLeo Yan 	}
492c52cfe98SLeo Yan 
493c52cfe98SLeo Yan 	return err;
494c52cfe98SLeo Yan }
495c52cfe98SLeo Yan 
arm_spe_pkt_desc(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)4964db25f66STan Xiaojun int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
4974db25f66STan Xiaojun 		     size_t buf_len)
4984db25f66STan Xiaojun {
499ab2aa439SLeo Yan 	int idx = packet->index;
5004db25f66STan Xiaojun 	unsigned long long payload = packet->payload;
5014db25f66STan Xiaojun 	const char *name = arm_spe_pkt_name(packet->type);
50275eeadddSLeo Yan 	char *buf_orig = buf;
50375eeadddSLeo Yan 	size_t blen = buf_len;
50475eeadddSLeo Yan 	int err = 0;
5054db25f66STan Xiaojun 
5064db25f66STan Xiaojun 	switch (packet->type) {
5074db25f66STan Xiaojun 	case ARM_SPE_BAD:
5084db25f66STan Xiaojun 	case ARM_SPE_PAD:
5094db25f66STan Xiaojun 	case ARM_SPE_END:
51075eeadddSLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
51175eeadddSLeo Yan 		break;
51275eeadddSLeo Yan 	case ARM_SPE_EVENTS:
513e66f6d75SLeo Yan 		err = arm_spe_pkt_desc_event(packet, buf, buf_len);
51475eeadddSLeo Yan 		break;
51575eeadddSLeo Yan 	case ARM_SPE_OP_TYPE:
5167488ffc4SLeo Yan 		err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
51775eeadddSLeo Yan 		break;
5184db25f66STan Xiaojun 	case ARM_SPE_DATA_SOURCE:
5194db25f66STan Xiaojun 	case ARM_SPE_TIMESTAMP:
52075eeadddSLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
52175eeadddSLeo Yan 		break;
5224db25f66STan Xiaojun 	case ARM_SPE_ADDRESS:
523ab2aa439SLeo Yan 		err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
52475eeadddSLeo Yan 		break;
5254db25f66STan Xiaojun 	case ARM_SPE_CONTEXT:
52675eeadddSLeo Yan 		arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
52775eeadddSLeo Yan 				       name, (unsigned long)payload, idx + 1);
52875eeadddSLeo Yan 		break;
52975eeadddSLeo Yan 	case ARM_SPE_COUNTER:
530c52cfe98SLeo Yan 		err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
53175eeadddSLeo Yan 		break;
53275eeadddSLeo Yan 	default:
53375eeadddSLeo Yan 		/* Unknown packet type */
53475eeadddSLeo Yan 		err = -1;
53575eeadddSLeo Yan 		break;
53675eeadddSLeo Yan 	}
5374db25f66STan Xiaojun 
53875eeadddSLeo Yan 	/* Output raw data if detect any error */
53975eeadddSLeo Yan 	if (err) {
54075eeadddSLeo Yan 		err = 0;
54175eeadddSLeo Yan 		arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
5424db25f66STan Xiaojun 				       name, payload, packet->index);
5434db25f66STan Xiaojun 	}
54475eeadddSLeo Yan 
54575eeadddSLeo Yan 	return err;
54675eeadddSLeo Yan }
547