From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751916AbdIUUWW (ORCPT ); Thu, 21 Sep 2017 16:22:22 -0400 Received: from relay2.sgi.com ([192.48.180.65]:43323 "EHLO relay.sgi.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751729AbdIUUWU (ORCPT ); Thu, 21 Sep 2017 16:22:20 -0400 X-Greylist: delayed 595 seconds by postgrey-1.27 at vger.kernel.org; Thu, 21 Sep 2017 16:22:19 EDT Message-Id: <20170921201222.033552716@stormcage.americas.sgi.com> References: <20170921201221.869441567@stormcage.americas.sgi.com> User-Agent: quilt/0.46-1 Date: Thu, 21 Sep 2017 15:12:22 -0500 From: To: Ingo Molnar , "H. Peter Anvin" , Thomas Gleixner Cc: Peter Zijlstra , Bin Gao , Prarit Bhargava , Dimitri Sivanich , Andrew Banman , Russ Anderson , linux-kernel@vger.kernel.org, x86@kernel.org Subject: [PATCH 1/3] x86/kernel: Add option that TSC on Socket 0 being non-null is valid Content-Disposition: inline; filename=add-base-nonzero Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add a flag to indicate that a TSC ADJUST value of non-zero is valid on Socket 0. This is required on multiple chassis systems for which the Time Stamp Counter on all the chassis are started asynchronously. The UV architecture is an example of this. In this scenario the UV system BIOS will adjust all the TSC ADJUST values forward so there are no negative ADJUST values. This may cause the TSC ADJUST value on socket 0 to not necessarily be zero. This procedure results TSC skew rates that are far less than the values as set by the current kernel TSC adjustment functions which force the TSC ADJUST to be zero on Socket 0. Note also that an assumption of zero for TSC ADJUST was also made by not initializing the adjust values. Signed-off-by: Mike Travis Reviewed-by: Dimitri Sivanich Reviewed-by: Russ Anderson Reviewed-by: Andrew Banman --- arch/x86/include/asm/tsc.h | 2 ++ arch/x86/kernel/tsc.c | 19 +++++++++++++++++++ arch/x86/kernel/tsc_sync.c | 25 +++++++++++++++++++++---- 3 files changed, 42 insertions(+), 4 deletions(-) --- linux.orig/arch/x86/include/asm/tsc.h +++ linux/arch/x86/include/asm/tsc.h @@ -35,6 +35,8 @@ extern void tsc_init(void); extern void mark_tsc_unstable(char *reason); extern int unsynchronized_tsc(void); extern int check_tsc_unstable(void); +extern int check_tsc_socket0_nonzero(void); +extern void mark_tsc_socket0_nonzero(char *reason); extern unsigned long native_calibrate_cpu(void); extern unsigned long native_calibrate_tsc(void); extern unsigned long long native_sched_clock_from_tsc(u64 tsc); --- linux.orig/arch/x86/kernel/tsc.c +++ linux/arch/x86/kernel/tsc.c @@ -37,6 +37,11 @@ EXPORT_SYMBOL(tsc_khz); */ static int __read_mostly tsc_unstable; +/* + * TSC on socket 0 being non-zero may be correct as set by BIOS + */ +static int __read_mostly tsc_socket0_nonzero; + /* native_sched_clock() is called before tsc_init(), so we must start with the TSC soft disabled to prevent erroneous rdtsc usage on !boot_cpu_has(X86_FEATURE_TSC) processors */ @@ -244,6 +249,20 @@ int check_tsc_unstable(void) } EXPORT_SYMBOL_GPL(check_tsc_unstable); +void mark_tsc_socket0_nonzero(char *reason) +{ + tsc_socket0_nonzero = 1; + pr_info("Marking TSC non-zero value valid for socket 0 due to %s\n", + reason); +} +EXPORT_SYMBOL_GPL(mark_tsc_socket0_nonzero); + +int check_tsc_socket0_nonzero(void) +{ + return tsc_socket0_nonzero; +} +EXPORT_SYMBOL_GPL(check_tsc_socket0_nonzero); + #ifdef CONFIG_X86_TSC int __init notsc_setup(char *str) { --- linux.orig/arch/x86/kernel/tsc_sync.c +++ linux/arch/x86/kernel/tsc_sync.c @@ -71,12 +71,22 @@ static void tsc_sanitize_first_cpu(struc * non zero. We don't do that on non boot cpus because physical * hotplug should have set the ADJUST register to a value > 0 so * the TSC is in sync with the already running cpus. + * + * Also don't force the ADJUST value from non-zero to zero if that + * is a valid value for socket 0 as determined by the system BIOS. + * This is required where multiple chassis are started asynchronously + * with each other and socket 0 may not have an TSC ADJUST value of 0. */ if (bootcpu && bootval != 0) { - pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu, - bootval); - wrmsrl(MSR_IA32_TSC_ADJUST, 0); - bootval = 0; + if (!check_tsc_socket0_nonzero()) { + pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", + cpu, bootval); + wrmsrl(MSR_IA32_TSC_ADJUST, 0); + bootval = 0; + } else { + pr_info("TSC ADJUST: CPU%u: %lld NOT forced to 0\n", + cpu, bootval); + } } cur->adjusted = bootval; } @@ -118,6 +128,13 @@ bool tsc_store_and_check_tsc_adjust(bool cur->warned = false; /* + * If a non-zero TSC value for socket 0 is valid then the default + * adjusted value cannot assumed to be zero. + */ + if (check_tsc_socket0_nonzero()) + cur->adjusted = bootval; + + /* * Check whether this CPU is the first in a package to come up. In * this case do not check the boot value against another package * because the new package might have been physically hotplugged, --