summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-04-02 01:02:42 +0000
committerjhb <jhb@FreeBSD.org>2015-04-02 01:02:42 +0000
commitb09b758bf25e41249b9253a3a796713405f28b4d (patch)
tree7694f537b30d0bb29bc4821549a8b28e4d2fb4b4 /sys
parent5fdf8ec7775f40bbf293206a9670387f9b26b1e2 (diff)
downloadFreeBSD-src-b09b758bf25e41249b9253a3a796713405f28b4d.zip
FreeBSD-src-b09b758bf25e41249b9253a3a796713405f28b4d.tar.gz
MFC 276724:
On some Intel CPUs with a P-state but not C-state invariant TSC the TSC may also halt in C2 and not just C3 (it seems that in some cases the BIOS advertises its C3 state as a C2 state in _CST). Just play it safe and disable both C2 and C3 states if a user forces the use of the TSC as the timecounter on such CPUs. PR: 192316
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/amd64/machdep.c2
-rw-r--r--sys/dev/acpica/acpi_cpu.c17
-rw-r--r--sys/i386/i386/machdep.c2
-rw-r--r--sys/kern/kern_clocksource.c11
-rw-r--r--sys/kern/kern_tc.c8
-rw-r--r--sys/sys/systm.h5
-rw-r--r--sys/sys/timetc.h2
-rw-r--r--sys/x86/x86/tsc.c12
8 files changed, 36 insertions, 23 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 06ab958..70e12bf 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -827,7 +827,7 @@ cpu_idle(int busy)
}
/* Apply AMD APIC timer C1E workaround. */
- if (cpu_ident_amdc1e && cpu_disable_deep_sleep) {
+ if (cpu_ident_amdc1e && cpu_disable_c3_sleep) {
msr = rdmsr(MSR_AMDK8_IPM);
if (msr & AMDK8_CMPHALT)
wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT);
diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c
index cfa833a..958ff9f 100644
--- a/sys/dev/acpica/acpi_cpu.c
+++ b/sys/dev/acpica/acpi_cpu.c
@@ -85,6 +85,7 @@ struct acpi_cpu_softc {
int cpu_prev_sleep;/* Last idle sleep duration. */
int cpu_features; /* Child driver supported features. */
/* Runtime state. */
+ int cpu_non_c2; /* Index of lowest non-C2 state. */
int cpu_non_c3; /* Index of lowest non-C3 state. */
u_int cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
/* Values for sysctl. */
@@ -664,8 +665,10 @@ acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc)
cx_ptr->type = ACPI_STATE_C1;
cx_ptr->trans_lat = 0;
cx_ptr++;
+ sc->cpu_non_c2 = sc->cpu_cx_count;
sc->cpu_non_c3 = sc->cpu_cx_count;
sc->cpu_cx_count++;
+ cpu_deepest_sleep = 1;
/*
* The spec says P_BLK must be 6 bytes long. However, some systems
@@ -691,6 +694,7 @@ acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc)
cx_ptr++;
sc->cpu_non_c3 = sc->cpu_cx_count;
sc->cpu_cx_count++;
+ cpu_deepest_sleep = 2;
}
}
if (sc->cpu_p_blk_len < 6)
@@ -707,7 +711,7 @@ acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc)
cx_ptr->trans_lat = AcpiGbl_FADT.C3Latency;
cx_ptr++;
sc->cpu_cx_count++;
- cpu_can_deep_sleep = 1;
+ cpu_deepest_sleep = 3;
}
}
}
@@ -753,6 +757,7 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
count = MAX_CX_STATES;
}
+ sc->cpu_non_c2 = 0;
sc->cpu_non_c3 = 0;
sc->cpu_cx_count = 0;
cx_ptr = sc->cpu_cx_states;
@@ -764,6 +769,7 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
cx_ptr->type = ACPI_STATE_C0;
cx_ptr++;
sc->cpu_cx_count++;
+ cpu_deepest_sleep = 1;
/* Set up all valid states. */
for (i = 0; i < count; i++) {
@@ -784,6 +790,7 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
/* This is the first C1 state. Use the reserved slot. */
sc->cpu_cx_states[0] = *cx_ptr;
} else {
+ sc->cpu_non_c2 = sc->cpu_cx_count;
sc->cpu_non_c3 = sc->cpu_cx_count;
cx_ptr++;
sc->cpu_cx_count++;
@@ -791,6 +798,8 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
continue;
case ACPI_STATE_C2:
sc->cpu_non_c3 = sc->cpu_cx_count;
+ if (cpu_deepest_sleep < 2)
+ cpu_deepest_sleep = 2;
break;
case ACPI_STATE_C3:
default:
@@ -800,7 +809,7 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
device_get_unit(sc->cpu_dev), i));
continue;
} else
- cpu_can_deep_sleep = 1;
+ cpu_deepest_sleep = 3;
break;
}
@@ -984,7 +993,9 @@ acpi_cpu_idle(sbintime_t sbt)
if (sbt >= 0 && us > (sbt >> 12))
us = (sbt >> 12);
cx_next_idx = 0;
- if (cpu_disable_deep_sleep)
+ if (cpu_disable_c2_sleep)
+ i = min(sc->cpu_cx_lowest, sc->cpu_non_c2);
+ else if (cpu_disable_c3_sleep)
i = min(sc->cpu_cx_lowest, sc->cpu_non_c3);
else
i = sc->cpu_cx_lowest;
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index bbedfe0..e2e2932 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -1478,7 +1478,7 @@ cpu_idle(int busy)
#ifndef XEN
/* Apply AMD APIC timer C1E workaround. */
- if (cpu_ident_amdc1e && cpu_disable_deep_sleep) {
+ if (cpu_ident_amdc1e && cpu_disable_c3_sleep) {
msr = rdmsr(MSR_AMDK8_IPM);
if (msr & AMDK8_CMPHALT)
wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT);
diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c
index 739f850..b98c4ed 100644
--- a/sys/kern/kern_clocksource.c
+++ b/sys/kern/kern_clocksource.c
@@ -60,8 +60,9 @@ __FBSDID("$FreeBSD$");
cyclic_clock_func_t cyclic_clock_func = NULL;
#endif
-int cpu_can_deep_sleep = 0; /* C3 state is available. */
-int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */
+int cpu_deepest_sleep = 0; /* Deepest Cx state available. */
+int cpu_disable_c2_sleep = 0; /* Timer dies in C2. */
+int cpu_disable_c3_sleep = 0; /* Timer dies in C3. */
static void setuptimer(void);
static void loadtimer(sbintime_t now, int first);
@@ -630,7 +631,7 @@ cpu_initclocks_bsp(void)
else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0)
periodic = 1;
if (timer->et_flags & ET_FLAGS_C3STOP)
- cpu_disable_deep_sleep++;
+ cpu_disable_c3_sleep++;
/*
* We honor the requested 'hz' value.
@@ -931,9 +932,9 @@ sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS)
configtimer(0);
et_free(timer);
if (et->et_flags & ET_FLAGS_C3STOP)
- cpu_disable_deep_sleep++;
+ cpu_disable_c3_sleep++;
if (timer->et_flags & ET_FLAGS_C3STOP)
- cpu_disable_deep_sleep--;
+ cpu_disable_c3_sleep--;
periodic = want_periodic;
timer = et;
et_init(timer, timercb, NULL, NULL);
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index 9fe7ebe..d671da5 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -1331,10 +1331,10 @@ tc_windup(void)
/* Now is a good time to change timecounters. */
if (th->th_counter != timecounter) {
#ifndef __arm__
- if ((timecounter->tc_flags & TC_FLAGS_C3STOP) != 0)
- cpu_disable_deep_sleep++;
- if ((th->th_counter->tc_flags & TC_FLAGS_C3STOP) != 0)
- cpu_disable_deep_sleep--;
+ if ((timecounter->tc_flags & TC_FLAGS_C2STOP) != 0)
+ cpu_disable_c2_sleep++;
+ if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0)
+ cpu_disable_c2_sleep--;
#endif
th->th_counter = timecounter;
th->th_offset_count = ncount;
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 006532d..bb0d64f 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -295,8 +295,9 @@ sbintime_t cpu_idleclock(void);
void cpu_activeclock(void);
void cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt);
void cpu_et_frequency(struct eventtimer *et, uint64_t newfreq);
-extern int cpu_can_deep_sleep;
-extern int cpu_disable_deep_sleep;
+extern int cpu_deepest_sleep;
+extern int cpu_disable_c2_sleep;
+extern int cpu_disable_c3_sleep;
int cr_cansee(struct ucred *u1, struct ucred *u2);
int cr_canseesocket(struct ucred *cred, struct socket *so);
diff --git a/sys/sys/timetc.h b/sys/sys/timetc.h
index 48b962f..e68e327 100644
--- a/sys/sys/timetc.h
+++ b/sys/sys/timetc.h
@@ -58,7 +58,7 @@ struct timecounter {
* means "only use at explicit request".
*/
u_int tc_flags;
-#define TC_FLAGS_C3STOP 1 /* Timer dies in C3. */
+#define TC_FLAGS_C2STOP 1 /* Timer dies in C2+. */
#define TC_FLAGS_SUSPEND_SAFE 2 /*
* Timer functional across
* suspend/resume.
diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c
index e96e405..28b61d5 100644
--- a/sys/x86/x86/tsc.c
+++ b/sys/x86/x86/tsc.c
@@ -528,16 +528,16 @@ init_TSC_tc(void)
}
/*
- * We cannot use the TSC if it stops incrementing in deep sleep.
- * Currently only Intel CPUs are known for this problem unless
- * the invariant TSC bit is set.
+ * We cannot use the TSC if it stops incrementing while idle.
+ * Intel CPUs without a C-state invariant TSC can stop the TSC
+ * in either C2 or C3.
*/
- if (cpu_can_deep_sleep && cpu_vendor_id == CPU_VENDOR_INTEL &&
+ if (cpu_deepest_sleep >= 2 && cpu_vendor_id == CPU_VENDOR_INTEL &&
(amd_pminfo & AMDPM_TSC_INVARIANT) == 0) {
tsc_timecounter.tc_quality = -1000;
- tsc_timecounter.tc_flags |= TC_FLAGS_C3STOP;
+ tsc_timecounter.tc_flags |= TC_FLAGS_C2STOP;
if (bootverbose)
- printf("TSC timecounter disabled: C3 enabled.\n");
+ printf("TSC timecounter disabled: C2/C3 may halt it.\n");
goto init;
}
OpenPOWER on IntegriCloud