|
@@ -65,7 +65,7 @@
|
|
|
#include <asm/mwait.h>
|
|
|
#include <asm/msr.h>
|
|
|
|
|
|
-#define INTEL_IDLE_VERSION "0.4"
|
|
|
+#define INTEL_IDLE_VERSION "0.4.1"
|
|
|
#define PREFIX "intel_idle: "
|
|
|
|
|
|
static struct cpuidle_driver intel_idle_driver = {
|
|
@@ -994,36 +994,92 @@ static void intel_idle_cpuidle_devices_uninit(void)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * intel_idle_state_table_update()
|
|
|
- *
|
|
|
- * Update the default state_table for this CPU-id
|
|
|
+ * ivt_idle_state_table_update(void)
|
|
|
*
|
|
|
- * Currently used to access tuned IVT multi-socket targets
|
|
|
+ * Tune IVT multi-socket targets
|
|
|
* Assumption: num_sockets == (max_package_num + 1)
|
|
|
*/
|
|
|
-void intel_idle_state_table_update(void)
|
|
|
+static void ivt_idle_state_table_update(void)
|
|
|
{
|
|
|
/* IVT uses a different table for 1-2, 3-4, and > 4 sockets */
|
|
|
- if (boot_cpu_data.x86_model == 0x3e) { /* IVT */
|
|
|
- int cpu, package_num, num_sockets = 1;
|
|
|
-
|
|
|
- for_each_online_cpu(cpu) {
|
|
|
- package_num = topology_physical_package_id(cpu);
|
|
|
- if (package_num + 1 > num_sockets) {
|
|
|
- num_sockets = package_num + 1;
|
|
|
-
|
|
|
- if (num_sockets > 4) {
|
|
|
- cpuidle_state_table = ivt_cstates_8s;
|
|
|
- return;
|
|
|
- }
|
|
|
+ int cpu, package_num, num_sockets = 1;
|
|
|
+
|
|
|
+ for_each_online_cpu(cpu) {
|
|
|
+ package_num = topology_physical_package_id(cpu);
|
|
|
+ if (package_num + 1 > num_sockets) {
|
|
|
+ num_sockets = package_num + 1;
|
|
|
+
|
|
|
+ if (num_sockets > 4) {
|
|
|
+ cpuidle_state_table = ivt_cstates_8s;
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num_sockets > 2)
|
|
|
+ cpuidle_state_table = ivt_cstates_4s;
|
|
|
+
|
|
|
+ /* else, 1 and 2 socket systems use default ivt_cstates */
|
|
|
+}
|
|
|
+/*
|
|
|
+ * sklh_idle_state_table_update(void)
|
|
|
+ *
|
|
|
+ * On SKL-H (model 0x5e) disable C8 and C9 if:
|
|
|
+ * C10 is enabled and SGX disabled
|
|
|
+ */
|
|
|
+static void sklh_idle_state_table_update(void)
|
|
|
+{
|
|
|
+ unsigned long long msr;
|
|
|
+ unsigned int eax, ebx, ecx, edx;
|
|
|
+
|
|
|
+
|
|
|
+ /* if PC10 disabled via cmdline intel_idle.max_cstate=7 or shallower */
|
|
|
+ if (max_cstate <= 7)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* if PC10 not present in CPUID.MWAIT.EDX */
|
|
|
+ if ((mwait_substates & (0xF << 28)) == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr);
|
|
|
+
|
|
|
+ /* PC10 is not enabled in PKG C-state limit */
|
|
|
+ if ((msr & 0xF) != 8)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ecx = 0;
|
|
|
+ cpuid(7, &eax, &ebx, &ecx, &edx);
|
|
|
+
|
|
|
+ /* if SGX is present */
|
|
|
+ if (ebx & (1 << 2)) {
|
|
|
|
|
|
- if (num_sockets > 2)
|
|
|
- cpuidle_state_table = ivt_cstates_4s;
|
|
|
- /* else, 1 and 2 socket systems use default ivt_cstates */
|
|
|
+ rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
|
|
|
+
|
|
|
+ /* if SGX is enabled */
|
|
|
+ if (msr & (1 << 18))
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ skl_cstates[5].disabled = 1; /* C8-SKL */
|
|
|
+ skl_cstates[6].disabled = 1; /* C9-SKL */
|
|
|
+}
|
|
|
+/*
|
|
|
+ * intel_idle_state_table_update()
|
|
|
+ *
|
|
|
+ * Update the default state_table for this CPU-id
|
|
|
+ */
|
|
|
+
|
|
|
+static void intel_idle_state_table_update(void)
|
|
|
+{
|
|
|
+ switch (boot_cpu_data.x86_model) {
|
|
|
+
|
|
|
+ case 0x3e: /* IVT */
|
|
|
+ ivt_idle_state_table_update();
|
|
|
+ break;
|
|
|
+ case 0x5e: /* SKL-H */
|
|
|
+ sklh_idle_state_table_update();
|
|
|
+ break;
|
|
|
}
|
|
|
- return;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1063,6 +1119,14 @@ static int __init intel_idle_cpuidle_driver_init(void)
|
|
|
if (num_substates == 0)
|
|
|
continue;
|
|
|
|
|
|
+ /* if state marked as disabled, skip it */
|
|
|
+ if (cpuidle_state_table[cstate].disabled != 0) {
|
|
|
+ pr_debug(PREFIX "state %s is disabled",
|
|
|
+ cpuidle_state_table[cstate].name);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
if (((mwait_cstate + 1) > 2) &&
|
|
|
!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
|
|
|
mark_tsc_unstable("TSC halts in idle"
|