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