Loading arch/x86/events/amd/core.c +1 −1 Original line number Diff line number Diff line Loading @@ -115,7 +115,7 @@ static __initconst const u64 amd_hw_cache_event_ids /* * AMD Performance Monitor K7 and later. */ static const u64 amd_perfmon_event_map[] = static const u64 amd_perfmon_event_map[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, Loading arch/x86/events/intel/lbr.c +4 −2 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ static enum { #define LBR_PLM (LBR_KERNEL | LBR_USER) #define LBR_SEL_MASK 0x1ff /* valid bits in LBR_SELECT */ #define LBR_SEL_MASK 0x3ff /* valid bits in LBR_SELECT */ #define LBR_NOT_SUPP -1 /* LBR filter not supported */ #define LBR_IGN 0 /* ignored */ Loading Loading @@ -621,8 +621,10 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event) * The first 9 bits (LBR_SEL_MASK) in LBR_SELECT operate * in suppress mode. So LBR_SELECT should be set to * (~mask & LBR_SEL_MASK) | (mask & ~LBR_SEL_MASK) * But the 10th bit LBR_CALL_STACK does not operate * in suppress mode. */ reg->config = mask ^ x86_pmu.lbr_sel_mask; reg->config = mask ^ (x86_pmu.lbr_sel_mask & ~LBR_CALL_STACK); if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) && (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) && Loading arch/x86/events/intel/pt.c +64 −11 Original line number Diff line number Diff line Loading @@ -136,9 +136,21 @@ static int __init pt_pmu_hw_init(void) struct dev_ext_attribute *de_attrs; struct attribute **attrs; size_t size; u64 reg; int ret; long i; if (boot_cpu_has(X86_FEATURE_VMX)) { /* * Intel SDM, 36.5 "Tracing post-VMXON" says that * "IA32_VMX_MISC[bit 14]" being 1 means PT can trace * post-VMXON. */ rdmsrl(MSR_IA32_VMX_MISC, reg); if (reg & BIT(14)) pt_pmu.vmx = true; } attrs = NULL; for (i = 0; i < PT_CPUID_LEAVES; i++) { Loading Loading @@ -269,20 +281,23 @@ static void pt_config(struct perf_event *event) reg |= (event->attr.config & PT_CONFIG_MASK); event->hw.config = reg; wrmsrl(MSR_IA32_RTIT_CTL, reg); } static void pt_config_start(bool start) static void pt_config_stop(struct perf_event *event) { u64 ctl; u64 ctl = READ_ONCE(event->hw.config); /* may be already stopped by a PMI */ if (!(ctl & RTIT_CTL_TRACEEN)) return; rdmsrl(MSR_IA32_RTIT_CTL, ctl); if (start) ctl |= RTIT_CTL_TRACEEN; else ctl &= ~RTIT_CTL_TRACEEN; wrmsrl(MSR_IA32_RTIT_CTL, ctl); WRITE_ONCE(event->hw.config, ctl); /* * A wrmsr that disables trace generation serializes other PT * registers and causes all data packets to be written to memory, Loading @@ -291,7 +306,6 @@ static void pt_config_start(bool start) * The below WMB, separating data store and aux_head store matches * the consumer's RMB that separates aux_head load and data load. */ if (!start) wmb(); } Loading Loading @@ -922,11 +936,17 @@ void intel_pt_interrupt(void) if (!ACCESS_ONCE(pt->handle_nmi)) return; pt_config_start(false); /* * If VMX is on and PT does not support it, don't touch anything. */ if (READ_ONCE(pt->vmx_on)) return; if (!event) return; pt_config_stop(event); buf = perf_get_aux(&pt->handle); if (!buf) return; Loading Loading @@ -963,6 +983,35 @@ void intel_pt_interrupt(void) } } void intel_pt_handle_vmx(int on) { struct pt *pt = this_cpu_ptr(&pt_ctx); struct perf_event *event; unsigned long flags; /* PT plays nice with VMX, do nothing */ if (pt_pmu.vmx) return; /* * VMXON will clear RTIT_CTL.TraceEn; we need to make * sure to not try to set it while VMX is on. Disable * interrupts to avoid racing with pmu callbacks; * concurrent PMI should be handled fine. */ local_irq_save(flags); WRITE_ONCE(pt->vmx_on, on); if (on) { /* prevent pt_config_stop() from writing RTIT_CTL */ event = pt->handle.event; if (event) event->hw.config = 0; } local_irq_restore(flags); } EXPORT_SYMBOL_GPL(intel_pt_handle_vmx); /* * PMU callbacks */ Loading @@ -973,6 +1022,9 @@ static void pt_event_start(struct perf_event *event, int mode) struct pt *pt = this_cpu_ptr(&pt_ctx); struct pt_buffer *buf; if (READ_ONCE(pt->vmx_on)) return; buf = perf_aux_output_begin(&pt->handle, event); if (!buf) goto fail_stop; Loading Loading @@ -1007,7 +1059,8 @@ static void pt_event_stop(struct perf_event *event, int mode) * see comment in intel_pt_interrupt(). */ ACCESS_ONCE(pt->handle_nmi) = 0; pt_config_start(false); pt_config_stop(event); if (event->hw.state == PERF_HES_STOPPED) return; Loading arch/x86/events/intel/pt.h +3 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ enum pt_capabilities { struct pt_pmu { struct pmu pmu; u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES]; bool vmx; }; /** Loading Loading @@ -107,10 +108,12 @@ struct pt_buffer { * struct pt - per-cpu pt context * @handle: perf output handle * @handle_nmi: do handle PT PMI on this cpu, there's an active event * @vmx_on: 1 if VMX is ON on this cpu */ struct pt { struct perf_output_handle handle; int handle_nmi; int vmx_on; }; #endif /* __INTEL_PT_H__ */ arch/x86/include/asm/perf_event.h +4 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,10 @@ static inline void perf_events_lapic_init(void) { } static inline void perf_check_microcode(void) { } #endif #ifdef CONFIG_CPU_SUP_INTEL extern void intel_pt_handle_vmx(int on); #endif #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) extern void amd_pmu_enable_virt(void); extern void amd_pmu_disable_virt(void); Loading Loading
arch/x86/events/amd/core.c +1 −1 Original line number Diff line number Diff line Loading @@ -115,7 +115,7 @@ static __initconst const u64 amd_hw_cache_event_ids /* * AMD Performance Monitor K7 and later. */ static const u64 amd_perfmon_event_map[] = static const u64 amd_perfmon_event_map[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, Loading
arch/x86/events/intel/lbr.c +4 −2 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ static enum { #define LBR_PLM (LBR_KERNEL | LBR_USER) #define LBR_SEL_MASK 0x1ff /* valid bits in LBR_SELECT */ #define LBR_SEL_MASK 0x3ff /* valid bits in LBR_SELECT */ #define LBR_NOT_SUPP -1 /* LBR filter not supported */ #define LBR_IGN 0 /* ignored */ Loading Loading @@ -621,8 +621,10 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event) * The first 9 bits (LBR_SEL_MASK) in LBR_SELECT operate * in suppress mode. So LBR_SELECT should be set to * (~mask & LBR_SEL_MASK) | (mask & ~LBR_SEL_MASK) * But the 10th bit LBR_CALL_STACK does not operate * in suppress mode. */ reg->config = mask ^ x86_pmu.lbr_sel_mask; reg->config = mask ^ (x86_pmu.lbr_sel_mask & ~LBR_CALL_STACK); if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) && (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) && Loading
arch/x86/events/intel/pt.c +64 −11 Original line number Diff line number Diff line Loading @@ -136,9 +136,21 @@ static int __init pt_pmu_hw_init(void) struct dev_ext_attribute *de_attrs; struct attribute **attrs; size_t size; u64 reg; int ret; long i; if (boot_cpu_has(X86_FEATURE_VMX)) { /* * Intel SDM, 36.5 "Tracing post-VMXON" says that * "IA32_VMX_MISC[bit 14]" being 1 means PT can trace * post-VMXON. */ rdmsrl(MSR_IA32_VMX_MISC, reg); if (reg & BIT(14)) pt_pmu.vmx = true; } attrs = NULL; for (i = 0; i < PT_CPUID_LEAVES; i++) { Loading Loading @@ -269,20 +281,23 @@ static void pt_config(struct perf_event *event) reg |= (event->attr.config & PT_CONFIG_MASK); event->hw.config = reg; wrmsrl(MSR_IA32_RTIT_CTL, reg); } static void pt_config_start(bool start) static void pt_config_stop(struct perf_event *event) { u64 ctl; u64 ctl = READ_ONCE(event->hw.config); /* may be already stopped by a PMI */ if (!(ctl & RTIT_CTL_TRACEEN)) return; rdmsrl(MSR_IA32_RTIT_CTL, ctl); if (start) ctl |= RTIT_CTL_TRACEEN; else ctl &= ~RTIT_CTL_TRACEEN; wrmsrl(MSR_IA32_RTIT_CTL, ctl); WRITE_ONCE(event->hw.config, ctl); /* * A wrmsr that disables trace generation serializes other PT * registers and causes all data packets to be written to memory, Loading @@ -291,7 +306,6 @@ static void pt_config_start(bool start) * The below WMB, separating data store and aux_head store matches * the consumer's RMB that separates aux_head load and data load. */ if (!start) wmb(); } Loading Loading @@ -922,11 +936,17 @@ void intel_pt_interrupt(void) if (!ACCESS_ONCE(pt->handle_nmi)) return; pt_config_start(false); /* * If VMX is on and PT does not support it, don't touch anything. */ if (READ_ONCE(pt->vmx_on)) return; if (!event) return; pt_config_stop(event); buf = perf_get_aux(&pt->handle); if (!buf) return; Loading Loading @@ -963,6 +983,35 @@ void intel_pt_interrupt(void) } } void intel_pt_handle_vmx(int on) { struct pt *pt = this_cpu_ptr(&pt_ctx); struct perf_event *event; unsigned long flags; /* PT plays nice with VMX, do nothing */ if (pt_pmu.vmx) return; /* * VMXON will clear RTIT_CTL.TraceEn; we need to make * sure to not try to set it while VMX is on. Disable * interrupts to avoid racing with pmu callbacks; * concurrent PMI should be handled fine. */ local_irq_save(flags); WRITE_ONCE(pt->vmx_on, on); if (on) { /* prevent pt_config_stop() from writing RTIT_CTL */ event = pt->handle.event; if (event) event->hw.config = 0; } local_irq_restore(flags); } EXPORT_SYMBOL_GPL(intel_pt_handle_vmx); /* * PMU callbacks */ Loading @@ -973,6 +1022,9 @@ static void pt_event_start(struct perf_event *event, int mode) struct pt *pt = this_cpu_ptr(&pt_ctx); struct pt_buffer *buf; if (READ_ONCE(pt->vmx_on)) return; buf = perf_aux_output_begin(&pt->handle, event); if (!buf) goto fail_stop; Loading Loading @@ -1007,7 +1059,8 @@ static void pt_event_stop(struct perf_event *event, int mode) * see comment in intel_pt_interrupt(). */ ACCESS_ONCE(pt->handle_nmi) = 0; pt_config_start(false); pt_config_stop(event); if (event->hw.state == PERF_HES_STOPPED) return; Loading
arch/x86/events/intel/pt.h +3 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ enum pt_capabilities { struct pt_pmu { struct pmu pmu; u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES]; bool vmx; }; /** Loading Loading @@ -107,10 +108,12 @@ struct pt_buffer { * struct pt - per-cpu pt context * @handle: perf output handle * @handle_nmi: do handle PT PMI on this cpu, there's an active event * @vmx_on: 1 if VMX is ON on this cpu */ struct pt { struct perf_output_handle handle; int handle_nmi; int vmx_on; }; #endif /* __INTEL_PT_H__ */
arch/x86/include/asm/perf_event.h +4 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,10 @@ static inline void perf_events_lapic_init(void) { } static inline void perf_check_microcode(void) { } #endif #ifdef CONFIG_CPU_SUP_INTEL extern void intel_pt_handle_vmx(int on); #endif #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) extern void amd_pmu_enable_virt(void); extern void amd_pmu_disable_virt(void); Loading