~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/power/x86/intel-speed-select/isst-core.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php