Module Name:    src
Committed By:   ad
Date:           Wed May 20 20:19:02 UTC 2020

Modified Files:
        src/sys/arch/x86/x86: tsc.c

Log Message:
The boot CPU suffers a cache miss during TSC sync, before RDTSC.  Make the
secondary CPU take a miss as well to try and delay it an equal amount.


To generate a diff of this commit:
cvs rdiff -u -r1.46 -r1.47 src/sys/arch/x86/x86/tsc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/tsc.c
diff -u src/sys/arch/x86/x86/tsc.c:1.46 src/sys/arch/x86/x86/tsc.c:1.47
--- src/sys/arch/x86/x86/tsc.c:1.46	Tue May 19 21:56:51 2020
+++ src/sys/arch/x86/x86/tsc.c	Wed May 20 20:19:02 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: tsc.c,v 1.46 2020/05/19 21:56:51 ad Exp $	*/
+/*	$NetBSD: tsc.c,v 1.47 2020/05/20 20:19:02 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tsc.c,v 1.46 2020/05/19 21:56:51 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tsc.c,v 1.47 2020/05/20 20:19:02 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -54,6 +54,7 @@ u_int	tsc_get_timecount(struct timecount
 
 static void	tsc_delay(unsigned int);
 
+static uint64_t	tsc_dummy_cacheline __cacheline_aligned;
 uint64_t	tsc_freq; /* exported for sysctl */
 static int64_t	tsc_drift_max = 1000;	/* max cycles */
 static int64_t	tsc_drift_observed;
@@ -200,7 +201,7 @@ tsc_sync_drift(int64_t drift)
  * Called during startup of APs, by the boot processor.  Interrupts
  * are disabled on entry.
  */
-static void
+static void __noinline
 tsc_read_bp(struct cpu_info *ci, uint64_t *bptscp, uint64_t *aptscp)
 {
 	uint64_t bptsc;
@@ -209,10 +210,13 @@ tsc_read_bp(struct cpu_info *ci, uint64_
 		panic("tsc_sync_bp: 1");
 	}
 
-	/* Flag it and read our TSC. */
+	/* Prepare a cache miss for the other side. */
+	(void)atomic_swap_uint((void *)&tsc_dummy_cacheline, 0);
+
+	/* Flag our readiness. */
 	atomic_or_uint(&ci->ci_flags, CPUF_SYNCTSC);
 
-	/* Wait for remote to complete, and read ours again. */
+	/* Wait for other side then read our TSC. */
 	while ((ci->ci_flags & CPUF_SYNCTSC) != 0) {
 		__insn_barrier();
 	}
@@ -254,7 +258,7 @@ tsc_sync_bp(struct cpu_info *ci)
  * Called during startup of AP, by the AP itself.  Interrupts are
  * disabled on entry.
  */
-static void
+static void __noinline
 tsc_post_ap(struct cpu_info *ci)
 {
 	uint64_t tsc;
@@ -266,7 +270,12 @@ tsc_post_ap(struct cpu_info *ci)
 
 	/* Instruct primary to read its counter. */
 	atomic_and_uint(&ci->ci_flags, ~CPUF_SYNCTSC);
-	tsc = rdtsc();
+
+	/* Suffer a cache miss, then read TSC. */
+	__insn_barrier();
+	tsc = tsc_dummy_cacheline;
+	__insn_barrier();
+	tsc += rdtsc();
 
 	/* Post result.  Ensure the whole value goes out atomically. */
 	(void)atomic_swap_64(&tsc_sync_val, tsc);

Reply via email to