1 // SPDX-License-Identifier: GPL-2.0
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
11 #include <linux/bitops.h>
14 #include "arm-spe-pkt-decoder.h"
16 #if __BYTE_ORDER == __BIG_ENDIAN
17 #define le16_to_cpu bswap_16
18 #define le32_to_cpu bswap_32
19 #define le64_to_cpu bswap_64
20 #define memcpy_le64(d, s, n) do { \
21 memcpy((d), (s), (n)); \
22 *(d) = le64_to_cpu(*(d)); \
28 #define memcpy_le64 memcpy
31 static const char * const arm_spe_packet_name[] = {
32 [ARM_SPE_PAD] = "PAD",
33 [ARM_SPE_END] = "END",
34 [ARM_SPE_TIMESTAMP] = "TS",
35 [ARM_SPE_ADDRESS] = "ADDR",
36 [ARM_SPE_COUNTER] = "LAT",
37 [ARM_SPE_CONTEXT] = "CONTEXT",
38 [ARM_SPE_OP_TYPE] = "OP-TYPE",
39 [ARM_SPE_EVENTS] = "EVENTS",
40 [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE",
43 const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
45 return arm_spe_packet_name[type];
49 * Extracts the field "sz" from header bits and converts to bytes:
55 static unsigned int arm_spe_payload_len(unsigned char hdr)
57 return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
60 static int arm_spe_get_payload(const unsigned char *buf, size_t len,
61 unsigned char ext_hdr,
62 struct arm_spe_pkt *packet)
64 size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
66 if (len < 1 + ext_hdr + payload_len)
67 return ARM_SPE_NEED_MORE_BYTES;
71 switch (payload_len) {
72 case 1: packet->payload = *(uint8_t *)buf; break;
73 case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
74 case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
75 case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
76 default: return ARM_SPE_BAD_PACKET;
79 return 1 + ext_hdr + payload_len;
82 static int arm_spe_get_pad(struct arm_spe_pkt *packet)
84 packet->type = ARM_SPE_PAD;
88 static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
89 struct arm_spe_pkt *packet)
91 unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
94 return ARM_SPE_NEED_MORE_BYTES;
96 packet->type = ARM_SPE_PAD;
97 return alignment - (((uintptr_t)buf) & (alignment - 1));
100 static int arm_spe_get_end(struct arm_spe_pkt *packet)
102 packet->type = ARM_SPE_END;
106 static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
107 struct arm_spe_pkt *packet)
109 packet->type = ARM_SPE_TIMESTAMP;
110 return arm_spe_get_payload(buf, len, 0, packet);
113 static int arm_spe_get_events(const unsigned char *buf, size_t len,
114 struct arm_spe_pkt *packet)
116 packet->type = ARM_SPE_EVENTS;
118 /* we use index to identify Events with a less number of
119 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
120 * LLC-REFILL, and REMOTE-ACCESS events are identified if
123 packet->index = arm_spe_payload_len(buf[0]);
125 return arm_spe_get_payload(buf, len, 0, packet);
128 static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
129 struct arm_spe_pkt *packet)
131 packet->type = ARM_SPE_DATA_SOURCE;
132 return arm_spe_get_payload(buf, len, 0, packet);
135 static int arm_spe_get_context(const unsigned char *buf, size_t len,
136 struct arm_spe_pkt *packet)
138 packet->type = ARM_SPE_CONTEXT;
139 packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
140 return arm_spe_get_payload(buf, len, 0, packet);
143 static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
144 struct arm_spe_pkt *packet)
146 packet->type = ARM_SPE_OP_TYPE;
147 packet->index = buf[0] & 0x3;
148 return arm_spe_get_payload(buf, len, 0, packet);
151 static int arm_spe_get_counter(const unsigned char *buf, size_t len,
152 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
154 packet->type = ARM_SPE_COUNTER;
156 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
158 packet->index = buf[0] & 0x7;
160 return arm_spe_get_payload(buf, len, ext_hdr, packet);
163 static int arm_spe_get_addr(const unsigned char *buf, size_t len,
164 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
166 packet->type = ARM_SPE_ADDRESS;
169 packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
171 packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
173 return arm_spe_get_payload(buf, len, ext_hdr, packet);
176 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
177 struct arm_spe_pkt *packet)
180 unsigned char ext_hdr = 0;
182 memset(packet, 0, sizeof(struct arm_spe_pkt));
185 return ARM_SPE_NEED_MORE_BYTES;
189 if (hdr == SPE_HEADER0_PAD)
190 return arm_spe_get_pad(packet);
192 if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
193 return arm_spe_get_end(packet);
195 if (hdr == SPE_HEADER0_TIMESTAMP)
196 return arm_spe_get_timestamp(buf, len, packet);
198 if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
199 return arm_spe_get_events(buf, len, packet);
201 if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
202 return arm_spe_get_data_source(buf, len, packet);
204 if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
205 return arm_spe_get_context(buf, len, packet);
207 if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
208 return arm_spe_get_op_type(buf, len, packet);
210 if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
211 /* 16-bit extended format header */
215 if (hdr == SPE_HEADER1_ALIGNMENT)
216 return arm_spe_get_alignment(buf, len, packet);
220 * The short format header's byte 0 or the extended format header's
221 * byte 1 has been assigned to 'hdr', which uses the same encoding for
222 * address packet and counter packet, so don't need to distinguish if
223 * it's short format or extended format and handle in once.
225 if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
226 return arm_spe_get_addr(buf, len, ext_hdr, packet);
228 if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
229 return arm_spe_get_counter(buf, len, ext_hdr, packet);
231 return ARM_SPE_BAD_PACKET;
234 int arm_spe_get_packet(const unsigned char *buf, size_t len,
235 struct arm_spe_pkt *packet)
239 ret = arm_spe_do_get_packet(buf, len, packet);
240 /* put multiple consecutive PADs on the same line, up to
241 * the fixed-width output format of 16 bytes per line.
243 if (ret > 0 && packet->type == ARM_SPE_PAD) {
244 while (ret < 16 && len > (size_t)ret && !buf[ret])
250 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
251 const char *fmt, ...)
256 /* Bail out if any error occurred */
261 ret = vsnprintf(*buf_p, *blen, fmt, ap);
269 * A return value of *blen or more means that the output was
270 * truncated and the buffer is overrun.
272 } else if ((size_t)ret >= *blen) {
273 (*buf_p)[*blen - 1] = '\0';
276 * Set *err to 'ret' to avoid overflow if tries to
277 * fill this buffer sequentially.
289 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
290 char *buf, size_t buf_len)
292 int ns, el, idx = packet->index;
293 u64 payload = packet->payload;
297 case SPE_ADDR_PKT_HDR_INDEX_INS:
298 case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
299 ns = !!SPE_ADDR_PKT_GET_NS(payload);
300 el = SPE_ADDR_PKT_GET_EL(payload);
301 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
302 arm_spe_pkt_out_string(&err, &buf, &buf_len,
303 "%s 0x%llx el%d ns=%d",
304 (idx == 1) ? "TGT" : "PC", payload, el, ns);
306 case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
307 arm_spe_pkt_out_string(&err, &buf, &buf_len,
308 "VA 0x%llx", payload);
310 case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
311 ns = !!SPE_ADDR_PKT_GET_NS(payload);
312 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
313 arm_spe_pkt_out_string(&err, &buf, &buf_len,
314 "PA 0x%llx ns=%d", payload, ns);
325 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
328 int idx = packet->index;
329 unsigned long long payload = packet->payload;
330 const char *name = arm_spe_pkt_name(packet->type);
331 char *buf_orig = buf;
332 size_t blen = buf_len;
335 switch (packet->type) {
339 arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
342 arm_spe_pkt_out_string(&err, &buf, &blen, "EV");
345 arm_spe_pkt_out_string(&err, &buf, &blen, " EXCEPTION-GEN");
347 arm_spe_pkt_out_string(&err, &buf, &blen, " RETIRED");
349 arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-ACCESS");
351 arm_spe_pkt_out_string(&err, &buf, &blen, " L1D-REFILL");
353 arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-ACCESS");
355 arm_spe_pkt_out_string(&err, &buf, &blen, " TLB-REFILL");
357 arm_spe_pkt_out_string(&err, &buf, &blen, " NOT-TAKEN");
359 arm_spe_pkt_out_string(&err, &buf, &blen, " MISPRED");
362 arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-ACCESS");
364 arm_spe_pkt_out_string(&err, &buf, &blen, " LLC-REFILL");
366 arm_spe_pkt_out_string(&err, &buf, &blen, " REMOTE-ACCESS");
369 case ARM_SPE_OP_TYPE:
372 arm_spe_pkt_out_string(&err, &buf, &blen,
373 payload & 0x1 ? "COND-SELECT" : "INSN-OTHER");
376 arm_spe_pkt_out_string(&err, &buf, &blen,
377 payload & 0x1 ? "ST" : "LD");
381 arm_spe_pkt_out_string(&err, &buf, &blen, " AT");
383 arm_spe_pkt_out_string(&err, &buf, &blen, " EXCL");
385 arm_spe_pkt_out_string(&err, &buf, &blen, " AR");
386 } else if (payload & 0x4) {
387 arm_spe_pkt_out_string(&err, &buf, &blen, " SIMD-FP");
391 arm_spe_pkt_out_string(&err, &buf, &blen, "B");
394 arm_spe_pkt_out_string(&err, &buf, &blen, " COND");
396 arm_spe_pkt_out_string(&err, &buf, &blen, " IND");
405 case ARM_SPE_DATA_SOURCE:
406 case ARM_SPE_TIMESTAMP:
407 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
409 case ARM_SPE_ADDRESS:
410 err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
412 case ARM_SPE_CONTEXT:
413 arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
414 name, (unsigned long)payload, idx + 1);
416 case ARM_SPE_COUNTER:
417 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %d ", name,
418 (unsigned short)payload);
421 arm_spe_pkt_out_string(&err, &buf, &blen, "TOT");
424 arm_spe_pkt_out_string(&err, &buf, &blen, "ISSUE");
427 arm_spe_pkt_out_string(&err, &buf, &blen, "XLAT");
434 /* Unknown packet type */
439 /* Output raw data if detect any error */
442 arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
443 name, payload, packet->index);