Loading...
Note: File does not exist in v4.17.
1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * Copyright (C) 2020 Advanced Micro Devices, Inc.
5 */
6#include <asm/cpu_device_id.h>
7
8#include <linux/bits.h>
9#include <linux/cpu.h>
10#include <linux/cpumask.h>
11#include <linux/delay.h>
12#include <linux/device.h>
13#include <linux/hwmon.h>
14#include <linux/kernel.h>
15#include <linux/kthread.h>
16#include <linux/list.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/processor.h>
20#include <linux/platform_device.h>
21#include <linux/sched.h>
22#include <linux/slab.h>
23#include <linux/topology.h>
24#include <linux/types.h>
25
26#define DRVNAME "amd_energy"
27
28#define ENERGY_PWR_UNIT_MSR 0xC0010299
29#define ENERGY_CORE_MSR 0xC001029A
30#define ENERGY_PKG_MSR 0xC001029B
31
32#define AMD_ENERGY_UNIT_MASK 0x01F00
33#define AMD_ENERGY_MASK 0xFFFFFFFF
34
35struct sensor_accumulator {
36 u64 energy_ctr;
37 u64 prev_value;
38 char label[10];
39};
40
41struct amd_energy_data {
42 struct hwmon_channel_info energy_info;
43 const struct hwmon_channel_info *info[2];
44 struct hwmon_chip_info chip;
45 struct task_struct *wrap_accumulate;
46 /* Lock around the accumulator */
47 struct mutex lock;
48 /* An accumulator for each core and socket */
49 struct sensor_accumulator *accums;
50 /* Energy Status Units */
51 u64 energy_units;
52 int nr_cpus;
53 int nr_socks;
54 int core_id;
55};
56
57static int amd_energy_read_labels(struct device *dev,
58 enum hwmon_sensor_types type,
59 u32 attr, int channel,
60 const char **str)
61{
62 struct amd_energy_data *data = dev_get_drvdata(dev);
63
64 *str = data->accums[channel].label;
65 return 0;
66}
67
68static void get_energy_units(struct amd_energy_data *data)
69{
70 u64 rapl_units;
71
72 rdmsrl_safe(ENERGY_PWR_UNIT_MSR, &rapl_units);
73 data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;
74}
75
76static void accumulate_socket_delta(struct amd_energy_data *data,
77 int sock, int cpu)
78{
79 struct sensor_accumulator *s_accum;
80 u64 input;
81
82 mutex_lock(&data->lock);
83 rdmsrl_safe_on_cpu(cpu, ENERGY_PKG_MSR, &input);
84 input &= AMD_ENERGY_MASK;
85
86 s_accum = &data->accums[data->nr_cpus + sock];
87 if (input >= s_accum->prev_value)
88 s_accum->energy_ctr +=
89 input - s_accum->prev_value;
90 else
91 s_accum->energy_ctr += UINT_MAX -
92 s_accum->prev_value + input;
93
94 s_accum->prev_value = input;
95 mutex_unlock(&data->lock);
96}
97
98static void accumulate_core_delta(struct amd_energy_data *data)
99{
100 struct sensor_accumulator *c_accum;
101 u64 input;
102 int cpu;
103
104 mutex_lock(&data->lock);
105 if (data->core_id >= data->nr_cpus)
106 data->core_id = 0;
107
108 cpu = data->core_id;
109
110 if (!cpu_online(cpu))
111 goto out;
112
113 rdmsrl_safe_on_cpu(cpu, ENERGY_CORE_MSR, &input);
114 input &= AMD_ENERGY_MASK;
115
116 c_accum = &data->accums[cpu];
117
118 if (input >= c_accum->prev_value)
119 c_accum->energy_ctr +=
120 input - c_accum->prev_value;
121 else
122 c_accum->energy_ctr += UINT_MAX -
123 c_accum->prev_value + input;
124
125 c_accum->prev_value = input;
126
127out:
128 data->core_id++;
129 mutex_unlock(&data->lock);
130}
131
132static void read_accumulate(struct amd_energy_data *data)
133{
134 int sock;
135
136 for (sock = 0; sock < data->nr_socks; sock++) {
137 int cpu;
138
139 cpu = cpumask_first_and(cpu_online_mask,
140 cpumask_of_node(sock));
141
142 accumulate_socket_delta(data, sock, cpu);
143 }
144
145 accumulate_core_delta(data);
146}
147
148static void amd_add_delta(struct amd_energy_data *data, int ch,
149 int cpu, long *val, bool is_core)
150{
151 struct sensor_accumulator *s_accum, *c_accum;
152 u64 input;
153
154 mutex_lock(&data->lock);
155 if (!is_core) {
156 rdmsrl_safe_on_cpu(cpu, ENERGY_PKG_MSR, &input);
157 input &= AMD_ENERGY_MASK;
158
159 s_accum = &data->accums[ch];
160 if (input >= s_accum->prev_value)
161 input += s_accum->energy_ctr -
162 s_accum->prev_value;
163 else
164 input += UINT_MAX - s_accum->prev_value +
165 s_accum->energy_ctr;
166 } else {
167 rdmsrl_safe_on_cpu(cpu, ENERGY_CORE_MSR, &input);
168 input &= AMD_ENERGY_MASK;
169
170 c_accum = &data->accums[ch];
171 if (input >= c_accum->prev_value)
172 input += c_accum->energy_ctr -
173 c_accum->prev_value;
174 else
175 input += UINT_MAX - c_accum->prev_value +
176 c_accum->energy_ctr;
177 }
178
179 /* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */
180 *val = div64_ul(input * 1000000UL, BIT(data->energy_units));
181
182 mutex_unlock(&data->lock);
183}
184
185static int amd_energy_read(struct device *dev,
186 enum hwmon_sensor_types type,
187 u32 attr, int channel, long *val)
188{
189 struct amd_energy_data *data = dev_get_drvdata(dev);
190 int cpu;
191
192 if (channel >= data->nr_cpus) {
193 cpu = cpumask_first_and(cpu_online_mask,
194 cpumask_of_node
195 (channel - data->nr_cpus));
196 amd_add_delta(data, channel, cpu, val, false);
197 } else {
198 cpu = channel;
199 if (!cpu_online(cpu))
200 return -ENODEV;
201
202 amd_add_delta(data, channel, cpu, val, true);
203 }
204
205 return 0;
206}
207
208static umode_t amd_energy_is_visible(const void *_data,
209 enum hwmon_sensor_types type,
210 u32 attr, int channel)
211{
212 return 0444;
213}
214
215static int energy_accumulator(void *p)
216{
217 struct amd_energy_data *data = (struct amd_energy_data *)p;
218
219 while (!kthread_should_stop()) {
220 /*
221 * Ignoring the conditions such as
222 * cpu being offline or rdmsr failure
223 */
224 read_accumulate(data);
225
226 set_current_state(TASK_INTERRUPTIBLE);
227 if (kthread_should_stop())
228 break;
229
230 /*
231 * On a 240W system, with default resolution the
232 * Socket Energy status register may wrap around in
233 * 2^32*15.3 e-6/240 = 273.8041 secs (~4.5 mins)
234 *
235 * let us accumulate for every 100secs
236 */
237 schedule_timeout(msecs_to_jiffies(100000));
238 }
239 return 0;
240}
241
242static const struct hwmon_ops amd_energy_ops = {
243 .is_visible = amd_energy_is_visible,
244 .read = amd_energy_read,
245 .read_string = amd_energy_read_labels,
246};
247
248static int amd_create_sensor(struct device *dev,
249 struct amd_energy_data *data,
250 u8 type, u32 config)
251{
252 struct hwmon_channel_info *info = &data->energy_info;
253 struct sensor_accumulator *accums;
254 int i, num_siblings, cpus, sockets;
255 u32 *s_config;
256
257 /* Identify the number of siblings per core */
258 num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1;
259
260 sockets = num_possible_nodes();
261
262 /*
263 * Energy counter register is accessed at core level.
264 * Hence, filterout the siblings.
265 */
266 cpus = num_present_cpus() / num_siblings;
267
268 s_config = devm_kcalloc(dev, cpus + sockets,
269 sizeof(u32), GFP_KERNEL);
270 if (!s_config)
271 return -ENOMEM;
272
273 accums = devm_kcalloc(dev, cpus + sockets,
274 sizeof(struct sensor_accumulator),
275 GFP_KERNEL);
276 if (!accums)
277 return -ENOMEM;
278
279 info->type = type;
280 info->config = s_config;
281
282 data->nr_cpus = cpus;
283 data->nr_socks = sockets;
284 data->accums = accums;
285
286 for (i = 0; i < cpus + sockets; i++) {
287 s_config[i] = config;
288 if (i < cpus)
289 scnprintf(accums[i].label, 10,
290 "Ecore%03u", i);
291 else
292 scnprintf(accums[i].label, 10,
293 "Esocket%u", (i - cpus));
294 }
295
296 return 0;
297}
298
299static int amd_energy_probe(struct platform_device *pdev)
300{
301 struct device *hwmon_dev;
302 struct amd_energy_data *data;
303 struct device *dev = &pdev->dev;
304
305 data = devm_kzalloc(dev,
306 sizeof(struct amd_energy_data), GFP_KERNEL);
307 if (!data)
308 return -ENOMEM;
309
310 data->chip.ops = &amd_energy_ops;
311 data->chip.info = data->info;
312
313 dev_set_drvdata(dev, data);
314 /* Populate per-core energy reporting */
315 data->info[0] = &data->energy_info;
316 amd_create_sensor(dev, data, hwmon_energy,
317 HWMON_E_INPUT | HWMON_E_LABEL);
318
319 mutex_init(&data->lock);
320 get_energy_units(data);
321
322 hwmon_dev = devm_hwmon_device_register_with_info(dev, DRVNAME,
323 data,
324 &data->chip,
325 NULL);
326 if (IS_ERR(hwmon_dev))
327 return PTR_ERR(hwmon_dev);
328
329 data->wrap_accumulate = kthread_run(energy_accumulator, data,
330 "%s", dev_name(hwmon_dev));
331 if (IS_ERR(data->wrap_accumulate))
332 return PTR_ERR(data->wrap_accumulate);
333
334 return PTR_ERR_OR_ZERO(data->wrap_accumulate);
335}
336
337static int amd_energy_remove(struct platform_device *pdev)
338{
339 struct amd_energy_data *data = dev_get_drvdata(&pdev->dev);
340
341 if (data && data->wrap_accumulate)
342 kthread_stop(data->wrap_accumulate);
343
344 return 0;
345}
346
347static const struct platform_device_id amd_energy_ids[] = {
348 { .name = DRVNAME, },
349 {}
350};
351MODULE_DEVICE_TABLE(platform, amd_energy_ids);
352
353static struct platform_driver amd_energy_driver = {
354 .probe = amd_energy_probe,
355 .remove = amd_energy_remove,
356 .id_table = amd_energy_ids,
357 .driver = {
358 .name = DRVNAME,
359 },
360};
361
362static struct platform_device *amd_energy_platdev;
363
364static const struct x86_cpu_id cpu_ids[] __initconst = {
365 X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x31, NULL),
366 {}
367};
368MODULE_DEVICE_TABLE(x86cpu, cpu_ids);
369
370static int __init amd_energy_init(void)
371{
372 int ret;
373
374 if (!x86_match_cpu(cpu_ids))
375 return -ENODEV;
376
377 ret = platform_driver_register(&amd_energy_driver);
378 if (ret)
379 return ret;
380
381 amd_energy_platdev = platform_device_alloc(DRVNAME, 0);
382 if (!amd_energy_platdev) {
383 platform_driver_unregister(&amd_energy_driver);
384 return -ENOMEM;
385 }
386
387 ret = platform_device_add(amd_energy_platdev);
388 if (ret) {
389 platform_device_put(amd_energy_platdev);
390 platform_driver_unregister(&amd_energy_driver);
391 return ret;
392 }
393
394 return ret;
395}
396
397static void __exit amd_energy_exit(void)
398{
399 platform_device_unregister(amd_energy_platdev);
400 platform_driver_unregister(&amd_energy_driver);
401}
402
403module_init(amd_energy_init);
404module_exit(amd_energy_exit);
405
406MODULE_DESCRIPTION("Driver for AMD Energy reporting from RAPL MSR via HWMON interface");
407MODULE_AUTHOR("Naveen Krishna Chatradhi <nchatrad@amd.com>");
408MODULE_LICENSE("GPL");