aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2018-05-25 07:33:20 +0000
committerAndriy Gapon <avg@FreeBSD.org>2018-05-25 07:33:20 +0000
commit279be68bfdf69ef764201a4adf9d689074a70d63 (patch)
tree9393a3233d7e2088969128e0cf3a75da0014fbcf
parent620b779158880a4c5c1e84cca36ebe3b3801cceb (diff)
Notes
-rw-r--r--sys/amd64/include/clock.h1
-rw-r--r--sys/dev/acpica/acpi.c5
-rw-r--r--sys/i386/include/clock.h1
-rw-r--r--sys/x86/x86/tsc.c32
4 files changed, 35 insertions, 4 deletions
diff --git a/sys/amd64/include/clock.h b/sys/amd64/include/clock.h
index 65bf8bd93bb4..86a4541568ed 100644
--- a/sys/amd64/include/clock.h
+++ b/sys/amd64/include/clock.h
@@ -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);
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index aec4e278053f..b9de85d236ed 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -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);
}
diff --git a/sys/i386/include/clock.h b/sys/i386/include/clock.h
index 564d231dde0c..91cdfe50f525 100644
--- a/sys/i386/include/clock.h
+++ b/sys/i386/include/clock.h
@@ -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);
diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c
index bb6e8768de5a..aecc6702d075 100644
--- a/sys/x86/x86/tsc.c
+++ b/sys/x86/x86/tsc.c
@@ -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;
@@ -615,6 +615,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
* use this to update CPU accounting in case it got a lower estimate at boot.