1 // SPDX-License-Identifier: GPL-2.0
3 * Intel Speed Select -- Enumerate and control features
4 * Copyright (c) 2019 Intel Corporation.
9 static struct isst_platform_ops
*isst_ops
;
11 #define CHECK_CB(_name) \
13 if (!isst_ops || !isst_ops->_name) { \
14 fprintf(stderr, "Invalid ops\n"); \
19 int isst_set_platform_ops(int api_version
)
21 switch (api_version
) {
23 isst_ops
= mbox_get_platform_ops();
27 isst_ops
= tpmi_get_platform_ops();
39 void isst_update_platform_param(enum isst_platform_param param
, int value
)
41 CHECK_CB(update_platform_param
);
43 isst_ops
->update_platform_param(param
, value
);
46 int isst_get_disp_freq_multiplier(void)
48 CHECK_CB(get_disp_freq_multiplier
);
49 return isst_ops
->get_disp_freq_multiplier();
52 int isst_get_trl_max_levels(void)
54 CHECK_CB(get_trl_max_levels
);
55 return isst_ops
->get_trl_max_levels();
58 char *isst_get_trl_level_name(int level
)
60 CHECK_CB(get_trl_level_name
);
61 return isst_ops
->get_trl_level_name(level
);
64 int isst_is_punit_valid(struct isst_id
*id
)
66 CHECK_CB(is_punit_valid
);
67 return isst_ops
->is_punit_valid(id
);
70 int isst_send_msr_command(unsigned int cpu
, unsigned int msr
, int write
,
71 unsigned long long *req_resp
)
73 struct isst_if_msr_cmds msr_cmds
;
74 const char *pathname
= "/dev/isst_interface";
75 FILE *outf
= get_output_file();
78 fd
= open(pathname
, O_RDWR
);
80 err(-1, "%s open failed", pathname
);
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
;
87 msr_cmds
.msr_cmd
[0].data
= *req_resp
;
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",
95 *req_resp
= msr_cmds
.msr_cmd
[0].data
;
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
);
107 int isst_read_pm_config(struct isst_id
*id
, int *cp_state
, int *cp_cap
)
109 CHECK_CB(read_pm_config
);
110 return isst_ops
->read_pm_config(id
, cp_state
, cp_cap
);
113 int isst_get_ctdp_levels(struct isst_id
*id
, struct isst_pkg_ctdp
*pkg_dev
)
115 CHECK_CB(get_config_levels
);
116 return isst_ops
->get_config_levels(id
, pkg_dev
);
119 int isst_get_ctdp_control(struct isst_id
*id
, int config_index
,
120 struct isst_pkg_ctdp_level_info
*ctdp_level
)
122 CHECK_CB(get_ctdp_control
);
123 return isst_ops
->get_ctdp_control(id
, config_index
, ctdp_level
);
126 int isst_get_tdp_info(struct isst_id
*id
, int config_index
,
127 struct isst_pkg_ctdp_level_info
*ctdp_level
)
129 CHECK_CB(get_tdp_info
);
130 return isst_ops
->get_tdp_info(id
, config_index
, ctdp_level
);
133 int isst_get_pwr_info(struct isst_id
*id
, int config_index
,
134 struct isst_pkg_ctdp_level_info
*ctdp_level
)
136 CHECK_CB(get_pwr_info
);
137 return isst_ops
->get_pwr_info(id
, config_index
, ctdp_level
);
140 int isst_get_coremask_info(struct isst_id
*id
, int config_index
,
141 struct isst_pkg_ctdp_level_info
*ctdp_level
)
143 CHECK_CB(get_coremask_info
);
144 return isst_ops
->get_coremask_info(id
, config_index
, ctdp_level
);
147 int isst_get_get_trl_from_msr(struct isst_id
*id
, int *trl
)
149 unsigned long long msr_trl
;
152 ret
= isst_send_msr_command(id
->cpu
, 0x1AD, 0, &msr_trl
);
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;
168 int isst_get_get_trl(struct isst_id
*id
, int level
, int avx_level
, int *trl
)
170 CHECK_CB(get_get_trl
);
171 return isst_ops
->get_get_trl(id
, level
, avx_level
, trl
);
174 int isst_get_get_trls(struct isst_id
*id
, int level
, struct isst_pkg_ctdp_level_info
*ctdp_level
)
176 CHECK_CB(get_get_trls
);
177 return isst_ops
->get_get_trls(id
, level
, ctdp_level
);
180 int isst_get_trl_bucket_info(struct isst_id
*id
, int level
, unsigned long long *buckets_info
)
182 CHECK_CB(get_trl_bucket_info
);
183 return isst_ops
->get_trl_bucket_info(id
, level
, buckets_info
);
186 int isst_set_tdp_level(struct isst_id
*id
, int tdp_level
)
188 CHECK_CB(set_tdp_level
);
189 return isst_ops
->set_tdp_level(id
, tdp_level
);
192 int isst_get_pbf_info(struct isst_id
*id
, int level
, struct isst_pbf_info
*pbf_info
)
194 struct isst_pkg_ctdp_level_info ctdp_level
;
195 struct isst_pkg_ctdp pkg_dev
;
198 ret
= isst_get_ctdp_levels(id
, &pkg_dev
);
200 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
204 if (level
> pkg_dev
.levels
) {
205 isst_display_error_info_message(1, "Invalid level", 1, level
);
209 ret
= isst_get_ctdp_control(id
, level
, &ctdp_level
);
213 if (!ctdp_level
.pbf_support
) {
214 isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, level
);
218 pbf_info
->core_cpumask_size
= alloc_cpu_set(&pbf_info
->core_cpumask
);
220 CHECK_CB(get_pbf_info
);
221 return isst_ops
->get_pbf_info(id
, level
, pbf_info
);
224 int isst_set_pbf_fact_status(struct isst_id
*id
, int pbf
, int enable
)
226 CHECK_CB(set_pbf_fact_status
);
227 return isst_ops
->set_pbf_fact_status(id
, pbf
, enable
);
232 int isst_get_fact_info(struct isst_id
*id
, int level
, int fact_bucket
, struct isst_fact_info
*fact_info
)
234 struct isst_pkg_ctdp_level_info ctdp_level
;
235 struct isst_pkg_ctdp pkg_dev
;
238 ret
= isst_get_ctdp_levels(id
, &pkg_dev
);
240 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
244 if (level
> pkg_dev
.levels
) {
245 isst_display_error_info_message(1, "Invalid level", 1, level
);
249 ret
= isst_get_ctdp_control(id
, level
, &ctdp_level
);
253 if (!ctdp_level
.fact_support
) {
254 isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, level
);
257 CHECK_CB(get_fact_info
);
258 return isst_ops
->get_fact_info(id
, level
, fact_bucket
, fact_info
);
261 int isst_get_trl(struct isst_id
*id
, unsigned long long *trl
)
265 ret
= isst_send_msr_command(id
->cpu
, 0x1AD, 0, trl
);
272 int isst_set_trl(struct isst_id
*id
, unsigned long long trl
)
277 trl
= 0xFFFFFFFFFFFFFFFFULL
;
279 ret
= isst_send_msr_command(id
->cpu
, 0x1AD, 1, &trl
);
286 #define MSR_TRL_FREQ_MULTIPLIER 100
288 int isst_set_trl_from_current_tdp(struct isst_id
*id
, unsigned long long trl
)
290 unsigned long long msr_trl
;
299 struct isst_pkg_ctdp pkg_dev
;
303 ret
= isst_get_ctdp_levels(id
, &pkg_dev
);
307 ret
= isst_get_get_trl(id
, pkg_dev
.current_level
, 0, trl
);
312 for (i
= 0; i
< 8; ++i
) {
313 unsigned long long _trl
= trl
[i
];
315 /* MSR is always in 100 MHz unit */
316 if (isst_get_disp_freq_multiplier() == 1)
317 _trl
/= MSR_TRL_FREQ_MULTIPLIER
;
319 msr_trl
|= (_trl
<< (i
* 8));
322 ret
= isst_send_msr_command(id
->cpu
, 0x1AD, 1, &msr_trl
);
329 /* Return 1 if locked */
330 int isst_get_config_tdp_lock_status(struct isst_id
*id
)
332 unsigned long long tdp_control
= 0;
335 ret
= isst_send_msr_command(id
->cpu
, 0x64b, 0, &tdp_control
);
339 ret
= !!(tdp_control
& BIT(31));
344 void isst_get_process_ctdp_complete(struct isst_id
*id
, struct isst_pkg_ctdp
*pkg_dev
)
348 if (!pkg_dev
->processed
)
351 for (i
= 0; i
< pkg_dev
->levels
; ++i
) {
352 struct isst_pkg_ctdp_level_info
*ctdp_level
;
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
);
361 void isst_adjust_uncore_freq(struct isst_id
*id
, int config_index
,
362 struct isst_pkg_ctdp_level_info
*ctdp_level
)
364 CHECK_CB(adjust_uncore_freq
);
365 return isst_ops
->adjust_uncore_freq(id
, config_index
, ctdp_level
);
368 int isst_get_process_ctdp(struct isst_id
*id
, int tdp_level
, struct isst_pkg_ctdp
*pkg_dev
)
370 int i
, ret
, valid
= 0;
372 if (pkg_dev
->processed
)
375 ret
= isst_get_ctdp_levels(id
, pkg_dev
);
379 debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",
380 id
->cpu
, pkg_dev
->enabled
, pkg_dev
->current_level
,
383 if (tdp_level
!= 0xff && tdp_level
> pkg_dev
->levels
) {
384 isst_display_error_info_message(1, "Invalid level", 0, 0);
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);
391 for (i
= 0; i
<= pkg_dev
->levels
; ++i
) {
392 struct isst_pkg_ctdp_level_info
*ctdp_level
;
394 if (tdp_level
!= 0xff && i
!= tdp_level
)
397 debug_printf("cpu:%d Get Information for TDP level:%d\n", id
->cpu
,
399 ctdp_level
= &pkg_dev
->ctdp_level
[i
];
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
;
406 ret
= isst_get_ctdp_control(id
, i
, ctdp_level
);
411 pkg_dev
->processed
= 1;
412 ctdp_level
->processed
= 1;
414 if (ctdp_level
->pbf_support
) {
415 ret
= isst_get_pbf_info(id
, i
, &ctdp_level
->pbf_info
);
417 ctdp_level
->pbf_found
= 1;
420 if (ctdp_level
->fact_support
) {
421 ret
= isst_get_fact_info(id
, i
, 0xff,
422 &ctdp_level
->fact_info
);
427 if (!pkg_dev
->enabled
&& is_skx_based_platform()) {
430 freq
= get_cpufreq_base_freq(id
->cpu
);
432 ctdp_level
->sse_p1
= freq
/ 100000;
433 ctdp_level
->tdp_ratio
= ctdp_level
->sse_p1
;
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
);
441 ret
= isst_get_tdp_info(id
, i
, ctdp_level
);
445 ret
= isst_get_pwr_info(id
, i
, ctdp_level
);
449 ctdp_level
->core_cpumask_size
=
450 alloc_cpu_set(&ctdp_level
->core_cpumask
);
451 ret
= isst_get_coremask_info(id
, i
, ctdp_level
);
455 ret
= isst_get_trl_bucket_info(id
, i
, &ctdp_level
->trl_cores
);
459 ret
= isst_get_get_trls(id
, i
, ctdp_level
);
465 isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id
->cpu
);
470 int isst_clos_get_clos_information(struct isst_id
*id
, int *enable
, int *type
)
472 CHECK_CB(get_clos_information
);
473 return isst_ops
->get_clos_information(id
, enable
, type
);
476 int isst_pm_qos_config(struct isst_id
*id
, int enable_clos
, int priority_type
)
478 CHECK_CB(pm_qos_config
);
479 return isst_ops
->pm_qos_config(id
, enable_clos
, priority_type
);
482 int isst_pm_get_clos(struct isst_id
*id
, int clos
, struct isst_clos_config
*clos_config
)
484 CHECK_CB(pm_get_clos
);
485 return isst_ops
->pm_get_clos(id
, clos
, clos_config
);
488 int isst_set_clos(struct isst_id
*id
, int clos
, struct isst_clos_config
*clos_config
)
491 return isst_ops
->set_clos(id
, clos
, clos_config
);
494 int isst_clos_get_assoc_status(struct isst_id
*id
, int *clos_id
)
496 CHECK_CB(clos_get_assoc_status
);
497 return isst_ops
->clos_get_assoc_status(id
, clos_id
);
500 int isst_clos_associate(struct isst_id
*id
, int clos_id
)
502 CHECK_CB(clos_associate
);
503 return isst_ops
->clos_associate(id
, clos_id
);