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