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
518 518
519 If control status is "forceoff" or "notsupported" writes519 If control status is "forceoff" or "notsupported" writes
520 are rejected.520 are rejected.
521
522What: /sys/devices/system/cpu/cpu#/power/energy_perf_bias
523Date: March 2019
524Contact: linux-pm@vger.kernel.org
525Description: 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======================================
5Intel 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
16Intel Performance and Energy Bias Attribute in ``sysfs``
17========================================================
18
19The Intel Performance and Energy Bias Hint (EPB) value for a given (logical) CPU
20can be checked or updated through a ``sysfs`` attribute (file) under
21:file:`/sys/devices/system/cpu/cpu<N>/power/`, where the CPU number ``<N>``
22is 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
38Note that while the EPB interface to the processor is defined at the logical CPU
39level, the physical register backing it may be shared by multiple CPUs (for
40example, SMT siblings or cores in one package). For this reason, updating the
41EPB 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
8 cpuidle8 cpuidle
9 cpufreq9 cpufreq
10 intel_pstate10 intel_pstate
11 intel_epb
arch/x86/kernel/cpu/Makefile+1−1
@@ -28,7 +28,7 @@ obj-y += cpuid-deps.o · 27 unmodified lines
28obj-$(CONFIG_PROC_FS) += proc.o28obj-$(CONFIG_PROC_FS) += proc.o
29obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o29obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
30 30
31obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o31obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o intel_epb.o
32obj-$(CONFIG_CPU_SUP_AMD) += amd.o32obj-$(CONFIG_CPU_SUP_AMD) += amd.o
33obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o33obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
34obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o34obj-$(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
1864}1864}
1865#endif1865#endif
1866 1866
1867static void bsp_resume(void)
1868{
1869 if (this_cpu->c_bsp_resume)
1870 this_cpu->c_bsp_resume(&boot_cpu_data);
1871}
1872
1873static struct syscore_ops cpu_syscore_ops = {
1874 .resume = bsp_resume,
1875};
1876
1877static int __init init_cpu_syscore(void)
1878{
1879 register_syscore_ops(&cpu_syscore_ops);
1880 return 0;
1881}
1882core_initcall(init_cpu_syscore);
1883
1884/*1867/*
1885 * The microcode loader calls this upon late microcode load to recheck features,1868 * The microcode loader calls this upon late microcode load to recheck features,
1886 * only when microcode has been updated. Caller holds microcode_mutex and CPU1869 * 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
14 void (*c_init)(struct cpuinfo_x86 *);14 void (*c_init)(struct cpuinfo_x86 *);
15 void (*c_identify)(struct cpuinfo_x86 *);15 void (*c_identify)(struct cpuinfo_x86 *);
16 void (*c_detect_tlb)(struct cpuinfo_x86 *);16 void (*c_detect_tlb)(struct cpuinfo_x86 *);
17 void (*c_bsp_resume)(struct cpuinfo_x86 *);
18 int c_x86_vendor;17 int c_x86_vendor;
19#ifdef CONFIG_X86_3218#ifdef CONFIG_X86_32
20 /* Optional vendor specific routine to obtain the cache size. */19 /* 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
596 c->x86_phys_bits -= keyid_bits;596 c->x86_phys_bits -= keyid_bits;
597}597}
598 598
599static 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
620static 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
629static void init_cpuid_fault(struct cpuinfo_x86 *c)599static void init_cpuid_fault(struct cpuinfo_x86 *c)
630{600{
631 u64 msr;601 u64 msr;
@@ -763,8 +733,6 @@ static void init_intel(struct cpuinfo_x86 *c) · 131 unmodified lines
763 if (cpu_has(c, X86_FEATURE_TME))733 if (cpu_has(c, X86_FEATURE_TME))
764 detect_tme(c);734 detect_tme(c);
765 735
766 init_intel_energy_perf(c);
767
768 init_intel_misc_features(c);736 init_intel_misc_features(c);
769}737}
770 738
@@ -1023,9 +991,7 @@ static const struct cpu_dev intel_cpu_dev = { · 252 unmodified lines
1023 .c_detect_tlb = intel_detect_tlb,991 .c_detect_tlb = intel_detect_tlb,
1024 .c_early_init = early_init_intel,992 .c_early_init = early_init_intel,
1025 .c_init = init_intel,993 .c_init = init_intel,
1026 .c_bsp_resume = intel_bsp_resume,
1027 .c_x86_vendor = X86_VENDOR_INTEL,994 .c_x86_vendor = X86_VENDOR_INTEL,
1028};995};
1029 996
1030cpu_dev_register(intel_cpu_dev);997cpu_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
55static DEFINE_PER_CPU(u8, saved_epb);
56
57#define EPB_MASK 0x0fULL
58#define EPB_SAVED 0x10ULL
59#define MAX_EPB EPB_MASK
60
61static 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
75static 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
100static struct syscore_ops intel_epb_syscore_ops = {
101 .suspend = intel_epb_save,
102 .resume = intel_epb_restore,
103};
104
105static const char * const energy_perf_strings[] = {
106 "performance",
107 "balance-performance",
108 "normal",
109 "balance-power",
110 "power"
111};
112static 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
120static 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
135static 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
162static DEVICE_ATTR_RW(energy_perf_bias);
163
164static struct attribute *intel_epb_attrs[] = {
165 &dev_attr_energy_perf_bias.attr,
166 NULL
167};
168
169static const struct attribute_group intel_epb_attr_group = {
170 .name = power_group_name,
171 .attrs = intel_epb_attrs
172};
173
174static 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
185static 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
196static __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
212err_out_online:
213 cpuhp_remove_state(CPUHP_AP_X86_INTEL_EPB_ONLINE);
214 return ret;
215}
216subsys_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
185/*185/*
186 * Secondary CPUs do not run through tsc_init(), so set up186 * Secondary CPUs do not run through tsc_init(), so set up
187 * all the scale factors for all CPUs, assuming the same187 * all the scale factors for all CPUs, assuming the same
188 * speed as the bootup CPU. (cpufreq notifiers will fix this188 * speed as the bootup CPU.
189 * up if their speed diverges)
190 */189 */
191static void __init cyc2ns_init_secondary_cpus(void)190static void __init cyc2ns_init_secondary_cpus(void)
192{191{
@@ -937,12 +936,12 @@ void tsc_restore_sched_clock_state(void) · 744 unmodified lines
937}936}
938 937
939#ifdef CONFIG_CPU_FREQ938#ifdef CONFIG_CPU_FREQ
940/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency939/*
940 * Frequency scaling support. Adjust the TSC based timer when the CPU frequency
941 * changes.941 * changes.
942 *942 *
943 * RED-PEN: On SMP we assume all CPUs run with the same frequency. It's943 * NOTE: On SMP the situation is not fixable in general, so simply mark the TSC
944 * not that important because current Opteron setups do not support944 * as unstable and give up in those cases.
945 * scaling on SMP anyroads.
946 *945 *
947 * Should fix up last_tsc too. Currently gettimeofday in the946 * Should fix up last_tsc too. Currently gettimeofday in the
948 * first tick after the change will be slightly wrong.947 * 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
956 void *data)955 void *data)
957{956{
958 struct cpufreq_freqs *freq = data;957 struct cpufreq_freqs *freq = data;
959 unsigned long *lpj;
960 958
961 lpj = &boot_cpu_data.loops_per_jiffy;959 if (num_online_cpus() > 1) {
962#ifdef CONFIG_SMP960 mark_tsc_unstable("cpufreq changes on SMP");
963 if (!(freq->flags & CPUFREQ_CONST_LOOPS))961 return 0;
964 lpj = &cpu_data(freq->cpu).loops_per_jiffy;962 }
965#endif
966 963
967 if (!ref_freq) {964 if (!ref_freq) {
968 ref_freq = freq->old;965 ref_freq = freq->old;
969 loops_per_jiffy_ref = *lpj;966 loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
970 tsc_khz_ref = tsc_khz;967 tsc_khz_ref = tsc_khz;
971 }968 }
969
972 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||970 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
973 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {971 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
974 *lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);972 boot_cpu_data.loops_per_jiffy =
973 cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
975 974
976 tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);975 tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
977 if (!(freq->flags & CPUFREQ_CONST_LOOPS))976 if (!(freq->flags & CPUFREQ_CONST_LOOPS))
include/linux/cpuhotplug.h+1−0
@@ -147,6 +147,7 @@ enum cpuhp_state { · 146 unmodified lines
147 CPUHP_AP_X86_VDSO_VMA_ONLINE,147 CPUHP_AP_X86_VDSO_VMA_ONLINE,
148 CPUHP_AP_IRQ_AFFINITY_ONLINE,148 CPUHP_AP_IRQ_AFFINITY_ONLINE,
149 CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,149 CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,
150 CPUHP_AP_X86_INTEL_EPB_ONLINE,
150 CPUHP_AP_PERF_ONLINE,151 CPUHP_AP_PERF_ONLINE,
151 CPUHP_AP_PERF_X86_ONLINE,152 CPUHP_AP_PERF_X86_ONLINE,
152 CPUHP_AP_PERF_X86_UNCORE_ONLINE,153 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