perf arm-spe: Add new function arm_spe_pkt_desc_op_type()
[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 #include <stdarg.h>
13
14 #include "arm-spe-pkt-decoder.h"
15
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)); \
23 } while (0)
24 #else
25 #define le16_to_cpu
26 #define le32_to_cpu
27 #define le64_to_cpu
28 #define memcpy_le64 memcpy
29 #endif
30
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",
41 };
42
43 const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
44 {
45         return arm_spe_packet_name[type];
46 }
47
48 /*
49  * Extracts the field "sz" from header bits and converts to bytes:
50  *   00 : byte (1)
51  *   01 : halfword (2)
52  *   10 : word (4)
53  *   11 : doubleword (8)
54  */
55 static unsigned int arm_spe_payload_len(unsigned char hdr)
56 {
57         return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
58 }
59
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)
63 {
64         size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
65
66         if (len < 1 + ext_hdr + payload_len)
67                 return ARM_SPE_NEED_MORE_BYTES;
68
69         buf += 1 + ext_hdr;
70
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;
77         }
78
79         return 1 + ext_hdr + payload_len;
80 }
81
82 static int arm_spe_get_pad(struct arm_spe_pkt *packet)
83 {
84         packet->type = ARM_SPE_PAD;
85         return 1;
86 }
87
88 static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
89                                  struct arm_spe_pkt *packet)
90 {
91         unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
92
93         if (len < alignment)
94                 return ARM_SPE_NEED_MORE_BYTES;
95
96         packet->type = ARM_SPE_PAD;
97         return alignment - (((uintptr_t)buf) & (alignment - 1));
98 }
99
100 static int arm_spe_get_end(struct arm_spe_pkt *packet)
101 {
102         packet->type = ARM_SPE_END;
103         return 1;
104 }
105
106 static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
107                                  struct arm_spe_pkt *packet)
108 {
109         packet->type = ARM_SPE_TIMESTAMP;
110         return arm_spe_get_payload(buf, len, 0, packet);
111 }
112
113 static int arm_spe_get_events(const unsigned char *buf, size_t len,
114                               struct arm_spe_pkt *packet)
115 {
116         packet->type = ARM_SPE_EVENTS;
117
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
121          * index > 1.
122          */
123         packet->index = arm_spe_payload_len(buf[0]);
124
125         return arm_spe_get_payload(buf, len, 0, packet);
126 }
127
128 static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
129                                    struct arm_spe_pkt *packet)
130 {
131         packet->type = ARM_SPE_DATA_SOURCE;
132         return arm_spe_get_payload(buf, len, 0, packet);
133 }
134
135 static int arm_spe_get_context(const unsigned char *buf, size_t len,
136                                struct arm_spe_pkt *packet)
137 {
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);
141 }
142
143 static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
144                                struct arm_spe_pkt *packet)
145 {
146         packet->type = ARM_SPE_OP_TYPE;
147         packet->index = buf[0] & 0x3;
148         return arm_spe_get_payload(buf, len, 0, packet);
149 }
150
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)
153 {
154         packet->type = ARM_SPE_COUNTER;
155
156         if (ext_hdr)
157                 packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
158         else
159                 packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
160
161         return arm_spe_get_payload(buf, len, ext_hdr, packet);
162 }
163
164 static int arm_spe_get_addr(const unsigned char *buf, size_t len,
165                             const unsigned char ext_hdr, struct arm_spe_pkt *packet)
166 {
167         packet->type = ARM_SPE_ADDRESS;
168
169         if (ext_hdr)
170                 packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
171         else
172                 packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
173
174         return arm_spe_get_payload(buf, len, ext_hdr, packet);
175 }
176
177 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
178                                  struct arm_spe_pkt *packet)
179 {
180         unsigned int hdr;
181         unsigned char ext_hdr = 0;
182
183         memset(packet, 0, sizeof(struct arm_spe_pkt));
184
185         if (!len)
186                 return ARM_SPE_NEED_MORE_BYTES;
187
188         hdr = buf[0];
189
190         if (hdr == SPE_HEADER0_PAD)
191                 return arm_spe_get_pad(packet);
192
193         if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
194                 return arm_spe_get_end(packet);
195
196         if (hdr == SPE_HEADER0_TIMESTAMP)
197                 return arm_spe_get_timestamp(buf, len, packet);
198
199         if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
200                 return arm_spe_get_events(buf, len, packet);
201
202         if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
203                 return arm_spe_get_data_source(buf, len, packet);
204
205         if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
206                 return arm_spe_get_context(buf, len, packet);
207
208         if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
209                 return arm_spe_get_op_type(buf, len, packet);
210
211         if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
212                 /* 16-bit extended format header */
213                 ext_hdr = 1;
214
215                 hdr = buf[1];
216                 if (hdr == SPE_HEADER1_ALIGNMENT)
217                         return arm_spe_get_alignment(buf, len, packet);
218         }
219
220         /*
221          * The short format header's byte 0 or the extended format header's
222          * byte 1 has been assigned to 'hdr', which uses the same encoding for
223          * address packet and counter packet, so don't need to distinguish if
224          * it's short format or extended format and handle in once.
225          */
226         if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
227                 return arm_spe_get_addr(buf, len, ext_hdr, packet);
228
229         if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
230                 return arm_spe_get_counter(buf, len, ext_hdr, packet);
231
232         return ARM_SPE_BAD_PACKET;
233 }
234
235 int arm_spe_get_packet(const unsigned char *buf, size_t len,
236                        struct arm_spe_pkt *packet)
237 {
238         int ret;
239
240         ret = arm_spe_do_get_packet(buf, len, packet);
241         /* put multiple consecutive PADs on the same line, up to
242          * the fixed-width output format of 16 bytes per line.
243          */
244         if (ret > 0 && packet->type == ARM_SPE_PAD) {
245                 while (ret < 16 && len > (size_t)ret && !buf[ret])
246                         ret += 1;
247         }
248         return ret;
249 }
250
251 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
252                                   const char *fmt, ...)
253 {
254         va_list ap;
255         int ret;
256
257         /* Bail out if any error occurred */
258         if (err && *err)
259                 return *err;
260
261         va_start(ap, fmt);
262         ret = vsnprintf(*buf_p, *blen, fmt, ap);
263         va_end(ap);
264
265         if (ret < 0) {
266                 if (err && !*err)
267                         *err = ret;
268
269         /*
270          * A return value of *blen or more means that the output was
271          * truncated and the buffer is overrun.
272          */
273         } else if ((size_t)ret >= *blen) {
274                 (*buf_p)[*blen - 1] = '\0';
275
276                 /*
277                  * Set *err to 'ret' to avoid overflow if tries to
278                  * fill this buffer sequentially.
279                  */
280                 if (err && !*err)
281                         *err = ret;
282         } else {
283                 *buf_p += ret;
284                 *blen -= ret;
285         }
286
287         return ret;
288 }
289
290 static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
291                                   char *buf, size_t buf_len)
292 {
293         u64 payload = packet->payload;
294         int err = 0;
295
296         arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
297
298         if (payload & BIT(EV_EXCEPTION_GEN))
299                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
300         if (payload & BIT(EV_RETIRED))
301                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
302         if (payload & BIT(EV_L1D_ACCESS))
303                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
304         if (payload & BIT(EV_L1D_REFILL))
305                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
306         if (payload & BIT(EV_TLB_ACCESS))
307                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
308         if (payload & BIT(EV_TLB_WALK))
309                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
310         if (payload & BIT(EV_NOT_TAKEN))
311                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
312         if (payload & BIT(EV_MISPRED))
313                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
314         if (payload & BIT(EV_LLC_ACCESS))
315                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
316         if (payload & BIT(EV_LLC_MISS))
317                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
318         if (payload & BIT(EV_REMOTE_ACCESS))
319                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
320
321         return err;
322 }
323
324 static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
325                                     char *buf, size_t buf_len)
326 {
327         u64 payload = packet->payload;
328         int err = 0;
329
330         switch (packet->index) {
331         case 0:
332                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
333                                 payload & 0x1 ? "COND-SELECT" : "INSN-OTHER");
334                 break;
335         case 1:
336                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
337                                        payload & 0x1 ? "ST" : "LD");
338
339                 if (payload & 0x2) {
340                         if (payload & 0x4)
341                                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
342                         if (payload & 0x8)
343                                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
344                         if (payload & 0x10)
345                                 arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
346                 } else if (payload & 0x4) {
347                         arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
348                 }
349                 break;
350         case 2:
351                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
352
353                 if (payload & 0x1)
354                         arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
355                 if (payload & 0x2)
356                         arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
357
358                 break;
359         default:
360                 /* Unknown index */
361                 err = -1;
362                 break;
363         }
364
365         return err;
366 }
367
368 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
369                                  char *buf, size_t buf_len)
370 {
371         int ns, el, idx = packet->index;
372         u64 payload = packet->payload;
373         int err = 0;
374
375         switch (idx) {
376         case SPE_ADDR_PKT_HDR_INDEX_INS:
377         case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
378                 ns = !!SPE_ADDR_PKT_GET_NS(payload);
379                 el = SPE_ADDR_PKT_GET_EL(payload);
380                 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
381                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
382                                 "%s 0x%llx el%d ns=%d",
383                                 (idx == 1) ? "TGT" : "PC", payload, el, ns);
384                 break;
385         case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
386                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
387                                        "VA 0x%llx", payload);
388                 break;
389         case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
390                 ns = !!SPE_ADDR_PKT_GET_NS(payload);
391                 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
392                 arm_spe_pkt_out_string(&err, &buf, &buf_len,
393                                        "PA 0x%llx ns=%d", payload, ns);
394                 break;
395         default:
396                 /* Unknown index */
397                 err = -1;
398                 break;
399         }
400
401         return err;
402 }
403
404 static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
405                                     char *buf, size_t buf_len)
406 {
407         u64 payload = packet->payload;
408         const char *name = arm_spe_pkt_name(packet->type);
409         int err = 0;
410
411         arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
412                                (unsigned short)payload);
413
414         switch (packet->index) {
415         case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
416                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
417                 break;
418         case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
419                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
420                 break;
421         case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
422                 arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
423                 break;
424         default:
425                 break;
426         }
427
428         return err;
429 }
430
431 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
432                      size_t buf_len)
433 {
434         int idx = packet->index;
435         unsigned long long payload = packet->payload;
436         const char *name = arm_spe_pkt_name(packet->type);
437         char *buf_orig = buf;
438         size_t blen = buf_len;
439         int err = 0;
440
441         switch (packet->type) {
442         case ARM_SPE_BAD:
443         case ARM_SPE_PAD:
444         case ARM_SPE_END:
445                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
446                 break;
447         case ARM_SPE_EVENTS:
448                 err = arm_spe_pkt_desc_event(packet, buf, buf_len);
449                 break;
450         case ARM_SPE_OP_TYPE:
451                 err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
452                 break;
453         case ARM_SPE_DATA_SOURCE:
454         case ARM_SPE_TIMESTAMP:
455                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
456                 break;
457         case ARM_SPE_ADDRESS:
458                 err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
459                 break;
460         case ARM_SPE_CONTEXT:
461                 arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
462                                        name, (unsigned long)payload, idx + 1);
463                 break;
464         case ARM_SPE_COUNTER:
465                 err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
466                 break;
467         default:
468                 /* Unknown packet type */
469                 err = -1;
470                 break;
471         }
472
473         /* Output raw data if detect any error */
474         if (err) {
475                 err = 0;
476                 arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
477                                        name, payload, packet->index);
478         }
479
480         return err;
481 }