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