svn commit: r334204 - in head/sys: amd64/include dev/acpica i386/include x86/x86

Andriy Gapon avg at FreeBSD.org
Fri May 25 07:33:22 UTC 2018


Author: avg
Date: Fri May 25 07:33:20 2018
New Revision: 334204
URL: https://svnweb.freebsd.org/changeset/base/334204

Log:
  re-synchronize TSC-s on SMP systems after resume, if necessary
  
  The TSC-s are checked and synchronized only if they were good
  originally.  That is, invariant, synchronized, etc.
  
  This is necessary on an AMD-based system where after a wakeup from STR I
  see that BSP clock differs from AP clocks by a count that roughly
  corresponds to one second.  The APs are in sync with each other.  Not
  sure if this is a hardware quirk or a firmware bug.
  
  This is what I see after a resume with this change:
      SMP: passed TSC synchronization test after adjustment
      acpi_timer0: restoring timecounter, ACPI-fast -> TSC-low
  
  Reviewed by:	kib
  MFC after:	3 weeks
  Differential Revision: https://reviews.freebsd.org/D15551

Modified:
  head/sys/amd64/include/clock.h
  head/sys/dev/acpica/acpi.c
  head/sys/i386/include/clock.h
  head/sys/x86/x86/tsc.c

Modified: head/sys/amd64/include/clock.h
==============================================================================
--- head/sys/amd64/include/clock.h	Fri May 25 07:29:52 2018	(r334203)
+++ head/sys/amd64/include/clock.h	Fri May 25 07:33:20 2018	(r334204)
@@ -34,6 +34,7 @@ void	clock_init(void);
 
 void	startrtclock(void);
 void	init_TSC(void);
+void	resume_TSC(void);
 
 #define	HAS_TIMER_SPKR 1
 int	timer_spkr_acquire(void);

Modified: head/sys/dev/acpica/acpi.c
==============================================================================
--- head/sys/dev/acpica/acpi.c	Fri May 25 07:29:52 2018	(r334203)
+++ head/sys/dev/acpica/acpi.c	Fri May 25 07:33:20 2018	(r334204)
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/timetc.h>
 
 #if defined(__i386__) || defined(__amd64__)
+#include <machine/clock.h>
 #include <machine/pci_cfgreg.h>
 #endif
 #include <machine/resource.h>
@@ -3040,6 +3041,10 @@ backout:
     if (slp_state >= ACPI_SS_SLP_PREP)
 	AcpiLeaveSleepState(state);
     if (slp_state >= ACPI_SS_SLEPT) {
+#if defined(__i386__) || defined(__amd64__)
+	/* NB: we are still using ACPI timecounter at this point. */
+	resume_TSC();
+#endif
 	acpi_resync_clock(sc);
 	acpi_enable_fixed_events(sc);
     }

Modified: head/sys/i386/include/clock.h
==============================================================================
--- head/sys/i386/include/clock.h	Fri May 25 07:29:52 2018	(r334203)
+++ head/sys/i386/include/clock.h	Fri May 25 07:33:20 2018	(r334204)
@@ -32,6 +32,7 @@ void	clock_init(void);
 void	startrtclock(void);
 void	timer_restore(void);
 void	init_TSC(void);
+void	resume_TSC(void);
 
 #define	HAS_TIMER_SPKR 1
 int	timer_spkr_acquire(void);

Modified: head/sys/x86/x86/tsc.c
==============================================================================
--- head/sys/x86/x86/tsc.c	Fri May 25 07:29:52 2018	(r334203)
+++ head/sys/x86/x86/tsc.c	Fri May 25 07:33:20 2018	(r334204)
@@ -451,7 +451,7 @@ adj_smp_tsc(void *arg)
 }
 
 static int
-test_tsc(void)
+test_tsc(int adj_max_count)
 {
 	uint64_t *data, *tsc;
 	u_int i, size, adj;
@@ -467,7 +467,7 @@ retry:
 	smp_tsc = 1;	/* XXX */
 	smp_rendezvous(smp_no_rendezvous_barrier, comp_smp_tsc,
 	    smp_no_rendezvous_barrier, data);
-	if (!smp_tsc && adj < smp_tsc_adjust) {
+	if (!smp_tsc && adj < adj_max_count) {
 		adj++;
 		smp_rendezvous(smp_no_rendezvous_barrier, adj_smp_tsc,
 		    smp_no_rendezvous_barrier, data);
@@ -512,7 +512,7 @@ retry:
  * on uniprocessor kernel.
  */
 static int
-test_tsc(void)
+test_tsc(int adj_max_count __unused)
 {
 
 	return (0);
@@ -579,7 +579,7 @@ init_TSC_tc(void)
 	 * environments, so it is set to a negative quality in those cases.
 	 */
 	if (mp_ncpus > 1)
-		tsc_timecounter.tc_quality = test_tsc();
+		tsc_timecounter.tc_quality = test_tsc(smp_tsc_adjust);
 	else if (tsc_is_invariant)
 		tsc_timecounter.tc_quality = 1000;
 	max_freq >>= tsc_shift;
@@ -614,6 +614,30 @@ init:
 	}
 }
 SYSINIT(tsc_tc, SI_SUB_SMP, SI_ORDER_ANY, init_TSC_tc, NULL);
+
+void
+resume_TSC(void)
+{
+	int quality;
+
+	/* If TSC was not good on boot, it is unlikely to become good now. */
+	if (tsc_timecounter.tc_quality < 0)
+		return;
+	/* Nothing to do with UP. */
+	if (mp_ncpus < 2)
+		return;
+
+	/*
+	 * If TSC was good, a single synchronization should be enough,
+	 * but honour smp_tsc_adjust if it's set.
+	 */
+	quality = test_tsc(MAX(smp_tsc_adjust, 1));
+	if (quality != tsc_timecounter.tc_quality) {
+		printf("TSC timecounter quality changed: %d -> %d\n",
+		    tsc_timecounter.tc_quality, quality);
+		tsc_timecounter.tc_quality = quality;
+	}
+}
 
 /*
  * When cpufreq levels change, find out about the (new) max frequency.  We


More information about the svn-src-head mailing list