diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 46b2f41..f76cca8 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -1030,6 +1030,7 @@ core_initcall(cpufreq_register_tsc_scaling); #endif /* CONFIG_CPU_FREQ */ #define ART_CPUID_LEAF (0x15) +#define MINIMUM_CPUID_EXTENDED_LEAF_THAT_MUST_HAVE_ART (0x80000008) #define ART_MIN_DENOMINATOR (1) @@ -1038,24 +1039,43 @@ core_initcall(cpufreq_register_tsc_scaling); */ static void detect_art(void) { - unsigned int unused[2]; - - if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF) - return; - - cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator, - &art_to_tsc_numerator, unused, unused+1); - + unsigned int v[2]; + + if(boot_cpu_data.cpuid_level < ART_CPUID_LEAF) + { + if(boot_cpu_data.extended_cpuid_level >= MINIMUM_CPUID_EXTENDED_LEAF_THAT_MUST_HAVE_ART) + { + pr_info("Would normally not use ART - cpuid_level:%d < %d - but extended_cpuid_level is: %x, so probing for ART support.\n", + boot_cpu_data.cpuid_level, ART_CPUID_LEAF, boot_cpu_data.extended_cpuid_level); + }else + return; + } + + cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator, + &art_to_tsc_numerator, v, v+1); + /* Don't enable ART in a VM, non-stop TSC required */ if (boot_cpu_has(X86_FEATURE_HYPERVISOR) || - !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) || - art_to_tsc_denominator < ART_MIN_DENOMINATOR) - return; - - if (rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset)) - return; - + !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) || + art_to_tsc_denominator < ART_MIN_DENOMINATOR) + { + pr_info("Not using Intel ART for TSC - HYPERVISOR:%d NO NONSTOP_TSC:%d bad TSC/Crystal ratio denominator: %d.", boot_cpu_has(X86_FEATURE_HYPERVISOR), !boot_cpu_has(X86_FEATURE_NONSTOP_TSC), art_to_tsc_denominator ); + return; + } + if ( (v[0]=rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset))!=0) /* will get fault on first read if nothing written yet */ + { + if((v[1]=wrmsrl_safe(MSR_IA32_TSC_ADJUST, 0))!=0) + { + pr_info("Not using Intel ART for TSC - failed to initialize TSC_ADJUST: %d %d.\n", v[0], v[1] ); + return; + }else + { + art_to_tsc_offset = 0; /* perhaps initalize to -1 * current rdtsc value ? */ + pr_info("Using Intel ART for TSC - TSC_ADJUST initialized to %llu.\n",art_to_tsc_offset); + } + } /* Make this sticky over multiple CPU init calls */ + pr_info("Using Intel Always Running Timer (ART) feature %x for TSC on all CPUs - TSC/CCC: %d/%d offset: %llu.\n", X86_FEATURE_ART, art_to_tsc_numerator, art_to_tsc_denominator, art_to_tsc_offset ); setup_force_cpu_cap(X86_FEATURE_ART); }