1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel Speed Select -- Enumerate and control features for TPMI Interface
4 * Copyright (c) 2022 Intel Corporation.
5 */
6
7#include <linux/isst_if.h>
8#include "isst.h"
9
10int tpmi_process_ioctl(int ioctl_no, void *info)
11{
12 const char *pathname = "/dev/isst_interface";
13 int fd;
14
15 if (is_debug_enabled()) {
16 debug_printf(format: "Issue IOCTL: ");
17 switch (ioctl_no) {
18 case ISST_IF_CORE_POWER_STATE:
19 debug_printf(format: "ISST_IF_CORE_POWER_STATE\n");
20 break;
21 case ISST_IF_CLOS_PARAM:
22 debug_printf(format: "ISST_IF_CLOS_PARAM\n");
23 break;
24 case ISST_IF_CLOS_ASSOC:
25 debug_printf(format: "ISST_IF_CLOS_ASSOC\n");
26 break;
27 case ISST_IF_PERF_LEVELS:
28 debug_printf(format: "ISST_IF_PERF_LEVELS\n");
29 break;
30 case ISST_IF_PERF_SET_LEVEL:
31 debug_printf(format: "ISST_IF_PERF_SET_LEVEL\n");
32 break;
33 case ISST_IF_PERF_SET_FEATURE:
34 debug_printf(format: "ISST_IF_PERF_SET_FEATURE\n");
35 break;
36 case ISST_IF_GET_PERF_LEVEL_INFO:
37 debug_printf(format: "ISST_IF_GET_PERF_LEVEL_INFO\n");
38 break;
39 case ISST_IF_GET_PERF_LEVEL_CPU_MASK:
40 debug_printf(format: "ISST_IF_GET_PERF_LEVEL_CPU_MASK\n");
41 break;
42 case ISST_IF_GET_BASE_FREQ_INFO:
43 debug_printf(format: "ISST_IF_GET_BASE_FREQ_INFO\n");
44 break;
45 case ISST_IF_GET_BASE_FREQ_CPU_MASK:
46 debug_printf(format: "ISST_IF_GET_BASE_FREQ_CPU_MASK\n");
47 break;
48 case ISST_IF_GET_TURBO_FREQ_INFO:
49 debug_printf(format: "ISST_IF_GET_TURBO_FREQ_INFO\n");
50 break;
51 case ISST_IF_COUNT_TPMI_INSTANCES:
52 debug_printf(format: "ISST_IF_COUNT_TPMI_INSTANCES\n");
53 break;
54 default:
55 debug_printf(format: "%d\n", ioctl_no);
56 break;
57 }
58 }
59
60 fd = open(pathname, O_RDWR);
61 if (fd < 0)
62 return -1;
63
64 if (ioctl(fd, ioctl_no, info) == -1) {
65 debug_printf(format: "IOCTL %d Failed\n", ioctl_no);
66 close(fd);
67 return -1;
68 }
69
70 close(fd);
71
72 return 0;
73}
74
75static int tpmi_get_disp_freq_multiplier(void)
76{
77 return 1;
78}
79
80static int tpmi_get_trl_max_levels(void)
81{
82 return TRL_MAX_LEVELS;
83}
84
85static char *tpmi_get_trl_level_name(int level)
86{
87 switch (level) {
88 case 0:
89 return "level-0";
90 case 1:
91 return "level-1";
92 case 2:
93 return "level-2";
94 case 3:
95 return "level-3";
96 case 4:
97 return "level-4";
98 case 5:
99 return "level-5";
100 case 6:
101 return "level-6";
102 case 7:
103 return "level-7";
104 default:
105 return NULL;
106 }
107}
108
109
110static void tpmi_update_platform_param(enum isst_platform_param param, int value)
111{
112 /* No params need to be updated for now */
113}
114
115static int tpmi_is_punit_valid(struct isst_id *id)
116{
117 struct isst_tpmi_instance_count info;
118 int ret;
119
120 if (id->punit < 0)
121 return 0;
122
123 info.socket_id = id->pkg;
124 ret = tpmi_process_ioctl(ISST_IF_COUNT_TPMI_INSTANCES, &info);
125 if (ret == -1)
126 return 0;
127
128 if (info.valid_mask & BIT(id->punit))
129 return 1;
130
131 return 0;
132}
133
134static int tpmi_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
135{
136 struct isst_core_power info;
137 int ret;
138
139 info.get_set = 0;
140 info.socket_id = id->pkg;
141 info.power_domain_id = id->punit;
142 ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
143 if (ret == -1)
144 return ret;
145
146 *cp_state = info.enable;
147 *cp_cap = info.supported;
148
149 return 0;
150}
151
152int tpmi_get_config_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
153{
154 struct isst_perf_level_info info;
155 int ret;
156
157 info.socket_id = id->pkg;
158 info.power_domain_id = id->punit;
159
160 ret = tpmi_process_ioctl(ISST_IF_PERF_LEVELS, &info);
161 if (ret == -1)
162 return ret;
163
164 pkg_dev->version = info.feature_rev;
165 pkg_dev->levels = info.max_level;
166 pkg_dev->locked = info.locked;
167 pkg_dev->current_level = info.current_level;
168 pkg_dev->locked = info.locked;
169 pkg_dev->enabled = info.enabled;
170
171 return 0;
172}
173
174static int tpmi_get_ctdp_control(struct isst_id *id, int config_index,
175 struct isst_pkg_ctdp_level_info *ctdp_level)
176{
177 struct isst_core_power core_power_info;
178 struct isst_perf_level_info info;
179 int level_mask;
180 int ret;
181
182 info.socket_id = id->pkg;
183 info.power_domain_id = id->punit;
184
185 ret = tpmi_process_ioctl(ISST_IF_PERF_LEVELS, &info);
186 if (ret == -1)
187 return -1;
188
189 if (config_index != 0xff)
190 level_mask = 1 << config_index;
191 else
192 level_mask = config_index;
193
194 if (!(info.level_mask & level_mask))
195 return -1;
196
197 if (api_version() > 2) {
198 ctdp_level->fact_support = info.sst_tf_support & BIT(config_index);
199 ctdp_level->pbf_support = info.sst_bf_support & BIT(config_index);
200 } else {
201 ctdp_level->fact_support = info.sst_tf_support;
202 ctdp_level->pbf_support = info.sst_bf_support;
203 }
204
205 ctdp_level->fact_enabled = !!(info.feature_state & BIT(1));
206 ctdp_level->pbf_enabled = !!(info.feature_state & BIT(0));
207
208 core_power_info.get_set = 0;
209 core_power_info.socket_id = id->pkg;
210 core_power_info.power_domain_id = id->punit;
211
212 ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &core_power_info);
213 if (ret == -1)
214 return ret;
215
216 ctdp_level->sst_cp_support = core_power_info.supported;
217 ctdp_level->sst_cp_enabled = core_power_info.enable;
218
219 debug_printf
220 (format: "cpu:%d CONFIG_TDP_GET_TDP_CONTROL fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
221 id->cpu, ctdp_level->fact_support, ctdp_level->pbf_support,
222 ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
223
224 return 0;
225}
226
227static int tpmi_get_tdp_info(struct isst_id *id, int config_index,
228 struct isst_pkg_ctdp_level_info *ctdp_level)
229{
230 struct isst_perf_level_fabric_info fabric_info;
231 struct isst_perf_level_data_info info;
232 int ret;
233
234 info.socket_id = id->pkg;
235 info.power_domain_id = id->punit;
236 info.level = config_index;
237
238 ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
239 if (ret == -1)
240 return ret;
241
242 ctdp_level->pkg_tdp = info.thermal_design_power_w;
243 ctdp_level->tdp_ratio = info.tdp_ratio;
244 ctdp_level->sse_p1 = info.base_freq_mhz;
245 ctdp_level->avx2_p1 = info.base_freq_avx2_mhz;
246 ctdp_level->avx512_p1 = info.base_freq_avx512_mhz;
247 ctdp_level->amx_p1 = info.base_freq_amx_mhz;
248
249 ctdp_level->t_proc_hot = info.tjunction_max_c;
250 ctdp_level->mem_freq = info.max_memory_freq_mhz;
251 ctdp_level->cooling_type = info.cooling_type;
252
253 ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz;
254 ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz;
255 ctdp_level->uncore_pm = info.pm_fabric_freq_mhz;
256
257 fabric_info.socket_id = id->pkg;
258 fabric_info.power_domain_id = id->punit;
259 fabric_info.level = config_index;
260
261 ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_FABRIC_INFO, &fabric_info);
262 if (ret != -1) {
263 ctdp_level->uncore1_p0 = fabric_info.p0_fabric_freq_mhz[1];
264 ctdp_level->uncore1_p1 = fabric_info.p1_fabric_freq_mhz[1];
265 ctdp_level->uncore1_pm = fabric_info.pm_fabric_freq_mhz[1];
266 }
267
268 debug_printf
269 (format: "cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO tdp_ratio:%d pkg_tdp:%d ctdp_level->t_proc_hot:%d\n",
270 id->cpu, config_index, ctdp_level->tdp_ratio, ctdp_level->pkg_tdp,
271 ctdp_level->t_proc_hot);
272
273 return 0;
274}
275
276static int tpmi_get_pwr_info(struct isst_id *id, int config_index,
277 struct isst_pkg_ctdp_level_info *ctdp_level)
278{
279 /* TBD */
280 ctdp_level->pkg_max_power = 0;
281 ctdp_level->pkg_min_power = 0;
282
283 debug_printf
284 (format: "cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO pkg_max_power:%d pkg_min_power:%d\n",
285 id->cpu, config_index, ctdp_level->pkg_max_power,
286 ctdp_level->pkg_min_power);
287
288 return 0;
289}
290
291int tpmi_get_coremask_info(struct isst_id *id, int config_index,
292 struct isst_pkg_ctdp_level_info *ctdp_level)
293{
294 struct isst_perf_level_cpu_mask info;
295 int ret, cpu_count;
296
297 info.socket_id = id->pkg;
298 info.power_domain_id = id->punit;
299 info.level = config_index;
300 info.punit_cpu_map = 1;
301
302 ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_CPU_MASK, &info);
303 if (ret == -1)
304 return ret;
305
306 set_cpu_mask_from_punit_coremask(id, info.mask,
307 ctdp_level->core_cpumask_size,
308 ctdp_level->core_cpumask, &cpu_count);
309 ctdp_level->cpu_count = cpu_count;
310
311 debug_printf(format: "cpu:%d ctdp:%d core_mask ino cpu count:%d\n",
312 id->cpu, config_index, ctdp_level->cpu_count);
313
314 return 0;
315}
316
317static int tpmi_get_get_trls(struct isst_id *id, int config_index,
318 struct isst_pkg_ctdp_level_info *ctdp_level)
319{
320 struct isst_perf_level_data_info info;
321 int ret, i, j;
322
323 info.socket_id = id->pkg;
324 info.power_domain_id = id->punit;
325 info.level = config_index;
326
327 ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
328 if (ret == -1)
329 return ret;
330
331 if (info.max_buckets > TRL_MAX_BUCKETS)
332 info.max_buckets = TRL_MAX_BUCKETS;
333
334 if (info.max_trl_levels > TRL_MAX_LEVELS)
335 info.max_trl_levels = TRL_MAX_LEVELS;
336
337 for (i = 0; i < info.max_trl_levels; ++i)
338 for (j = 0; j < info.max_buckets; ++j)
339 ctdp_level->trl_ratios[i][j] = info.trl_freq_mhz[i][j];
340
341 return 0;
342}
343
344static int tpmi_get_get_trl(struct isst_id *id, int config_index, int level,
345 int *trl)
346{
347 struct isst_pkg_ctdp_level_info ctdp_level;
348 int ret, i;
349
350 ret = tpmi_get_get_trls(id, config_index, ctdp_level: &ctdp_level);
351 if (ret)
352 return ret;
353
354 /* FIX ME: Just return for level 0 */
355 for (i = 0; i < 8; ++i)
356 trl[i] = ctdp_level.trl_ratios[0][i];
357
358 return 0;
359}
360
361static int tpmi_get_trl_bucket_info(struct isst_id *id, int config_index,
362 unsigned long long *buckets_info)
363{
364 struct isst_perf_level_data_info info;
365 unsigned char *mask = (unsigned char *)buckets_info;
366 int ret, i;
367
368 info.socket_id = id->pkg;
369 info.power_domain_id = id->punit;
370 info.level = config_index;
371
372 ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
373 if (ret == -1)
374 return ret;
375
376 if (info.max_buckets > TRL_MAX_BUCKETS)
377 info.max_buckets = TRL_MAX_BUCKETS;
378
379 for (i = 0; i < info.max_buckets; ++i)
380 mask[i] = info.bucket_core_counts[i];
381
382 debug_printf(format: "cpu:%d TRL bucket info: 0x%llx\n", id->cpu,
383 *buckets_info);
384
385 return 0;
386}
387
388static int tpmi_set_tdp_level(struct isst_id *id, int tdp_level)
389{
390 struct isst_perf_level_control info;
391 int ret;
392
393 info.socket_id = id->pkg;
394 info.power_domain_id = id->punit;
395 info.level = tdp_level;
396
397 ret = tpmi_process_ioctl(ISST_IF_PERF_SET_LEVEL, &info);
398 if (ret == -1)
399 return ret;
400
401 return 0;
402}
403
404static int _pbf_get_coremask_info(struct isst_id *id, int config_index,
405 struct isst_pbf_info *pbf_info)
406{
407 struct isst_perf_level_cpu_mask info;
408 int ret, cpu_count;
409
410 info.socket_id = id->pkg;
411 info.power_domain_id = id->punit;
412 info.level = config_index;
413 info.punit_cpu_map = 1;
414
415 ret = tpmi_process_ioctl(ISST_IF_GET_BASE_FREQ_CPU_MASK, &info);
416 if (ret == -1)
417 return ret;
418
419 set_cpu_mask_from_punit_coremask(id, info.mask,
420 pbf_info->core_cpumask_size,
421 pbf_info->core_cpumask, &cpu_count);
422
423 debug_printf(format: "cpu:%d ctdp:%d pbf core_mask info cpu count:%d\n",
424 id->cpu, config_index, cpu_count);
425
426 return 0;
427}
428
429static int tpmi_get_pbf_info(struct isst_id *id, int level,
430 struct isst_pbf_info *pbf_info)
431{
432 struct isst_base_freq_info info;
433 int ret;
434
435 info.socket_id = id->pkg;
436 info.power_domain_id = id->punit;
437 info.level = level;
438
439 ret = tpmi_process_ioctl(ISST_IF_GET_BASE_FREQ_INFO, &info);
440 if (ret == -1)
441 return ret;
442
443 pbf_info->p1_low = info.low_base_freq_mhz;
444 pbf_info->p1_high = info.high_base_freq_mhz;
445 pbf_info->tdp = info.thermal_design_power_w;
446 pbf_info->t_prochot = info.tjunction_max_c;
447
448 debug_printf(format: "cpu:%d ctdp:%d pbf info:%d:%d:%d:%d\n",
449 id->cpu, level, pbf_info->p1_low, pbf_info->p1_high,
450 pbf_info->tdp, pbf_info->t_prochot);
451
452 return _pbf_get_coremask_info(id, config_index: level, pbf_info);
453}
454
455#define FEATURE_ENABLE_WAIT_US 1000
456#define FEATURE_ENABLE_RETRIES 5
457
458static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
459{
460 struct isst_pkg_ctdp pkg_dev;
461 struct isst_pkg_ctdp_level_info ctdp_level;
462 int current_level;
463 struct isst_perf_feature_control info;
464 int ret, i;
465
466 ret = isst_get_ctdp_levels(id, pkg_dev: &pkg_dev);
467 if (ret)
468 debug_printf(format: "cpu:%d No support for dynamic ISST\n", id->cpu);
469
470 current_level = pkg_dev.current_level;
471
472 ret = isst_get_ctdp_control(id, config_index: current_level, ctdp_level: &ctdp_level);
473 if (ret)
474 return ret;
475
476 info.socket_id = id->pkg;
477 info.power_domain_id = id->punit;
478
479 info.feature = 0;
480
481 if (pbf) {
482 if (ctdp_level.fact_enabled)
483 info.feature |= BIT(1);
484
485 if (enable)
486 info.feature |= BIT(0);
487 else
488 info.feature &= ~BIT(0);
489 } else {
490
491 if (enable && !ctdp_level.sst_cp_enabled)
492 isst_display_error_info_message(error: 0,
493 msg: "Make sure to execute before: core-power enable",
494 arg_valid: 0, arg: 0);
495
496 if (ctdp_level.pbf_enabled)
497 info.feature |= BIT(0);
498
499 if (enable)
500 info.feature |= BIT(1);
501 else
502 info.feature &= ~BIT(1);
503 }
504
505 ret = tpmi_process_ioctl(ISST_IF_PERF_SET_FEATURE, &info);
506 if (ret == -1)
507 return ret;
508
509 for (i = 0; i < FEATURE_ENABLE_RETRIES; ++i) {
510
511 usleep(FEATURE_ENABLE_WAIT_US);
512
513 /* Check status */
514 ret = isst_get_ctdp_control(id, config_index: current_level, ctdp_level: &ctdp_level);
515 if (ret)
516 return ret;
517
518 debug_printf(format: "pbf_enabled:%d fact_enabled:%d\n",
519 ctdp_level.pbf_enabled, ctdp_level.fact_enabled);
520
521 if (pbf) {
522 if (ctdp_level.pbf_enabled == enable)
523 break;
524 } else {
525 if (ctdp_level.fact_enabled == enable)
526 break;
527 }
528 }
529
530 if (i == FEATURE_ENABLE_RETRIES)
531 return -1;
532
533 return 0;
534}
535
536static int tpmi_get_fact_info(struct isst_id *id, int level, int fact_bucket,
537 struct isst_fact_info *fact_info)
538{
539 struct isst_turbo_freq_info info;
540 int i, j;
541 int ret;
542
543 memset(&info, 0, sizeof(info));
544 info.socket_id = id->pkg;
545 info.power_domain_id = id->punit;
546 info.level = level;
547
548 ret = tpmi_process_ioctl(ISST_IF_GET_TURBO_FREQ_INFO, &info);
549 if (ret == -1)
550 return ret;
551
552 for (i = 0; i < info.max_clip_freqs; ++i)
553 fact_info->lp_ratios[i] = info.lp_clip_freq_mhz[i];
554
555 if (info.max_buckets > TRL_MAX_BUCKETS)
556 info.max_buckets = TRL_MAX_BUCKETS;
557
558 if (info.max_trl_levels > TRL_MAX_LEVELS)
559 info.max_trl_levels = TRL_MAX_LEVELS;
560
561 for (i = 0; i < info.max_trl_levels; ++i) {
562 for (j = 0; j < info.max_buckets; ++j)
563 fact_info->bucket_info[j].hp_ratios[i] =
564 info.trl_freq_mhz[i][j];
565 }
566
567 for (i = 0; i < info.max_buckets; ++i)
568 fact_info->bucket_info[i].hp_cores = info.bucket_core_counts[i];
569
570 return 0;
571}
572
573static void _set_uncore_min_max(struct isst_id *id, int max, int freq)
574{
575 DIR *dir;
576 FILE *filep;
577 struct dirent *entry;
578 char buffer[512];
579 unsigned int tmp_id;
580 int ret;
581
582 dir = opendir("/sys/devices/system/cpu/intel_uncore_frequency/");
583 if (!dir)
584 return;
585
586 while ((entry = readdir(dir)) != NULL ) {
587 /* Check domain_id */
588 snprintf(buffer, sizeof(buffer),
589 "/sys/devices/system/cpu/intel_uncore_frequency/%s/domain_id", entry->d_name);
590
591 filep = fopen(buffer, "r");
592 if (!filep)
593 goto end;
594
595 ret = fscanf(filep, "%u", &tmp_id);
596 fclose(filep);
597 if (ret != 1)
598 goto end;
599
600 if (tmp_id != id->punit)
601 continue;
602
603 /* Check package_id */
604 snprintf(buffer, sizeof(buffer),
605 "/sys/devices/system/cpu/intel_uncore_frequency/%s/package_id", entry->d_name);
606
607 filep = fopen(buffer, "r");
608 if (!filep)
609 goto end;
610
611 ret = fscanf(filep, "%u", &tmp_id);
612 fclose(filep);
613
614 if (ret != 1)
615 goto end;
616
617 if (tmp_id != id->pkg)
618 continue;
619
620 /* Found the right sysfs path, adjust and quit */
621 if (max)
622 snprintf(buffer, sizeof(buffer),
623 "/sys/devices/system/cpu/intel_uncore_frequency/%s/max_freq_khz", entry->d_name);
624 else
625 snprintf(buffer, sizeof(buffer),
626 "/sys/devices/system/cpu/intel_uncore_frequency/%s/min_freq_khz", entry->d_name);
627
628 filep = fopen(buffer, "w");
629 if (!filep)
630 goto end;
631
632 fprintf(filep, "%d\n", freq);
633 fclose(filep);
634 break;
635 }
636
637end:
638 closedir(dir);
639}
640
641static void tpmi_adjust_uncore_freq(struct isst_id *id, int config_index,
642 struct isst_pkg_ctdp_level_info *ctdp_level)
643{
644 struct isst_perf_level_data_info info;
645 int ret;
646
647 info.socket_id = id->pkg;
648 info.power_domain_id = id->punit;
649 info.level = config_index;
650
651 ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
652 if (ret == -1)
653 return;
654
655 ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz;
656 ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz;
657 ctdp_level->uncore_pm = info.pm_fabric_freq_mhz;
658
659 if (ctdp_level->uncore_pm)
660 _set_uncore_min_max(id, max: 0, freq: ctdp_level->uncore_pm * 100000);
661
662 if (ctdp_level->uncore_p0)
663 _set_uncore_min_max(id, max: 1, freq: ctdp_level->uncore_p0 * 100000);
664
665 return;
666}
667
668static int tpmi_get_clos_information(struct isst_id *id, int *enable, int *type)
669{
670 struct isst_core_power info;
671 int ret;
672
673 info.get_set = 0;
674 info.socket_id = id->pkg;
675 info.power_domain_id = id->punit;
676 ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
677 if (ret == -1)
678 return ret;
679
680 *enable = info.enable;
681 *type = info.priority_type;
682
683 return 0;
684}
685
686static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
687 int priority_type)
688{
689 struct isst_core_power info;
690 int cp_state = 0, cp_cap = 0;
691 int i, j, ret, saved_punit;
692
693 info.get_set = 1;
694 info.socket_id = id->pkg;
695 info.power_domain_id = id->punit;
696 info.enable = enable_clos;
697 info.priority_type = priority_type;
698
699 saved_punit = id->punit;
700
701 /* Set for all other dies also. This is per package setting */
702 for (i = 0; i < MAX_PUNIT_PER_DIE; i++) {
703 id->punit = i;
704 if (isst_is_punit_valid(id)) {
705 info.power_domain_id = i;
706 ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
707 if (ret == -1) {
708 id->punit = saved_punit;
709 return ret;
710 }
711 /* Get status */
712 for (j = 0; j < FEATURE_ENABLE_RETRIES; ++j) {
713 usleep(FEATURE_ENABLE_WAIT_US);
714 ret = tpmi_read_pm_config(id, cp_state: &cp_state, cp_cap: &cp_cap);
715 debug_printf(format: "ret:%d cp_state:%d enable_clos:%d\n", ret,
716 cp_state, enable_clos);
717 if (ret || cp_state == enable_clos)
718 break;
719 }
720 if (j == FEATURE_ENABLE_RETRIES) {
721 id->punit = saved_punit;
722 return -1;
723 }
724 }
725 }
726
727 id->punit = saved_punit;
728
729 return 0;
730}
731
732int tpmi_pm_get_clos(struct isst_id *id, int clos,
733 struct isst_clos_config *clos_config)
734{
735 struct isst_clos_param info;
736 int ret;
737
738 info.get_set = 0;
739 info.socket_id = id->pkg;
740 info.power_domain_id = id->punit;
741 info.clos = clos;
742
743 ret = tpmi_process_ioctl(ISST_IF_CLOS_PARAM, &info);
744 if (ret == -1)
745 return ret;
746
747 clos_config->epp = 0;
748 clos_config->clos_prop_prio = info.prop_prio;
749 clos_config->clos_min = info.min_freq_mhz;
750 clos_config->clos_max = info.max_freq_mhz;
751 clos_config->clos_desired = 0;
752
753 debug_printf(format: "cpu:%d clos:%d min:%d max:%d\n", id->cpu, clos,
754 clos_config->clos_min, clos_config->clos_max);
755
756 return 0;
757}
758
759int tpmi_set_clos(struct isst_id *id, int clos,
760 struct isst_clos_config *clos_config)
761{
762 struct isst_clos_param info;
763 int i, ret, saved_punit;
764
765 info.get_set = 1;
766 info.socket_id = id->pkg;
767 info.power_domain_id = id->punit;
768 info.clos = clos;
769 info.prop_prio = clos_config->clos_prop_prio;
770
771 info.min_freq_mhz = clos_config->clos_min;
772 info.max_freq_mhz = clos_config->clos_max;
773
774 if (info.min_freq_mhz <= 0xff)
775 info.min_freq_mhz *= 100;
776 if (info.max_freq_mhz <= 0xff)
777 info.max_freq_mhz *= 100;
778
779 saved_punit = id->punit;
780
781 /* Set for all other dies also. This is per package setting */
782 for (i = 0; i < MAX_PUNIT_PER_DIE; i++) {
783 id->punit = i;
784 if (isst_is_punit_valid(id)) {
785 info.power_domain_id = i;
786 ret = tpmi_process_ioctl(ISST_IF_CLOS_PARAM, &info);
787 if (ret == -1) {
788 id->punit = saved_punit;
789 return ret;
790 }
791 }
792 }
793
794 id->punit = saved_punit;
795
796 debug_printf(format: "set cpu:%d clos:%d min:%d max:%d\n", id->cpu, clos,
797 clos_config->clos_min, clos_config->clos_max);
798
799 return 0;
800}
801
802static int tpmi_clos_get_assoc_status(struct isst_id *id, int *clos_id)
803{
804 struct isst_if_clos_assoc_cmds assoc_cmds;
805 int ret;
806
807 assoc_cmds.cmd_count = 1;
808 assoc_cmds.get_set = 0;
809 assoc_cmds.punit_cpu_map = 1;
810 assoc_cmds.assoc_info[0].logical_cpu = find_phy_core_num(logical_cpu: id->cpu);
811 assoc_cmds.assoc_info[0].socket_id = id->pkg;
812 assoc_cmds.assoc_info[0].power_domain_id = id->punit;
813
814 ret = tpmi_process_ioctl(ISST_IF_CLOS_ASSOC, &assoc_cmds);
815 if (ret == -1)
816 return ret;
817
818 *clos_id = assoc_cmds.assoc_info[0].clos;
819
820 return 0;
821}
822
823static int tpmi_clos_associate(struct isst_id *id, int clos_id)
824{
825 struct isst_if_clos_assoc_cmds assoc_cmds;
826 int ret;
827
828 assoc_cmds.cmd_count = 1;
829 assoc_cmds.get_set = 1;
830 assoc_cmds.punit_cpu_map = 1;
831 assoc_cmds.assoc_info[0].logical_cpu = find_phy_core_num(logical_cpu: id->cpu);
832 assoc_cmds.assoc_info[0].clos = clos_id;
833 assoc_cmds.assoc_info[0].socket_id = id->pkg;
834 assoc_cmds.assoc_info[0].power_domain_id = id->punit;
835
836 ret = tpmi_process_ioctl(ISST_IF_CLOS_ASSOC, &assoc_cmds);
837 if (ret == -1)
838 return ret;
839
840 return 0;
841}
842
843static struct isst_platform_ops tpmi_ops = {
844 .get_disp_freq_multiplier = tpmi_get_disp_freq_multiplier,
845 .get_trl_max_levels = tpmi_get_trl_max_levels,
846 .get_trl_level_name = tpmi_get_trl_level_name,
847 .update_platform_param = tpmi_update_platform_param,
848 .is_punit_valid = tpmi_is_punit_valid,
849 .read_pm_config = tpmi_read_pm_config,
850 .get_config_levels = tpmi_get_config_levels,
851 .get_ctdp_control = tpmi_get_ctdp_control,
852 .get_tdp_info = tpmi_get_tdp_info,
853 .get_pwr_info = tpmi_get_pwr_info,
854 .get_coremask_info = tpmi_get_coremask_info,
855 .get_get_trl = tpmi_get_get_trl,
856 .get_get_trls = tpmi_get_get_trls,
857 .get_trl_bucket_info = tpmi_get_trl_bucket_info,
858 .set_tdp_level = tpmi_set_tdp_level,
859 .get_pbf_info = tpmi_get_pbf_info,
860 .set_pbf_fact_status = tpmi_set_pbf_fact_status,
861 .get_fact_info = tpmi_get_fact_info,
862 .adjust_uncore_freq = tpmi_adjust_uncore_freq,
863 .get_clos_information = tpmi_get_clos_information,
864 .pm_qos_config = tpmi_pm_qos_config,
865 .pm_get_clos = tpmi_pm_get_clos,
866 .set_clos = tpmi_set_clos,
867 .clos_get_assoc_status = tpmi_clos_get_assoc_status,
868 .clos_associate = tpmi_clos_associate,
869};
870
871struct isst_platform_ops *tpmi_get_platform_ops(void)
872{
873 return &tpmi_ops;
874}
875

source code of linux/tools/power/x86/intel-speed-select/isst-core-tpmi.c