freebsd-dev/sys
Konstantin Belousov 814124c33e diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c
index c253a96..3d8bd30 100644
--- a/sys/x86/x86/tsc.c
+++ b/sys/x86/x86/tsc.c
@@ -82,7 +82,11 @@ static void tsc_freq_changed(void *arg, const struct cf_level *level,
 static void tsc_freq_changing(void *arg, const struct cf_level *level,
     int *status);
 static unsigned tsc_get_timecount(struct timecounter *tc);
-static unsigned tsc_get_timecount_low(struct timecounter *tc);
+static inline unsigned tsc_get_timecount_low(struct timecounter *tc);
+static unsigned tsc_get_timecount_lfence(struct timecounter *tc);
+static unsigned tsc_get_timecount_low_lfence(struct timecounter *tc);
+static unsigned tsc_get_timecount_mfence(struct timecounter *tc);
+static unsigned tsc_get_timecount_low_mfence(struct timecounter *tc);
 static void tsc_levels_changed(void *arg, int unit);

 static struct timecounter tsc_timecounter = {
@@ -262,6 +266,10 @@ probe_tsc_freq(void)
 		    (vm_guest == VM_GUEST_NO &&
 		    CPUID_TO_FAMILY(cpu_id) >= 0x10))
 			tsc_is_invariant = 1;
+		if (cpu_feature & CPUID_SSE2) {
+			tsc_timecounter.tc_get_timecount =
+			    tsc_get_timecount_mfence;
+		}
 		break;
 	case CPU_VENDOR_INTEL:
 		if ((amd_pminfo & AMDPM_TSC_INVARIANT) != 0 ||
@@ -271,6 +279,10 @@ probe_tsc_freq(void)
 		    (CPUID_TO_FAMILY(cpu_id) == 0xf &&
 		    CPUID_TO_MODEL(cpu_id) >= 0x3))))
 			tsc_is_invariant = 1;
+		if (cpu_feature & CPUID_SSE2) {
+			tsc_timecounter.tc_get_timecount =
+			    tsc_get_timecount_lfence;
+		}
 		break;
 	case CPU_VENDOR_CENTAUR:
 		if (vm_guest == VM_GUEST_NO &&
@@ -278,6 +290,10 @@ probe_tsc_freq(void)
 		    CPUID_TO_MODEL(cpu_id) >= 0xf &&
 		    (rdmsr(0x1203) & 0x100000000ULL) == 0)
 			tsc_is_invariant = 1;
+		if (cpu_feature & CPUID_SSE2) {
+			tsc_timecounter.tc_get_timecount =
+			    tsc_get_timecount_lfence;
+		}
 		break;
 	}

@@ -328,16 +344,31 @@ init_TSC(void)

 #ifdef SMP

