Path: blob/master/arch/x86/kernel/cpu/perf_event_intel_lbr.c
10699 views
#ifdef CONFIG_CPU_SUP_INTEL12enum {3LBR_FORMAT_32 = 0x00,4LBR_FORMAT_LIP = 0x01,5LBR_FORMAT_EIP = 0x02,6LBR_FORMAT_EIP_FLAGS = 0x03,7};89/*10* We only support LBR implementations that have FREEZE_LBRS_ON_PMI11* otherwise it becomes near impossible to get a reliable stack.12*/1314static void __intel_pmu_lbr_enable(void)15{16u64 debugctl;1718rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);19debugctl |= (DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);20wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);21}2223static void __intel_pmu_lbr_disable(void)24{25u64 debugctl;2627rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);28debugctl &= ~(DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);29wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);30}3132static void intel_pmu_lbr_reset_32(void)33{34int i;3536for (i = 0; i < x86_pmu.lbr_nr; i++)37wrmsrl(x86_pmu.lbr_from + i, 0);38}3940static void intel_pmu_lbr_reset_64(void)41{42int i;4344for (i = 0; i < x86_pmu.lbr_nr; i++) {45wrmsrl(x86_pmu.lbr_from + i, 0);46wrmsrl(x86_pmu.lbr_to + i, 0);47}48}4950static void intel_pmu_lbr_reset(void)51{52if (!x86_pmu.lbr_nr)53return;5455if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)56intel_pmu_lbr_reset_32();57else58intel_pmu_lbr_reset_64();59}6061static void intel_pmu_lbr_enable(struct perf_event *event)62{63struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);6465if (!x86_pmu.lbr_nr)66return;6768WARN_ON_ONCE(cpuc->enabled);6970/*71* Reset the LBR stack if we changed task context to72* avoid data leaks.73*/7475if (event->ctx->task && cpuc->lbr_context != event->ctx) {76intel_pmu_lbr_reset();77cpuc->lbr_context = event->ctx;78}7980cpuc->lbr_users++;81}8283static void intel_pmu_lbr_disable(struct perf_event *event)84{85struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);8687if (!x86_pmu.lbr_nr)88return;8990cpuc->lbr_users--;91WARN_ON_ONCE(cpuc->lbr_users < 0);9293if (cpuc->enabled && !cpuc->lbr_users)94__intel_pmu_lbr_disable();95}9697static void intel_pmu_lbr_enable_all(void)98{99struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);100101if (cpuc->lbr_users)102__intel_pmu_lbr_enable();103}104105static void intel_pmu_lbr_disable_all(void)106{107struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);108109if (cpuc->lbr_users)110__intel_pmu_lbr_disable();111}112113static inline u64 intel_pmu_lbr_tos(void)114{115u64 tos;116117rdmsrl(x86_pmu.lbr_tos, tos);118119return tos;120}121122static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)123{124unsigned long mask = x86_pmu.lbr_nr - 1;125u64 tos = intel_pmu_lbr_tos();126int i;127128for (i = 0; i < x86_pmu.lbr_nr; i++) {129unsigned long lbr_idx = (tos - i) & mask;130union {131struct {132u32 from;133u32 to;134};135u64 lbr;136} msr_lastbranch;137138rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr);139140cpuc->lbr_entries[i].from = msr_lastbranch.from;141cpuc->lbr_entries[i].to = msr_lastbranch.to;142cpuc->lbr_entries[i].flags = 0;143}144cpuc->lbr_stack.nr = i;145}146147#define LBR_FROM_FLAG_MISPRED (1ULL << 63)148149/*150* Due to lack of segmentation in Linux the effective address (offset)151* is the same as the linear address, allowing us to merge the LIP and EIP152* LBR formats.153*/154static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)155{156unsigned long mask = x86_pmu.lbr_nr - 1;157int lbr_format = x86_pmu.intel_cap.lbr_format;158u64 tos = intel_pmu_lbr_tos();159int i;160161for (i = 0; i < x86_pmu.lbr_nr; i++) {162unsigned long lbr_idx = (tos - i) & mask;163u64 from, to, flags = 0;164165rdmsrl(x86_pmu.lbr_from + lbr_idx, from);166rdmsrl(x86_pmu.lbr_to + lbr_idx, to);167168if (lbr_format == LBR_FORMAT_EIP_FLAGS) {169flags = !!(from & LBR_FROM_FLAG_MISPRED);170from = (u64)((((s64)from) << 1) >> 1);171}172173cpuc->lbr_entries[i].from = from;174cpuc->lbr_entries[i].to = to;175cpuc->lbr_entries[i].flags = flags;176}177cpuc->lbr_stack.nr = i;178}179180static void intel_pmu_lbr_read(void)181{182struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);183184if (!cpuc->lbr_users)185return;186187if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)188intel_pmu_lbr_read_32(cpuc);189else190intel_pmu_lbr_read_64(cpuc);191}192193static void intel_pmu_lbr_init_core(void)194{195x86_pmu.lbr_nr = 4;196x86_pmu.lbr_tos = 0x01c9;197x86_pmu.lbr_from = 0x40;198x86_pmu.lbr_to = 0x60;199}200201static void intel_pmu_lbr_init_nhm(void)202{203x86_pmu.lbr_nr = 16;204x86_pmu.lbr_tos = 0x01c9;205x86_pmu.lbr_from = 0x680;206x86_pmu.lbr_to = 0x6c0;207}208209static void intel_pmu_lbr_init_atom(void)210{211x86_pmu.lbr_nr = 8;212x86_pmu.lbr_tos = 0x01c9;213x86_pmu.lbr_from = 0x40;214x86_pmu.lbr_to = 0x60;215}216217#endif /* CONFIG_CPU_SUP_INTEL */218219220