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 #include <linux/kernel.h>
14 #include <linux/unaligned.h>
15
16 #include "arm-spe-pkt-decoder.h"
17
18 static const char * const arm_spe_packet_name[] = {
19 [ARM_SPE_PAD] = "PAD",
20 [ARM_SPE_END] = "END",
21 [ARM_SPE_TIMESTAMP] = "TS",
22 [ARM_SPE_ADDRESS] = "ADDR",
23 [ARM_SPE_COUNTER] = "LAT",
24 [ARM_SPE_CONTEXT] = "CONTEXT",
25 [ARM_SPE_OP_TYPE] = "OP-TYPE",
26 [ARM_SPE_EVENTS] = "EVENTS",
27 [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE",
28 };
29
arm_spe_pkt_name(enum arm_spe_pkt_type type)30 const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
31 {
32 return arm_spe_packet_name[type];
33 }
34
35 /*
36 * Extracts the field "sz" from header bits and converts to bytes:
37 * 00 : byte (1)
38 * 01 : halfword (2)
39 * 10 : word (4)
40 * 11 : doubleword (8)
41 */
arm_spe_payload_len(unsigned char hdr)42 static unsigned int arm_spe_payload_len(unsigned char hdr)
43 {
44 return 1U << ((hdr & GENMASK_ULL(5, 4)) >> 4);
45 }
46
arm_spe_get_payload(const unsigned char * buf,size_t len,unsigned char ext_hdr,struct arm_spe_pkt * packet)47 static int arm_spe_get_payload(const unsigned char *buf, size_t len,
48 unsigned char ext_hdr,
49 struct arm_spe_pkt *packet)
50 {
51 size_t payload_len = arm_spe_payload_len(buf[ext_hdr]);
52
53 if (len < 1 + ext_hdr + payload_len)
54 return ARM_SPE_NEED_MORE_BYTES;
55
56 buf += 1 + ext_hdr;
57
58 switch (payload_len) {
59 case 1: packet->payload = *(uint8_t *)buf; break;
60 case 2: packet->payload = get_unaligned_le16(buf); break;
61 case 4: packet->payload = get_unaligned_le32(buf); break;
62 case 8: packet->payload = get_unaligned_le64(buf); break;
63 default: return ARM_SPE_BAD_PACKET;
64 }
65
66 return 1 + ext_hdr + payload_len;
67 }
68
arm_spe_get_pad(struct arm_spe_pkt * packet)69 static int arm_spe_get_pad(struct arm_spe_pkt *packet)
70 {
71 packet->type = ARM_SPE_PAD;
72 return 1;
73 }
74
arm_spe_get_alignment(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)75 static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
76 struct arm_spe_pkt *packet)
77 {
78 unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
79
80 if (len < alignment)
81 return ARM_SPE_NEED_MORE_BYTES;
82
83 packet->type = ARM_SPE_PAD;
84 return alignment - (((uintptr_t)buf) & (alignment - 1));
85 }
86
arm_spe_get_end(struct arm_spe_pkt * packet)87 static int arm_spe_get_end(struct arm_spe_pkt *packet)
88 {
89 packet->type = ARM_SPE_END;
90 return 1;
91 }
92
arm_spe_get_timestamp(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)93 static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
94 struct arm_spe_pkt *packet)
95 {
96 packet->type = ARM_SPE_TIMESTAMP;
97 return arm_spe_get_payload(buf, len, 0, packet);
98 }
99
arm_spe_get_events(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)100 static int arm_spe_get_events(const unsigned char *buf, size_t len,
101 struct arm_spe_pkt *packet)
102 {
103 packet->type = ARM_SPE_EVENTS;
104
105 /* we use index to identify Events with a less number of
106 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
107 * LLC-REFILL, and REMOTE-ACCESS events are identified if
108 * index > 1.
109 */
110 packet->index = arm_spe_payload_len(buf[0]);
111
112 return arm_spe_get_payload(buf, len, 0, packet);
113 }
114
arm_spe_get_data_source(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)115 static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
116 struct arm_spe_pkt *packet)
117 {
118 packet->type = ARM_SPE_DATA_SOURCE;
119 return arm_spe_get_payload(buf, len, 0, packet);
120 }
121
arm_spe_get_context(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)122 static int arm_spe_get_context(const unsigned char *buf, size_t len,
123 struct arm_spe_pkt *packet)
124 {
125 packet->type = ARM_SPE_CONTEXT;
126 packet->index = SPE_CTX_PKT_HDR_INDEX(buf[0]);
127 return arm_spe_get_payload(buf, len, 0, packet);
128 }
129
arm_spe_get_op_type(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)130 static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
131 struct arm_spe_pkt *packet)
132 {
133 packet->type = ARM_SPE_OP_TYPE;
134 packet->index = SPE_OP_PKT_HDR_CLASS(buf[0]);
135 return arm_spe_get_payload(buf, len, 0, packet);
136 }
137
arm_spe_get_counter(const unsigned char * buf,size_t len,const unsigned char ext_hdr,struct arm_spe_pkt * packet)138 static int arm_spe_get_counter(const unsigned char *buf, size_t len,
139 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
140 {
141 packet->type = ARM_SPE_COUNTER;
142
143 if (ext_hdr)
144 packet->index = SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
145 else
146 packet->index = SPE_HDR_SHORT_INDEX(buf[0]);
147
148 return arm_spe_get_payload(buf, len, ext_hdr, packet);
149 }
150
arm_spe_get_addr(const unsigned char * buf,size_t len,const unsigned char ext_hdr,struct arm_spe_pkt * packet)151 static int arm_spe_get_addr(const unsigned char *buf, size_t len,
152 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
153 {
154 packet->type = ARM_SPE_ADDRESS;
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
arm_spe_do_get_packet(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)164 static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
165 struct arm_spe_pkt *packet)
166 {
167 unsigned int hdr;
168 unsigned char ext_hdr = 0;
169
170 memset(packet, 0, sizeof(struct arm_spe_pkt));
171
172 if (!len)
173 return ARM_SPE_NEED_MORE_BYTES;
174
175 hdr = buf[0];
176
177 if (hdr == SPE_HEADER0_PAD)
178 return arm_spe_get_pad(packet);
179
180 if (hdr == SPE_HEADER0_END) /* no timestamp at end of record */
181 return arm_spe_get_end(packet);
182
183 if (hdr == SPE_HEADER0_TIMESTAMP)
184 return arm_spe_get_timestamp(buf, len, packet);
185
186 if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_EVENTS)
187 return arm_spe_get_events(buf, len, packet);
188
189 if ((hdr & SPE_HEADER0_MASK1) == SPE_HEADER0_SOURCE)
190 return arm_spe_get_data_source(buf, len, packet);
191
192 if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_CONTEXT)
193 return arm_spe_get_context(buf, len, packet);
194
195 if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_OP_TYPE)
196 return arm_spe_get_op_type(buf, len, packet);
197
198 if ((hdr & SPE_HEADER0_MASK2) == SPE_HEADER0_EXTENDED) {
199 /* 16-bit extended format header */
200 if (len == 1)
201 return ARM_SPE_BAD_PACKET;
202
203 ext_hdr = 1;
204 hdr = buf[1];
205 if (hdr == SPE_HEADER1_ALIGNMENT)
206 return arm_spe_get_alignment(buf, len, packet);
207 }
208
209 /*
210 * The short format header's byte 0 or the extended format header's
211 * byte 1 has been assigned to 'hdr', which uses the same encoding for
212 * address packet and counter packet, so don't need to distinguish if
213 * it's short format or extended format and handle in once.
214 */
215 if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_ADDRESS)
216 return arm_spe_get_addr(buf, len, ext_hdr, packet);
217
218 if ((hdr & SPE_HEADER0_MASK3) == SPE_HEADER0_COUNTER)
219 return arm_spe_get_counter(buf, len, ext_hdr, packet);
220
221 return ARM_SPE_BAD_PACKET;
222 }
223
arm_spe_get_packet(const unsigned char * buf,size_t len,struct arm_spe_pkt * packet)224 int arm_spe_get_packet(const unsigned char *buf, size_t len,
225 struct arm_spe_pkt *packet)
226 {
227 int ret;
228
229 ret = arm_spe_do_get_packet(buf, len, packet);
230 /* put multiple consecutive PADs on the same line, up to
231 * the fixed-width output format of 16 bytes per line.
232 */
233 if (ret > 0 && packet->type == ARM_SPE_PAD) {
234 while (ret < 16 && len > (size_t)ret && !buf[ret])
235 ret += 1;
236 }
237 return ret;
238 }
239
arm_spe_pkt_out_string(int * err,char ** buf_p,size_t * blen,const char * fmt,...)240 static int arm_spe_pkt_out_string(int *err, char **buf_p, size_t *blen,
241 const char *fmt, ...)
242 {
243 va_list ap;
244 int ret;
245
246 /* Bail out if any error occurred */
247 if (err && *err)
248 return *err;
249
250 va_start(ap, fmt);
251 ret = vsnprintf(*buf_p, *blen, fmt, ap);
252 va_end(ap);
253
254 if (ret < 0) {
255 if (err && !*err)
256 *err = ret;
257
258 /*
259 * A return value of *blen or more means that the output was
260 * truncated and the buffer is overrun.
261 */
262 } else if ((size_t)ret >= *blen) {
263 (*buf_p)[*blen - 1] = '\0';
264
265 /*
266 * Set *err to 'ret' to avoid overflow if tries to
267 * fill this buffer sequentially.
268 */
269 if (err && !*err)
270 *err = ret;
271 } else {
272 *buf_p += ret;
273 *blen -= ret;
274 }
275
276 return ret;
277 }
278
arm_spe_pkt_desc_event(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)279 static int arm_spe_pkt_desc_event(const struct arm_spe_pkt *packet,
280 char *buf, size_t buf_len)
281 {
282 u64 payload = packet->payload;
283 int err = 0;
284
285 arm_spe_pkt_out_string(&err, &buf, &buf_len, "EV");
286
287 if (payload & BIT(EV_EXCEPTION_GEN))
288 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCEPTION-GEN");
289 if (payload & BIT(EV_RETIRED))
290 arm_spe_pkt_out_string(&err, &buf, &buf_len, " RETIRED");
291 if (payload & BIT(EV_L1D_ACCESS))
292 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-ACCESS");
293 if (payload & BIT(EV_L1D_REFILL))
294 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L1D-REFILL");
295 if (payload & BIT(EV_TLB_ACCESS))
296 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-ACCESS");
297 if (payload & BIT(EV_TLB_WALK))
298 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TLB-REFILL");
299 if (payload & BIT(EV_NOT_TAKEN))
300 arm_spe_pkt_out_string(&err, &buf, &buf_len, " NOT-TAKEN");
301 if (payload & BIT(EV_MISPRED))
302 arm_spe_pkt_out_string(&err, &buf, &buf_len, " MISPRED");
303 if (payload & BIT(EV_LLC_ACCESS))
304 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-ACCESS");
305 if (payload & BIT(EV_LLC_MISS))
306 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LLC-REFILL");
307 if (payload & BIT(EV_REMOTE_ACCESS))
308 arm_spe_pkt_out_string(&err, &buf, &buf_len, " REMOTE-ACCESS");
309 if (payload & BIT(EV_ALIGNMENT))
310 arm_spe_pkt_out_string(&err, &buf, &buf_len, " ALIGNMENT");
311 if (payload & BIT(EV_TRANSACTIONAL))
312 arm_spe_pkt_out_string(&err, &buf, &buf_len, " TXN");
313 if (payload & BIT(EV_PARTIAL_PREDICATE))
314 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-PARTIAL-PRED");
315 if (payload & BIT(EV_EMPTY_PREDICATE))
316 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-EMPTY-PRED");
317 if (payload & BIT(EV_L2D_ACCESS))
318 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L2D-ACCESS");
319 if (payload & BIT(EV_L2D_MISS))
320 arm_spe_pkt_out_string(&err, &buf, &buf_len, " L2D-MISS");
321 if (payload & BIT(EV_CACHE_DATA_MODIFIED))
322 arm_spe_pkt_out_string(&err, &buf, &buf_len, " HITM");
323 if (payload & BIT(EV_RECENTLY_FETCHED))
324 arm_spe_pkt_out_string(&err, &buf, &buf_len, " LFB");
325 if (payload & BIT(EV_DATA_SNOOPED))
326 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SNOOPED");
327 if (payload & BIT(EV_STREAMING_SVE_MODE))
328 arm_spe_pkt_out_string(&err, &buf, &buf_len, " STREAMING-SVE");
329 if (payload & BIT(EV_SMCU))
330 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SMCU");
331
332 return err;
333 }
334
arm_spe_pkt_desc_op_type(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)335 static int arm_spe_pkt_desc_op_type(const struct arm_spe_pkt *packet,
336 char *buf, size_t buf_len)
337 {
338 u64 payload = packet->payload;
339 int err = 0;
340
341 switch (packet->index) {
342 case SPE_OP_PKT_HDR_CLASS_OTHER:
343 if (SPE_OP_PKT_OTHER_SUBCLASS_SVE(payload)) {
344 arm_spe_pkt_out_string(&err, &buf, &buf_len, "SVE-OTHER");
345
346 /* SVE effective vector length */
347 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
348 SPE_OP_PKG_SVE_EVL(payload));
349
350 if (payload & SPE_OP_PKT_SVE_FP)
351 arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
352 if (payload & SPE_OP_PKT_SVE_PRED)
353 arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
354 } else if (SPE_OP_PKT_OTHER_SUBCLASS_SME(payload)) {
355 arm_spe_pkt_out_string(&err, &buf, &buf_len, "SME-OTHER");
356
357 /* SME effective vector length or tile size */
358 arm_spe_pkt_out_string(&err, &buf, &buf_len, " ETS %d",
359 SPE_OP_PKG_SME_ETS(payload));
360
361 if (payload & SPE_OP_PKT_OTHER_FP)
362 arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
363 } else if (SPE_OP_PKT_OTHER_SUBCLASS_OTHER(payload)) {
364 arm_spe_pkt_out_string(&err, &buf, &buf_len, "OTHER");
365 if (payload & SPE_OP_PKT_OTHER_ASE)
366 arm_spe_pkt_out_string(&err, &buf, &buf_len, " ASE");
367 if (payload & SPE_OP_PKT_OTHER_FP)
368 arm_spe_pkt_out_string(&err, &buf, &buf_len, " FP");
369 arm_spe_pkt_out_string(&err, &buf, &buf_len, " %s",
370 payload & SPE_OP_PKT_COND ?
371 "COND-SELECT" : "INSN-OTHER");
372 }
373 break;
374 case SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
375 arm_spe_pkt_out_string(&err, &buf, &buf_len,
376 payload & 0x1 ? "ST" : "LD");
377
378 if (SPE_OP_PKT_LDST_SUBCLASS_EXTENDED(payload)) {
379 if (payload & SPE_OP_PKT_AT)
380 arm_spe_pkt_out_string(&err, &buf, &buf_len, " AT");
381 if (payload & SPE_OP_PKT_EXCL)
382 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EXCL");
383 if (payload & SPE_OP_PKT_AR)
384 arm_spe_pkt_out_string(&err, &buf, &buf_len, " AR");
385 } else if (SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP(payload)) {
386 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SIMD-FP");
387 } else if (SPE_OP_PKT_LDST_SUBCLASS_GP_REG(payload)) {
388 arm_spe_pkt_out_string(&err, &buf, &buf_len, " GP-REG");
389 } else if (SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG(payload)) {
390 arm_spe_pkt_out_string(&err, &buf, &buf_len, " UNSPEC-REG");
391 } else if (SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG(payload)) {
392 arm_spe_pkt_out_string(&err, &buf, &buf_len, " NV-SYSREG");
393 } else if (SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG(payload)) {
394 arm_spe_pkt_out_string(&err, &buf, &buf_len, " MTE-TAG");
395 } else if (SPE_OP_PKT_LDST_SUBCLASS_MEMCPY(payload)) {
396 arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMCPY");
397 } else if (SPE_OP_PKT_LDST_SUBCLASS_MEMSET(payload)) {
398 arm_spe_pkt_out_string(&err, &buf, &buf_len, " MEMSET");
399 } else if (SPE_OP_PKT_LDST_SUBCLASS_SVE_SME_REG(payload)) {
400 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SVE-SME-REG");
401
402 /* SVE effective vector length */
403 arm_spe_pkt_out_string(&err, &buf, &buf_len, " EVLEN %d",
404 SPE_OP_PKG_SVE_EVL(payload));
405
406 if (payload & SPE_OP_PKT_SVE_PRED)
407 arm_spe_pkt_out_string(&err, &buf, &buf_len, " PRED");
408 if (payload & SPE_OP_PKT_SVE_SG)
409 arm_spe_pkt_out_string(&err, &buf, &buf_len, " SG");
410 } else if (SPE_OP_PKT_LDST_SUBCLASS_GCS(payload)) {
411 arm_spe_pkt_out_string(&err, &buf, &buf_len, " GCS");
412 if (payload & SPE_OP_PKT_GCS_COMM)
413 arm_spe_pkt_out_string(&err, &buf, &buf_len, " COMM");
414 }
415 break;
416 case SPE_OP_PKT_HDR_CLASS_BR_ERET:
417 arm_spe_pkt_out_string(&err, &buf, &buf_len, "B");
418
419 if (payload & SPE_OP_PKT_COND)
420 arm_spe_pkt_out_string(&err, &buf, &buf_len, " COND");
421 if (payload & SPE_OP_PKT_INDIRECT_BRANCH)
422 arm_spe_pkt_out_string(&err, &buf, &buf_len, " IND");
423 if (payload & SPE_OP_PKT_GCS)
424 arm_spe_pkt_out_string(&err, &buf, &buf_len, " GCS");
425 if (SPE_OP_PKT_CR_BL(payload))
426 arm_spe_pkt_out_string(&err, &buf, &buf_len, " CR-BL");
427 if (SPE_OP_PKT_CR_RET(payload))
428 arm_spe_pkt_out_string(&err, &buf, &buf_len, " CR-RET");
429 if (SPE_OP_PKT_CR_NON_BL_RET(payload))
430 arm_spe_pkt_out_string(&err, &buf, &buf_len, " CR-NON-BL-RET");
431 break;
432 default:
433 /* Unknown index */
434 err = -1;
435 break;
436 }
437
438 return err;
439 }
440
arm_spe_pkt_desc_addr(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)441 static int arm_spe_pkt_desc_addr(const struct arm_spe_pkt *packet,
442 char *buf, size_t buf_len)
443 {
444 int ns, el, idx = packet->index;
445 int ch, pat;
446 u64 payload = packet->payload;
447 int err = 0;
448 static const char *idx_name[] = {"PC", "TGT", "VA", "PA", "PBT"};
449
450 switch (idx) {
451 case SPE_ADDR_PKT_HDR_INDEX_INS:
452 case SPE_ADDR_PKT_HDR_INDEX_BRANCH:
453 case SPE_ADDR_PKT_HDR_INDEX_PREV_BRANCH:
454 ns = !!SPE_ADDR_PKT_GET_NS(payload);
455 el = SPE_ADDR_PKT_GET_EL(payload);
456 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
457 arm_spe_pkt_out_string(&err, &buf, &buf_len,
458 "%s 0x%llx el%d ns=%d",
459 idx_name[idx], payload, el, ns);
460 break;
461 case SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
462 arm_spe_pkt_out_string(&err, &buf, &buf_len,
463 "VA 0x%llx", payload);
464 break;
465 case SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
466 ns = !!SPE_ADDR_PKT_GET_NS(payload);
467 ch = !!SPE_ADDR_PKT_GET_CH(payload);
468 pat = SPE_ADDR_PKT_GET_PAT(payload);
469 payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
470 arm_spe_pkt_out_string(&err, &buf, &buf_len,
471 "PA 0x%llx ns=%d ch=%d pat=%x",
472 payload, ns, ch, pat);
473 break;
474 default:
475 /* Unknown index */
476 err = -1;
477 break;
478 }
479
480 return err;
481 }
482
arm_spe_pkt_desc_counter(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)483 static int arm_spe_pkt_desc_counter(const struct arm_spe_pkt *packet,
484 char *buf, size_t buf_len)
485 {
486 u64 payload = packet->payload;
487 const char *name = arm_spe_pkt_name(packet->type);
488 int err = 0;
489
490 arm_spe_pkt_out_string(&err, &buf, &buf_len, "%s %d ", name,
491 (unsigned short)payload);
492
493 switch (packet->index) {
494 case SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
495 arm_spe_pkt_out_string(&err, &buf, &buf_len, "TOT");
496 break;
497 case SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
498 arm_spe_pkt_out_string(&err, &buf, &buf_len, "ISSUE");
499 break;
500 case SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
501 arm_spe_pkt_out_string(&err, &buf, &buf_len, "XLAT");
502 break;
503 default:
504 break;
505 }
506
507 return err;
508 }
509
arm_spe_pkt_desc(const struct arm_spe_pkt * packet,char * buf,size_t buf_len)510 int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
511 size_t buf_len)
512 {
513 int idx = packet->index;
514 unsigned long long payload = packet->payload;
515 const char *name = arm_spe_pkt_name(packet->type);
516 char *buf_orig = buf;
517 size_t blen = buf_len;
518 int err = 0;
519
520 switch (packet->type) {
521 case ARM_SPE_BAD:
522 case ARM_SPE_PAD:
523 case ARM_SPE_END:
524 arm_spe_pkt_out_string(&err, &buf, &blen, "%s", name);
525 break;
526 case ARM_SPE_EVENTS:
527 err = arm_spe_pkt_desc_event(packet, buf, buf_len);
528 break;
529 case ARM_SPE_OP_TYPE:
530 err = arm_spe_pkt_desc_op_type(packet, buf, buf_len);
531 break;
532 case ARM_SPE_DATA_SOURCE:
533 case ARM_SPE_TIMESTAMP:
534 arm_spe_pkt_out_string(&err, &buf, &blen, "%s %lld", name, payload);
535 break;
536 case ARM_SPE_ADDRESS:
537 err = arm_spe_pkt_desc_addr(packet, buf, buf_len);
538 break;
539 case ARM_SPE_CONTEXT:
540 arm_spe_pkt_out_string(&err, &buf, &blen, "%s 0x%lx el%d",
541 name, (unsigned long)payload, idx + 1);
542 break;
543 case ARM_SPE_COUNTER:
544 err = arm_spe_pkt_desc_counter(packet, buf, buf_len);
545 break;
546 default:
547 /* Unknown packet type */
548 err = -1;
549 break;
550 }
551
552 /* Output raw data if detect any error */
553 if (err) {
554 err = 0;
555 arm_spe_pkt_out_string(&err, &buf_orig, &buf_len, "%s 0x%llx (%d)",
556 name, payload, packet->index);
557 }
558
559 return err;
560 }
561