x86/cpu: Restore MSR_IA32_ENERGY_PERF_BIAS after resume
authorLaura Abbott <labbott@fedoraproject.org>
Mon, 20 Jul 2015 21:47:58 +0000 (14:47 -0700)
committerIngo Molnar <mingo@kernel.org>
Tue, 21 Jul 2015 05:51:38 +0000 (07:51 +0200)
MSR_IA32_ENERGY_PERF_BIAS is lost after suspend/resume:

x86_energy_perf_policy -r before

cpu0: 0x0000000000000006
cpu1: 0x0000000000000006
cpu2: 0x0000000000000006
cpu3: 0x0000000000000006
cpu4: 0x0000000000000006
cpu5: 0x0000000000000006
cpu6: 0x0000000000000006
cpu7: 0x0000000000000006

after

cpu0: 0x0000000000000000
cpu1: 0x0000000000000006
cpu2: 0x0000000000000006
cpu3: 0x0000000000000006
cpu4: 0x0000000000000006
cpu5: 0x0000000000000006
cpu6: 0x0000000000000006
cpu7: 0x0000000000000006

Resulting in inconsistent energy policy settings across CPUs.

This register is set via init_intel() at bootup. During resume,
the secondary CPUs are brought online again and init_intel() is
callled which re-initializes the register. The boot CPU however
never reinitializes the register.

Add a syscore callback to reinitialize the register for the boot CPU.

Signed-off-by: Laura Abbott <labbott@fedoraproject.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1437428878-4105-1-git-send-email-labbott@fedoraproject.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/intel.c

index 922c5e0cea4c961b1aa6e7a266ce588de7f7a300..fa95bb8829ce9bc736082c4824cde04521239144 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kgdb.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/stackprotector.h>
 #include <asm/perf_event.h>
@@ -1488,3 +1489,20 @@ inline bool __static_cpu_has_safe(u16 bit)
        return boot_cpu_has(bit);
 }
 EXPORT_SYMBOL_GPL(__static_cpu_has_safe);
+
+static void bsp_resume(void)
+{
+       if (this_cpu->c_bsp_resume)
+               this_cpu->c_bsp_resume(&boot_cpu_data);
+}
+
+static struct syscore_ops cpu_syscore_ops = {
+       .resume         = bsp_resume,
+};
+
+static int __init init_cpu_syscore(void)
+{
+       register_syscore_ops(&cpu_syscore_ops);
+       return 0;
+}
+core_initcall(init_cpu_syscore);
index c37dc37e8317f107bc1b79b118b5eab13368482d..2584265d474556be72714dcb91721580290b8c6b 100644 (file)
@@ -13,6 +13,7 @@ struct cpu_dev {
        void            (*c_init)(struct cpuinfo_x86 *);
        void            (*c_identify)(struct cpuinfo_x86 *);
        void            (*c_detect_tlb)(struct cpuinfo_x86 *);
+       void            (*c_bsp_resume)(struct cpuinfo_x86 *);
        int             c_x86_vendor;
 #ifdef CONFIG_X86_32
        /* Optional vendor specific routine to obtain the cache size. */
index 50163fa9034f0d2f4db28767432a249ad9e0cb35..98a13db5f4be5826a47c8572f3f7f65950658270 100644 (file)
@@ -371,6 +371,36 @@ static void detect_vmx_virtcap(struct cpuinfo_x86 *c)
        }
 }
 
+static void init_intel_energy_perf(struct cpuinfo_x86 *c)
+{
+       u64 epb;
+
+       /*
+        * Initialize MSR_IA32_ENERGY_PERF_BIAS if not already initialized.
+        * (x86_energy_perf_policy(8) is available to change it at run-time.)
+        */
+       if (!cpu_has(c, X86_FEATURE_EPB))
+               return;
+
+       rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
+       if ((epb & 0xF) != ENERGY_PERF_BIAS_PERFORMANCE)
+               return;
+
+       pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n");
+       pr_warn_once("ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)\n");
+       epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL;
+       wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
+}
+
+static void intel_bsp_resume(struct cpuinfo_x86 *c)
+{
+       /*
+        * MSR_IA32_ENERGY_PERF_BIAS is lost across suspend/resume,
+        * so reinitialize it properly like during bootup:
+        */
+       init_intel_energy_perf(c);
+}
+
 static void init_intel(struct cpuinfo_x86 *c)
 {
        unsigned int l2 = 0;
@@ -478,21 +508,7 @@ static void init_intel(struct cpuinfo_x86 *c)
        if (cpu_has(c, X86_FEATURE_VMX))
                detect_vmx_virtcap(c);
 
-       /*
-        * Initialize MSR_IA32_ENERGY_PERF_BIAS if BIOS did not.
-        * x86_energy_perf_policy(8) is available to change it at run-time
-        */
-       if (cpu_has(c, X86_FEATURE_EPB)) {
-               u64 epb;
-
-               rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
-               if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) {
-                       pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n");
-                       pr_warn_once("ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)\n");
-                       epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL;
-                       wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
-               }
-       }
+       init_intel_energy_perf(c);
 }
 
 #ifdef CONFIG_X86_32
@@ -747,6 +763,7 @@ static const struct cpu_dev intel_cpu_dev = {
        .c_detect_tlb   = intel_detect_tlb,
        .c_early_init   = early_init_intel,
        .c_init         = init_intel,
+       .c_bsp_resume   = intel_bsp_resume,
        .c_x86_vendor   = X86_VENDOR_INTEL,
 };