Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/power/x86/intel-speed-select/isst-core.c
26295 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Intel Speed Select -- Enumerate and control features
4
* Copyright (c) 2019 Intel Corporation.
5
*/
6
7
#include "isst.h"
8
9
static struct isst_platform_ops *isst_ops;
10
11
#define CHECK_CB(_name) \
12
do { \
13
if (!isst_ops || !isst_ops->_name) { \
14
fprintf(stderr, "Invalid ops\n"); \
15
exit(0); \
16
} \
17
} while (0)
18
19
int isst_set_platform_ops(int api_version)
20
{
21
switch (api_version) {
22
case 1:
23
isst_ops = mbox_get_platform_ops();
24
break;
25
case 2:
26
case 3:
27
isst_ops = tpmi_get_platform_ops();
28
break;
29
default:
30
isst_ops = NULL;
31
break;
32
}
33
34
if (!isst_ops)
35
return -1;
36
return 0;
37
}
38
39
void isst_update_platform_param(enum isst_platform_param param, int value)
40
{
41
CHECK_CB(update_platform_param);
42
43
isst_ops->update_platform_param(param, value);
44
}
45
46
int isst_get_disp_freq_multiplier(void)
47
{
48
CHECK_CB(get_disp_freq_multiplier);
49
return isst_ops->get_disp_freq_multiplier();
50
}
51
52
int isst_get_trl_max_levels(void)
53
{
54
CHECK_CB(get_trl_max_levels);
55
return isst_ops->get_trl_max_levels();
56
}
57
58
char *isst_get_trl_level_name(int level)
59
{
60
CHECK_CB(get_trl_level_name);
61
return isst_ops->get_trl_level_name(level);
62
}
63
64
int isst_is_punit_valid(struct isst_id *id)
65
{
66
CHECK_CB(is_punit_valid);
67
return isst_ops->is_punit_valid(id);
68
}
69
70
int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
71
unsigned long long *req_resp)
72
{
73
struct isst_if_msr_cmds msr_cmds;
74
const char *pathname = "/dev/isst_interface";
75
FILE *outf = get_output_file();
76
int fd;
77
78
fd = open(pathname, O_RDWR);
79
if (fd < 0)
80
err(-1, "%s open failed", pathname);
81
82
msr_cmds.cmd_count = 1;
83
msr_cmds.msr_cmd[0].logical_cpu = cpu;
84
msr_cmds.msr_cmd[0].msr = msr;
85
msr_cmds.msr_cmd[0].read_write = write;
86
if (write)
87
msr_cmds.msr_cmd[0].data = *req_resp;
88
89
if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
90
perror("ISST_IF_MSR_COMMAND");
91
fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
92
cpu, msr, write);
93
} else {
94
if (!write)
95
*req_resp = msr_cmds.msr_cmd[0].data;
96
97
debug_printf(
98
"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
99
cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
100
}
101
102
close(fd);
103
104
return 0;
105
}
106
107
int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
108
{
109
CHECK_CB(read_pm_config);
110
return isst_ops->read_pm_config(id, cp_state, cp_cap);
111
}
112
113
int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
114
{
115
CHECK_CB(get_config_levels);
116
return isst_ops->get_config_levels(id, pkg_dev);
117
}
118
119
int isst_get_ctdp_control(struct isst_id *id, int config_index,
120
struct isst_pkg_ctdp_level_info *ctdp_level)
121
{
122
CHECK_CB(get_ctdp_control);
123
return isst_ops->get_ctdp_control(id, config_index, ctdp_level);
124
}
125
126
int isst_get_tdp_info(struct isst_id *id, int config_index,
127
struct isst_pkg_ctdp_level_info *ctdp_level)
128
{
129
CHECK_CB(get_tdp_info);
130
return isst_ops->get_tdp_info(id, config_index, ctdp_level);
131
}
132
133
int isst_get_pwr_info(struct isst_id *id, int config_index,
134
struct isst_pkg_ctdp_level_info *ctdp_level)
135
{
136
CHECK_CB(get_pwr_info);
137
return isst_ops->get_pwr_info(id, config_index, ctdp_level);
138
}
139
140
int isst_get_coremask_info(struct isst_id *id, int config_index,
141
struct isst_pkg_ctdp_level_info *ctdp_level)
142
{
143
CHECK_CB(get_coremask_info);
144
return isst_ops->get_coremask_info(id, config_index, ctdp_level);
145
}
146
147
int isst_get_get_trl_from_msr(struct isst_id *id, int *trl)
148
{
149
unsigned long long msr_trl;
150
int ret;
151
152
ret = isst_send_msr_command(id->cpu, 0x1AD, 0, &msr_trl);
153
if (ret)
154
return ret;
155
156
trl[0] = msr_trl & GENMASK(7, 0);
157
trl[1] = (msr_trl & GENMASK(15, 8)) >> 8;
158
trl[2] = (msr_trl & GENMASK(23, 16)) >> 16;
159
trl[3] = (msr_trl & GENMASK(31, 24)) >> 24;
160
trl[4] = (msr_trl & GENMASK(39, 32)) >> 32;
161
trl[5] = (msr_trl & GENMASK(47, 40)) >> 40;
162
trl[6] = (msr_trl & GENMASK(55, 48)) >> 48;
163
trl[7] = (msr_trl & GENMASK(63, 56)) >> 56;
164
165
return 0;
166
}
167
168
int isst_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)
169
{
170
CHECK_CB(get_get_trl);
171
return isst_ops->get_get_trl(id, level, avx_level, trl);
172
}
173
174
int isst_get_get_trls(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level)
175
{
176
CHECK_CB(get_get_trls);
177
return isst_ops->get_get_trls(id, level, ctdp_level);
178
}
179
180
int isst_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info)
181
{
182
CHECK_CB(get_trl_bucket_info);
183
return isst_ops->get_trl_bucket_info(id, level, buckets_info);
184
}
185
186
int isst_set_tdp_level(struct isst_id *id, int tdp_level)
187
{
188
CHECK_CB(set_tdp_level);
189
return isst_ops->set_tdp_level(id, tdp_level);
190
}
191
192
int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)
193
{
194
struct isst_pkg_ctdp_level_info ctdp_level;
195
struct isst_pkg_ctdp pkg_dev;
196
int ret;
197
198
ret = isst_get_ctdp_levels(id, &pkg_dev);
199
if (ret) {
200
isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
201
return ret;
202
}
203
204
if (level > pkg_dev.levels) {
205
isst_display_error_info_message(1, "Invalid level", 1, level);
206
return -1;
207
}
208
209
ret = isst_get_ctdp_control(id, level, &ctdp_level);
210
if (ret)
211
return ret;
212
213
if (!ctdp_level.pbf_support) {
214
isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, level);
215
return -1;
216
}
217
218
pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
219
220
CHECK_CB(get_pbf_info);
221
return isst_ops->get_pbf_info(id, level, pbf_info);
222
}
223
224
int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
225
{
226
CHECK_CB(set_pbf_fact_status);
227
return isst_ops->set_pbf_fact_status(id, pbf, enable);
228
}
229
230
231
232
int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info)
233
{
234
struct isst_pkg_ctdp_level_info ctdp_level;
235
struct isst_pkg_ctdp pkg_dev;
236
int ret;
237
238
ret = isst_get_ctdp_levels(id, &pkg_dev);
239
if (ret) {
240
isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
241
return ret;
242
}
243
244
if (level > pkg_dev.levels) {
245
isst_display_error_info_message(1, "Invalid level", 1, level);
246
return -1;
247
}
248
249
ret = isst_get_ctdp_control(id, level, &ctdp_level);
250
if (ret)
251
return ret;
252
253
if (!ctdp_level.fact_support) {
254
isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, level);
255
return -1;
256
}
257
CHECK_CB(get_fact_info);
258
return isst_ops->get_fact_info(id, level, fact_bucket, fact_info);
259
}
260
261
int isst_get_trl(struct isst_id *id, unsigned long long *trl)
262
{
263
int ret;
264
265
ret = isst_send_msr_command(id->cpu, 0x1AD, 0, trl);
266
if (ret)
267
return ret;
268
269
return 0;
270
}
271
272
int isst_set_trl(struct isst_id *id, unsigned long long trl)
273
{
274
int ret;
275
276
if (!trl)
277
trl = 0xFFFFFFFFFFFFFFFFULL;
278
279
ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &trl);
280
if (ret)
281
return ret;
282
283
return 0;
284
}
285
286
#define MSR_TRL_FREQ_MULTIPLIER 100
287
288
int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl)
289
{
290
unsigned long long msr_trl;
291
int ret;
292
293
if (id->cpu < 0)
294
return 0;
295
296
if (trl) {
297
msr_trl = trl;
298
} else {
299
struct isst_pkg_ctdp pkg_dev;
300
int trl[8];
301
int i;
302
303
ret = isst_get_ctdp_levels(id, &pkg_dev);
304
if (ret)
305
return ret;
306
307
ret = isst_get_get_trl(id, pkg_dev.current_level, 0, trl);
308
if (ret)
309
return ret;
310
311
msr_trl = 0;
312
for (i = 0; i < 8; ++i) {
313
unsigned long long _trl = trl[i];
314
315
/* MSR is always in 100 MHz unit */
316
if (isst_get_disp_freq_multiplier() == 1)
317
_trl /= MSR_TRL_FREQ_MULTIPLIER;
318
319
msr_trl |= (_trl << (i * 8));
320
}
321
}
322
ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &msr_trl);
323
if (ret)
324
return ret;
325
326
return 0;
327
}
328
329
/* Return 1 if locked */
330
int isst_get_config_tdp_lock_status(struct isst_id *id)
331
{
332
unsigned long long tdp_control = 0;
333
int ret;
334
335
ret = isst_send_msr_command(id->cpu, 0x64b, 0, &tdp_control);
336
if (ret)
337
return ret;
338
339
ret = !!(tdp_control & BIT(31));
340
341
return ret;
342
}
343
344
void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
345
{
346
int i;
347
348
if (!pkg_dev->processed)
349
return;
350
351
for (i = 0; i < pkg_dev->levels; ++i) {
352
struct isst_pkg_ctdp_level_info *ctdp_level;
353
354
ctdp_level = &pkg_dev->ctdp_level[i];
355
if (ctdp_level->pbf_support)
356
free_cpu_set(ctdp_level->pbf_info.core_cpumask);
357
free_cpu_set(ctdp_level->core_cpumask);
358
}
359
}
360
361
void isst_adjust_uncore_freq(struct isst_id *id, int config_index,
362
struct isst_pkg_ctdp_level_info *ctdp_level)
363
{
364
CHECK_CB(adjust_uncore_freq);
365
return isst_ops->adjust_uncore_freq(id, config_index, ctdp_level);
366
}
367
368
int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
369
{
370
int i, ret, valid = 0;
371
372
if (pkg_dev->processed)
373
return 0;
374
375
ret = isst_get_ctdp_levels(id, pkg_dev);
376
if (ret)
377
return ret;
378
379
debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",
380
id->cpu, pkg_dev->enabled, pkg_dev->current_level,
381
pkg_dev->levels);
382
383
if (tdp_level != 0xff && tdp_level > pkg_dev->levels) {
384
isst_display_error_info_message(1, "Invalid level", 0, 0);
385
return -1;
386
}
387
388
if (!pkg_dev->enabled)
389
isst_display_error_info_message(0, "perf-profile feature is not supported, just base-config level 0 is valid", 0, 0);
390
391
for (i = 0; i <= pkg_dev->levels; ++i) {
392
struct isst_pkg_ctdp_level_info *ctdp_level;
393
394
if (tdp_level != 0xff && i != tdp_level)
395
continue;
396
397
debug_printf("cpu:%d Get Information for TDP level:%d\n", id->cpu,
398
i);
399
ctdp_level = &pkg_dev->ctdp_level[i];
400
401
ctdp_level->level = i;
402
ctdp_level->control_cpu = id->cpu;
403
ctdp_level->pkg_id = id->pkg;
404
ctdp_level->die_id = id->die;
405
406
ret = isst_get_ctdp_control(id, i, ctdp_level);
407
if (ret)
408
continue;
409
410
valid = 1;
411
pkg_dev->processed = 1;
412
ctdp_level->processed = 1;
413
414
if (ctdp_level->pbf_support) {
415
ret = isst_get_pbf_info(id, i, &ctdp_level->pbf_info);
416
if (!ret)
417
ctdp_level->pbf_found = 1;
418
}
419
420
if (ctdp_level->fact_support) {
421
ret = isst_get_fact_info(id, i, 0xff,
422
&ctdp_level->fact_info);
423
if (ret)
424
return ret;
425
}
426
427
if (!pkg_dev->enabled && is_skx_based_platform()) {
428
int freq;
429
430
freq = get_cpufreq_base_freq(id->cpu);
431
if (freq > 0) {
432
ctdp_level->sse_p1 = freq / 100000;
433
ctdp_level->tdp_ratio = ctdp_level->sse_p1;
434
}
435
436
isst_get_get_trl_from_msr(id, ctdp_level->trl_ratios[0]);
437
isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
438
continue;
439
}
440
441
ret = isst_get_tdp_info(id, i, ctdp_level);
442
if (ret)
443
return ret;
444
445
ret = isst_get_pwr_info(id, i, ctdp_level);
446
if (ret)
447
return ret;
448
449
ctdp_level->core_cpumask_size =
450
alloc_cpu_set(&ctdp_level->core_cpumask);
451
ret = isst_get_coremask_info(id, i, ctdp_level);
452
if (ret)
453
return ret;
454
455
ret = isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
456
if (ret)
457
return ret;
458
459
ret = isst_get_get_trls(id, i, ctdp_level);
460
if (ret)
461
return ret;
462
}
463
464
if (!valid)
465
isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id->cpu);
466
467
return 0;
468
}
469
470
int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type)
471
{
472
CHECK_CB(get_clos_information);
473
return isst_ops->get_clos_information(id, enable, type);
474
}
475
476
int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)
477
{
478
CHECK_CB(pm_qos_config);
479
return isst_ops->pm_qos_config(id, enable_clos, priority_type);
480
}
481
482
int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
483
{
484
CHECK_CB(pm_get_clos);
485
return isst_ops->pm_get_clos(id, clos, clos_config);
486
}
487
488
int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
489
{
490
CHECK_CB(set_clos);
491
return isst_ops->set_clos(id, clos, clos_config);
492
}
493
494
int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id)
495
{
496
CHECK_CB(clos_get_assoc_status);
497
return isst_ops->clos_get_assoc_status(id, clos_id);
498
}
499
500
int isst_clos_associate(struct isst_id *id, int clos_id)
501
{
502
CHECK_CB(clos_associate);
503
return isst_ops->clos_associate(id, clos_id);
504
505
}
506
507