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