18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Arm Statistical Profiling Extensions (SPE) support 48c2ecf20Sopenharmony_ci * Copyright (c) 2017-2018, Arm Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <stdio.h> 88c2ecf20Sopenharmony_ci#include <string.h> 98c2ecf20Sopenharmony_ci#include <endian.h> 108c2ecf20Sopenharmony_ci#include <byteswap.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "arm-spe-pkt-decoder.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define BIT(n) (1ULL << (n)) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define NS_FLAG BIT(63) 178c2ecf20Sopenharmony_ci#define EL_FLAG (BIT(62) | BIT(61)) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define SPE_HEADER0_PAD 0x0 208c2ecf20Sopenharmony_ci#define SPE_HEADER0_END 0x1 218c2ecf20Sopenharmony_ci#define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */ 228c2ecf20Sopenharmony_ci#define SPE_HEADER0_ADDRESS_MASK 0x38 238c2ecf20Sopenharmony_ci#define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */ 248c2ecf20Sopenharmony_ci#define SPE_HEADER0_COUNTER_MASK 0x38 258c2ecf20Sopenharmony_ci#define SPE_HEADER0_TIMESTAMP 0x71 268c2ecf20Sopenharmony_ci#define SPE_HEADER0_TIMESTAMP 0x71 278c2ecf20Sopenharmony_ci#define SPE_HEADER0_EVENTS 0x2 288c2ecf20Sopenharmony_ci#define SPE_HEADER0_EVENTS_MASK 0xf 298c2ecf20Sopenharmony_ci#define SPE_HEADER0_SOURCE 0x3 308c2ecf20Sopenharmony_ci#define SPE_HEADER0_SOURCE_MASK 0xf 318c2ecf20Sopenharmony_ci#define SPE_HEADER0_CONTEXT 0x24 328c2ecf20Sopenharmony_ci#define SPE_HEADER0_CONTEXT_MASK 0x3c 338c2ecf20Sopenharmony_ci#define SPE_HEADER0_OP_TYPE 0x8 348c2ecf20Sopenharmony_ci#define SPE_HEADER0_OP_TYPE_MASK 0x3c 358c2ecf20Sopenharmony_ci#define SPE_HEADER1_ALIGNMENT 0x0 368c2ecf20Sopenharmony_ci#define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */ 378c2ecf20Sopenharmony_ci#define SPE_HEADER1_ADDRESS_MASK 0xf8 388c2ecf20Sopenharmony_ci#define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */ 398c2ecf20Sopenharmony_ci#define SPE_HEADER1_COUNTER_MASK 0xf8 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#if __BYTE_ORDER == __BIG_ENDIAN 428c2ecf20Sopenharmony_ci#define le16_to_cpu bswap_16 438c2ecf20Sopenharmony_ci#define le32_to_cpu bswap_32 448c2ecf20Sopenharmony_ci#define le64_to_cpu bswap_64 458c2ecf20Sopenharmony_ci#define memcpy_le64(d, s, n) do { \ 468c2ecf20Sopenharmony_ci memcpy((d), (s), (n)); \ 478c2ecf20Sopenharmony_ci *(d) = le64_to_cpu(*(d)); \ 488c2ecf20Sopenharmony_ci} while (0) 498c2ecf20Sopenharmony_ci#else 508c2ecf20Sopenharmony_ci#define le16_to_cpu 518c2ecf20Sopenharmony_ci#define le32_to_cpu 528c2ecf20Sopenharmony_ci#define le64_to_cpu 538c2ecf20Sopenharmony_ci#define memcpy_le64 memcpy 548c2ecf20Sopenharmony_ci#endif 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const char * const arm_spe_packet_name[] = { 578c2ecf20Sopenharmony_ci [ARM_SPE_PAD] = "PAD", 588c2ecf20Sopenharmony_ci [ARM_SPE_END] = "END", 598c2ecf20Sopenharmony_ci [ARM_SPE_TIMESTAMP] = "TS", 608c2ecf20Sopenharmony_ci [ARM_SPE_ADDRESS] = "ADDR", 618c2ecf20Sopenharmony_ci [ARM_SPE_COUNTER] = "LAT", 628c2ecf20Sopenharmony_ci [ARM_SPE_CONTEXT] = "CONTEXT", 638c2ecf20Sopenharmony_ci [ARM_SPE_OP_TYPE] = "OP-TYPE", 648c2ecf20Sopenharmony_ci [ARM_SPE_EVENTS] = "EVENTS", 658c2ecf20Sopenharmony_ci [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE", 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciconst char *arm_spe_pkt_name(enum arm_spe_pkt_type type) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return arm_spe_packet_name[type]; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* return ARM SPE payload size from its encoding, 748c2ecf20Sopenharmony_ci * which is in bits 5:4 of the byte. 758c2ecf20Sopenharmony_ci * 00 : byte 768c2ecf20Sopenharmony_ci * 01 : halfword (2) 778c2ecf20Sopenharmony_ci * 10 : word (4) 788c2ecf20Sopenharmony_ci * 11 : doubleword (8) 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic int payloadlen(unsigned char byte) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return 1 << ((byte & 0x30) >> 4); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int arm_spe_get_payload(const unsigned char *buf, size_t len, 868c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci size_t payload_len = payloadlen(buf[0]); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (len < 1 + payload_len) 918c2ecf20Sopenharmony_ci return ARM_SPE_NEED_MORE_BYTES; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci buf++; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci switch (payload_len) { 968c2ecf20Sopenharmony_ci case 1: packet->payload = *(uint8_t *)buf; break; 978c2ecf20Sopenharmony_ci case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break; 988c2ecf20Sopenharmony_ci case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break; 998c2ecf20Sopenharmony_ci case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break; 1008c2ecf20Sopenharmony_ci default: return ARM_SPE_BAD_PACKET; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 1 + payload_len; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int arm_spe_get_pad(struct arm_spe_pkt *packet) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci packet->type = ARM_SPE_PAD; 1098c2ecf20Sopenharmony_ci return 1; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int arm_spe_get_alignment(const unsigned char *buf, size_t len, 1138c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci unsigned int alignment = 1 << ((buf[0] & 0xf) + 1); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (len < alignment) 1188c2ecf20Sopenharmony_ci return ARM_SPE_NEED_MORE_BYTES; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci packet->type = ARM_SPE_PAD; 1218c2ecf20Sopenharmony_ci return alignment - (((uintptr_t)buf) & (alignment - 1)); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int arm_spe_get_end(struct arm_spe_pkt *packet) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci packet->type = ARM_SPE_END; 1278c2ecf20Sopenharmony_ci return 1; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int arm_spe_get_timestamp(const unsigned char *buf, size_t len, 1318c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci packet->type = ARM_SPE_TIMESTAMP; 1348c2ecf20Sopenharmony_ci return arm_spe_get_payload(buf, len, packet); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int arm_spe_get_events(const unsigned char *buf, size_t len, 1388c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int ret = arm_spe_get_payload(buf, len, packet); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci packet->type = ARM_SPE_EVENTS; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* we use index to identify Events with a less number of 1458c2ecf20Sopenharmony_ci * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS, 1468c2ecf20Sopenharmony_ci * LLC-REFILL, and REMOTE-ACCESS events are identified iff 1478c2ecf20Sopenharmony_ci * index > 1. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci packet->index = ret - 1; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return ret; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int arm_spe_get_data_source(const unsigned char *buf, size_t len, 1558c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci packet->type = ARM_SPE_DATA_SOURCE; 1588c2ecf20Sopenharmony_ci return arm_spe_get_payload(buf, len, packet); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int arm_spe_get_context(const unsigned char *buf, size_t len, 1628c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci packet->type = ARM_SPE_CONTEXT; 1658c2ecf20Sopenharmony_ci packet->index = buf[0] & 0x3; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return arm_spe_get_payload(buf, len, packet); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int arm_spe_get_op_type(const unsigned char *buf, size_t len, 1718c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci packet->type = ARM_SPE_OP_TYPE; 1748c2ecf20Sopenharmony_ci packet->index = buf[0] & 0x3; 1758c2ecf20Sopenharmony_ci return arm_spe_get_payload(buf, len, packet); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int arm_spe_get_counter(const unsigned char *buf, size_t len, 1798c2ecf20Sopenharmony_ci const unsigned char ext_hdr, struct arm_spe_pkt *packet) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (len < 2) 1828c2ecf20Sopenharmony_ci return ARM_SPE_NEED_MORE_BYTES; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci packet->type = ARM_SPE_COUNTER; 1858c2ecf20Sopenharmony_ci if (ext_hdr) 1868c2ecf20Sopenharmony_ci packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci packet->index = buf[0] & 0x7; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1)); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 1 + ext_hdr + 2; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int arm_spe_get_addr(const unsigned char *buf, size_t len, 1968c2ecf20Sopenharmony_ci const unsigned char ext_hdr, struct arm_spe_pkt *packet) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci if (len < 8) 1998c2ecf20Sopenharmony_ci return ARM_SPE_NEED_MORE_BYTES; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci packet->type = ARM_SPE_ADDRESS; 2028c2ecf20Sopenharmony_ci if (ext_hdr) 2038c2ecf20Sopenharmony_ci packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7); 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci packet->index = buf[0] & 0x7; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci memcpy_le64(&packet->payload, buf + 1, 8); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return 1 + ext_hdr + 8; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int arm_spe_do_get_packet(const unsigned char *buf, size_t len, 2138c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci unsigned int byte; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci memset(packet, 0, sizeof(struct arm_spe_pkt)); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (!len) 2208c2ecf20Sopenharmony_ci return ARM_SPE_NEED_MORE_BYTES; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci byte = buf[0]; 2238c2ecf20Sopenharmony_ci if (byte == SPE_HEADER0_PAD) 2248c2ecf20Sopenharmony_ci return arm_spe_get_pad(packet); 2258c2ecf20Sopenharmony_ci else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */ 2268c2ecf20Sopenharmony_ci return arm_spe_get_end(packet); 2278c2ecf20Sopenharmony_ci else if (byte & 0xc0 /* 0y11xxxxxx */) { 2288c2ecf20Sopenharmony_ci if (byte & 0x80) { 2298c2ecf20Sopenharmony_ci if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS) 2308c2ecf20Sopenharmony_ci return arm_spe_get_addr(buf, len, 0, packet); 2318c2ecf20Sopenharmony_ci if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER) 2328c2ecf20Sopenharmony_ci return arm_spe_get_counter(buf, len, 0, packet); 2338c2ecf20Sopenharmony_ci } else 2348c2ecf20Sopenharmony_ci if (byte == SPE_HEADER0_TIMESTAMP) 2358c2ecf20Sopenharmony_ci return arm_spe_get_timestamp(buf, len, packet); 2368c2ecf20Sopenharmony_ci else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS) 2378c2ecf20Sopenharmony_ci return arm_spe_get_events(buf, len, packet); 2388c2ecf20Sopenharmony_ci else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE) 2398c2ecf20Sopenharmony_ci return arm_spe_get_data_source(buf, len, packet); 2408c2ecf20Sopenharmony_ci else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT) 2418c2ecf20Sopenharmony_ci return arm_spe_get_context(buf, len, packet); 2428c2ecf20Sopenharmony_ci else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE) 2438c2ecf20Sopenharmony_ci return arm_spe_get_op_type(buf, len, packet); 2448c2ecf20Sopenharmony_ci } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) { 2458c2ecf20Sopenharmony_ci /* 16-bit header */ 2468c2ecf20Sopenharmony_ci byte = buf[1]; 2478c2ecf20Sopenharmony_ci if (byte == SPE_HEADER1_ALIGNMENT) 2488c2ecf20Sopenharmony_ci return arm_spe_get_alignment(buf, len, packet); 2498c2ecf20Sopenharmony_ci else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS) 2508c2ecf20Sopenharmony_ci return arm_spe_get_addr(buf, len, 1, packet); 2518c2ecf20Sopenharmony_ci else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER) 2528c2ecf20Sopenharmony_ci return arm_spe_get_counter(buf, len, 1, packet); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return ARM_SPE_BAD_PACKET; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ciint arm_spe_get_packet(const unsigned char *buf, size_t len, 2598c2ecf20Sopenharmony_ci struct arm_spe_pkt *packet) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = arm_spe_do_get_packet(buf, len, packet); 2648c2ecf20Sopenharmony_ci /* put multiple consecutive PADs on the same line, up to 2658c2ecf20Sopenharmony_ci * the fixed-width output format of 16 bytes per line. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (ret > 0 && packet->type == ARM_SPE_PAD) { 2688c2ecf20Sopenharmony_ci while (ret < 16 && len > (size_t)ret && !buf[ret]) 2698c2ecf20Sopenharmony_ci ret += 1; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ciint arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, 2758c2ecf20Sopenharmony_ci size_t buf_len) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int ret, ns, el, idx = packet->index; 2788c2ecf20Sopenharmony_ci unsigned long long payload = packet->payload; 2798c2ecf20Sopenharmony_ci const char *name = arm_spe_pkt_name(packet->type); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci switch (packet->type) { 2828c2ecf20Sopenharmony_ci case ARM_SPE_BAD: 2838c2ecf20Sopenharmony_ci case ARM_SPE_PAD: 2848c2ecf20Sopenharmony_ci case ARM_SPE_END: 2858c2ecf20Sopenharmony_ci return snprintf(buf, buf_len, "%s", name); 2868c2ecf20Sopenharmony_ci case ARM_SPE_EVENTS: { 2878c2ecf20Sopenharmony_ci size_t blen = buf_len; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ret = 0; 2908c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, "EV"); 2918c2ecf20Sopenharmony_ci buf += ret; 2928c2ecf20Sopenharmony_ci blen -= ret; 2938c2ecf20Sopenharmony_ci if (payload & 0x1) { 2948c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " EXCEPTION-GEN"); 2958c2ecf20Sopenharmony_ci buf += ret; 2968c2ecf20Sopenharmony_ci blen -= ret; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci if (payload & 0x2) { 2998c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " RETIRED"); 3008c2ecf20Sopenharmony_ci buf += ret; 3018c2ecf20Sopenharmony_ci blen -= ret; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci if (payload & 0x4) { 3048c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " L1D-ACCESS"); 3058c2ecf20Sopenharmony_ci buf += ret; 3068c2ecf20Sopenharmony_ci blen -= ret; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci if (payload & 0x8) { 3098c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " L1D-REFILL"); 3108c2ecf20Sopenharmony_ci buf += ret; 3118c2ecf20Sopenharmony_ci blen -= ret; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci if (payload & 0x10) { 3148c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " TLB-ACCESS"); 3158c2ecf20Sopenharmony_ci buf += ret; 3168c2ecf20Sopenharmony_ci blen -= ret; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci if (payload & 0x20) { 3198c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " TLB-REFILL"); 3208c2ecf20Sopenharmony_ci buf += ret; 3218c2ecf20Sopenharmony_ci blen -= ret; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci if (payload & 0x40) { 3248c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " NOT-TAKEN"); 3258c2ecf20Sopenharmony_ci buf += ret; 3268c2ecf20Sopenharmony_ci blen -= ret; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci if (payload & 0x80) { 3298c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " MISPRED"); 3308c2ecf20Sopenharmony_ci buf += ret; 3318c2ecf20Sopenharmony_ci blen -= ret; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci if (idx > 1) { 3348c2ecf20Sopenharmony_ci if (payload & 0x100) { 3358c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " LLC-ACCESS"); 3368c2ecf20Sopenharmony_ci buf += ret; 3378c2ecf20Sopenharmony_ci blen -= ret; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci if (payload & 0x200) { 3408c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " LLC-REFILL"); 3418c2ecf20Sopenharmony_ci buf += ret; 3428c2ecf20Sopenharmony_ci blen -= ret; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci if (payload & 0x400) { 3458c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " REMOTE-ACCESS"); 3468c2ecf20Sopenharmony_ci buf += ret; 3478c2ecf20Sopenharmony_ci blen -= ret; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci if (ret < 0) 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci blen -= ret; 3538c2ecf20Sopenharmony_ci return buf_len - blen; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci case ARM_SPE_OP_TYPE: 3568c2ecf20Sopenharmony_ci switch (idx) { 3578c2ecf20Sopenharmony_ci case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ? 3588c2ecf20Sopenharmony_ci "COND-SELECT" : "INSN-OTHER"); 3598c2ecf20Sopenharmony_ci case 1: { 3608c2ecf20Sopenharmony_ci size_t blen = buf_len; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (payload & 0x1) 3638c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, "ST"); 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, "LD"); 3668c2ecf20Sopenharmony_ci buf += ret; 3678c2ecf20Sopenharmony_ci blen -= ret; 3688c2ecf20Sopenharmony_ci if (payload & 0x2) { 3698c2ecf20Sopenharmony_ci if (payload & 0x4) { 3708c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " AT"); 3718c2ecf20Sopenharmony_ci buf += ret; 3728c2ecf20Sopenharmony_ci blen -= ret; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci if (payload & 0x8) { 3758c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " EXCL"); 3768c2ecf20Sopenharmony_ci buf += ret; 3778c2ecf20Sopenharmony_ci blen -= ret; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci if (payload & 0x10) { 3808c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " AR"); 3818c2ecf20Sopenharmony_ci buf += ret; 3828c2ecf20Sopenharmony_ci blen -= ret; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } else if (payload & 0x4) { 3858c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " SIMD-FP"); 3868c2ecf20Sopenharmony_ci buf += ret; 3878c2ecf20Sopenharmony_ci blen -= ret; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci if (ret < 0) 3908c2ecf20Sopenharmony_ci return ret; 3918c2ecf20Sopenharmony_ci blen -= ret; 3928c2ecf20Sopenharmony_ci return buf_len - blen; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci case 2: { 3958c2ecf20Sopenharmony_ci size_t blen = buf_len; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, "B"); 3988c2ecf20Sopenharmony_ci buf += ret; 3998c2ecf20Sopenharmony_ci blen -= ret; 4008c2ecf20Sopenharmony_ci if (payload & 0x1) { 4018c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " COND"); 4028c2ecf20Sopenharmony_ci buf += ret; 4038c2ecf20Sopenharmony_ci blen -= ret; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci if (payload & 0x2) { 4068c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, " IND"); 4078c2ecf20Sopenharmony_ci buf += ret; 4088c2ecf20Sopenharmony_ci blen -= ret; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci if (ret < 0) 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci blen -= ret; 4138c2ecf20Sopenharmony_ci return buf_len - blen; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci default: return 0; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci case ARM_SPE_DATA_SOURCE: 4188c2ecf20Sopenharmony_ci case ARM_SPE_TIMESTAMP: 4198c2ecf20Sopenharmony_ci return snprintf(buf, buf_len, "%s %lld", name, payload); 4208c2ecf20Sopenharmony_ci case ARM_SPE_ADDRESS: 4218c2ecf20Sopenharmony_ci switch (idx) { 4228c2ecf20Sopenharmony_ci case 0: 4238c2ecf20Sopenharmony_ci case 1: ns = !!(packet->payload & NS_FLAG); 4248c2ecf20Sopenharmony_ci el = (packet->payload & EL_FLAG) >> 61; 4258c2ecf20Sopenharmony_ci payload &= ~(0xffULL << 56); 4268c2ecf20Sopenharmony_ci return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d", 4278c2ecf20Sopenharmony_ci (idx == 1) ? "TGT" : "PC", payload, el, ns); 4288c2ecf20Sopenharmony_ci case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload); 4298c2ecf20Sopenharmony_ci case 3: ns = !!(packet->payload & NS_FLAG); 4308c2ecf20Sopenharmony_ci payload &= ~(0xffULL << 56); 4318c2ecf20Sopenharmony_ci return snprintf(buf, buf_len, "PA 0x%llx ns=%d", 4328c2ecf20Sopenharmony_ci payload, ns); 4338c2ecf20Sopenharmony_ci default: return 0; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci case ARM_SPE_CONTEXT: 4368c2ecf20Sopenharmony_ci return snprintf(buf, buf_len, "%s 0x%lx el%d", name, 4378c2ecf20Sopenharmony_ci (unsigned long)payload, idx + 1); 4388c2ecf20Sopenharmony_ci case ARM_SPE_COUNTER: { 4398c2ecf20Sopenharmony_ci size_t blen = buf_len; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ret = snprintf(buf, buf_len, "%s %d ", name, 4428c2ecf20Sopenharmony_ci (unsigned short)payload); 4438c2ecf20Sopenharmony_ci buf += ret; 4448c2ecf20Sopenharmony_ci blen -= ret; 4458c2ecf20Sopenharmony_ci switch (idx) { 4468c2ecf20Sopenharmony_ci case 0: ret = snprintf(buf, buf_len, "TOT"); break; 4478c2ecf20Sopenharmony_ci case 1: ret = snprintf(buf, buf_len, "ISSUE"); break; 4488c2ecf20Sopenharmony_ci case 2: ret = snprintf(buf, buf_len, "XLAT"); break; 4498c2ecf20Sopenharmony_ci default: ret = 0; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci if (ret < 0) 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci blen -= ret; 4548c2ecf20Sopenharmony_ci return buf_len - blen; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci default: 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return snprintf(buf, buf_len, "%s 0x%llx (%d)", 4618c2ecf20Sopenharmony_ci name, payload, packet->index); 4628c2ecf20Sopenharmony_ci} 463