This source file includes following definitions.
- intel_epb_save
- intel_epb_restore
- energy_perf_bias_show
- energy_perf_bias_store
- intel_epb_online
- intel_epb_offline
- intel_epb_init
1
2
3
4
5
6
7
8
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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
68
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
86
87
88
89
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);