18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 38c2ecf20Sopenharmony_ci#include <linux/types.h> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <asm/perf_event.h> 68c2ecf20Sopenharmony_ci#include <asm/msr.h> 78c2ecf20Sopenharmony_ci#include <asm/insn.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "../perf_event.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic const enum { 128c2ecf20Sopenharmony_ci LBR_EIP_FLAGS = 1, 138c2ecf20Sopenharmony_ci LBR_TSX = 2, 148c2ecf20Sopenharmony_ci} lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = { 158c2ecf20Sopenharmony_ci [LBR_FORMAT_EIP_FLAGS] = LBR_EIP_FLAGS, 168c2ecf20Sopenharmony_ci [LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX, 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Intel LBR_SELECT bits 218c2ecf20Sopenharmony_ci * Intel Vol3a, April 2011, Section 16.7 Table 16-10 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Hardware branch filter (not available on all CPUs) 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci#define LBR_KERNEL_BIT 0 /* do not capture at ring0 */ 268c2ecf20Sopenharmony_ci#define LBR_USER_BIT 1 /* do not capture at ring > 0 */ 278c2ecf20Sopenharmony_ci#define LBR_JCC_BIT 2 /* do not capture conditional branches */ 288c2ecf20Sopenharmony_ci#define LBR_REL_CALL_BIT 3 /* do not capture relative calls */ 298c2ecf20Sopenharmony_ci#define LBR_IND_CALL_BIT 4 /* do not capture indirect calls */ 308c2ecf20Sopenharmony_ci#define LBR_RETURN_BIT 5 /* do not capture near returns */ 318c2ecf20Sopenharmony_ci#define LBR_IND_JMP_BIT 6 /* do not capture indirect jumps */ 328c2ecf20Sopenharmony_ci#define LBR_REL_JMP_BIT 7 /* do not capture relative jumps */ 338c2ecf20Sopenharmony_ci#define LBR_FAR_BIT 8 /* do not capture far branches */ 348c2ecf20Sopenharmony_ci#define LBR_CALL_STACK_BIT 9 /* enable call stack */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Following bit only exists in Linux; we mask it out before writing it to 388c2ecf20Sopenharmony_ci * the actual MSR. But it helps the constraint perf code to understand 398c2ecf20Sopenharmony_ci * that this is a separate configuration. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#define LBR_NO_INFO_BIT 63 /* don't read LBR_INFO. */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define LBR_KERNEL (1 << LBR_KERNEL_BIT) 448c2ecf20Sopenharmony_ci#define LBR_USER (1 << LBR_USER_BIT) 458c2ecf20Sopenharmony_ci#define LBR_JCC (1 << LBR_JCC_BIT) 468c2ecf20Sopenharmony_ci#define LBR_REL_CALL (1 << LBR_REL_CALL_BIT) 478c2ecf20Sopenharmony_ci#define LBR_IND_CALL (1 << LBR_IND_CALL_BIT) 488c2ecf20Sopenharmony_ci#define LBR_RETURN (1 << LBR_RETURN_BIT) 498c2ecf20Sopenharmony_ci#define LBR_REL_JMP (1 << LBR_REL_JMP_BIT) 508c2ecf20Sopenharmony_ci#define LBR_IND_JMP (1 << LBR_IND_JMP_BIT) 518c2ecf20Sopenharmony_ci#define LBR_FAR (1 << LBR_FAR_BIT) 528c2ecf20Sopenharmony_ci#define LBR_CALL_STACK (1 << LBR_CALL_STACK_BIT) 538c2ecf20Sopenharmony_ci#define LBR_NO_INFO (1ULL << LBR_NO_INFO_BIT) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define LBR_PLM (LBR_KERNEL | LBR_USER) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define LBR_SEL_MASK 0x3ff /* valid bits in LBR_SELECT */ 588c2ecf20Sopenharmony_ci#define LBR_NOT_SUPP -1 /* LBR filter not supported */ 598c2ecf20Sopenharmony_ci#define LBR_IGN 0 /* ignored */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define LBR_ANY \ 628c2ecf20Sopenharmony_ci (LBR_JCC |\ 638c2ecf20Sopenharmony_ci LBR_REL_CALL |\ 648c2ecf20Sopenharmony_ci LBR_IND_CALL |\ 658c2ecf20Sopenharmony_ci LBR_RETURN |\ 668c2ecf20Sopenharmony_ci LBR_REL_JMP |\ 678c2ecf20Sopenharmony_ci LBR_IND_JMP |\ 688c2ecf20Sopenharmony_ci LBR_FAR) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define LBR_FROM_FLAG_MISPRED BIT_ULL(63) 718c2ecf20Sopenharmony_ci#define LBR_FROM_FLAG_IN_TX BIT_ULL(62) 728c2ecf20Sopenharmony_ci#define LBR_FROM_FLAG_ABORT BIT_ULL(61) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define LBR_FROM_SIGNEXT_2MSB (BIT_ULL(60) | BIT_ULL(59)) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * x86control flow change classification 788c2ecf20Sopenharmony_ci * x86control flow changes include branches, interrupts, traps, faults 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cienum { 818c2ecf20Sopenharmony_ci X86_BR_NONE = 0, /* unknown */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci X86_BR_USER = 1 << 0, /* branch target is user */ 848c2ecf20Sopenharmony_ci X86_BR_KERNEL = 1 << 1, /* branch target is kernel */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci X86_BR_CALL = 1 << 2, /* call */ 878c2ecf20Sopenharmony_ci X86_BR_RET = 1 << 3, /* return */ 888c2ecf20Sopenharmony_ci X86_BR_SYSCALL = 1 << 4, /* syscall */ 898c2ecf20Sopenharmony_ci X86_BR_SYSRET = 1 << 5, /* syscall return */ 908c2ecf20Sopenharmony_ci X86_BR_INT = 1 << 6, /* sw interrupt */ 918c2ecf20Sopenharmony_ci X86_BR_IRET = 1 << 7, /* return from interrupt */ 928c2ecf20Sopenharmony_ci X86_BR_JCC = 1 << 8, /* conditional */ 938c2ecf20Sopenharmony_ci X86_BR_JMP = 1 << 9, /* jump */ 948c2ecf20Sopenharmony_ci X86_BR_IRQ = 1 << 10,/* hw interrupt or trap or fault */ 958c2ecf20Sopenharmony_ci X86_BR_IND_CALL = 1 << 11,/* indirect calls */ 968c2ecf20Sopenharmony_ci X86_BR_ABORT = 1 << 12,/* transaction abort */ 978c2ecf20Sopenharmony_ci X86_BR_IN_TX = 1 << 13,/* in transaction */ 988c2ecf20Sopenharmony_ci X86_BR_NO_TX = 1 << 14,/* not in transaction */ 998c2ecf20Sopenharmony_ci X86_BR_ZERO_CALL = 1 << 15,/* zero length call */ 1008c2ecf20Sopenharmony_ci X86_BR_CALL_STACK = 1 << 16,/* call stack */ 1018c2ecf20Sopenharmony_ci X86_BR_IND_JMP = 1 << 17,/* indirect jump */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci X86_BR_TYPE_SAVE = 1 << 18,/* indicate to save branch type */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL) 1088c2ecf20Sopenharmony_ci#define X86_BR_ANYTX (X86_BR_NO_TX | X86_BR_IN_TX) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#define X86_BR_ANY \ 1118c2ecf20Sopenharmony_ci (X86_BR_CALL |\ 1128c2ecf20Sopenharmony_ci X86_BR_RET |\ 1138c2ecf20Sopenharmony_ci X86_BR_SYSCALL |\ 1148c2ecf20Sopenharmony_ci X86_BR_SYSRET |\ 1158c2ecf20Sopenharmony_ci X86_BR_INT |\ 1168c2ecf20Sopenharmony_ci X86_BR_IRET |\ 1178c2ecf20Sopenharmony_ci X86_BR_JCC |\ 1188c2ecf20Sopenharmony_ci X86_BR_JMP |\ 1198c2ecf20Sopenharmony_ci X86_BR_IRQ |\ 1208c2ecf20Sopenharmony_ci X86_BR_ABORT |\ 1218c2ecf20Sopenharmony_ci X86_BR_IND_CALL |\ 1228c2ecf20Sopenharmony_ci X86_BR_IND_JMP |\ 1238c2ecf20Sopenharmony_ci X86_BR_ZERO_CALL) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define X86_BR_ANY_CALL \ 1288c2ecf20Sopenharmony_ci (X86_BR_CALL |\ 1298c2ecf20Sopenharmony_ci X86_BR_IND_CALL |\ 1308c2ecf20Sopenharmony_ci X86_BR_ZERO_CALL |\ 1318c2ecf20Sopenharmony_ci X86_BR_SYSCALL |\ 1328c2ecf20Sopenharmony_ci X86_BR_IRQ |\ 1338c2ecf20Sopenharmony_ci X86_BR_INT) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * Intel LBR_CTL bits 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Hardware branch filter for Arch LBR 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci#define ARCH_LBR_KERNEL_BIT 1 /* capture at ring0 */ 1418c2ecf20Sopenharmony_ci#define ARCH_LBR_USER_BIT 2 /* capture at ring > 0 */ 1428c2ecf20Sopenharmony_ci#define ARCH_LBR_CALL_STACK_BIT 3 /* enable call stack */ 1438c2ecf20Sopenharmony_ci#define ARCH_LBR_JCC_BIT 16 /* capture conditional branches */ 1448c2ecf20Sopenharmony_ci#define ARCH_LBR_REL_JMP_BIT 17 /* capture relative jumps */ 1458c2ecf20Sopenharmony_ci#define ARCH_LBR_IND_JMP_BIT 18 /* capture indirect jumps */ 1468c2ecf20Sopenharmony_ci#define ARCH_LBR_REL_CALL_BIT 19 /* capture relative calls */ 1478c2ecf20Sopenharmony_ci#define ARCH_LBR_IND_CALL_BIT 20 /* capture indirect calls */ 1488c2ecf20Sopenharmony_ci#define ARCH_LBR_RETURN_BIT 21 /* capture near returns */ 1498c2ecf20Sopenharmony_ci#define ARCH_LBR_OTHER_BRANCH_BIT 22 /* capture other branches */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define ARCH_LBR_KERNEL (1ULL << ARCH_LBR_KERNEL_BIT) 1528c2ecf20Sopenharmony_ci#define ARCH_LBR_USER (1ULL << ARCH_LBR_USER_BIT) 1538c2ecf20Sopenharmony_ci#define ARCH_LBR_CALL_STACK (1ULL << ARCH_LBR_CALL_STACK_BIT) 1548c2ecf20Sopenharmony_ci#define ARCH_LBR_JCC (1ULL << ARCH_LBR_JCC_BIT) 1558c2ecf20Sopenharmony_ci#define ARCH_LBR_REL_JMP (1ULL << ARCH_LBR_REL_JMP_BIT) 1568c2ecf20Sopenharmony_ci#define ARCH_LBR_IND_JMP (1ULL << ARCH_LBR_IND_JMP_BIT) 1578c2ecf20Sopenharmony_ci#define ARCH_LBR_REL_CALL (1ULL << ARCH_LBR_REL_CALL_BIT) 1588c2ecf20Sopenharmony_ci#define ARCH_LBR_IND_CALL (1ULL << ARCH_LBR_IND_CALL_BIT) 1598c2ecf20Sopenharmony_ci#define ARCH_LBR_RETURN (1ULL << ARCH_LBR_RETURN_BIT) 1608c2ecf20Sopenharmony_ci#define ARCH_LBR_OTHER_BRANCH (1ULL << ARCH_LBR_OTHER_BRANCH_BIT) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define ARCH_LBR_ANY \ 1638c2ecf20Sopenharmony_ci (ARCH_LBR_JCC |\ 1648c2ecf20Sopenharmony_ci ARCH_LBR_REL_JMP |\ 1658c2ecf20Sopenharmony_ci ARCH_LBR_IND_JMP |\ 1668c2ecf20Sopenharmony_ci ARCH_LBR_REL_CALL |\ 1678c2ecf20Sopenharmony_ci ARCH_LBR_IND_CALL |\ 1688c2ecf20Sopenharmony_ci ARCH_LBR_RETURN |\ 1698c2ecf20Sopenharmony_ci ARCH_LBR_OTHER_BRANCH) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define ARCH_LBR_CTL_MASK 0x7f000e 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void intel_pmu_lbr_filter(struct cpu_hw_events *cpuc); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic __always_inline bool is_lbr_call_stack_bit_set(u64 config) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR)) 1788c2ecf20Sopenharmony_ci return !!(config & ARCH_LBR_CALL_STACK); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return !!(config & LBR_CALL_STACK); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * We only support LBR implementations that have FREEZE_LBRS_ON_PMI 1858c2ecf20Sopenharmony_ci * otherwise it becomes near impossible to get a reliable stack. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void __intel_pmu_lbr_enable(bool pmi) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 1918c2ecf20Sopenharmony_ci u64 debugctl, lbr_select = 0, orig_debugctl; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * No need to unfreeze manually, as v4 can do that as part 1958c2ecf20Sopenharmony_ci * of the GLOBAL_STATUS ack. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci if (pmi && x86_pmu.version >= 4) 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * No need to reprogram LBR_SELECT in a PMI, as it 2028c2ecf20Sopenharmony_ci * did not change. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci if (cpuc->lbr_sel) 2058c2ecf20Sopenharmony_ci lbr_select = cpuc->lbr_sel->config & x86_pmu.lbr_sel_mask; 2068c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_ARCH_LBR) && !pmi && cpuc->lbr_sel) 2078c2ecf20Sopenharmony_ci wrmsrl(MSR_LBR_SELECT, lbr_select); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); 2108c2ecf20Sopenharmony_ci orig_debugctl = debugctl; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_ARCH_LBR)) 2138c2ecf20Sopenharmony_ci debugctl |= DEBUGCTLMSR_LBR; 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * LBR callstack does not work well with FREEZE_LBRS_ON_PMI. 2168c2ecf20Sopenharmony_ci * If FREEZE_LBRS_ON_PMI is set, PMI near call/return instructions 2178c2ecf20Sopenharmony_ci * may cause superfluous increase/decrease of LBR_TOS. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci if (is_lbr_call_stack_bit_set(lbr_select)) 2208c2ecf20Sopenharmony_ci debugctl &= ~DEBUGCTLMSR_FREEZE_LBRS_ON_PMI; 2218c2ecf20Sopenharmony_ci else 2228c2ecf20Sopenharmony_ci debugctl |= DEBUGCTLMSR_FREEZE_LBRS_ON_PMI; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (orig_debugctl != debugctl) 2258c2ecf20Sopenharmony_ci wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR)) 2288c2ecf20Sopenharmony_ci wrmsrl(MSR_ARCH_LBR_CTL, lbr_select | ARCH_LBR_CTL_LBREN); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void __intel_pmu_lbr_disable(void) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci u64 debugctl; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR)) { 2368c2ecf20Sopenharmony_ci wrmsrl(MSR_ARCH_LBR_CTL, 0); 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); 2418c2ecf20Sopenharmony_ci debugctl &= ~(DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI); 2428c2ecf20Sopenharmony_ci wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_civoid intel_pmu_lbr_reset_32(void) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int i; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) 2508c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_from + i, 0); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_civoid intel_pmu_lbr_reset_64(void) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int i; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) { 2588c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_from + i, 0); 2598c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_to + i, 0); 2608c2ecf20Sopenharmony_ci if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) 2618c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_info + i, 0); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_reset(void) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci /* Write to ARCH_LBR_DEPTH MSR, all LBR entries are reset to 0 */ 2688c2ecf20Sopenharmony_ci wrmsrl(MSR_ARCH_LBR_DEPTH, x86_pmu.lbr_nr); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_civoid intel_pmu_lbr_reset(void) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_nr) 2768c2ecf20Sopenharmony_ci return; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci x86_pmu.lbr_reset(); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci cpuc->last_task_ctx = NULL; 2818c2ecf20Sopenharmony_ci cpuc->last_log_id = 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* 2858c2ecf20Sopenharmony_ci * TOS = most recently recorded branch 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_cistatic inline u64 intel_pmu_lbr_tos(void) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci u64 tos; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci rdmsrl(x86_pmu.lbr_tos, tos); 2928c2ecf20Sopenharmony_ci return tos; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cienum { 2968c2ecf20Sopenharmony_ci LBR_NONE, 2978c2ecf20Sopenharmony_ci LBR_VALID, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/* 3018c2ecf20Sopenharmony_ci * For formats with LBR_TSX flags (e.g. LBR_FORMAT_EIP_FLAGS2), bits 61:62 in 3028c2ecf20Sopenharmony_ci * MSR_LAST_BRANCH_FROM_x are the TSX flags when TSX is supported, but when 3038c2ecf20Sopenharmony_ci * TSX is not supported they have no consistent behavior: 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * - For wrmsr(), bits 61:62 are considered part of the sign extension. 3068c2ecf20Sopenharmony_ci * - For HW updates (branch captures) bits 61:62 are always OFF and are not 3078c2ecf20Sopenharmony_ci * part of the sign extension. 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Therefore, if: 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci * 1) LBR has TSX format 3128c2ecf20Sopenharmony_ci * 2) CPU has no TSX support enabled 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * ... then any value passed to wrmsr() must be sign extended to 63 bits and any 3158c2ecf20Sopenharmony_ci * value from rdmsr() must be converted to have a 61 bits sign extension, 3168c2ecf20Sopenharmony_ci * ignoring the TSX flags. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_cistatic inline bool lbr_from_signext_quirk_needed(void) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci int lbr_format = x86_pmu.intel_cap.lbr_format; 3218c2ecf20Sopenharmony_ci bool tsx_support = boot_cpu_has(X86_FEATURE_HLE) || 3228c2ecf20Sopenharmony_ci boot_cpu_has(X86_FEATURE_RTM); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return !tsx_support && (lbr_desc[lbr_format] & LBR_TSX); 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* If quirk is enabled, ensure sign extension is 63 bits: */ 3308c2ecf20Sopenharmony_ciinline u64 lbr_from_signext_quirk_wr(u64 val) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci if (static_branch_unlikely(&lbr_from_quirk_key)) { 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * Sign extend into bits 61:62 while preserving bit 63. 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * Quirk is enabled when TSX is disabled. Therefore TSX bits 3378c2ecf20Sopenharmony_ci * in val are always OFF and must be changed to be sign 3388c2ecf20Sopenharmony_ci * extension bits. Since bits 59:60 are guaranteed to be 3398c2ecf20Sopenharmony_ci * part of the sign extension bits, we can just copy them 3408c2ecf20Sopenharmony_ci * to 61:62. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci val |= (LBR_FROM_SIGNEXT_2MSB & val) << 2; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci return val; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* 3488c2ecf20Sopenharmony_ci * If quirk is needed, ensure sign extension is 61 bits: 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_cistatic u64 lbr_from_signext_quirk_rd(u64 val) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci if (static_branch_unlikely(&lbr_from_quirk_key)) { 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * Quirk is on when TSX is not enabled. Therefore TSX 3558c2ecf20Sopenharmony_ci * flags must be read as OFF. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci val &= ~(LBR_FROM_FLAG_IN_TX | LBR_FROM_FLAG_ABORT); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci return val; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic __always_inline void wrlbr_from(unsigned int idx, u64 val) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci val = lbr_from_signext_quirk_wr(val); 3658c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_from + idx, val); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic __always_inline void wrlbr_to(unsigned int idx, u64 val) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_to + idx, val); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic __always_inline void wrlbr_info(unsigned int idx, u64 val) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_info + idx, val); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic __always_inline u64 rdlbr_from(unsigned int idx, struct lbr_entry *lbr) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci u64 val; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (lbr) 3838c2ecf20Sopenharmony_ci return lbr->from; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci rdmsrl(x86_pmu.lbr_from + idx, val); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return lbr_from_signext_quirk_rd(val); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic __always_inline u64 rdlbr_to(unsigned int idx, struct lbr_entry *lbr) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u64 val; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (lbr) 3958c2ecf20Sopenharmony_ci return lbr->to; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci rdmsrl(x86_pmu.lbr_to + idx, val); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return val; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic __always_inline u64 rdlbr_info(unsigned int idx, struct lbr_entry *lbr) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci u64 val; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (lbr) 4078c2ecf20Sopenharmony_ci return lbr->info; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci rdmsrl(x86_pmu.lbr_info + idx, val); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return val; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic inline void 4158c2ecf20Sopenharmony_ciwrlbr_all(struct lbr_entry *lbr, unsigned int idx, bool need_info) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci wrlbr_from(idx, lbr->from); 4188c2ecf20Sopenharmony_ci wrlbr_to(idx, lbr->to); 4198c2ecf20Sopenharmony_ci if (need_info) 4208c2ecf20Sopenharmony_ci wrlbr_info(idx, lbr->info); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic inline bool 4248c2ecf20Sopenharmony_cirdlbr_all(struct lbr_entry *lbr, unsigned int idx, bool need_info) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci u64 from = rdlbr_from(idx, NULL); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Don't read invalid entry */ 4298c2ecf20Sopenharmony_ci if (!from) 4308c2ecf20Sopenharmony_ci return false; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci lbr->from = from; 4338c2ecf20Sopenharmony_ci lbr->to = rdlbr_to(idx, NULL); 4348c2ecf20Sopenharmony_ci if (need_info) 4358c2ecf20Sopenharmony_ci lbr->info = rdlbr_info(idx, NULL); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return true; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_civoid intel_pmu_lbr_restore(void *ctx) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO; 4438c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 4448c2ecf20Sopenharmony_ci struct x86_perf_task_context *task_ctx = ctx; 4458c2ecf20Sopenharmony_ci int i; 4468c2ecf20Sopenharmony_ci unsigned lbr_idx, mask; 4478c2ecf20Sopenharmony_ci u64 tos = task_ctx->tos; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci mask = x86_pmu.lbr_nr - 1; 4508c2ecf20Sopenharmony_ci for (i = 0; i < task_ctx->valid_lbrs; i++) { 4518c2ecf20Sopenharmony_ci lbr_idx = (tos - i) & mask; 4528c2ecf20Sopenharmony_ci wrlbr_all(&task_ctx->lbr[i], lbr_idx, need_info); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci for (; i < x86_pmu.lbr_nr; i++) { 4568c2ecf20Sopenharmony_ci lbr_idx = (tos - i) & mask; 4578c2ecf20Sopenharmony_ci wrlbr_from(lbr_idx, 0); 4588c2ecf20Sopenharmony_ci wrlbr_to(lbr_idx, 0); 4598c2ecf20Sopenharmony_ci if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) 4608c2ecf20Sopenharmony_ci wrlbr_info(lbr_idx, 0); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci wrmsrl(x86_pmu.lbr_tos, tos); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (cpuc->lbr_select) 4668c2ecf20Sopenharmony_ci wrmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_restore(void *ctx) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct x86_perf_task_context_arch_lbr *task_ctx = ctx; 4728c2ecf20Sopenharmony_ci struct lbr_entry *entries = task_ctx->entries; 4738c2ecf20Sopenharmony_ci int i; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Fast reset the LBRs before restore if the call stack is not full. */ 4768c2ecf20Sopenharmony_ci if (!entries[x86_pmu.lbr_nr - 1].from) 4778c2ecf20Sopenharmony_ci intel_pmu_arch_lbr_reset(); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) { 4808c2ecf20Sopenharmony_ci if (!entries[i].from) 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci wrlbr_all(&entries[i], i, true); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/* 4878c2ecf20Sopenharmony_ci * Restore the Architecture LBR state from the xsave area in the perf 4888c2ecf20Sopenharmony_ci * context data for the task via the XRSTORS instruction. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_xrstors(void *ctx) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct x86_perf_task_context_arch_lbr_xsave *task_ctx = ctx; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci copy_kernel_to_dynamic_supervisor(&task_ctx->xsave, XFEATURE_MASK_LBR); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic __always_inline bool lbr_is_reset_in_cstate(void *ctx) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR)) 5008c2ecf20Sopenharmony_ci return x86_pmu.lbr_deep_c_reset && !rdlbr_from(0, NULL); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci return !rdlbr_from(((struct x86_perf_task_context *)ctx)->tos, NULL); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic void __intel_pmu_lbr_restore(void *ctx) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (task_context_opt(ctx)->lbr_callstack_users == 0 || 5108c2ecf20Sopenharmony_ci task_context_opt(ctx)->lbr_stack_state == LBR_NONE) { 5118c2ecf20Sopenharmony_ci intel_pmu_lbr_reset(); 5128c2ecf20Sopenharmony_ci return; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * Does not restore the LBR registers, if 5178c2ecf20Sopenharmony_ci * - No one else touched them, and 5188c2ecf20Sopenharmony_ci * - Was not cleared in Cstate 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ci if ((ctx == cpuc->last_task_ctx) && 5218c2ecf20Sopenharmony_ci (task_context_opt(ctx)->log_id == cpuc->last_log_id) && 5228c2ecf20Sopenharmony_ci !lbr_is_reset_in_cstate(ctx)) { 5238c2ecf20Sopenharmony_ci task_context_opt(ctx)->lbr_stack_state = LBR_NONE; 5248c2ecf20Sopenharmony_ci return; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci x86_pmu.lbr_restore(ctx); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci task_context_opt(ctx)->lbr_stack_state = LBR_NONE; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_civoid intel_pmu_lbr_save(void *ctx) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO; 5358c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 5368c2ecf20Sopenharmony_ci struct x86_perf_task_context *task_ctx = ctx; 5378c2ecf20Sopenharmony_ci unsigned lbr_idx, mask; 5388c2ecf20Sopenharmony_ci u64 tos; 5398c2ecf20Sopenharmony_ci int i; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci mask = x86_pmu.lbr_nr - 1; 5428c2ecf20Sopenharmony_ci tos = intel_pmu_lbr_tos(); 5438c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) { 5448c2ecf20Sopenharmony_ci lbr_idx = (tos - i) & mask; 5458c2ecf20Sopenharmony_ci if (!rdlbr_all(&task_ctx->lbr[i], lbr_idx, need_info)) 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci task_ctx->valid_lbrs = i; 5498c2ecf20Sopenharmony_ci task_ctx->tos = tos; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (cpuc->lbr_select) 5528c2ecf20Sopenharmony_ci rdmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_save(void *ctx) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct x86_perf_task_context_arch_lbr *task_ctx = ctx; 5588c2ecf20Sopenharmony_ci struct lbr_entry *entries = task_ctx->entries; 5598c2ecf20Sopenharmony_ci int i; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) { 5628c2ecf20Sopenharmony_ci if (!rdlbr_all(&entries[i], i, true)) 5638c2ecf20Sopenharmony_ci break; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* LBR call stack is not full. Reset is required in restore. */ 5678c2ecf20Sopenharmony_ci if (i < x86_pmu.lbr_nr) 5688c2ecf20Sopenharmony_ci entries[x86_pmu.lbr_nr - 1].from = 0; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/* 5728c2ecf20Sopenharmony_ci * Save the Architecture LBR state to the xsave area in the perf 5738c2ecf20Sopenharmony_ci * context data for the task via the XSAVES instruction. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_xsaves(void *ctx) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct x86_perf_task_context_arch_lbr_xsave *task_ctx = ctx; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci copy_dynamic_supervisor_to_kernel(&task_ctx->xsave, XFEATURE_MASK_LBR); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void __intel_pmu_lbr_save(void *ctx) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (task_context_opt(ctx)->lbr_callstack_users == 0) { 5878c2ecf20Sopenharmony_ci task_context_opt(ctx)->lbr_stack_state = LBR_NONE; 5888c2ecf20Sopenharmony_ci return; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci x86_pmu.lbr_save(ctx); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci task_context_opt(ctx)->lbr_stack_state = LBR_VALID; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci cpuc->last_task_ctx = ctx; 5968c2ecf20Sopenharmony_ci cpuc->last_log_id = ++task_context_opt(ctx)->log_id; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_civoid intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev, 6008c2ecf20Sopenharmony_ci struct perf_event_context *next) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci void *prev_ctx_data, *next_ctx_data; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci swap(prev->task_ctx_data, next->task_ctx_data); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* 6078c2ecf20Sopenharmony_ci * Architecture specific synchronization makes sense in 6088c2ecf20Sopenharmony_ci * case both prev->task_ctx_data and next->task_ctx_data 6098c2ecf20Sopenharmony_ci * pointers are allocated. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci prev_ctx_data = next->task_ctx_data; 6138c2ecf20Sopenharmony_ci next_ctx_data = prev->task_ctx_data; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (!prev_ctx_data || !next_ctx_data) 6168c2ecf20Sopenharmony_ci return; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci swap(task_context_opt(prev_ctx_data)->lbr_callstack_users, 6198c2ecf20Sopenharmony_ci task_context_opt(next_ctx_data)->lbr_callstack_users); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_civoid intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 6258c2ecf20Sopenharmony_ci void *task_ctx; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (!cpuc->lbr_users) 6288c2ecf20Sopenharmony_ci return; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * If LBR callstack feature is enabled and the stack was saved when 6328c2ecf20Sopenharmony_ci * the task was scheduled out, restore the stack. Otherwise flush 6338c2ecf20Sopenharmony_ci * the LBR stack. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci task_ctx = ctx ? ctx->task_ctx_data : NULL; 6368c2ecf20Sopenharmony_ci if (task_ctx) { 6378c2ecf20Sopenharmony_ci if (sched_in) 6388c2ecf20Sopenharmony_ci __intel_pmu_lbr_restore(task_ctx); 6398c2ecf20Sopenharmony_ci else 6408c2ecf20Sopenharmony_ci __intel_pmu_lbr_save(task_ctx); 6418c2ecf20Sopenharmony_ci return; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* 6458c2ecf20Sopenharmony_ci * Since a context switch can flip the address space and LBR entries 6468c2ecf20Sopenharmony_ci * are not tagged with an identifier, we need to wipe the LBR, even for 6478c2ecf20Sopenharmony_ci * per-cpu events. You simply cannot resolve the branches from the old 6488c2ecf20Sopenharmony_ci * address space. 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_ci if (sched_in) 6518c2ecf20Sopenharmony_ci intel_pmu_lbr_reset(); 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic inline bool branch_user_callstack(unsigned br_sel) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci return (br_sel & X86_BR_USER) && (br_sel & X86_BR_CALL_STACK); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_civoid intel_pmu_lbr_add(struct perf_event *event) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_nr) 6648c2ecf20Sopenharmony_ci return; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (event->hw.flags & PERF_X86_EVENT_LBR_SELECT) 6678c2ecf20Sopenharmony_ci cpuc->lbr_select = 1; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci cpuc->br_sel = event->hw.branch_reg.reg; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data) 6728c2ecf20Sopenharmony_ci task_context_opt(event->ctx->task_ctx_data)->lbr_callstack_users++; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * Request pmu::sched_task() callback, which will fire inside the 6768c2ecf20Sopenharmony_ci * regular perf event scheduling, so that call will: 6778c2ecf20Sopenharmony_ci * 6788c2ecf20Sopenharmony_ci * - restore or wipe; when LBR-callstack, 6798c2ecf20Sopenharmony_ci * - wipe; otherwise, 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * when this is from __perf_event_task_sched_in(). 6828c2ecf20Sopenharmony_ci * 6838c2ecf20Sopenharmony_ci * However, if this is from perf_install_in_context(), no such callback 6848c2ecf20Sopenharmony_ci * will follow and we'll need to reset the LBR here if this is the 6858c2ecf20Sopenharmony_ci * first LBR event. 6868c2ecf20Sopenharmony_ci * 6878c2ecf20Sopenharmony_ci * The problem is, we cannot tell these cases apart... but we can 6888c2ecf20Sopenharmony_ci * exclude the biggest chunk of cases by looking at 6898c2ecf20Sopenharmony_ci * event->total_time_running. An event that has accrued runtime cannot 6908c2ecf20Sopenharmony_ci * be 'new'. Conversely, a new event can get installed through the 6918c2ecf20Sopenharmony_ci * context switch path for the first time. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0) 6948c2ecf20Sopenharmony_ci cpuc->lbr_pebs_users++; 6958c2ecf20Sopenharmony_ci perf_sched_cb_inc(event->ctx->pmu); 6968c2ecf20Sopenharmony_ci if (!cpuc->lbr_users++ && !event->total_time_running) 6978c2ecf20Sopenharmony_ci intel_pmu_lbr_reset(); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_civoid release_lbr_buffers(void) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct kmem_cache *kmem_cache; 7038c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc; 7048c2ecf20Sopenharmony_ci int cpu; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_ARCH_LBR)) 7078c2ecf20Sopenharmony_ci return; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 7108c2ecf20Sopenharmony_ci cpuc = per_cpu_ptr(&cpu_hw_events, cpu); 7118c2ecf20Sopenharmony_ci kmem_cache = x86_get_pmu(cpu)->task_ctx_cache; 7128c2ecf20Sopenharmony_ci if (kmem_cache && cpuc->lbr_xsave) { 7138c2ecf20Sopenharmony_ci kmem_cache_free(kmem_cache, cpuc->lbr_xsave); 7148c2ecf20Sopenharmony_ci cpuc->lbr_xsave = NULL; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_civoid reserve_lbr_buffers(void) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct kmem_cache *kmem_cache; 7228c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc; 7238c2ecf20Sopenharmony_ci int cpu; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_ARCH_LBR)) 7268c2ecf20Sopenharmony_ci return; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 7298c2ecf20Sopenharmony_ci cpuc = per_cpu_ptr(&cpu_hw_events, cpu); 7308c2ecf20Sopenharmony_ci kmem_cache = x86_get_pmu(cpu)->task_ctx_cache; 7318c2ecf20Sopenharmony_ci if (!kmem_cache || cpuc->lbr_xsave) 7328c2ecf20Sopenharmony_ci continue; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci cpuc->lbr_xsave = kmem_cache_alloc_node(kmem_cache, 7358c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO, 7368c2ecf20Sopenharmony_ci cpu_to_node(cpu)); 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_civoid intel_pmu_lbr_del(struct perf_event *event) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_nr) 7458c2ecf20Sopenharmony_ci return; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (branch_user_callstack(cpuc->br_sel) && 7488c2ecf20Sopenharmony_ci event->ctx->task_ctx_data) 7498c2ecf20Sopenharmony_ci task_context_opt(event->ctx->task_ctx_data)->lbr_callstack_users--; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (event->hw.flags & PERF_X86_EVENT_LBR_SELECT) 7528c2ecf20Sopenharmony_ci cpuc->lbr_select = 0; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0) 7558c2ecf20Sopenharmony_ci cpuc->lbr_pebs_users--; 7568c2ecf20Sopenharmony_ci cpuc->lbr_users--; 7578c2ecf20Sopenharmony_ci WARN_ON_ONCE(cpuc->lbr_users < 0); 7588c2ecf20Sopenharmony_ci WARN_ON_ONCE(cpuc->lbr_pebs_users < 0); 7598c2ecf20Sopenharmony_ci perf_sched_cb_dec(event->ctx->pmu); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic inline bool vlbr_exclude_host(void) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return test_bit(INTEL_PMC_IDX_FIXED_VLBR, 7678c2ecf20Sopenharmony_ci (unsigned long *)&cpuc->intel_ctrl_guest_mask); 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_civoid intel_pmu_lbr_enable_all(bool pmi) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (cpuc->lbr_users && !vlbr_exclude_host()) 7758c2ecf20Sopenharmony_ci __intel_pmu_lbr_enable(pmi); 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_civoid intel_pmu_lbr_disable_all(void) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (cpuc->lbr_users && !vlbr_exclude_host()) 7838c2ecf20Sopenharmony_ci __intel_pmu_lbr_disable(); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_civoid intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci unsigned long mask = x86_pmu.lbr_nr - 1; 7898c2ecf20Sopenharmony_ci u64 tos = intel_pmu_lbr_tos(); 7908c2ecf20Sopenharmony_ci int i; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) { 7938c2ecf20Sopenharmony_ci unsigned long lbr_idx = (tos - i) & mask; 7948c2ecf20Sopenharmony_ci union { 7958c2ecf20Sopenharmony_ci struct { 7968c2ecf20Sopenharmony_ci u32 from; 7978c2ecf20Sopenharmony_ci u32 to; 7988c2ecf20Sopenharmony_ci }; 7998c2ecf20Sopenharmony_ci u64 lbr; 8008c2ecf20Sopenharmony_ci } msr_lastbranch; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].from = msr_lastbranch.from; 8058c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].to = msr_lastbranch.to; 8068c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].mispred = 0; 8078c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].predicted = 0; 8088c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].in_tx = 0; 8098c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].abort = 0; 8108c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].cycles = 0; 8118c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].type = 0; 8128c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].reserved = 0; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci cpuc->lbr_stack.nr = i; 8158c2ecf20Sopenharmony_ci cpuc->lbr_stack.hw_idx = tos; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci/* 8198c2ecf20Sopenharmony_ci * Due to lack of segmentation in Linux the effective address (offset) 8208c2ecf20Sopenharmony_ci * is the same as the linear address, allowing us to merge the LIP and EIP 8218c2ecf20Sopenharmony_ci * LBR formats. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_civoid intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci bool need_info = false, call_stack = false; 8268c2ecf20Sopenharmony_ci unsigned long mask = x86_pmu.lbr_nr - 1; 8278c2ecf20Sopenharmony_ci int lbr_format = x86_pmu.intel_cap.lbr_format; 8288c2ecf20Sopenharmony_ci u64 tos = intel_pmu_lbr_tos(); 8298c2ecf20Sopenharmony_ci int i; 8308c2ecf20Sopenharmony_ci int out = 0; 8318c2ecf20Sopenharmony_ci int num = x86_pmu.lbr_nr; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (cpuc->lbr_sel) { 8348c2ecf20Sopenharmony_ci need_info = !(cpuc->lbr_sel->config & LBR_NO_INFO); 8358c2ecf20Sopenharmony_ci if (cpuc->lbr_sel->config & LBR_CALL_STACK) 8368c2ecf20Sopenharmony_ci call_stack = true; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 8408c2ecf20Sopenharmony_ci unsigned long lbr_idx = (tos - i) & mask; 8418c2ecf20Sopenharmony_ci u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0; 8428c2ecf20Sopenharmony_ci int skip = 0; 8438c2ecf20Sopenharmony_ci u16 cycles = 0; 8448c2ecf20Sopenharmony_ci int lbr_flags = lbr_desc[lbr_format]; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci from = rdlbr_from(lbr_idx, NULL); 8478c2ecf20Sopenharmony_ci to = rdlbr_to(lbr_idx, NULL); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* 8508c2ecf20Sopenharmony_ci * Read LBR call stack entries 8518c2ecf20Sopenharmony_ci * until invalid entry (0s) is detected. 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_ci if (call_stack && !from) 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (lbr_format == LBR_FORMAT_INFO && need_info) { 8578c2ecf20Sopenharmony_ci u64 info; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci info = rdlbr_info(lbr_idx, NULL); 8608c2ecf20Sopenharmony_ci mis = !!(info & LBR_INFO_MISPRED); 8618c2ecf20Sopenharmony_ci pred = !mis; 8628c2ecf20Sopenharmony_ci in_tx = !!(info & LBR_INFO_IN_TX); 8638c2ecf20Sopenharmony_ci abort = !!(info & LBR_INFO_ABORT); 8648c2ecf20Sopenharmony_ci cycles = (info & LBR_INFO_CYCLES); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (lbr_format == LBR_FORMAT_TIME) { 8688c2ecf20Sopenharmony_ci mis = !!(from & LBR_FROM_FLAG_MISPRED); 8698c2ecf20Sopenharmony_ci pred = !mis; 8708c2ecf20Sopenharmony_ci skip = 1; 8718c2ecf20Sopenharmony_ci cycles = ((to >> 48) & LBR_INFO_CYCLES); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci to = (u64)((((s64)to) << 16) >> 16); 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (lbr_flags & LBR_EIP_FLAGS) { 8778c2ecf20Sopenharmony_ci mis = !!(from & LBR_FROM_FLAG_MISPRED); 8788c2ecf20Sopenharmony_ci pred = !mis; 8798c2ecf20Sopenharmony_ci skip = 1; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci if (lbr_flags & LBR_TSX) { 8828c2ecf20Sopenharmony_ci in_tx = !!(from & LBR_FROM_FLAG_IN_TX); 8838c2ecf20Sopenharmony_ci abort = !!(from & LBR_FROM_FLAG_ABORT); 8848c2ecf20Sopenharmony_ci skip = 3; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci from = (u64)((((s64)from) << skip) >> skip); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* 8898c2ecf20Sopenharmony_ci * Some CPUs report duplicated abort records, 8908c2ecf20Sopenharmony_ci * with the second entry not having an abort bit set. 8918c2ecf20Sopenharmony_ci * Skip them here. This loop runs backwards, 8928c2ecf20Sopenharmony_ci * so we need to undo the previous record. 8938c2ecf20Sopenharmony_ci * If the abort just happened outside the window 8948c2ecf20Sopenharmony_ci * the extra entry cannot be removed. 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_ci if (abort && x86_pmu.lbr_double_abort && out > 0) 8978c2ecf20Sopenharmony_ci out--; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].from = from; 9008c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].to = to; 9018c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].mispred = mis; 9028c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].predicted = pred; 9038c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].in_tx = in_tx; 9048c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].abort = abort; 9058c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].cycles = cycles; 9068c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].type = 0; 9078c2ecf20Sopenharmony_ci cpuc->lbr_entries[out].reserved = 0; 9088c2ecf20Sopenharmony_ci out++; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci cpuc->lbr_stack.nr = out; 9118c2ecf20Sopenharmony_ci cpuc->lbr_stack.hw_idx = tos; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic __always_inline int get_lbr_br_type(u64 info) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci if (!static_cpu_has(X86_FEATURE_ARCH_LBR) || !x86_pmu.lbr_br_type) 9178c2ecf20Sopenharmony_ci return 0; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return (info & LBR_INFO_BR_TYPE) >> LBR_INFO_BR_TYPE_OFFSET; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic __always_inline bool get_lbr_mispred(u64 info) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR) && !x86_pmu.lbr_mispred) 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci return !!(info & LBR_INFO_MISPRED); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic __always_inline bool get_lbr_predicted(u64 info) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR) && !x86_pmu.lbr_mispred) 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci return !(info & LBR_INFO_MISPRED); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic __always_inline u16 get_lbr_cycles(u64 info) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR) && 9418c2ecf20Sopenharmony_ci !(x86_pmu.lbr_timed_lbr && info & LBR_INFO_CYC_CNT_VALID)) 9428c2ecf20Sopenharmony_ci return 0; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return info & LBR_INFO_CYCLES; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic void intel_pmu_store_lbr(struct cpu_hw_events *cpuc, 9488c2ecf20Sopenharmony_ci struct lbr_entry *entries) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct perf_branch_entry *e; 9518c2ecf20Sopenharmony_ci struct lbr_entry *lbr; 9528c2ecf20Sopenharmony_ci u64 from, to, info; 9538c2ecf20Sopenharmony_ci int i; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci for (i = 0; i < x86_pmu.lbr_nr; i++) { 9568c2ecf20Sopenharmony_ci lbr = entries ? &entries[i] : NULL; 9578c2ecf20Sopenharmony_ci e = &cpuc->lbr_entries[i]; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci from = rdlbr_from(i, lbr); 9608c2ecf20Sopenharmony_ci /* 9618c2ecf20Sopenharmony_ci * Read LBR entries until invalid entry (0s) is detected. 9628c2ecf20Sopenharmony_ci */ 9638c2ecf20Sopenharmony_ci if (!from) 9648c2ecf20Sopenharmony_ci break; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci to = rdlbr_to(i, lbr); 9678c2ecf20Sopenharmony_ci info = rdlbr_info(i, lbr); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci e->from = from; 9708c2ecf20Sopenharmony_ci e->to = to; 9718c2ecf20Sopenharmony_ci e->mispred = get_lbr_mispred(info); 9728c2ecf20Sopenharmony_ci e->predicted = get_lbr_predicted(info); 9738c2ecf20Sopenharmony_ci e->in_tx = !!(info & LBR_INFO_IN_TX); 9748c2ecf20Sopenharmony_ci e->abort = !!(info & LBR_INFO_ABORT); 9758c2ecf20Sopenharmony_ci e->cycles = get_lbr_cycles(info); 9768c2ecf20Sopenharmony_ci e->type = get_lbr_br_type(info); 9778c2ecf20Sopenharmony_ci e->reserved = 0; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci cpuc->lbr_stack.nr = i; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_read(struct cpu_hw_events *cpuc) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci intel_pmu_store_lbr(cpuc, NULL); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic void intel_pmu_arch_lbr_read_xsave(struct cpu_hw_events *cpuc) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct x86_perf_task_context_arch_lbr_xsave *xsave = cpuc->lbr_xsave; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (!xsave) { 9938c2ecf20Sopenharmony_ci intel_pmu_store_lbr(cpuc, NULL); 9948c2ecf20Sopenharmony_ci return; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci copy_dynamic_supervisor_to_kernel(&xsave->xsave, XFEATURE_MASK_LBR); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci intel_pmu_store_lbr(cpuc, xsave->lbr.entries); 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_civoid intel_pmu_lbr_read(void) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* 10068c2ecf20Sopenharmony_ci * Don't read when all LBRs users are using adaptive PEBS. 10078c2ecf20Sopenharmony_ci * 10088c2ecf20Sopenharmony_ci * This could be smarter and actually check the event, 10098c2ecf20Sopenharmony_ci * but this simple approach seems to work for now. 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_ci if (!cpuc->lbr_users || vlbr_exclude_host() || 10128c2ecf20Sopenharmony_ci cpuc->lbr_users == cpuc->lbr_pebs_users) 10138c2ecf20Sopenharmony_ci return; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci x86_pmu.lbr_read(cpuc); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci intel_pmu_lbr_filter(cpuc); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci/* 10218c2ecf20Sopenharmony_ci * SW filter is used: 10228c2ecf20Sopenharmony_ci * - in case there is no HW filter 10238c2ecf20Sopenharmony_ci * - in case the HW filter has errata or limitations 10248c2ecf20Sopenharmony_ci */ 10258c2ecf20Sopenharmony_cistatic int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci u64 br_type = event->attr.branch_sample_type; 10288c2ecf20Sopenharmony_ci int mask = 0; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_USER) 10318c2ecf20Sopenharmony_ci mask |= X86_BR_USER; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_KERNEL) 10348c2ecf20Sopenharmony_ci mask |= X86_BR_KERNEL; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* we ignore BRANCH_HV here */ 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_ANY) 10398c2ecf20Sopenharmony_ci mask |= X86_BR_ANY; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_ANY_CALL) 10428c2ecf20Sopenharmony_ci mask |= X86_BR_ANY_CALL; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_ANY_RETURN) 10458c2ecf20Sopenharmony_ci mask |= X86_BR_RET | X86_BR_IRET | X86_BR_SYSRET; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_IND_CALL) 10488c2ecf20Sopenharmony_ci mask |= X86_BR_IND_CALL; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_ABORT_TX) 10518c2ecf20Sopenharmony_ci mask |= X86_BR_ABORT; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_IN_TX) 10548c2ecf20Sopenharmony_ci mask |= X86_BR_IN_TX; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_NO_TX) 10578c2ecf20Sopenharmony_ci mask |= X86_BR_NO_TX; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_COND) 10608c2ecf20Sopenharmony_ci mask |= X86_BR_JCC; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_CALL_STACK) { 10638c2ecf20Sopenharmony_ci if (!x86_pmu_has_lbr_callstack()) 10648c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10658c2ecf20Sopenharmony_ci if (mask & ~(X86_BR_USER | X86_BR_KERNEL)) 10668c2ecf20Sopenharmony_ci return -EINVAL; 10678c2ecf20Sopenharmony_ci mask |= X86_BR_CALL | X86_BR_IND_CALL | X86_BR_RET | 10688c2ecf20Sopenharmony_ci X86_BR_CALL_STACK; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_IND_JUMP) 10728c2ecf20Sopenharmony_ci mask |= X86_BR_IND_JMP; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_CALL) 10758c2ecf20Sopenharmony_ci mask |= X86_BR_CALL | X86_BR_ZERO_CALL; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (br_type & PERF_SAMPLE_BRANCH_TYPE_SAVE) 10788c2ecf20Sopenharmony_ci mask |= X86_BR_TYPE_SAVE; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci /* 10818c2ecf20Sopenharmony_ci * stash actual user request into reg, it may 10828c2ecf20Sopenharmony_ci * be used by fixup code for some CPU 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_ci event->hw.branch_reg.reg = mask; 10858c2ecf20Sopenharmony_ci return 0; 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci/* 10898c2ecf20Sopenharmony_ci * setup the HW LBR filter 10908c2ecf20Sopenharmony_ci * Used only when available, may not be enough to disambiguate 10918c2ecf20Sopenharmony_ci * all branches, may need the help of the SW filter 10928c2ecf20Sopenharmony_ci */ 10938c2ecf20Sopenharmony_cistatic int intel_pmu_setup_hw_lbr_filter(struct perf_event *event) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci struct hw_perf_event_extra *reg; 10968c2ecf20Sopenharmony_ci u64 br_type = event->attr.branch_sample_type; 10978c2ecf20Sopenharmony_ci u64 mask = 0, v; 10988c2ecf20Sopenharmony_ci int i; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci for (i = 0; i < PERF_SAMPLE_BRANCH_MAX_SHIFT; i++) { 11018c2ecf20Sopenharmony_ci if (!(br_type & (1ULL << i))) 11028c2ecf20Sopenharmony_ci continue; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci v = x86_pmu.lbr_sel_map[i]; 11058c2ecf20Sopenharmony_ci if (v == LBR_NOT_SUPP) 11068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (v != LBR_IGN) 11098c2ecf20Sopenharmony_ci mask |= v; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci reg = &event->hw.branch_reg; 11138c2ecf20Sopenharmony_ci reg->idx = EXTRA_REG_LBR; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR)) { 11168c2ecf20Sopenharmony_ci reg->config = mask; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* 11198c2ecf20Sopenharmony_ci * The Arch LBR HW can retrieve the common branch types 11208c2ecf20Sopenharmony_ci * from the LBR_INFO. It doesn't require the high overhead 11218c2ecf20Sopenharmony_ci * SW disassemble. 11228c2ecf20Sopenharmony_ci * Enable the branch type by default for the Arch LBR. 11238c2ecf20Sopenharmony_ci */ 11248c2ecf20Sopenharmony_ci reg->reg |= X86_BR_TYPE_SAVE; 11258c2ecf20Sopenharmony_ci return 0; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* 11298c2ecf20Sopenharmony_ci * The first 9 bits (LBR_SEL_MASK) in LBR_SELECT operate 11308c2ecf20Sopenharmony_ci * in suppress mode. So LBR_SELECT should be set to 11318c2ecf20Sopenharmony_ci * (~mask & LBR_SEL_MASK) | (mask & ~LBR_SEL_MASK) 11328c2ecf20Sopenharmony_ci * But the 10th bit LBR_CALL_STACK does not operate 11338c2ecf20Sopenharmony_ci * in suppress mode. 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_ci reg->config = mask ^ (x86_pmu.lbr_sel_mask & ~LBR_CALL_STACK); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) && 11388c2ecf20Sopenharmony_ci (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) && 11398c2ecf20Sopenharmony_ci (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)) 11408c2ecf20Sopenharmony_ci reg->config |= LBR_NO_INFO; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ciint intel_pmu_setup_lbr_filter(struct perf_event *event) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci int ret = 0; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* 11508c2ecf20Sopenharmony_ci * no LBR on this PMU 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_nr) 11538c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * setup SW LBR filter 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci ret = intel_pmu_setup_sw_lbr_filter(event); 11598c2ecf20Sopenharmony_ci if (ret) 11608c2ecf20Sopenharmony_ci return ret; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * setup HW LBR filter, if any 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ci if (x86_pmu.lbr_sel_map) 11668c2ecf20Sopenharmony_ci ret = intel_pmu_setup_hw_lbr_filter(event); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci return ret; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci/* 11728c2ecf20Sopenharmony_ci * return the type of control flow change at address "from" 11738c2ecf20Sopenharmony_ci * instruction is not necessarily a branch (in case of interrupt). 11748c2ecf20Sopenharmony_ci * 11758c2ecf20Sopenharmony_ci * The branch type returned also includes the priv level of the 11768c2ecf20Sopenharmony_ci * target of the control flow change (X86_BR_USER, X86_BR_KERNEL). 11778c2ecf20Sopenharmony_ci * 11788c2ecf20Sopenharmony_ci * If a branch type is unknown OR the instruction cannot be 11798c2ecf20Sopenharmony_ci * decoded (e.g., text page not present), then X86_BR_NONE is 11808c2ecf20Sopenharmony_ci * returned. 11818c2ecf20Sopenharmony_ci */ 11828c2ecf20Sopenharmony_cistatic int branch_type(unsigned long from, unsigned long to, int abort) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci struct insn insn; 11858c2ecf20Sopenharmony_ci void *addr; 11868c2ecf20Sopenharmony_ci int bytes_read, bytes_left; 11878c2ecf20Sopenharmony_ci int ret = X86_BR_NONE; 11888c2ecf20Sopenharmony_ci int ext, to_plm, from_plm; 11898c2ecf20Sopenharmony_ci u8 buf[MAX_INSN_SIZE]; 11908c2ecf20Sopenharmony_ci int is64 = 0; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER; 11938c2ecf20Sopenharmony_ci from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* 11968c2ecf20Sopenharmony_ci * maybe zero if lbr did not fill up after a reset by the time 11978c2ecf20Sopenharmony_ci * we get a PMU interrupt 11988c2ecf20Sopenharmony_ci */ 11998c2ecf20Sopenharmony_ci if (from == 0 || to == 0) 12008c2ecf20Sopenharmony_ci return X86_BR_NONE; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (abort) 12038c2ecf20Sopenharmony_ci return X86_BR_ABORT | to_plm; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (from_plm == X86_BR_USER) { 12068c2ecf20Sopenharmony_ci /* 12078c2ecf20Sopenharmony_ci * can happen if measuring at the user level only 12088c2ecf20Sopenharmony_ci * and we interrupt in a kernel thread, e.g., idle. 12098c2ecf20Sopenharmony_ci */ 12108c2ecf20Sopenharmony_ci if (!current->mm) 12118c2ecf20Sopenharmony_ci return X86_BR_NONE; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* may fail if text not present */ 12148c2ecf20Sopenharmony_ci bytes_left = copy_from_user_nmi(buf, (void __user *)from, 12158c2ecf20Sopenharmony_ci MAX_INSN_SIZE); 12168c2ecf20Sopenharmony_ci bytes_read = MAX_INSN_SIZE - bytes_left; 12178c2ecf20Sopenharmony_ci if (!bytes_read) 12188c2ecf20Sopenharmony_ci return X86_BR_NONE; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci addr = buf; 12218c2ecf20Sopenharmony_ci } else { 12228c2ecf20Sopenharmony_ci /* 12238c2ecf20Sopenharmony_ci * The LBR logs any address in the IP, even if the IP just 12248c2ecf20Sopenharmony_ci * faulted. This means userspace can control the from address. 12258c2ecf20Sopenharmony_ci * Ensure we don't blindy read any address by validating it is 12268c2ecf20Sopenharmony_ci * a known text address. 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_ci if (kernel_text_address(from)) { 12298c2ecf20Sopenharmony_ci addr = (void *)from; 12308c2ecf20Sopenharmony_ci /* 12318c2ecf20Sopenharmony_ci * Assume we can get the maximum possible size 12328c2ecf20Sopenharmony_ci * when grabbing kernel data. This is not 12338c2ecf20Sopenharmony_ci * _strictly_ true since we could possibly be 12348c2ecf20Sopenharmony_ci * executing up next to a memory hole, but 12358c2ecf20Sopenharmony_ci * it is very unlikely to be a problem. 12368c2ecf20Sopenharmony_ci */ 12378c2ecf20Sopenharmony_ci bytes_read = MAX_INSN_SIZE; 12388c2ecf20Sopenharmony_ci } else { 12398c2ecf20Sopenharmony_ci return X86_BR_NONE; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci /* 12448c2ecf20Sopenharmony_ci * decoder needs to know the ABI especially 12458c2ecf20Sopenharmony_ci * on 64-bit systems running 32-bit apps 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 12488c2ecf20Sopenharmony_ci is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32); 12498c2ecf20Sopenharmony_ci#endif 12508c2ecf20Sopenharmony_ci insn_init(&insn, addr, bytes_read, is64); 12518c2ecf20Sopenharmony_ci insn_get_opcode(&insn); 12528c2ecf20Sopenharmony_ci if (!insn.opcode.got) 12538c2ecf20Sopenharmony_ci return X86_BR_ABORT; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci switch (insn.opcode.bytes[0]) { 12568c2ecf20Sopenharmony_ci case 0xf: 12578c2ecf20Sopenharmony_ci switch (insn.opcode.bytes[1]) { 12588c2ecf20Sopenharmony_ci case 0x05: /* syscall */ 12598c2ecf20Sopenharmony_ci case 0x34: /* sysenter */ 12608c2ecf20Sopenharmony_ci ret = X86_BR_SYSCALL; 12618c2ecf20Sopenharmony_ci break; 12628c2ecf20Sopenharmony_ci case 0x07: /* sysret */ 12638c2ecf20Sopenharmony_ci case 0x35: /* sysexit */ 12648c2ecf20Sopenharmony_ci ret = X86_BR_SYSRET; 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci case 0x80 ... 0x8f: /* conditional */ 12678c2ecf20Sopenharmony_ci ret = X86_BR_JCC; 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci default: 12708c2ecf20Sopenharmony_ci ret = X86_BR_NONE; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci break; 12738c2ecf20Sopenharmony_ci case 0x70 ... 0x7f: /* conditional */ 12748c2ecf20Sopenharmony_ci ret = X86_BR_JCC; 12758c2ecf20Sopenharmony_ci break; 12768c2ecf20Sopenharmony_ci case 0xc2: /* near ret */ 12778c2ecf20Sopenharmony_ci case 0xc3: /* near ret */ 12788c2ecf20Sopenharmony_ci case 0xca: /* far ret */ 12798c2ecf20Sopenharmony_ci case 0xcb: /* far ret */ 12808c2ecf20Sopenharmony_ci ret = X86_BR_RET; 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci case 0xcf: /* iret */ 12838c2ecf20Sopenharmony_ci ret = X86_BR_IRET; 12848c2ecf20Sopenharmony_ci break; 12858c2ecf20Sopenharmony_ci case 0xcc ... 0xce: /* int */ 12868c2ecf20Sopenharmony_ci ret = X86_BR_INT; 12878c2ecf20Sopenharmony_ci break; 12888c2ecf20Sopenharmony_ci case 0xe8: /* call near rel */ 12898c2ecf20Sopenharmony_ci insn_get_immediate(&insn); 12908c2ecf20Sopenharmony_ci if (insn.immediate1.value == 0) { 12918c2ecf20Sopenharmony_ci /* zero length call */ 12928c2ecf20Sopenharmony_ci ret = X86_BR_ZERO_CALL; 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci fallthrough; 12968c2ecf20Sopenharmony_ci case 0x9a: /* call far absolute */ 12978c2ecf20Sopenharmony_ci ret = X86_BR_CALL; 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci case 0xe0 ... 0xe3: /* loop jmp */ 13008c2ecf20Sopenharmony_ci ret = X86_BR_JCC; 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci case 0xe9 ... 0xeb: /* jmp */ 13038c2ecf20Sopenharmony_ci ret = X86_BR_JMP; 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci case 0xff: /* call near absolute, call far absolute ind */ 13068c2ecf20Sopenharmony_ci insn_get_modrm(&insn); 13078c2ecf20Sopenharmony_ci ext = (insn.modrm.bytes[0] >> 3) & 0x7; 13088c2ecf20Sopenharmony_ci switch (ext) { 13098c2ecf20Sopenharmony_ci case 2: /* near ind call */ 13108c2ecf20Sopenharmony_ci case 3: /* far ind call */ 13118c2ecf20Sopenharmony_ci ret = X86_BR_IND_CALL; 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci case 4: 13148c2ecf20Sopenharmony_ci case 5: 13158c2ecf20Sopenharmony_ci ret = X86_BR_IND_JMP; 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci default: 13208c2ecf20Sopenharmony_ci ret = X86_BR_NONE; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci /* 13238c2ecf20Sopenharmony_ci * interrupts, traps, faults (and thus ring transition) may 13248c2ecf20Sopenharmony_ci * occur on any instructions. Thus, to classify them correctly, 13258c2ecf20Sopenharmony_ci * we need to first look at the from and to priv levels. If they 13268c2ecf20Sopenharmony_ci * are different and to is in the kernel, then it indicates 13278c2ecf20Sopenharmony_ci * a ring transition. If the from instruction is not a ring 13288c2ecf20Sopenharmony_ci * transition instr (syscall, systenter, int), then it means 13298c2ecf20Sopenharmony_ci * it was a irq, trap or fault. 13308c2ecf20Sopenharmony_ci * 13318c2ecf20Sopenharmony_ci * we have no way of detecting kernel to kernel faults. 13328c2ecf20Sopenharmony_ci */ 13338c2ecf20Sopenharmony_ci if (from_plm == X86_BR_USER && to_plm == X86_BR_KERNEL 13348c2ecf20Sopenharmony_ci && ret != X86_BR_SYSCALL && ret != X86_BR_INT) 13358c2ecf20Sopenharmony_ci ret = X86_BR_IRQ; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* 13388c2ecf20Sopenharmony_ci * branch priv level determined by target as 13398c2ecf20Sopenharmony_ci * is done by HW when LBR_SELECT is implemented 13408c2ecf20Sopenharmony_ci */ 13418c2ecf20Sopenharmony_ci if (ret != X86_BR_NONE) 13428c2ecf20Sopenharmony_ci ret |= to_plm; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci return ret; 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci#define X86_BR_TYPE_MAP_MAX 16 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic int branch_map[X86_BR_TYPE_MAP_MAX] = { 13508c2ecf20Sopenharmony_ci PERF_BR_CALL, /* X86_BR_CALL */ 13518c2ecf20Sopenharmony_ci PERF_BR_RET, /* X86_BR_RET */ 13528c2ecf20Sopenharmony_ci PERF_BR_SYSCALL, /* X86_BR_SYSCALL */ 13538c2ecf20Sopenharmony_ci PERF_BR_SYSRET, /* X86_BR_SYSRET */ 13548c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_INT */ 13558c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_IRET */ 13568c2ecf20Sopenharmony_ci PERF_BR_COND, /* X86_BR_JCC */ 13578c2ecf20Sopenharmony_ci PERF_BR_UNCOND, /* X86_BR_JMP */ 13588c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_IRQ */ 13598c2ecf20Sopenharmony_ci PERF_BR_IND_CALL, /* X86_BR_IND_CALL */ 13608c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_ABORT */ 13618c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_IN_TX */ 13628c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_NO_TX */ 13638c2ecf20Sopenharmony_ci PERF_BR_CALL, /* X86_BR_ZERO_CALL */ 13648c2ecf20Sopenharmony_ci PERF_BR_UNKNOWN, /* X86_BR_CALL_STACK */ 13658c2ecf20Sopenharmony_ci PERF_BR_IND, /* X86_BR_IND_JMP */ 13668c2ecf20Sopenharmony_ci}; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic int 13698c2ecf20Sopenharmony_cicommon_branch_type(int type) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci int i; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci type >>= 2; /* skip X86_BR_USER and X86_BR_KERNEL */ 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (type) { 13768c2ecf20Sopenharmony_ci i = __ffs(type); 13778c2ecf20Sopenharmony_ci if (i < X86_BR_TYPE_MAP_MAX) 13788c2ecf20Sopenharmony_ci return branch_map[i]; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci return PERF_BR_UNKNOWN; 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cienum { 13858c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_JCC = 0, 13868c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_NEAR_IND_JMP = 1, 13878c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_NEAR_REL_JMP = 2, 13888c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_NEAR_IND_CALL = 3, 13898c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_NEAR_REL_CALL = 4, 13908c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_NEAR_RET = 5, 13918c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_KNOWN_MAX = ARCH_LBR_BR_TYPE_NEAR_RET, 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci ARCH_LBR_BR_TYPE_MAP_MAX = 16, 13948c2ecf20Sopenharmony_ci}; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic const int arch_lbr_br_type_map[ARCH_LBR_BR_TYPE_MAP_MAX] = { 13978c2ecf20Sopenharmony_ci [ARCH_LBR_BR_TYPE_JCC] = X86_BR_JCC, 13988c2ecf20Sopenharmony_ci [ARCH_LBR_BR_TYPE_NEAR_IND_JMP] = X86_BR_IND_JMP, 13998c2ecf20Sopenharmony_ci [ARCH_LBR_BR_TYPE_NEAR_REL_JMP] = X86_BR_JMP, 14008c2ecf20Sopenharmony_ci [ARCH_LBR_BR_TYPE_NEAR_IND_CALL] = X86_BR_IND_CALL, 14018c2ecf20Sopenharmony_ci [ARCH_LBR_BR_TYPE_NEAR_REL_CALL] = X86_BR_CALL, 14028c2ecf20Sopenharmony_ci [ARCH_LBR_BR_TYPE_NEAR_RET] = X86_BR_RET, 14038c2ecf20Sopenharmony_ci}; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci/* 14068c2ecf20Sopenharmony_ci * implement actual branch filter based on user demand. 14078c2ecf20Sopenharmony_ci * Hardware may not exactly satisfy that request, thus 14088c2ecf20Sopenharmony_ci * we need to inspect opcodes. Mismatched branches are 14098c2ecf20Sopenharmony_ci * discarded. Therefore, the number of branches returned 14108c2ecf20Sopenharmony_ci * in PERF_SAMPLE_BRANCH_STACK sample may vary. 14118c2ecf20Sopenharmony_ci */ 14128c2ecf20Sopenharmony_cistatic void 14138c2ecf20Sopenharmony_ciintel_pmu_lbr_filter(struct cpu_hw_events *cpuc) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci u64 from, to; 14168c2ecf20Sopenharmony_ci int br_sel = cpuc->br_sel; 14178c2ecf20Sopenharmony_ci int i, j, type, to_plm; 14188c2ecf20Sopenharmony_ci bool compress = false; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* if sampling all branches, then nothing to filter */ 14218c2ecf20Sopenharmony_ci if (((br_sel & X86_BR_ALL) == X86_BR_ALL) && 14228c2ecf20Sopenharmony_ci ((br_sel & X86_BR_TYPE_SAVE) != X86_BR_TYPE_SAVE)) 14238c2ecf20Sopenharmony_ci return; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci for (i = 0; i < cpuc->lbr_stack.nr; i++) { 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci from = cpuc->lbr_entries[i].from; 14288c2ecf20Sopenharmony_ci to = cpuc->lbr_entries[i].to; 14298c2ecf20Sopenharmony_ci type = cpuc->lbr_entries[i].type; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* 14328c2ecf20Sopenharmony_ci * Parse the branch type recorded in LBR_x_INFO MSR. 14338c2ecf20Sopenharmony_ci * Doesn't support OTHER_BRANCH decoding for now. 14348c2ecf20Sopenharmony_ci * OTHER_BRANCH branch type still rely on software decoding. 14358c2ecf20Sopenharmony_ci */ 14368c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR) && 14378c2ecf20Sopenharmony_ci type <= ARCH_LBR_BR_TYPE_KNOWN_MAX) { 14388c2ecf20Sopenharmony_ci to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER; 14398c2ecf20Sopenharmony_ci type = arch_lbr_br_type_map[type] | to_plm; 14408c2ecf20Sopenharmony_ci } else 14418c2ecf20Sopenharmony_ci type = branch_type(from, to, cpuc->lbr_entries[i].abort); 14428c2ecf20Sopenharmony_ci if (type != X86_BR_NONE && (br_sel & X86_BR_ANYTX)) { 14438c2ecf20Sopenharmony_ci if (cpuc->lbr_entries[i].in_tx) 14448c2ecf20Sopenharmony_ci type |= X86_BR_IN_TX; 14458c2ecf20Sopenharmony_ci else 14468c2ecf20Sopenharmony_ci type |= X86_BR_NO_TX; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* if type does not correspond, then discard */ 14508c2ecf20Sopenharmony_ci if (type == X86_BR_NONE || (br_sel & type) != type) { 14518c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].from = 0; 14528c2ecf20Sopenharmony_ci compress = true; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if ((br_sel & X86_BR_TYPE_SAVE) == X86_BR_TYPE_SAVE) 14568c2ecf20Sopenharmony_ci cpuc->lbr_entries[i].type = common_branch_type(type); 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (!compress) 14608c2ecf20Sopenharmony_ci return; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /* remove all entries with from=0 */ 14638c2ecf20Sopenharmony_ci for (i = 0; i < cpuc->lbr_stack.nr; ) { 14648c2ecf20Sopenharmony_ci if (!cpuc->lbr_entries[i].from) { 14658c2ecf20Sopenharmony_ci j = i; 14668c2ecf20Sopenharmony_ci while (++j < cpuc->lbr_stack.nr) 14678c2ecf20Sopenharmony_ci cpuc->lbr_entries[j-1] = cpuc->lbr_entries[j]; 14688c2ecf20Sopenharmony_ci cpuc->lbr_stack.nr--; 14698c2ecf20Sopenharmony_ci if (!cpuc->lbr_entries[i].from) 14708c2ecf20Sopenharmony_ci continue; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci i++; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_civoid intel_pmu_store_pebs_lbrs(struct lbr_entry *lbr) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* Cannot get TOS for large PEBS and Arch LBR */ 14818c2ecf20Sopenharmony_ci if (static_cpu_has(X86_FEATURE_ARCH_LBR) || 14828c2ecf20Sopenharmony_ci (cpuc->n_pebs == cpuc->n_large_pebs)) 14838c2ecf20Sopenharmony_ci cpuc->lbr_stack.hw_idx = -1ULL; 14848c2ecf20Sopenharmony_ci else 14858c2ecf20Sopenharmony_ci cpuc->lbr_stack.hw_idx = intel_pmu_lbr_tos(); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci intel_pmu_store_lbr(cpuc, lbr); 14888c2ecf20Sopenharmony_ci intel_pmu_lbr_filter(cpuc); 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci/* 14928c2ecf20Sopenharmony_ci * Map interface branch filters onto LBR filters 14938c2ecf20Sopenharmony_ci */ 14948c2ecf20Sopenharmony_cistatic const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { 14958c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, 14968c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, 14978c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, 14988c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_HV_SHIFT] = LBR_IGN, 14998c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = LBR_RETURN | LBR_REL_JMP 15008c2ecf20Sopenharmony_ci | LBR_IND_JMP | LBR_FAR, 15018c2ecf20Sopenharmony_ci /* 15028c2ecf20Sopenharmony_ci * NHM/WSM erratum: must include REL_JMP+IND_JMP to get CALL branches 15038c2ecf20Sopenharmony_ci */ 15048c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = 15058c2ecf20Sopenharmony_ci LBR_REL_CALL | LBR_IND_CALL | LBR_REL_JMP | LBR_IND_JMP | LBR_FAR, 15068c2ecf20Sopenharmony_ci /* 15078c2ecf20Sopenharmony_ci * NHM/WSM erratum: must include IND_JMP to capture IND_CALL 15088c2ecf20Sopenharmony_ci */ 15098c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL | LBR_IND_JMP, 15108c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, 15118c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, 15128c2ecf20Sopenharmony_ci}; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { 15158c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, 15168c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, 15178c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, 15188c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_HV_SHIFT] = LBR_IGN, 15198c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = LBR_RETURN | LBR_FAR, 15208c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = LBR_REL_CALL | LBR_IND_CALL 15218c2ecf20Sopenharmony_ci | LBR_FAR, 15228c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL, 15238c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, 15248c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, 15258c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_REL_CALL, 15268c2ecf20Sopenharmony_ci}; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { 15298c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_ANY, 15308c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_USER, 15318c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_KERNEL, 15328c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_HV_SHIFT] = LBR_IGN, 15338c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = LBR_RETURN | LBR_FAR, 15348c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = LBR_REL_CALL | LBR_IND_CALL 15358c2ecf20Sopenharmony_ci | LBR_FAR, 15368c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL, 15378c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, 15388c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] = LBR_REL_CALL | LBR_IND_CALL 15398c2ecf20Sopenharmony_ci | LBR_RETURN | LBR_CALL_STACK, 15408c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, 15418c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_REL_CALL, 15428c2ecf20Sopenharmony_ci}; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_cistatic int arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { 15458c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_SHIFT] = ARCH_LBR_ANY, 15468c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_USER_SHIFT] = ARCH_LBR_USER, 15478c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = ARCH_LBR_KERNEL, 15488c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_HV_SHIFT] = LBR_IGN, 15498c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = ARCH_LBR_RETURN | 15508c2ecf20Sopenharmony_ci ARCH_LBR_OTHER_BRANCH, 15518c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = ARCH_LBR_REL_CALL | 15528c2ecf20Sopenharmony_ci ARCH_LBR_IND_CALL | 15538c2ecf20Sopenharmony_ci ARCH_LBR_OTHER_BRANCH, 15548c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = ARCH_LBR_IND_CALL, 15558c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_COND_SHIFT] = ARCH_LBR_JCC, 15568c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] = ARCH_LBR_REL_CALL | 15578c2ecf20Sopenharmony_ci ARCH_LBR_IND_CALL | 15588c2ecf20Sopenharmony_ci ARCH_LBR_RETURN | 15598c2ecf20Sopenharmony_ci ARCH_LBR_CALL_STACK, 15608c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = ARCH_LBR_IND_JMP, 15618c2ecf20Sopenharmony_ci [PERF_SAMPLE_BRANCH_CALL_SHIFT] = ARCH_LBR_REL_CALL, 15628c2ecf20Sopenharmony_ci}; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci/* core */ 15658c2ecf20Sopenharmony_civoid __init intel_pmu_lbr_init_core(void) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 4; 15688c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 15698c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_CORE_FROM; 15708c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_CORE_TO; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci /* 15738c2ecf20Sopenharmony_ci * SW branch filter usage: 15748c2ecf20Sopenharmony_ci * - compensate for lack of HW filter 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci/* nehalem/westmere */ 15798c2ecf20Sopenharmony_civoid __init intel_pmu_lbr_init_nhm(void) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 16; 15828c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 15838c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_NHM_FROM; 15848c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_NHM_TO; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_mask = LBR_SEL_MASK; 15878c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_map = nhm_lbr_sel_map; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* 15908c2ecf20Sopenharmony_ci * SW branch filter usage: 15918c2ecf20Sopenharmony_ci * - workaround LBR_SEL errata (see above) 15928c2ecf20Sopenharmony_ci * - support syscall, sysret capture. 15938c2ecf20Sopenharmony_ci * That requires LBR_FAR but that means far 15948c2ecf20Sopenharmony_ci * jmp need to be filtered out 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci/* sandy bridge */ 15998c2ecf20Sopenharmony_civoid __init intel_pmu_lbr_init_snb(void) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 16; 16028c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 16038c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_NHM_FROM; 16048c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_NHM_TO; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_mask = LBR_SEL_MASK; 16078c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_map = snb_lbr_sel_map; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* 16108c2ecf20Sopenharmony_ci * SW branch filter usage: 16118c2ecf20Sopenharmony_ci * - support syscall, sysret capture. 16128c2ecf20Sopenharmony_ci * That requires LBR_FAR but that means far 16138c2ecf20Sopenharmony_ci * jmp need to be filtered out 16148c2ecf20Sopenharmony_ci */ 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic inline struct kmem_cache * 16188c2ecf20Sopenharmony_cicreate_lbr_kmem_cache(size_t size, size_t align) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci return kmem_cache_create("x86_lbr", size, align, 0, NULL); 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci/* haswell */ 16248c2ecf20Sopenharmony_civoid intel_pmu_lbr_init_hsw(void) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci size_t size = sizeof(struct x86_perf_task_context); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 16; 16298c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 16308c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_NHM_FROM; 16318c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_NHM_TO; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_mask = LBR_SEL_MASK; 16348c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_map = hsw_lbr_sel_map; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci x86_get_pmu(smp_processor_id())->task_ctx_cache = create_lbr_kmem_cache(size, 0); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (lbr_from_signext_quirk_needed()) 16398c2ecf20Sopenharmony_ci static_branch_enable(&lbr_from_quirk_key); 16408c2ecf20Sopenharmony_ci} 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci/* skylake */ 16438c2ecf20Sopenharmony_ci__init void intel_pmu_lbr_init_skl(void) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci size_t size = sizeof(struct x86_perf_task_context); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 32; 16488c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 16498c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_NHM_FROM; 16508c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_NHM_TO; 16518c2ecf20Sopenharmony_ci x86_pmu.lbr_info = MSR_LBR_INFO_0; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_mask = LBR_SEL_MASK; 16548c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_map = hsw_lbr_sel_map; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci x86_get_pmu(smp_processor_id())->task_ctx_cache = create_lbr_kmem_cache(size, 0); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci /* 16598c2ecf20Sopenharmony_ci * SW branch filter usage: 16608c2ecf20Sopenharmony_ci * - support syscall, sysret capture. 16618c2ecf20Sopenharmony_ci * That requires LBR_FAR but that means far 16628c2ecf20Sopenharmony_ci * jmp need to be filtered out 16638c2ecf20Sopenharmony_ci */ 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/* atom */ 16678c2ecf20Sopenharmony_civoid __init intel_pmu_lbr_init_atom(void) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci /* 16708c2ecf20Sopenharmony_ci * only models starting at stepping 10 seems 16718c2ecf20Sopenharmony_ci * to have an operational LBR which can freeze 16728c2ecf20Sopenharmony_ci * on PMU interrupt 16738c2ecf20Sopenharmony_ci */ 16748c2ecf20Sopenharmony_ci if (boot_cpu_data.x86_model == 28 16758c2ecf20Sopenharmony_ci && boot_cpu_data.x86_stepping < 10) { 16768c2ecf20Sopenharmony_ci pr_cont("LBR disabled due to erratum"); 16778c2ecf20Sopenharmony_ci return; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 8; 16818c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 16828c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_CORE_FROM; 16838c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_CORE_TO; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci /* 16868c2ecf20Sopenharmony_ci * SW branch filter usage: 16878c2ecf20Sopenharmony_ci * - compensate for lack of HW filter 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci/* slm */ 16928c2ecf20Sopenharmony_civoid __init intel_pmu_lbr_init_slm(void) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 8; 16958c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 16968c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_CORE_FROM; 16978c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_CORE_TO; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_mask = LBR_SEL_MASK; 17008c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_map = nhm_lbr_sel_map; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* 17038c2ecf20Sopenharmony_ci * SW branch filter usage: 17048c2ecf20Sopenharmony_ci * - compensate for lack of HW filter 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_ci pr_cont("8-deep LBR, "); 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci/* Knights Landing */ 17108c2ecf20Sopenharmony_civoid intel_pmu_lbr_init_knl(void) 17118c2ecf20Sopenharmony_ci{ 17128c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = 8; 17138c2ecf20Sopenharmony_ci x86_pmu.lbr_tos = MSR_LBR_TOS; 17148c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_LBR_NHM_FROM; 17158c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_LBR_NHM_TO; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_mask = LBR_SEL_MASK; 17188c2ecf20Sopenharmony_ci x86_pmu.lbr_sel_map = snb_lbr_sel_map; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Knights Landing does have MISPREDICT bit */ 17218c2ecf20Sopenharmony_ci if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_LIP) 17228c2ecf20Sopenharmony_ci x86_pmu.intel_cap.lbr_format = LBR_FORMAT_EIP_FLAGS; 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci/* 17268c2ecf20Sopenharmony_ci * LBR state size is variable based on the max number of registers. 17278c2ecf20Sopenharmony_ci * This calculates the expected state size, which should match 17288c2ecf20Sopenharmony_ci * what the hardware enumerates for the size of XFEATURE_LBR. 17298c2ecf20Sopenharmony_ci */ 17308c2ecf20Sopenharmony_cistatic inline unsigned int get_lbr_state_size(void) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci return sizeof(struct arch_lbr_state) + 17338c2ecf20Sopenharmony_ci x86_pmu.lbr_nr * sizeof(struct lbr_entry); 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cistatic bool is_arch_lbr_xsave_available(void) 17378c2ecf20Sopenharmony_ci{ 17388c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_XSAVES)) 17398c2ecf20Sopenharmony_ci return false; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci /* 17428c2ecf20Sopenharmony_ci * Check the LBR state with the corresponding software structure. 17438c2ecf20Sopenharmony_ci * Disable LBR XSAVES support if the size doesn't match. 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_ci if (xfeature_size(XFEATURE_LBR) == 0) 17468c2ecf20Sopenharmony_ci return false; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (WARN_ON(xfeature_size(XFEATURE_LBR) != get_lbr_state_size())) 17498c2ecf20Sopenharmony_ci return false; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci return true; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_civoid __init intel_pmu_arch_lbr_init(void) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci struct pmu *pmu = x86_get_pmu(smp_processor_id()); 17578c2ecf20Sopenharmony_ci union cpuid28_eax eax; 17588c2ecf20Sopenharmony_ci union cpuid28_ebx ebx; 17598c2ecf20Sopenharmony_ci union cpuid28_ecx ecx; 17608c2ecf20Sopenharmony_ci unsigned int unused_edx; 17618c2ecf20Sopenharmony_ci bool arch_lbr_xsave; 17628c2ecf20Sopenharmony_ci size_t size; 17638c2ecf20Sopenharmony_ci u64 lbr_nr; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* Arch LBR Capabilities */ 17668c2ecf20Sopenharmony_ci cpuid(28, &eax.full, &ebx.full, &ecx.full, &unused_edx); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci lbr_nr = fls(eax.split.lbr_depth_mask) * 8; 17698c2ecf20Sopenharmony_ci if (!lbr_nr) 17708c2ecf20Sopenharmony_ci goto clear_arch_lbr; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* Apply the max depth of Arch LBR */ 17738c2ecf20Sopenharmony_ci if (wrmsrl_safe(MSR_ARCH_LBR_DEPTH, lbr_nr)) 17748c2ecf20Sopenharmony_ci goto clear_arch_lbr; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci x86_pmu.lbr_depth_mask = eax.split.lbr_depth_mask; 17778c2ecf20Sopenharmony_ci x86_pmu.lbr_deep_c_reset = eax.split.lbr_deep_c_reset; 17788c2ecf20Sopenharmony_ci x86_pmu.lbr_lip = eax.split.lbr_lip; 17798c2ecf20Sopenharmony_ci x86_pmu.lbr_cpl = ebx.split.lbr_cpl; 17808c2ecf20Sopenharmony_ci x86_pmu.lbr_filter = ebx.split.lbr_filter; 17818c2ecf20Sopenharmony_ci x86_pmu.lbr_call_stack = ebx.split.lbr_call_stack; 17828c2ecf20Sopenharmony_ci x86_pmu.lbr_mispred = ecx.split.lbr_mispred; 17838c2ecf20Sopenharmony_ci x86_pmu.lbr_timed_lbr = ecx.split.lbr_timed_lbr; 17848c2ecf20Sopenharmony_ci x86_pmu.lbr_br_type = ecx.split.lbr_br_type; 17858c2ecf20Sopenharmony_ci x86_pmu.lbr_nr = lbr_nr; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci arch_lbr_xsave = is_arch_lbr_xsave_available(); 17898c2ecf20Sopenharmony_ci if (arch_lbr_xsave) { 17908c2ecf20Sopenharmony_ci size = sizeof(struct x86_perf_task_context_arch_lbr_xsave) + 17918c2ecf20Sopenharmony_ci get_lbr_state_size(); 17928c2ecf20Sopenharmony_ci pmu->task_ctx_cache = create_lbr_kmem_cache(size, 17938c2ecf20Sopenharmony_ci XSAVE_ALIGNMENT); 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (!pmu->task_ctx_cache) { 17978c2ecf20Sopenharmony_ci arch_lbr_xsave = false; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci size = sizeof(struct x86_perf_task_context_arch_lbr) + 18008c2ecf20Sopenharmony_ci lbr_nr * sizeof(struct lbr_entry); 18018c2ecf20Sopenharmony_ci pmu->task_ctx_cache = create_lbr_kmem_cache(size, 0); 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci x86_pmu.lbr_from = MSR_ARCH_LBR_FROM_0; 18058c2ecf20Sopenharmony_ci x86_pmu.lbr_to = MSR_ARCH_LBR_TO_0; 18068c2ecf20Sopenharmony_ci x86_pmu.lbr_info = MSR_ARCH_LBR_INFO_0; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci /* LBR callstack requires both CPL and Branch Filtering support */ 18098c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_cpl || 18108c2ecf20Sopenharmony_ci !x86_pmu.lbr_filter || 18118c2ecf20Sopenharmony_ci !x86_pmu.lbr_call_stack) 18128c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] = LBR_NOT_SUPP; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_cpl) { 18158c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_USER_SHIFT] = LBR_NOT_SUPP; 18168c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_KERNEL_SHIFT] = LBR_NOT_SUPP; 18178c2ecf20Sopenharmony_ci } else if (!x86_pmu.lbr_filter) { 18188c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_ANY_SHIFT] = LBR_NOT_SUPP; 18198c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT] = LBR_NOT_SUPP; 18208c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] = LBR_NOT_SUPP; 18218c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_NOT_SUPP; 18228c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_NOT_SUPP; 18238c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_NOT_SUPP; 18248c2ecf20Sopenharmony_ci arch_lbr_ctl_map[PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_NOT_SUPP; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci x86_pmu.lbr_ctl_mask = ARCH_LBR_CTL_MASK; 18288c2ecf20Sopenharmony_ci x86_pmu.lbr_ctl_map = arch_lbr_ctl_map; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (!x86_pmu.lbr_cpl && !x86_pmu.lbr_filter) 18318c2ecf20Sopenharmony_ci x86_pmu.lbr_ctl_map = NULL; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci x86_pmu.lbr_reset = intel_pmu_arch_lbr_reset; 18348c2ecf20Sopenharmony_ci if (arch_lbr_xsave) { 18358c2ecf20Sopenharmony_ci x86_pmu.lbr_save = intel_pmu_arch_lbr_xsaves; 18368c2ecf20Sopenharmony_ci x86_pmu.lbr_restore = intel_pmu_arch_lbr_xrstors; 18378c2ecf20Sopenharmony_ci x86_pmu.lbr_read = intel_pmu_arch_lbr_read_xsave; 18388c2ecf20Sopenharmony_ci pr_cont("XSAVE "); 18398c2ecf20Sopenharmony_ci } else { 18408c2ecf20Sopenharmony_ci x86_pmu.lbr_save = intel_pmu_arch_lbr_save; 18418c2ecf20Sopenharmony_ci x86_pmu.lbr_restore = intel_pmu_arch_lbr_restore; 18428c2ecf20Sopenharmony_ci x86_pmu.lbr_read = intel_pmu_arch_lbr_read; 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci pr_cont("Architectural LBR, "); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci return; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ciclear_arch_lbr: 18508c2ecf20Sopenharmony_ci setup_clear_cpu_cap(X86_FEATURE_ARCH_LBR); 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci/** 18548c2ecf20Sopenharmony_ci * x86_perf_get_lbr - get the LBR records information 18558c2ecf20Sopenharmony_ci * 18568c2ecf20Sopenharmony_ci * @lbr: the caller's memory to store the LBR records information 18578c2ecf20Sopenharmony_ci * 18588c2ecf20Sopenharmony_ci * Returns: 0 indicates the LBR info has been successfully obtained 18598c2ecf20Sopenharmony_ci */ 18608c2ecf20Sopenharmony_ciint x86_perf_get_lbr(struct x86_pmu_lbr *lbr) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci int lbr_fmt = x86_pmu.intel_cap.lbr_format; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci lbr->nr = x86_pmu.lbr_nr; 18658c2ecf20Sopenharmony_ci lbr->from = x86_pmu.lbr_from; 18668c2ecf20Sopenharmony_ci lbr->to = x86_pmu.lbr_to; 18678c2ecf20Sopenharmony_ci lbr->info = (lbr_fmt == LBR_FORMAT_INFO) ? x86_pmu.lbr_info : 0; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci return 0; 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(x86_perf_get_lbr); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_cistruct event_constraint vlbr_constraint = 18748c2ecf20Sopenharmony_ci __EVENT_CONSTRAINT(INTEL_FIXED_VLBR_EVENT, (1ULL << INTEL_PMC_IDX_FIXED_VLBR), 18758c2ecf20Sopenharmony_ci FIXED_EVENT_FLAGS, 1, 0, PERF_X86_EVENT_LBR_SELECT); 1876