diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 4372ed2d16372cd88300ec8dc9d402c8ef1b99c6..1786e8d85b6b0f9c1d071742902198589e4cc969 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -4414,6 +4414,25 @@ static u8 adl_get_hybrid_cpu_type(void) return hybrid_big; } +static inline bool erratum_hsw11(struct perf_event *event) +{ + return (event->hw.config & INTEL_ARCH_EVENT_MASK) == + X86_CONFIG(.event=0xc0, .umask=0x01); +} + +/* + * The HSW11 requires a period larger than 100 which is the same as the BDM11. + * A minimum period of 128 is enforced as well for the INST_RETIRED.ALL. + * + * The message 'interrupt took too long' can be observed on any counter which + * was armed with a period < 32 and two events expired in the same NMI. + * A minimum period of 32 is enforced for the rest of the events. + */ +static u64 hsw_limit_period(struct perf_event *event, u64 left) +{ + return max(left, erratum_hsw11(event) ? 128ULL : 32ULL); +} + /* * Broadwell: * @@ -4431,8 +4450,7 @@ static u8 adl_get_hybrid_cpu_type(void) */ static u64 bdw_limit_period(struct perf_event *event, u64 left) { - if ((event->hw.config & INTEL_ARCH_EVENT_MASK) == - X86_CONFIG(.event=0xc0, .umask=0x01)) { + if (erratum_hsw11(event)) { if (left < 128) left = 128; left &= ~0x3fULL; @@ -6406,6 +6424,7 @@ __init int intel_pmu_init(void) x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = hsw_get_event_constraints; + x86_pmu.limit_period = hsw_limit_period; x86_pmu.lbr_double_abort = true; extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? hsw_format_attr : nhm_format_attr;