Date: Mon, 9 May 2011 17:34:00 +0000 (UTC) From: Jung-uk Kim <jkim@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r221703 - in head/sys: amd64/include i386/include x86/isa x86/x86 Message-ID: <201105091734.p49HY0P3006180@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jkim Date: Mon May 9 17:34:00 2011 New Revision: 221703 URL: http://svn.freebsd.org/changeset/base/221703 Log: Implement boot-time TSC synchronization test for SMP. This test is executed when the user has indicated that the system has synchronized TSCs or it has P-state invariant TSCs. For the former case, we may clear the tunable if it fails the test to prevent accidental foot-shooting. For the latter case, we may set it if it passes the test to notify the user that it may be usable. Modified: head/sys/amd64/include/clock.h head/sys/i386/include/clock.h head/sys/x86/isa/clock.c head/sys/x86/x86/tsc.c Modified: head/sys/amd64/include/clock.h ============================================================================== --- head/sys/amd64/include/clock.h Mon May 9 17:30:25 2011 (r221702) +++ head/sys/amd64/include/clock.h Mon May 9 17:34:00 2011 (r221703) @@ -29,7 +29,6 @@ void i8254_init(void); void startrtclock(void); void init_TSC(void); -void init_TSC_tc(void); #define HAS_TIMER_SPKR 1 int timer_spkr_acquire(void); Modified: head/sys/i386/include/clock.h ============================================================================== --- head/sys/i386/include/clock.h Mon May 9 17:30:25 2011 (r221702) +++ head/sys/i386/include/clock.h Mon May 9 17:34:00 2011 (r221703) @@ -30,7 +30,6 @@ void i8254_init(void); void startrtclock(void); void timer_restore(void); void init_TSC(void); -void init_TSC_tc(void); #define HAS_TIMER_SPKR 1 int timer_spkr_acquire(void); Modified: head/sys/x86/isa/clock.c ============================================================================== --- head/sys/x86/isa/clock.c Mon May 9 17:30:25 2011 (r221702) +++ head/sys/x86/isa/clock.c Mon May 9 17:34:00 2011 (r221703) @@ -498,7 +498,6 @@ void cpu_initclocks(void) { - init_TSC_tc(); cpu_initclocks_bsp(); } Modified: head/sys/x86/x86/tsc.c ============================================================================== --- head/sys/x86/x86/tsc.c Mon May 9 17:30:25 2011 (r221702) +++ head/sys/x86/x86/tsc.c Mon May 9 17:34:00 2011 (r221703) @@ -326,7 +326,73 @@ init_TSC(void) tsc_levels_changed, NULL, EVENTHANDLER_PRI_ANY); } -void +#ifdef SMP + +#define TSC_READ(x) \ +static void \ +tsc_read_##x(void *arg) \ +{ \ + uint32_t *tsc = arg; \ + u_int cpu = PCPU_GET(cpuid); \ + \ + tsc[cpu * 3 + x] = rdtsc32(); \ +} +TSC_READ(0) +TSC_READ(1) +TSC_READ(2) +#undef TSC_READ + +#define N 1000 + +static void +comp_smp_tsc(void *arg) +{ + uint32_t *tsc; + int32_t d1, d2; + u_int cpu = PCPU_GET(cpuid); + u_int i, j, size; + + size = (mp_maxid + 1) * 3; + for (i = 0, tsc = arg; i < N; i++, tsc += size) + CPU_FOREACH(j) { + if (j == cpu) + continue; + d1 = tsc[cpu * 3 + 1] - tsc[j * 3]; + d2 = tsc[cpu * 3 + 2] - tsc[j * 3 + 1]; + if (d1 <= 0 || d2 <= 0) { + smp_tsc = 0; + return; + } + } +} + +static int +test_smp_tsc(void) +{ + uint32_t *data, *tsc; + u_int i, size; + + if (!smp_tsc && !tsc_is_invariant) + return (-100); + size = (mp_maxid + 1) * 3; + data = malloc(sizeof(*data) * size * N, M_TEMP, M_WAITOK); + for (i = 0, tsc = data; i < N; i++, tsc += size) + smp_rendezvous(tsc_read_0, tsc_read_1, tsc_read_2, tsc); + smp_tsc = 1; /* XXX */ + smp_rendezvous(smp_no_rendevous_barrier, comp_smp_tsc, + smp_no_rendevous_barrier, data); + free(data, M_TEMP); + if (bootverbose) + printf("SMP: %sed TSC synchronization test\n", + smp_tsc ? "pass" : "fail"); + return (smp_tsc ? 800 : -100); +} + +#undef N + +#endif /* SMP */ + +static void init_TSC_tc(void) { @@ -347,26 +413,25 @@ init_TSC_tc(void) tsc_timecounter.tc_quality = -1000; if (bootverbose) printf("TSC timecounter disabled: APM enabled.\n"); + goto init; } #ifdef SMP /* - * We can not use the TSC in SMP mode unless the TSCs on all CPUs - * are somehow synchronized. Some hardware configurations do - * this, but we have no way of determining whether this is the - * case, so we do not use the TSC in multi-processor systems - * unless the user indicated (by setting kern.timecounter.smp_tsc - * to 1) that he believes that his TSCs are synchronized. + * We can not use the TSC in SMP mode unless the TSCs on all CPUs are + * synchronized. If the user is sure that the system has synchronized + * TSCs, set kern.timecounter.smp_tsc tunable to a non-zero value. */ - if (mp_ncpus > 1 && !smp_tsc) - tsc_timecounter.tc_quality = -100; + if (smp_cpus > 1) + tsc_timecounter.tc_quality = test_smp_tsc(); #endif - +init: if (tsc_freq != 0) { tsc_timecounter.tc_frequency = tsc_freq; tc_init(&tsc_timecounter); } } +SYSINIT(tsc_tc, SI_SUB_SMP, SI_ORDER_ANY, init_TSC_tc, NULL); /* * When cpufreq levels change, find out about the (new) max frequency. We
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105091734.p49HY0P3006180>