1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Arm Statistical Profiling Extensions (SPE) support
4*4882a593Smuzhiyun * Copyright (c) 2017-2018, Arm Ltd.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <stdio.h>
8*4882a593Smuzhiyun #include <string.h>
9*4882a593Smuzhiyun #include <endian.h>
10*4882a593Smuzhiyun #include <byteswap.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include "arm-spe-pkt-decoder.h"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define BIT(n) (1ULL << (n))
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define NS_FLAG BIT(63)
17*4882a593Smuzhiyun #define EL_FLAG (BIT(62) | BIT(61))
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define SPE_HEADER0_PAD 0x0
20*4882a593Smuzhiyun #define SPE_HEADER0_END 0x1
21*4882a593Smuzhiyun #define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */
22*4882a593Smuzhiyun #define SPE_HEADER0_ADDRESS_MASK 0x38
23*4882a593Smuzhiyun #define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */
24*4882a593Smuzhiyun #define SPE_HEADER0_COUNTER_MASK 0x38
25*4882a593Smuzhiyun #define SPE_HEADER0_TIMESTAMP 0x71
26*4882a593Smuzhiyun #define SPE_HEADER0_TIMESTAMP 0x71
27*4882a593Smuzhiyun #define SPE_HEADER0_EVENTS 0x2
28*4882a593Smuzhiyun #define SPE_HEADER0_EVENTS_MASK 0xf
29*4882a593Smuzhiyun #define SPE_HEADER0_SOURCE 0x3
30*4882a593Smuzhiyun #define SPE_HEADER0_SOURCE_MASK 0xf
31*4882a593Smuzhiyun #define SPE_HEADER0_CONTEXT 0x24
32*4882a593Smuzhiyun #define SPE_HEADER0_CONTEXT_MASK 0x3c
33*4882a593Smuzhiyun #define SPE_HEADER0_OP_TYPE 0x8
34*4882a593Smuzhiyun #define SPE_HEADER0_OP_TYPE_MASK 0x3c
35*4882a593Smuzhiyun #define SPE_HEADER1_ALIGNMENT 0x0
36*4882a593Smuzhiyun #define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */
37*4882a593Smuzhiyun #define SPE_HEADER1_ADDRESS_MASK 0xf8
38*4882a593Smuzhiyun #define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */
39*4882a593Smuzhiyun #define SPE_HEADER1_COUNTER_MASK 0xf8
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #if __BYTE_ORDER == __BIG_ENDIAN
42*4882a593Smuzhiyun #define le16_to_cpu bswap_16
43*4882a593Smuzhiyun #define le32_to_cpu bswap_32
44*4882a593Smuzhiyun #define le64_to_cpu bswap_64
45*4882a593Smuzhiyun #define memcpy_le64(d, s, n) do { \
46*4882a593Smuzhiyun memcpy((d), (s), (n)); \
47*4882a593Smuzhiyun *(d) = le64_to_cpu(*(d)); \
48*4882a593Smuzhiyun } while (0)
49*4882a593Smuzhiyun #else
50*4882a593Smuzhiyun #define le16_to_cpu
51*4882a593Smuzhiyun #define le32_to_cpu
52*4882a593Smuzhiyun #define le64_to_cpu
53*4882a593Smuzhiyun #define memcpy_le64 memcpy
54*4882a593Smuzhiyun #endif
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun static const char * const arm_spe_packet_name[] = {
57*4882a593Smuzhiyun [ARM_SPE_PAD] = "PAD",
58*4882a593Smuzhiyun [ARM_SPE_END] = "END",
59*4882a593Smuzhiyun [ARM_SPE_TIMESTAMP] = "TS",
60*4882a593Smuzhiyun [ARM_SPE_ADDRESS] = "ADDR",
61*4882a593Smuzhiyun [ARM_SPE_COUNTER] = "LAT",
62*4882a593Smuzhiyun [ARM_SPE_CONTEXT] = "CONTEXT",
63*4882a593Smuzhiyun [ARM_SPE_OP_TYPE] = "OP-TYPE",
64*4882a593Smuzhiyun [ARM_SPE_EVENTS] = "EVENTS",
65*4882a593Smuzhiyun [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE",
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun
arm_spe_pkt_name(enum arm_spe_pkt_type type)68*4882a593Smuzhiyun const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun return arm_spe_packet_name[type];
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* return ARM SPE payload size from its encoding,
74*4882a593Smuzhiyun * which is in bits 5:4 of the byte.
75*4882a593Smuzhiyun * 00 : byte
76*4882a593Smuzhiyun * 01 : halfword (2)
77*4882a593Smuzhiyun * 10 : word (4)
78*4882a593Smuzhiyun * 11 : doubleword (8)
79*4882a593Smuzhiyun */
payloadlen(unsigned char byte)80*4882a593Smuzhiyun static int payloadlen(unsigned char byte)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun return 1 << ((byte & 0x30) >> 4);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
arm_spe_get_payload(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)85*4882a593Smuzhiyun static int arm_spe_get_payload(const unsigned char *buf, size_t len,
86*4882a593Smuzhiyun struct arm_spe_pkt *packet)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun size_t payload_len = payloadlen(buf[0]);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (len < 1 + payload_len)
91*4882a593Smuzhiyun return ARM_SPE_NEED_MORE_BYTES;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun buf++;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun switch (payload_len) {
96*4882a593Smuzhiyun case 1: packet->payload = *(uint8_t *)buf; break;
97*4882a593Smuzhiyun case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
98*4882a593Smuzhiyun case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
99*4882a593Smuzhiyun case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
100*4882a593Smuzhiyun default: return ARM_SPE_BAD_PACKET;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return 1 + payload_len;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
arm_spe_get_pad(struct arm_spe_pkt * packet)106*4882a593Smuzhiyun static int arm_spe_get_pad(struct arm_spe_pkt *packet)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun packet->type = ARM_SPE_PAD;
109*4882a593Smuzhiyun return 1;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
arm_spe_get_alignment(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)112*4882a593Smuzhiyun static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
113*4882a593Smuzhiyun struct arm_spe_pkt *packet)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (len < alignment)
118*4882a593Smuzhiyun return ARM_SPE_NEED_MORE_BYTES;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun packet->type = ARM_SPE_PAD;
121*4882a593Smuzhiyun return alignment - (((uintptr_t)buf) & (alignment - 1));
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
arm_spe_get_end(struct arm_spe_pkt * packet)124*4882a593Smuzhiyun static int arm_spe_get_end(struct arm_spe_pkt *packet)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun packet->type = ARM_SPE_END;
127*4882a593Smuzhiyun return 1;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
arm_spe_get_timestamp(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)130*4882a593Smuzhiyun static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
131*4882a593Smuzhiyun struct arm_spe_pkt *packet)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun packet->type = ARM_SPE_TIMESTAMP;
134*4882a593Smuzhiyun return arm_spe_get_payload(buf, len, packet);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
arm_spe_get_events(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)137*4882a593Smuzhiyun static int arm_spe_get_events(const unsigned char *buf, size_t len,
138*4882a593Smuzhiyun struct arm_spe_pkt *packet)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun int ret = arm_spe_get_payload(buf, len, packet);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun packet->type = ARM_SPE_EVENTS;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* we use index to identify Events with a less number of
145*4882a593Smuzhiyun * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
146*4882a593Smuzhiyun * LLC-REFILL, and REMOTE-ACCESS events are identified iff
147*4882a593Smuzhiyun * index > 1.
148*4882a593Smuzhiyun */
149*4882a593Smuzhiyun packet->index = ret - 1;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return ret;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
arm_spe_get_data_source(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)154*4882a593Smuzhiyun static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
155*4882a593Smuzhiyun struct arm_spe_pkt *packet)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun packet->type = ARM_SPE_DATA_SOURCE;
158*4882a593Smuzhiyun return arm_spe_get_payload(buf, len, packet);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
arm_spe_get_context(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)161*4882a593Smuzhiyun static int arm_spe_get_context(const unsigned char *buf, size_t len,
162*4882a593Smuzhiyun struct arm_spe_pkt *packet)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun packet->type = ARM_SPE_CONTEXT;
165*4882a593Smuzhiyun packet->index = buf[0] & 0x3;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun return arm_spe_get_payload(buf, len, packet);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
arm_spe_get_op_type(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)170*4882a593Smuzhiyun static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
171*4882a593Smuzhiyun struct arm_spe_pkt *packet)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun packet->type = ARM_SPE_OP_TYPE;
174*4882a593Smuzhiyun packet->index = buf[0] & 0x3;
175*4882a593Smuzhiyun return arm_spe_get_payload(buf, len, packet);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
arm_spe_get_counter(const unsigned char * buf,size_t len,const unsigned char ext_hdr,struct arm_spe_pkt * packet)178*4882a593Smuzhiyun static int arm_spe_get_counter(const unsigned char *buf, size_t len,
179*4882a593Smuzhiyun const unsigned char ext_hdr, struct arm_spe_pkt *packet)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun if (len < 2)
182*4882a593Smuzhiyun return ARM_SPE_NEED_MORE_BYTES;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun packet->type = ARM_SPE_COUNTER;
185*4882a593Smuzhiyun if (ext_hdr)
186*4882a593Smuzhiyun packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
187*4882a593Smuzhiyun else
188*4882a593Smuzhiyun packet->index = buf[0] & 0x7;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1));
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun return 1 + ext_hdr + 2;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
arm_spe_get_addr(const unsigned char * buf,size_t len,const unsigned char ext_hdr,struct arm_spe_pkt * packet)195*4882a593Smuzhiyun static int arm_spe_get_addr(const unsigned char *buf, size_t len,
196*4882a593Smuzhiyun const unsigned char ext_hdr, struct arm_spe_pkt *packet)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun if (len < 8)
199*4882a593Smuzhiyun return ARM_SPE_NEED_MORE_BYTES;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun packet->type = ARM_SPE_ADDRESS;
202*4882a593Smuzhiyun if (ext_hdr)
203*4882a593Smuzhiyun packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
204*4882a593Smuzhiyun else
205*4882a593Smuzhiyun packet->index = buf[0] & 0x7;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun memcpy_le64(&packet->payload, buf + 1, 8);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun return 1 + ext_hdr + 8;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
arm_spe_do_get_packet(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)212*4882a593Smuzhiyun static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
213*4882a593Smuzhiyun struct arm_spe_pkt *packet)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun unsigned int byte;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun memset(packet, 0, sizeof(struct arm_spe_pkt));
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (!len)
220*4882a593Smuzhiyun return ARM_SPE_NEED_MORE_BYTES;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun byte = buf[0];
223*4882a593Smuzhiyun if (byte == SPE_HEADER0_PAD)
224*4882a593Smuzhiyun return arm_spe_get_pad(packet);
225*4882a593Smuzhiyun else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */
226*4882a593Smuzhiyun return arm_spe_get_end(packet);
227*4882a593Smuzhiyun else if (byte & 0xc0 /* 0y11xxxxxx */) {
228*4882a593Smuzhiyun if (byte & 0x80) {
229*4882a593Smuzhiyun if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS)
230*4882a593Smuzhiyun return arm_spe_get_addr(buf, len, 0, packet);
231*4882a593Smuzhiyun if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER)
232*4882a593Smuzhiyun return arm_spe_get_counter(buf, len, 0, packet);
233*4882a593Smuzhiyun } else
234*4882a593Smuzhiyun if (byte == SPE_HEADER0_TIMESTAMP)
235*4882a593Smuzhiyun return arm_spe_get_timestamp(buf, len, packet);
236*4882a593Smuzhiyun else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS)
237*4882a593Smuzhiyun return arm_spe_get_events(buf, len, packet);
238*4882a593Smuzhiyun else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE)
239*4882a593Smuzhiyun return arm_spe_get_data_source(buf, len, packet);
240*4882a593Smuzhiyun else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT)
241*4882a593Smuzhiyun return arm_spe_get_context(buf, len, packet);
242*4882a593Smuzhiyun else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE)
243*4882a593Smuzhiyun return arm_spe_get_op_type(buf, len, packet);
244*4882a593Smuzhiyun } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) {
245*4882a593Smuzhiyun /* 16-bit header */
246*4882a593Smuzhiyun byte = buf[1];
247*4882a593Smuzhiyun if (byte == SPE_HEADER1_ALIGNMENT)
248*4882a593Smuzhiyun return arm_spe_get_alignment(buf, len, packet);
249*4882a593Smuzhiyun else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS)
250*4882a593Smuzhiyun return arm_spe_get_addr(buf, len, 1, packet);
251*4882a593Smuzhiyun else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER)
252*4882a593Smuzhiyun return arm_spe_get_counter(buf, len, 1, packet);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun return ARM_SPE_BAD_PACKET;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
arm_spe_get_packet(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)258*4882a593Smuzhiyun int arm_spe_get_packet(const unsigned char *buf, size_t len,
259*4882a593Smuzhiyun struct arm_spe_pkt *packet)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun int ret;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun ret = arm_spe_do_get_packet(buf, len, packet);
264*4882a593Smuzhiyun /* put multiple consecutive PADs on the same line, up to
265*4882a593Smuzhiyun * the fixed-width output format of 16 bytes per line.
266*4882a593Smuzhiyun */
267*4882a593Smuzhiyun if (ret > 0 && packet->type == ARM_SPE_PAD) {
268*4882a593Smuzhiyun while (ret < 16 && len > (size_t)ret && !buf[ret])
269*4882a593Smuzhiyun ret += 1;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun return ret;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
arm_spe_pkt_desc(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)274*4882a593Smuzhiyun int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
275*4882a593Smuzhiyun size_t buf_len)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun int ret, ns, el, idx = packet->index;
278*4882a593Smuzhiyun unsigned long long payload = packet->payload;
279*4882a593Smuzhiyun const char *name = arm_spe_pkt_name(packet->type);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun switch (packet->type) {
282*4882a593Smuzhiyun case ARM_SPE_BAD:
283*4882a593Smuzhiyun case ARM_SPE_PAD:
284*4882a593Smuzhiyun case ARM_SPE_END:
285*4882a593Smuzhiyun return snprintf(buf, buf_len, "%s", name);
286*4882a593Smuzhiyun case ARM_SPE_EVENTS: {
287*4882a593Smuzhiyun size_t blen = buf_len;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun ret = 0;
290*4882a593Smuzhiyun ret = snprintf(buf, buf_len, "EV");
291*4882a593Smuzhiyun buf += ret;
292*4882a593Smuzhiyun blen -= ret;
293*4882a593Smuzhiyun if (payload & 0x1) {
294*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " EXCEPTION-GEN");
295*4882a593Smuzhiyun buf += ret;
296*4882a593Smuzhiyun blen -= ret;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun if (payload & 0x2) {
299*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " RETIRED");
300*4882a593Smuzhiyun buf += ret;
301*4882a593Smuzhiyun blen -= ret;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun if (payload & 0x4) {
304*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " L1D-ACCESS");
305*4882a593Smuzhiyun buf += ret;
306*4882a593Smuzhiyun blen -= ret;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun if (payload & 0x8) {
309*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " L1D-REFILL");
310*4882a593Smuzhiyun buf += ret;
311*4882a593Smuzhiyun blen -= ret;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun if (payload & 0x10) {
314*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " TLB-ACCESS");
315*4882a593Smuzhiyun buf += ret;
316*4882a593Smuzhiyun blen -= ret;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun if (payload & 0x20) {
319*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " TLB-REFILL");
320*4882a593Smuzhiyun buf += ret;
321*4882a593Smuzhiyun blen -= ret;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun if (payload & 0x40) {
324*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " NOT-TAKEN");
325*4882a593Smuzhiyun buf += ret;
326*4882a593Smuzhiyun blen -= ret;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun if (payload & 0x80) {
329*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " MISPRED");
330*4882a593Smuzhiyun buf += ret;
331*4882a593Smuzhiyun blen -= ret;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun if (idx > 1) {
334*4882a593Smuzhiyun if (payload & 0x100) {
335*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " LLC-ACCESS");
336*4882a593Smuzhiyun buf += ret;
337*4882a593Smuzhiyun blen -= ret;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun if (payload & 0x200) {
340*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " LLC-REFILL");
341*4882a593Smuzhiyun buf += ret;
342*4882a593Smuzhiyun blen -= ret;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun if (payload & 0x400) {
345*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " REMOTE-ACCESS");
346*4882a593Smuzhiyun buf += ret;
347*4882a593Smuzhiyun blen -= ret;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun if (ret < 0)
351*4882a593Smuzhiyun return ret;
352*4882a593Smuzhiyun blen -= ret;
353*4882a593Smuzhiyun return buf_len - blen;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun case ARM_SPE_OP_TYPE:
356*4882a593Smuzhiyun switch (idx) {
357*4882a593Smuzhiyun case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ?
358*4882a593Smuzhiyun "COND-SELECT" : "INSN-OTHER");
359*4882a593Smuzhiyun case 1: {
360*4882a593Smuzhiyun size_t blen = buf_len;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (payload & 0x1)
363*4882a593Smuzhiyun ret = snprintf(buf, buf_len, "ST");
364*4882a593Smuzhiyun else
365*4882a593Smuzhiyun ret = snprintf(buf, buf_len, "LD");
366*4882a593Smuzhiyun buf += ret;
367*4882a593Smuzhiyun blen -= ret;
368*4882a593Smuzhiyun if (payload & 0x2) {
369*4882a593Smuzhiyun if (payload & 0x4) {
370*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " AT");
371*4882a593Smuzhiyun buf += ret;
372*4882a593Smuzhiyun blen -= ret;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun if (payload & 0x8) {
375*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " EXCL");
376*4882a593Smuzhiyun buf += ret;
377*4882a593Smuzhiyun blen -= ret;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun if (payload & 0x10) {
380*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " AR");
381*4882a593Smuzhiyun buf += ret;
382*4882a593Smuzhiyun blen -= ret;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun } else if (payload & 0x4) {
385*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " SIMD-FP");
386*4882a593Smuzhiyun buf += ret;
387*4882a593Smuzhiyun blen -= ret;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun if (ret < 0)
390*4882a593Smuzhiyun return ret;
391*4882a593Smuzhiyun blen -= ret;
392*4882a593Smuzhiyun return buf_len - blen;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun case 2: {
395*4882a593Smuzhiyun size_t blen = buf_len;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun ret = snprintf(buf, buf_len, "B");
398*4882a593Smuzhiyun buf += ret;
399*4882a593Smuzhiyun blen -= ret;
400*4882a593Smuzhiyun if (payload & 0x1) {
401*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " COND");
402*4882a593Smuzhiyun buf += ret;
403*4882a593Smuzhiyun blen -= ret;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun if (payload & 0x2) {
406*4882a593Smuzhiyun ret = snprintf(buf, buf_len, " IND");
407*4882a593Smuzhiyun buf += ret;
408*4882a593Smuzhiyun blen -= ret;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun if (ret < 0)
411*4882a593Smuzhiyun return ret;
412*4882a593Smuzhiyun blen -= ret;
413*4882a593Smuzhiyun return buf_len - blen;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun default: return 0;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun case ARM_SPE_DATA_SOURCE:
418*4882a593Smuzhiyun case ARM_SPE_TIMESTAMP:
419*4882a593Smuzhiyun return snprintf(buf, buf_len, "%s %lld", name, payload);
420*4882a593Smuzhiyun case ARM_SPE_ADDRESS:
421*4882a593Smuzhiyun switch (idx) {
422*4882a593Smuzhiyun case 0:
423*4882a593Smuzhiyun case 1: ns = !!(packet->payload & NS_FLAG);
424*4882a593Smuzhiyun el = (packet->payload & EL_FLAG) >> 61;
425*4882a593Smuzhiyun payload &= ~(0xffULL << 56);
426*4882a593Smuzhiyun return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d",
427*4882a593Smuzhiyun (idx == 1) ? "TGT" : "PC", payload, el, ns);
428*4882a593Smuzhiyun case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload);
429*4882a593Smuzhiyun case 3: ns = !!(packet->payload & NS_FLAG);
430*4882a593Smuzhiyun payload &= ~(0xffULL << 56);
431*4882a593Smuzhiyun return snprintf(buf, buf_len, "PA 0x%llx ns=%d",
432*4882a593Smuzhiyun payload, ns);
433*4882a593Smuzhiyun default: return 0;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun case ARM_SPE_CONTEXT:
436*4882a593Smuzhiyun return snprintf(buf, buf_len, "%s 0x%lx el%d", name,
437*4882a593Smuzhiyun (unsigned long)payload, idx + 1);
438*4882a593Smuzhiyun case ARM_SPE_COUNTER: {
439*4882a593Smuzhiyun size_t blen = buf_len;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun ret = snprintf(buf, buf_len, "%s %d ", name,
442*4882a593Smuzhiyun (unsigned short)payload);
443*4882a593Smuzhiyun buf += ret;
444*4882a593Smuzhiyun blen -= ret;
445*4882a593Smuzhiyun switch (idx) {
446*4882a593Smuzhiyun case 0: ret = snprintf(buf, buf_len, "TOT"); break;
447*4882a593Smuzhiyun case 1: ret = snprintf(buf, buf_len, "ISSUE"); break;
448*4882a593Smuzhiyun case 2: ret = snprintf(buf, buf_len, "XLAT"); break;
449*4882a593Smuzhiyun default: ret = 0;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun if (ret < 0)
452*4882a593Smuzhiyun return ret;
453*4882a593Smuzhiyun blen -= ret;
454*4882a593Smuzhiyun return buf_len - blen;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun default:
457*4882a593Smuzhiyun break;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return snprintf(buf, buf_len, "%s 0x%llx (%d)",
461*4882a593Smuzhiyun name, payload, packet->index);
462*4882a593Smuzhiyun }
463