-/* rmb is required here because rdtsc is not a serializing instruction. */
-#define	TSC_READ(x)			\
-static void				\
-tsc_read_##x(void *arg)			\
-{					\
-	uint32_t *tsc = arg;		\
-	u_int cpu = PCPU_GET(cpuid);	\
-					\
-	rmb();				\
-	tsc[cpu * 3 + x] = rdtsc32();	\
+/*
+ * RDTSC is not a serializing instruction, and does not drain
+ * instruction stream, so we need to drain the stream before executing
+ * it.  It could be fixed by use of RDTSCP, except the instruction is
+ * not available everywhere.
+ *
+ * Use CPUID for draining in the boot-time SMP constistency test.  The
+ * timecounters use MFENCE for AMD CPUs, and LFENCE for others (Intel
+ * and VIA) when SSE2 is present, and nothing on older machines which
+ * also do not issue RDTSC prematurely.  There, testing for SSE2 and
+ * vendor is too cumbersome, and we learn about TSC presence from
+ * CPUID.
+ *
+ * Do not use do_cpuid(), since we do not need CPUID results, which
+ * have to be written into memory with do_cpuid().
+ */
+#define	TSC_READ(x)							\
+static void								\
+tsc_read_##x(void *arg)							\
+{									\
+	uint32_t *tsc = arg;						\
+	u_int cpu = PCPU_GET(cpuid);					\
+									\
+	__asm __volatile("cpuid" : : : "eax", "ebx", "ecx", "edx");	\
+	tsc[cpu * 3 + x] = rdtsc32();					\
 }
 TSC_READ(0)
 TSC_READ(1)
@@ -487,7 +518,16 @@ init:
 	for (shift = 0; shift < 31 && (tsc_freq >> shift) > max_freq; shift++)
 		;
 	if (shift > 0) {
-		tsc_timecounter.tc_get_timecount = tsc_get_timecount_low;
+		if (cpu_feature & CPUID_SSE2) {
+			if (cpu_vendor_id == CPU_VENDOR_AMD) {
+				tsc_timecounter.tc_get_timecount =
+				    tsc_get_timecount_low_mfence;
+			} else {
+				tsc_timecounter.tc_get_timecount =
+				    tsc_get_timecount_low_lfence;
+			}
+		} else
+			tsc_timecounter.tc_get_timecount = tsc_get_timecount_low;
 		tsc_timecounter.tc_name = "TSC-low";
 		if (bootverbose)
 			printf("TSC timecounter discards lower %d bit(s)\n",
@@ -599,16 +639,48 @@ tsc_get_timecount(struct timecounter *tc __unused)
 	return (rdtsc32());
 }

-static u_int
+static inline u_int
 tsc_get_timecount_low(struct timecounter *tc)
 {
 	uint32_t rv;

 	__asm __volatile("rdtsc; shrd %%cl, %%edx, %0"
-	: "=a" (rv) : "c" ((int)(intptr_t)tc->tc_priv) : "edx");
+	    : "=a" (rv) : "c" ((int)(intptr_t)tc->tc_priv) : "edx");
 	return (rv);
 }

+static u_int
+tsc_get_timecount_lfence(struct timecounter *tc __unused)
+{
+
+	lfence();
+	return (rdtsc32());
+}
+
+static u_int
+tsc_get_timecount_low_lfence(struct timecounter *tc)
+{
+
+	lfence();
+	return (tsc_get_timecount_low(tc));
+}
+
+static u_int
+tsc_get_timecount_mfence(struct timecounter *tc __unused)
+{
+
+	mfence();
+	return (rdtsc32());
+}
+
+static u_int
+tsc_get_timecount_low_mfence(struct timecounter *tc)
+{
+
+	mfence();
+	return (tsc_get_timecount_low(tc));
+}
+
 uint32_t
 cpu_fill_vdso_timehands(struct vdso_timehands *vdso_th)
 {
2012-08-01 17:26:22 +00:00
..
amd64 Add lfence(). 2012-08-01 17:24:53 +00:00
arm Prefer ate over macb. macb doesn't work anymore, and ate has more 2012-07-31 19:41:12 +00:00
boot Pull the tier-2 card and change the sparc64 ZFS loader to no longer probe 2012-07-27 18:23:11 +00:00
bsm
cam Remove opt_enc.h from files committed with r235911. enc(4) is the 2012-07-30 03:00:58 +00:00
cddl Partial MFV (illumos-gate 13753:2aba784c276b) 2012-07-30 23:14:24 +00:00
compat Cosmetics: define FREEBSD32_MINUSER and AOUT32_MINUSER for struct 2012-07-22 13:41:45 +00:00
conf Until now KTR_ENTRIES, which defines the size of circular buffer used in 2012-07-30 22:46:42 +00:00
contrib Update to latest git version of dtc to get new dtsv2 support, 2012-07-24 16:29:33 +00:00
crypto Add support for the extended FPU states on amd64, both for native 2012-01-21 17:45:27 +00:00
ddb Update the ddb and gdb backends for the new 'trace_thread' hook. 2012-04-12 21:34:58 +00:00
dev Fix kernel panic on camcontrol reset for specific target, caused by 2012-08-01 12:24:13 +00:00
fs I am comparing current pipe code with the one in 8.3-STABLE r236165, 2012-07-31 05:48:35 +00:00
gdb Update the ddb and gdb backends for the new 'trace_thread' hook. 2012-04-12 21:34:58 +00:00
geom Partially revert r238886 in part of GEOM_VFS spoiling. 2012-07-29 20:04:09 +00:00
gnu/fs Fix build: 2012-05-23 06:49:50 +00:00
i386 Add lfence(). 2012-08-01 17:24:53 +00:00
ia64 Move PCPU initialization to a new function called cpu_pcpu_setup(). 2012-07-08 18:00:22 +00:00
isa
kern Reorder the managament of advisory locks on open files so that the advisory 2012-07-31 18:25:00 +00:00
kgssapi
libkern Fix unloading of libiconv module. 2012-06-11 17:42:39 +00:00
mips Merge FreeBSD/beri Perforce change @211945 to head: 2012-07-28 11:09:03 +00:00
modules Remove opt_enc.h from files committed with r235911. enc(4) is the 2012-07-30 03:00:58 +00:00
net Some more whitespace cleanup. 2012-08-01 09:00:26 +00:00
net80211 Fixed some debug output in hwmp_recv_prep. 2012-07-31 08:05:40 +00:00
netatalk Fix typos 2012-02-28 15:07:05 +00:00
netgraph Add version so others can depend on this module 2012-07-27 13:57:28 +00:00
netinet Some more whitespace cleanup. 2012-08-01 09:00:26 +00:00
netinet6 Some more whitespace cleanup. 2012-08-01 09:00:26 +00:00
netipsec Fix a bug introduced in r221129 that leads to a panic wen using bundled 2012-07-22 17:46:05 +00:00
netipx
netnatm
netncp Add characters mapping for codepages used in Germany. 2012-06-01 03:59:08 +00:00
netsmb Change a duplicated check to clarify that we really want to set a 2012-07-10 21:02:59 +00:00
nfs Add multi-FIB IPv6 support to the core network stack supplementing 2012-02-03 13:08:44 +00:00
nfsclient PR# 165923 reported intermittent write failures for dirty 2012-05-12 12:02:51 +00:00
nfsserver
nlm jwd@ reported a problem via email to freebsd-fs@ on Aug 25, 2011 2012-01-31 02:11:05 +00:00
ofed Fix clang warning when compiling iw_cxgb. 2012-06-25 16:52:27 +00:00
opencrypto
pc98 Partially revert r217515 so that the mem_range_softc variable is always 2012-07-09 20:42:08 +00:00
pci intpm: add ATI IXP400 pci id 2012-04-16 10:33:46 +00:00
powerpc Avoid recursion on the pvh global lock in the aim oea pmap. 2012-07-10 22:10:21 +00:00
rpc
security Check vplabel for NULL before dereferencing it. Fixes a panic 2012-05-03 15:51:34 +00:00
sparc64 Switch back to the 4BSD scheduler for now. There is some more or less 2012-06-30 14:55:36 +00:00
sys I am comparing current pipe code with the one in 8.3-STABLE r236165, 2012-07-31 05:48:35 +00:00
teken
tools Make vnode_if.awk parse vnode operations with underscores, like VOP_FOO_BAR. 2012-02-21 19:35:59 +00:00
ufs Use NULL instead of 0 for pointers 2012-07-22 15:40:31 +00:00
vm Eliminate an unneeded declaration. (I should have removed this as part 2012-07-30 20:38:37 +00:00
x86 diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c 2012-08-01 17:26:22 +00:00
xdr
xen blkif interface comment cleanups. No functional changes 2012-02-29 17:47:01 +00:00
Makefile Add sys/ofed to the 'make cscope' target. 2012-03-20 18:05:15 +00:00