History

Merge branch 'pm-x86'

* pm-x86: x86: tsc: Rework time_cpufreq_notifier() admin-guide: pm: intel_epb: Add SPDX license tag and copyright notice PM / arch: x86: MSR_IA32_ENERGY_PERF_BIAS sysfs interface PM / arch: x86: Rework the MSR_IA32_ENERGY_PERF_BIAS handling

Rafael J. Wysocki committed 7 years ago

Commit 4566e2d2 parents 5a28654 c208ac810 files · +292 −68Browse files

Unified · Split

10 files
  1. Documentation/ABI/testing/sysfs-devices-system-cpu +18 −0
  2. Documentation/admin-guide/pm/intel_epb.rst +41 −0
  3. Documentation/admin-guide/pm/working-state.rst +1 −0
  4. arch/x86/kernel/cpu/Makefile +1 −1
  5. arch/x86/kernel/cpu/common.c +0 −17
  6. arch/x86/kernel/cpu/cpu.h +0 −1
  7. arch/x86/kernel/cpu/intel.c +0 −34
  8. arch/x86/kernel/cpu/intel_epb.c +216 −0
  9. arch/x86/kernel/tsc.c +14 −15
  10. include/linux/cpuhotplug.h +1 −0
Documentation/ABI/testing/sysfs-devices-system-cpu+18−0
@@ -518,3 +518,21 @@ Description: Control Symetric Multi Threading (SMT) · 517 unmodified lines
518518
519519 If control status is "forceoff" or "notsupported" writes
520520 are rejected.
521+
522+What: /sys/devices/system/cpu/cpu#/power/energy_perf_bias
523+Date: March 2019
524+Contact: linux-pm@vger.kernel.org
525+Description: Intel Energy and Performance Bias Hint (EPB)
526+
527+ EPB for the given CPU in a sliding scale 0 - 15, where a value
528+ of 0 corresponds to a hint preference for highest performance
529+ and a value of 15 corresponds to the maximum energy savings.
530+
531+ In order to change the EPB value for the CPU, write either
532+ a number in the 0 - 15 sliding scale above, or one of the
533+ strings: "performance", "balance-performance", "normal",
534+ "balance-power", "power" (that represent values reflected by
535+ their meaning), to this attribute.
536+
537+ This attribute is present for all online CPUs supporting the
538+ Intel EPB feature.
Documentation/admin-guide/pm/intel_epb.rst+41−0
@@ -0,0 +1,41 @@
1+.. SPDX-License-Identifier: GPL-2.0
2+.. include:: <isonum.txt>
3+
4+======================================
5+Intel Performance and Energy Bias Hint
6+======================================
7+
8+:Copyright: |copy| 2019 Intel Corporation
9+
10+:Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
11+
12+
13+.. kernel-doc:: arch/x86/kernel/cpu/intel_epb.c
14+ :doc: overview
15+
16+Intel Performance and Energy Bias Attribute in ``sysfs``
17+========================================================
18+
19+The Intel Performance and Energy Bias Hint (EPB) value for a given (logical) CPU
20+can be checked or updated through a ``sysfs`` attribute (file) under
21+:file:`/sys/devices/system/cpu/cpu<N>/power/`, where the CPU number ``<N>``
22+is allocated at the system initialization time:
23+
24+``energy_perf_bias``
25+ Shows the current EPB value for the CPU in a sliding scale 0 - 15, where
26+ a value of 0 corresponds to a hint preference for highest performance
27+ and a value of 15 corresponds to the maximum energy savings.
28+
29+ In order to update the EPB value for the CPU, this attribute can be
30+ written to, either with a number in the 0 - 15 sliding scale above, or
31+ with one of the strings: "performance", "balance-performance", "normal",
32+ "balance-power", "power" that represent values reflected by their
33+ meaning.
34+
35+ This attribute is present for all online CPUs supporting the EPB
36+ feature.
37+
38+Note that while the EPB interface to the processor is defined at the logical CPU
39+level, the physical register backing it may be shared by multiple CPUs (for
40+example, SMT siblings or cores in one package). For this reason, updating the
41+EPB value for one CPU may cause the EPB values for other CPUs to change.
Documentation/admin-guide/pm/working-state.rst+1−0
@@ -8,3 +8,4 @@ Working-State Power Management · 7 unmodified lines
88 cpuidle
99 cpufreq
1010 intel_pstate
11+ intel_epb
arch/x86/kernel/cpu/Makefile+1−1
@@ -28,7 +28,7 @@ obj-y += cpuid-deps.o · 27 unmodified lines
2828 obj-$(CONFIG_PROC_FS) += proc.o
2929 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
3030
31−obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o
31+obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o intel_epb.o
3232 obj-$(CONFIG_CPU_SUP_AMD) += amd.o
3333 obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
3434 obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
arch/x86/kernel/cpu/common.c+0−17
@@ -1864,23 +1864,6 @@ void cpu_init(void) · 1863 unmodified lines
18641864 }
18651865 #endif
18661866
1867−static void bsp_resume(void)
1868−{
1869− if (this_cpu->c_bsp_resume)
1870− this_cpu->c_bsp_resume(&boot_cpu_data);
1871−}
1872−
1873−static struct syscore_ops cpu_syscore_ops = {
1874− .resume = bsp_resume,
1875−};
1876−
1877−static int __init init_cpu_syscore(void)
1878−{
1879− register_syscore_ops(&cpu_syscore_ops);
1880− return 0;
1881−}
1882−core_initcall(init_cpu_syscore);
1883−
18841867 /*
18851868 * The microcode loader calls this upon late microcode load to recheck features,
18861869 * only when microcode has been updated. Caller holds microcode_mutex and CPU
arch/x86/kernel/cpu/cpu.h+0−1
@@ -14,7 +14,6 @@ struct cpu_dev { · 13 unmodified lines
1414 void (*c_init)(struct cpuinfo_x86 *);
1515 void (*c_identify)(struct cpuinfo_x86 *);
1616 void (*c_detect_tlb)(struct cpuinfo_x86 *);
17− void (*c_bsp_resume)(struct cpuinfo_x86 *);
1817 int c_x86_vendor;
1918 #ifdef CONFIG_X86_32
2019 /* Optional vendor specific routine to obtain the cache size. */
arch/x86/kernel/cpu/intel.c+0−34
@@ -596,36 +596,6 @@ detect_keyid_bits: · 595 unmodified lines
596596 c->x86_phys_bits -= keyid_bits;
597597 }
598598
599−static void init_intel_energy_perf(struct cpuinfo_x86 *c)
600−{
601− u64 epb;
602−
603− /*
604− * Initialize MSR_IA32_ENERGY_PERF_BIAS if not already initialized.
605− * (x86_energy_perf_policy(8) is available to change it at run-time.)
606− */
607− if (!cpu_has(c, X86_FEATURE_EPB))
608− return;
609−
610− rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
611− if ((epb & 0xF) != ENERGY_PERF_BIAS_PERFORMANCE)
612− return;
613−
614− pr_info_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n");
615− pr_info_once("ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)\n");
616− epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL;
617− wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
618−}
619−
620−static void intel_bsp_resume(struct cpuinfo_x86 *c)
621−{
622− /*
623− * MSR_IA32_ENERGY_PERF_BIAS is lost across suspend/resume,
624− * so reinitialize it properly like during bootup:
625− */
626− init_intel_energy_perf(c);
627−}
628−
629599 static void init_cpuid_fault(struct cpuinfo_x86 *c)
630600 {
631601 u64 msr;
@@ -763,8 +733,6 @@ static void init_intel(struct cpuinfo_x86 *c) · 131 unmodified lines
763733 if (cpu_has(c, X86_FEATURE_TME))
764734 detect_tme(c);
765735
766− init_intel_energy_perf(c);
767−
768736 init_intel_misc_features(c);
769737 }
770738
@@ -1023,9 +991,7 @@ static const struct cpu_dev intel_cpu_dev = { · 252 unmodified lines
1023991 .c_detect_tlb = intel_detect_tlb,
1024992 .c_early_init = early_init_intel,
1025993 .c_init = init_intel,
1026− .c_bsp_resume = intel_bsp_resume,
1027994 .c_x86_vendor = X86_VENDOR_INTEL,
1028995 };
1029996
1030997 cpu_dev_register(intel_cpu_dev);
1031−
arch/x86/kernel/cpu/intel_epb.c+216−0
@@ -0,0 +1,216 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/*
3+ * Intel Performance and Energy Bias Hint support.
4+ *
5+ * Copyright (C) 2019 Intel Corporation
6+ *
7+ * Author:
8+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
9+ */
10+
11+#include <linux/cpuhotplug.h>
12+#include <linux/cpu.h>
13+#include <linux/device.h>
14+#include <linux/kernel.h>
15+#include <linux/string.h>
16+#include <linux/syscore_ops.h>
17+#include <linux/pm.h>
18+
19+#include <asm/cpufeature.h>
20+#include <asm/msr.h>
21+
22+/**
23+ * DOC: overview
24+ *
25+ * The Performance and Energy Bias Hint (EPB) allows software to specify its
26+ * preference with respect to the power-performance tradeoffs present in the
27+ * processor. Generally, the EPB is expected to be set by user space (directly
28+ * via sysfs or with the help of the x86_energy_perf_policy tool), but there are
29+ * two reasons for the kernel to update it.
30+ *
31+ * First, there are systems where the platform firmware resets the EPB during
32+ * system-wide transitions from sleep states back into the working state
33+ * effectively causing the previous EPB updates by user space to be lost.
34+ * Thus the kernel needs to save the current EPB values for all CPUs during
35+ * system-wide transitions to sleep states and restore them on the way back to
36+ * the working state. That can be achieved by saving EPB for secondary CPUs
37+ * when they are taken offline during transitions into system sleep states and
38+ * for the boot CPU in a syscore suspend operation, so that it can be restored
39+ * for the boot CPU in a syscore resume operation and for the other CPUs when
40+ * they are brought back online. However, CPUs that are already offline when
41+ * a system-wide PM transition is started are not taken offline again, but their
42+ * EPB values may still be reset by the platform firmware during the transition,
43+ * so in fact it is necessary to save the EPB of any CPU taken offline and to
44+ * restore it when the given CPU goes back online at all times.
45+ *
46+ * Second, on many systems the initial EPB value coming from the platform
47+ * firmware is 0 ('performance') and at least on some of them that is because
48+ * the platform firmware does not initialize EPB at all with the assumption that
49+ * the OS will do that anyway. That sometimes is problematic, as it may cause
50+ * the system battery to drain too fast, for example, so it is better to adjust
51+ * it on CPU bring-up and if the initial EPB value for a given CPU is 0, the
52+ * kernel changes it to 6 ('normal').
53+ */
54+
55+static DEFINE_PER_CPU(u8, saved_epb);
56+
57+#define EPB_MASK 0x0fULL
58+#define EPB_SAVED 0x10ULL
59+#define MAX_EPB EPB_MASK
60+
61+static int intel_epb_save(void)
62+{
63+ u64 epb;
64+
65+ rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
66+ /*
67+ * Ensure that saved_epb will always be nonzero after this write even if
68+ * the EPB value read from the MSR is 0.
69+ */
70+ this_cpu_write(saved_epb, (epb & EPB_MASK) | EPB_SAVED);
71+
72+ return 0;
73+}
74+
75+static void intel_epb_restore(void)
76+{
77+ u64 val = this_cpu_read(saved_epb);
78+ u64 epb;
79+
80+ rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
81+ if (val) {
82+ val &= EPB_MASK;
83+ } else {
84+ /*
85+ * Because intel_epb_save() has not run for the current CPU yet,
86+ * it is going online for the first time, so if its EPB value is
87+ * 0 ('performance') at this point, assume that it has not been
88+ * initialized by the platform firmware and set it to 6
89+ * ('normal').
90+ */
91+ val = epb & EPB_MASK;
92+ if (val == ENERGY_PERF_BIAS_PERFORMANCE) {
93+ val = ENERGY_PERF_BIAS_NORMAL;
94+ pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n");
95+ }
96+ }
97+ wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val);
98+}
99+
100+static struct syscore_ops intel_epb_syscore_ops = {
101+ .suspend = intel_epb_save,
102+ .resume = intel_epb_restore,
103+};
104+
105+static const char * const energy_perf_strings[] = {
106+ "performance",
107+ "balance-performance",
108+ "normal",
109+ "balance-power",
110+ "power"
111+};
112+static const u8 energ_perf_values[] = {
113+ ENERGY_PERF_BIAS_PERFORMANCE,
114+ ENERGY_PERF_BIAS_BALANCE_PERFORMANCE,
115+ ENERGY_PERF_BIAS_NORMAL,
116+ ENERGY_PERF_BIAS_BALANCE_POWERSAVE,
117+ ENERGY_PERF_BIAS_POWERSAVE
118+};
119+
120+static ssize_t energy_perf_bias_show(struct device *dev,
121+ struct device_attribute *attr,
122+ char *buf)
123+{
124+ unsigned int cpu = dev->id;
125+ u64 epb;
126+ int ret;
127+
128+ ret = rdmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb);
129+ if (ret < 0)
130+ return ret;
131+
132+ return sprintf(buf, "%llu\n", epb);
133+}
134+
135+static ssize_t energy_perf_bias_store(struct device *dev,
136+ struct device_attribute *attr,
137+ const char *buf, size_t count)
138+{
139+ unsigned int cpu = dev->id;
140+ u64 epb, val;
141+ int ret;
142+
143+ ret = __sysfs_match_string(energy_perf_strings,
144+ ARRAY_SIZE(energy_perf_strings), buf);
145+ if (ret >= 0)
146+ val = energ_perf_values[ret];
147+ else if (kstrtou64(buf, 0, &val) || val > MAX_EPB)
148+ return -EINVAL;
149+
150+ ret = rdmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb);
151+ if (ret < 0)
152+ return ret;
153+
154+ ret = wrmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS,
155+ (epb & ~EPB_MASK) | val);
156+ if (ret < 0)
157+ return ret;
158+
159+ return count;
160+}
161+
162+static DEVICE_ATTR_RW(energy_perf_bias);
163+
164+static struct attribute *intel_epb_attrs[] = {
165+ &dev_attr_energy_perf_bias.attr,
166+ NULL
167+};
168+
169+static const struct attribute_group intel_epb_attr_group = {
170+ .name = power_group_name,
171+ .attrs = intel_epb_attrs
172+};
173+
174+static int intel_epb_online(unsigned int cpu)
175+{
176+ struct device *cpu_dev = get_cpu_device(cpu);
177+
178+ intel_epb_restore();
179+ if (!cpuhp_tasks_frozen)
180+ sysfs_merge_group(&cpu_dev->kobj, &intel_epb_attr_group);
181+
182+ return 0;
183+}
184+
185+static int intel_epb_offline(unsigned int cpu)
186+{
187+ struct device *cpu_dev = get_cpu_device(cpu);
188+
189+ if (!cpuhp_tasks_frozen)
190+ sysfs_unmerge_group(&cpu_dev->kobj, &intel_epb_attr_group);
191+
192+ intel_epb_save();
193+ return 0;
194+}
195+
196+static __init int intel_epb_init(void)
197+{
198+ int ret;
199+
200+ if (!boot_cpu_has(X86_FEATURE_EPB))
201+ return -ENODEV;
202+
203+ ret = cpuhp_setup_state(CPUHP_AP_X86_INTEL_EPB_ONLINE,
204+ "x86/intel/epb:online", intel_epb_online,
205+ intel_epb_offline);
206+ if (ret < 0)
207+ goto err_out_online;
208+
209+ register_syscore_ops(&intel_epb_syscore_ops);
210+ return 0;
211+
212+err_out_online:
213+ cpuhp_remove_state(CPUHP_AP_X86_INTEL_EPB_ONLINE);
214+ return ret;
215+}
216+subsys_initcall(intel_epb_init);
arch/x86/kernel/tsc.c+14−15
@@ -185,8 +185,7 @@ static void __init cyc2ns_init_boot_cpu(void) · 184 unmodified lines
185185 /*
186186 * Secondary CPUs do not run through tsc_init(), so set up
187187 * all the scale factors for all CPUs, assuming the same
188− * speed as the bootup CPU. (cpufreq notifiers will fix this
189− * up if their speed diverges)
188+ * speed as the bootup CPU.
190189 */
191190 static void __init cyc2ns_init_secondary_cpus(void)
192191 {
@@ -937,12 +936,12 @@ void tsc_restore_sched_clock_state(void) · 744 unmodified lines
937936 }
938937
939938 #ifdef CONFIG_CPU_FREQ
940−/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency
939+/*
940+ * Frequency scaling support. Adjust the TSC based timer when the CPU frequency
941941 * changes.
942942 *
943− * RED-PEN: On SMP we assume all CPUs run with the same frequency. It's
944− * not that important because current Opteron setups do not support
945− * scaling on SMP anyroads.
943+ * NOTE: On SMP the situation is not fixable in general, so simply mark the TSC
944+ * as unstable and give up in those cases.
946945 *
947946 * Should fix up last_tsc too. Currently gettimeofday in the
948947 * first tick after the change will be slightly wrong.
@@ -956,22 +955,22 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, · 7 unmodified lines
956955 void *data)
957956 {
958957 struct cpufreq_freqs *freq = data;
959− unsigned long *lpj;
960958
961− lpj = &boot_cpu_data.loops_per_jiffy;
962−#ifdef CONFIG_SMP
963− if (!(freq->flags & CPUFREQ_CONST_LOOPS))
964− lpj = &cpu_data(freq->cpu).loops_per_jiffy;
965−#endif
959+ if (num_online_cpus() > 1) {
960+ mark_tsc_unstable("cpufreq changes on SMP");
961+ return 0;
962+ }
966963
967964 if (!ref_freq) {
968965 ref_freq = freq->old;
969− loops_per_jiffy_ref = *lpj;
966+ loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
970967 tsc_khz_ref = tsc_khz;
971968 }
969+
972970 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
973− (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
974− *lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
971+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
972+ boot_cpu_data.loops_per_jiffy =
973+ cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
975974
976975 tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
977976 if (!(freq->flags & CPUFREQ_CONST_LOOPS))
include/linux/cpuhotplug.h+1−0
@@ -147,6 +147,7 @@ enum cpuhp_state { · 146 unmodified lines
147147 CPUHP_AP_X86_VDSO_VMA_ONLINE,
148148 CPUHP_AP_IRQ_AFFINITY_ONLINE,
149149 CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,
150+ CPUHP_AP_X86_INTEL_EPB_ONLINE,
150151 CPUHP_AP_PERF_ONLINE,
151152 CPUHP_AP_PERF_X86_ONLINE,
152153 CPUHP_AP_PERF_X86_UNCORE_ONLINE,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t