From: dongsheng For Intel Atom CPUs, the PMU events "Instruction Retired" or "Branch Instruction Retired" may be overcounted for some certain instructions, like FAR CALL/JMP, RETF, IRET, VMENTRY/VMEXIT/VMPTRLD and complex SGX/SMX/CSTATE instructions/flows. The detailed information can be found in the errata (section SRF7): https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/sierra-forest/xeon-6700-series-processor-with-e-cores-specification-update/errata-details/ For the Atom platforms before Sierra Forest (including Sierra Forest), Both 2 events "Instruction Retired" and "Branch Instruction Retired" would be overcounted on these certain instructions, but for Clearwater Forest only "Instruction Retired" event is overcounted on these instructions. So add a helper detect_inst_overcount_flags() to detect whether the platform has the overcount issue and the later patches would relax the precise count check by leveraging the gotten overcount flags from this helper. Signed-off-by: dongsheng [Rewrite comments and commit message - Dapeng] Signed-off-by: Dapeng Mi Tested-by: Yi Lai [sean: put errata detection and tracking in pmu_init()] Signed-off-by: Sean Christopherson --- lib/x86/pmu.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/x86/pmu.h | 5 +++++ lib/x86/processor.h | 26 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/lib/x86/pmu.c b/lib/x86/pmu.c index fb46b196..67f3b23e 100644 --- a/lib/x86/pmu.c +++ b/lib/x86/pmu.c @@ -2,11 +2,50 @@ struct pmu_caps pmu; +/* + * For Intel Atom CPUs, the PMU events "Instruction Retired" or + * "Branch Instruction Retired" may be overcounted for some certain + * instructions, like FAR CALL/JMP, RETF, IRET, VMENTRY/VMEXIT/VMPTRLD + * and complex SGX/SMX/CSTATE instructions/flows. + * + * The detailed information can be found in the errata (section SRF7): + * https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/sierra-forest/xeon-6700-series-processor-with-e-cores-specification-update/errata-details/ + * + * For the Atom platforms before Sierra Forest (including Sierra Forest), + * Both 2 events "Instruction Retired" and "Branch Instruction Retired" would + * be overcounted on these certain instructions, but for Clearwater Forest + * only "Instruction Retired" event is overcounted on these instructions. + */ +static void pmu_detect_intel_overcount_errata(void) +{ + struct cpuid c = cpuid(1); + + if (x86_family(c.a) == 0x6) { + switch (x86_model(c.a)) { + case 0xDD: /* Clearwater Forest */ + pmu.errata.instructions_retired_overcount = true; + break; + + case 0xAF: /* Sierra Forest */ + case 0x4D: /* Avaton, Rangely */ + case 0x5F: /* Denverton */ + case 0x86: /* Jacobsville */ + pmu.errata.instructions_retired_overcount = true; + pmu.errata.branches_retired_overcount = true; + break; + default: + break; + } + } +} + void pmu_init(void) { pmu.is_intel = is_intel(); if (pmu.is_intel) { + pmu_detect_intel_overcount_errata(); + pmu.version = this_cpu_property(X86_PROPERTY_PMU_VERSION); if (pmu.version > 1) { diff --git a/lib/x86/pmu.h b/lib/x86/pmu.h index c7dc68c1..e84b37dc 100644 --- a/lib/x86/pmu.h +++ b/lib/x86/pmu.h @@ -73,6 +73,11 @@ struct pmu_caps { u32 msr_global_status_clr; u64 perf_cap; + + struct { + bool instructions_retired_overcount; + bool branches_retired_overcount; + } errata; }; extern struct pmu_caps pmu; diff --git a/lib/x86/processor.h b/lib/x86/processor.h index 8a73af5e..68bd774b 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -226,6 +226,32 @@ static inline bool is_intel(void) return strcmp((char *)name, "GenuineIntel") == 0; } +static inline u32 x86_family(u32 sig) +{ + u32 x86; + + x86 = (sig >> 8) & 0xf; + + if (x86 == 0xf) + x86 += (sig >> 20) & 0xff; + + return x86; +} + +static inline u32 x86_model(u32 sig) +{ + u32 fam, model; + + fam = x86_family(sig); + + model = (sig >> 4) & 0xf; + + if (fam >= 0x6) + model += ((sig >> 16) & 0xf) << 4; + + return model; +} + /* * Pack the information into a 64-bit value so that each X86_FEATURE_XXX can be * passed by value with no overhead. -- 2.52.0.rc2.455.g230fcf2819-goog