1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel Speed Select -- Enumerate and control features for Mailbox Interface
4  * Copyright (c) 2023 Intel Corporation.
5  */
6 #include "isst.h"
7 
8 static int mbox_get_disp_freq_multiplier(void)
9 {
10         return DISP_FREQ_MULTIPLIER;
11 }
12 
13 static int mbox_get_trl_max_levels(void)
14 {
15         return 3;
16 }
17 
18 static char *mbox_get_trl_level_name(int level)
19 {
20         switch (level) {
21         case 0:
22                 return "sse";
23         case 1:
24                 return "avx2";
25         case 2:
26                 return "avx512";
27         default:
28                 return NULL;
29         }
30 }
31 
32 static int mbox_is_punit_valid(struct isst_id *id)
33 {
34 	if (id->cpu < 0)
35 		return 0;
36 
37 	if (id->pkg < 0 || id->die < 0 || id->punit)
38 		return 0;
39 
40 	return 1;
41 }
42 
43 static int mbox_get_config_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
44 {
45 	unsigned int resp;
46 	int ret;
47 
48 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
49 				     CONFIG_TDP_GET_LEVELS_INFO, 0, 0, &resp);
50 	if (ret) {
51 		pkg_dev->levels = 0;
52 		pkg_dev->locked = 1;
53 		pkg_dev->current_level = 0;
54 		pkg_dev->version = 0;
55 		pkg_dev->enabled = 0;
56 		return 0;
57 	}
58 
59 	debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", id->cpu, resp);
60 
61 	pkg_dev->version = resp & 0xff;
62 	pkg_dev->levels = (resp >> 8) & 0xff;
63 	pkg_dev->current_level = (resp >> 16) & 0xff;
64 	pkg_dev->locked = !!(resp & BIT(24));
65 	pkg_dev->enabled = !!(resp & BIT(31));
66 
67 	return 0;
68 }
69 
70 static int mbox_get_ctdp_control(struct isst_id *id, int config_index,
71 			  struct isst_pkg_ctdp_level_info *ctdp_level)
72 {
73 	int cp_state, cp_cap;
74 	unsigned int resp;
75 	int ret;
76 
77 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
78 				     CONFIG_TDP_GET_TDP_CONTROL, 0,
79 				     config_index, &resp);
80 	if (ret)
81 		return ret;
82 
83 	ctdp_level->fact_support = resp & BIT(0);
84 	ctdp_level->pbf_support = !!(resp & BIT(1));
85 	ctdp_level->fact_enabled = !!(resp & BIT(16));
86 	ctdp_level->pbf_enabled = !!(resp & BIT(17));
87 
88 	ret = isst_read_pm_config(id, &cp_state, &cp_cap);
89 	if (ret) {
90 		debug_printf("cpu:%d pm_config is not supported\n", id->cpu);
91 	} else {
92 		debug_printf("cpu:%d pm_config SST-CP state:%d cap:%d\n", id->cpu, cp_state, cp_cap);
93 		ctdp_level->sst_cp_support = cp_cap;
94 		ctdp_level->sst_cp_enabled = cp_state;
95 	}
96 
97 	debug_printf(
98 		"cpu:%d CONFIG_TDP_GET_TDP_CONTROL resp:%x fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
99 		id->cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
100 		ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
101 
102 	return 0;
103 }
104 
105 static int mbox_get_tdp_info(struct isst_id *id, int config_index,
106 		      struct isst_pkg_ctdp_level_info *ctdp_level)
107 {
108 	unsigned int resp;
109 	int ret;
110 
111 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_INFO,
112 				     0, config_index, &resp);
113 	if (ret) {
114 		isst_display_error_info_message(1, "Invalid level, Can't get TDP information at level", 1, config_index);
115 		return ret;
116 	}
117 
118 	ctdp_level->pkg_tdp = resp & GENMASK(14, 0);
119 	ctdp_level->tdp_ratio = (resp & GENMASK(23, 16)) >> 16;
120 
121 	debug_printf(
122 		"cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO resp:%x tdp_ratio:%d pkg_tdp:%d\n",
123 		id->cpu, config_index, resp, ctdp_level->tdp_ratio,
124 		ctdp_level->pkg_tdp);
125 
126 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TJMAX_INFO,
127 				     0, config_index, &resp);
128 	if (ret)
129 		return ret;
130 
131 	ctdp_level->t_proc_hot = resp & GENMASK(7, 0);
132 
133 	debug_printf(
134 		"cpu:%d ctdp:%d CONFIG_TDP_GET_TJMAX_INFO resp:%x t_proc_hot:%d\n",
135 		id->cpu, config_index, resp, ctdp_level->t_proc_hot);
136 
137 	return 0;
138 }
139 
140 static int mbox_get_pwr_info(struct isst_id *id, int config_index,
141 		      struct isst_pkg_ctdp_level_info *ctdp_level)
142 {
143 	unsigned int resp;
144 	int ret;
145 
146 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_PWR_INFO,
147 				     0, config_index, &resp);
148 	if (ret)
149 		return ret;
150 
151 	ctdp_level->pkg_max_power = resp & GENMASK(14, 0);
152 	ctdp_level->pkg_min_power = (resp & GENMASK(30, 16)) >> 16;
153 
154 	debug_printf(
155 		"cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO resp:%x pkg_max_power:%d pkg_min_power:%d\n",
156 		id->cpu, config_index, resp, ctdp_level->pkg_max_power,
157 		ctdp_level->pkg_min_power);
158 
159 	return 0;
160 }
161 
162 static int mbox_get_coremask_info(struct isst_id *id, int config_index,
163 			   struct isst_pkg_ctdp_level_info *ctdp_level)
164 {
165 	unsigned int resp;
166 	int i, ret;
167 
168 	ctdp_level->cpu_count = 0;
169 	for (i = 0; i < 2; ++i) {
170 		unsigned long long mask;
171 		int cpu_count = 0;
172 
173 		ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
174 					     CONFIG_TDP_GET_CORE_MASK, 0,
175 					     (i << 8) | config_index, &resp);
176 		if (ret)
177 			return ret;
178 
179 		debug_printf(
180 			"cpu:%d ctdp:%d mask:%d CONFIG_TDP_GET_CORE_MASK resp:%x\n",
181 			id->cpu, config_index, i, resp);
182 
183 		mask = (unsigned long long)resp << (32 * i);
184 		set_cpu_mask_from_punit_coremask(id, mask,
185 						 ctdp_level->core_cpumask_size,
186 						 ctdp_level->core_cpumask,
187 						 &cpu_count);
188 		ctdp_level->cpu_count += cpu_count;
189 		debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", id->cpu,
190 			     config_index, i, ctdp_level->cpu_count);
191 	}
192 
193 	return 0;
194 }
195 
196 static int mbox_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)
197 {
198 	unsigned int req, resp;
199 	int ret;
200 
201 	req = level | (avx_level << 16);
202 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
203 				     CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
204 				     &resp);
205 	if (ret)
206 		return ret;
207 
208 	debug_printf(
209 		"cpu:%d CONFIG_TDP_GET_TURBO_LIMIT_RATIOS req:%x resp:%x\n",
210 		id->cpu, req, resp);
211 
212 	trl[0] = resp & GENMASK(7, 0);
213 	trl[1] = (resp & GENMASK(15, 8)) >> 8;
214 	trl[2] = (resp & GENMASK(23, 16)) >> 16;
215 	trl[3] = (resp & GENMASK(31, 24)) >> 24;
216 
217 	req = level | BIT(8) | (avx_level << 16);
218 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
219 				     CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
220 				     &resp);
221 	if (ret)
222 		return ret;
223 
224 	debug_printf("cpu:%d CONFIG_TDP_GET_TURBO_LIMIT req:%x resp:%x\n", id->cpu,
225 		     req, resp);
226 
227 	trl[4] = resp & GENMASK(7, 0);
228 	trl[5] = (resp & GENMASK(15, 8)) >> 8;
229 	trl[6] = (resp & GENMASK(23, 16)) >> 16;
230 	trl[7] = (resp & GENMASK(31, 24)) >> 24;
231 
232 	return 0;
233 }
234 
235 static int mbox_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info)
236 {
237 	int ret;
238 
239 	debug_printf("cpu:%d bucket info via MSR\n", id->cpu);
240 
241 	*buckets_info = 0;
242 
243 	ret = isst_send_msr_command(id->cpu, 0x1ae, 0, buckets_info);
244 	if (ret)
245 		return ret;
246 
247 	debug_printf("cpu:%d bucket info via MSR successful 0x%llx\n", id->cpu,
248 		     *buckets_info);
249 
250 	return 0;
251 }
252 
253 static int mbox_set_tdp_level(struct isst_id *id, int tdp_level)
254 {
255 	unsigned int resp;
256 	int ret;
257 
258 
259 	if (isst_get_config_tdp_lock_status(id)) {
260 		isst_display_error_info_message(1, "TDP is locked", 0, 0);
261 		return -1;
262 
263 	}
264 
265 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_SET_LEVEL, 0,
266 				     tdp_level, &resp);
267 	if (ret) {
268 		isst_display_error_info_message(1, "Set TDP level failed for level", 1, tdp_level);
269 		return ret;
270 	}
271 
272 	return 0;
273 }
274 
275 static int mbox_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)
276 {
277 	int max_punit_core, max_mask_index;
278 	unsigned int req, resp;
279 	int i, ret;
280 
281 	max_punit_core = get_max_punit_core_id(id);
282 	max_mask_index = max_punit_core > 32 ? 2 : 1;
283 
284 	for (i = 0; i < max_mask_index; ++i) {
285 		unsigned long long mask;
286 		int count;
287 
288 		ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
289 					     CONFIG_TDP_PBF_GET_CORE_MASK_INFO,
290 					     0, (i << 8) | level, &resp);
291 		if (ret)
292 			break;
293 
294 		debug_printf(
295 			"cpu:%d CONFIG_TDP_PBF_GET_CORE_MASK_INFO resp:%x\n",
296 			id->cpu, resp);
297 
298 		mask = (unsigned long long)resp << (32 * i);
299 		set_cpu_mask_from_punit_coremask(id, mask,
300 						 pbf_info->core_cpumask_size,
301 						 pbf_info->core_cpumask,
302 						 &count);
303 	}
304 
305 	req = level;
306 	ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
307 				     CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO, 0, req,
308 				     &resp);
309 	if (ret)
310 		return ret;
311 
312 	debug_printf("cpu:%d CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO resp:%x\n", id->cpu,
313 		     resp);
314 
315 	pbf_info->p1_low = resp & 0xff;
316 	pbf_info->p1_high = (resp & GENMASK(15, 8)) >> 8;
317 
318 	req = level;
319 	ret = isst_send_mbox_command(
320 		id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TDP_INFO, 0, req, &resp);
321 	if (ret)
322 		return ret;
323 
324 	debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TDP_INFO resp:%x\n", id->cpu, resp);
325 
326 	pbf_info->tdp = resp & 0xffff;
327 
328 	req = level;
329 	ret = isst_send_mbox_command(
330 		id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TJ_MAX_INFO, 0, req, &resp);
331 	if (ret)
332 		return ret;
333 
334 	debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TJ_MAX_INFO resp:%x\n", id->cpu,
335 		     resp);
336 	pbf_info->t_control = (resp >> 8) & 0xff;
337 	pbf_info->t_prochot = resp & 0xff;
338 
339 	return 0;
340 }
341 
342 static struct isst_platform_ops mbox_ops = {
343 	.get_disp_freq_multiplier = mbox_get_disp_freq_multiplier,
344 	.get_trl_max_levels = mbox_get_trl_max_levels,
345 	.get_trl_level_name = mbox_get_trl_level_name,
346 	.is_punit_valid = mbox_is_punit_valid,
347 	.get_config_levels = mbox_get_config_levels,
348 	.get_ctdp_control = mbox_get_ctdp_control,
349 	.get_tdp_info = mbox_get_tdp_info,
350 	.get_pwr_info = mbox_get_pwr_info,
351 	.get_coremask_info = mbox_get_coremask_info,
352 	.get_get_trl = mbox_get_get_trl,
353 	.get_trl_bucket_info = mbox_get_trl_bucket_info,
354 	.set_tdp_level = mbox_set_tdp_level,
355 	.get_pbf_info = mbox_get_pbf_info,
356 };
357 
358 struct isst_platform_ops *mbox_get_platform_ops(void)
359 {
360 	return &mbox_ops;
361 }
362