xref: /linux/drivers/cpufreq/amd-pstate-ut.c (revision 5d7f3375cd574fc83f0cd30839b21455c0e79ae2)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * AMD Processor P-state Frequency Driver Unit Test
4  *
5  * Copyright (C) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
6  *
7  * Author: Meng Li <li.meng@amd.com>
8  *
9  * The AMD P-State Unit Test is a test module for testing the amd-pstate
10  * driver. 1) It can help all users to verify their processor support
11  * (SBIOS/Firmware or Hardware). 2) Kernel can have a basic function
12  * test to avoid the kernel regression during the update. 3) We can
13  * introduce more functional or performance tests to align the result
14  * together, it will benefit power and performance scale optimization.
15  *
16  * This driver implements basic framework with plans to enhance it with
17  * additional test cases to improve the depth and coverage of the test.
18  *
19  * See Documentation/admin-guide/pm/amd-pstate.rst Unit Tests for
20  * amd-pstate to get more detail.
21  */
22 
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24 
25 #include <linux/bitfield.h>
26 #include <linux/cpufeature.h>
27 #include <linux/cpufreq.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/moduleparam.h>
31 #include <linux/mm.h>
32 #include <linux/fs.h>
33 #include <linux/cleanup.h>
34 
35 #include <acpi/cppc_acpi.h>
36 
37 #include <asm/msr.h>
38 
39 #include "amd-pstate.h"
40 
41 static char *test_list;
42 module_param(test_list, charp, 0444);
43 MODULE_PARM_DESC(test_list,
44 	"Comma-delimited list of tests to run (empty means run all tests)");
45 DEFINE_FREE(cleanup_page, void *, if (_T) free_page((unsigned long)_T))
46 
47 struct amd_pstate_ut_struct {
48 	const char *name;
49 	int (*func)(u32 index);
50 };
51 
52 /*
53  * Kernel module for testing the AMD P-State unit test
54  */
55 static int amd_pstate_ut_acpi_cpc_valid(u32 index);
56 static int amd_pstate_ut_check_enabled(u32 index);
57 static int amd_pstate_ut_check_perf(u32 index);
58 static int amd_pstate_ut_check_freq(u32 index);
59 static int amd_pstate_ut_epp(u32 index);
60 static int amd_pstate_ut_check_driver(u32 index);
61 static int amd_pstate_ut_check_freq_attrs(u32 index);
62 static int amd_pstate_ut_check_floor_freq(u32 index);
63 
64 static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
65 	{"amd_pstate_ut_acpi_cpc_valid",    amd_pstate_ut_acpi_cpc_valid   },
66 	{"amd_pstate_ut_check_enabled",     amd_pstate_ut_check_enabled    },
67 	{"amd_pstate_ut_check_perf",        amd_pstate_ut_check_perf       },
68 	{"amd_pstate_ut_check_freq",        amd_pstate_ut_check_freq       },
69 	{"amd_pstate_ut_epp",               amd_pstate_ut_epp              },
70 	{"amd_pstate_ut_check_driver",      amd_pstate_ut_check_driver     },
71 	{"amd_pstate_ut_check_freq_attrs",  amd_pstate_ut_check_freq_attrs },
72 	{"amd_pstate_ut_check_floor_freq",  amd_pstate_ut_check_floor_freq },
73 };
74 
75 static bool test_in_list(const char *list, const char *name)
76 {
77 	size_t name_len = strlen(name);
78 	const char *p = list;
79 
80 	while (*p) {
81 		const char *sep = strchr(p, ',');
82 		size_t token_len = sep ? sep - p : strlen(p);
83 
84 		if (token_len == name_len && !strncmp(p, name, token_len))
85 			return true;
86 		if (!sep)
87 			break;
88 		p = sep + 1;
89 	}
90 
91 	return false;
92 }
93 
94 static bool get_shared_mem(void)
95 {
96 	bool result = false;
97 
98 	if (!boot_cpu_has(X86_FEATURE_CPPC))
99 		result = true;
100 
101 	return result;
102 }
103 
104 /*
105  * check the _CPC object is present in SBIOS.
106  */
107 static int amd_pstate_ut_acpi_cpc_valid(u32 index)
108 {
109 	if (!acpi_cpc_valid()) {
110 		pr_err("%s the _CPC object is not present in SBIOS!\n", __func__);
111 		return -EINVAL;
112 	}
113 
114 	return 0;
115 }
116 
117 /*
118  * check if amd pstate is enabled
119  */
120 static int amd_pstate_ut_check_enabled(u32 index)
121 {
122 	u64 cppc_enable = 0;
123 	int ret;
124 
125 	if (get_shared_mem())
126 		return 0;
127 
128 	ret = rdmsrq_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable);
129 	if (ret) {
130 		pr_err("%s rdmsrq_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret);
131 		return ret;
132 	}
133 
134 	if (!cppc_enable) {
135 		pr_err("%s amd pstate must be enabled!\n", __func__);
136 		return -EINVAL;
137 	}
138 
139 	return 0;
140 }
141 
142 /*
143  * check if performance values are reasonable.
144  * highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0
145  */
146 static int amd_pstate_ut_check_perf(u32 index)
147 {
148 	int cpu = 0, ret = 0;
149 	u32 highest_perf = 0, nominal_perf = 0, lowest_nonlinear_perf = 0, lowest_perf = 0;
150 	u64 cap1 = 0;
151 	struct cppc_perf_caps cppc_perf;
152 	union perf_cached cur_perf;
153 
154 	for_each_online_cpu(cpu) {
155 		struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
156 		struct amd_cpudata *cpudata;
157 
158 		policy = cpufreq_cpu_get(cpu);
159 		if (!policy)
160 			continue;
161 		cpudata = policy->driver_data;
162 
163 		if (get_shared_mem()) {
164 			ret = cppc_get_perf_caps(cpu, &cppc_perf);
165 			if (ret) {
166 				pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret);
167 				return ret;
168 			}
169 
170 			highest_perf = cppc_perf.highest_perf;
171 			nominal_perf = cppc_perf.nominal_perf;
172 			lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf;
173 			lowest_perf = cppc_perf.lowest_perf;
174 		} else {
175 			ret = rdmsrq_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
176 			if (ret) {
177 				pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret);
178 				return ret;
179 			}
180 
181 			highest_perf = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1);
182 			nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1);
183 			lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1);
184 			lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
185 		}
186 
187 		cur_perf = READ_ONCE(cpudata->perf);
188 		if (highest_perf != cur_perf.highest_perf && !cpudata->hw_prefcore) {
189 			pr_err("%s cpu%d highest=%d %d highest perf doesn't match\n",
190 				__func__, cpu, highest_perf, cur_perf.highest_perf);
191 			return -EINVAL;
192 		}
193 		if (nominal_perf != cur_perf.nominal_perf ||
194 		   (lowest_nonlinear_perf != cur_perf.lowest_nonlinear_perf) ||
195 		   (lowest_perf != cur_perf.lowest_perf)) {
196 			pr_err("%s cpu%d nominal=%d %d lowest_nonlinear=%d %d lowest=%d %d, they should be equal!\n",
197 				__func__, cpu, nominal_perf, cur_perf.nominal_perf,
198 				lowest_nonlinear_perf, cur_perf.lowest_nonlinear_perf,
199 				lowest_perf, cur_perf.lowest_perf);
200 			return -EINVAL;
201 		}
202 
203 		if (!((highest_perf >= nominal_perf) &&
204 			(nominal_perf > lowest_nonlinear_perf) &&
205 			(lowest_nonlinear_perf >= lowest_perf) &&
206 			(lowest_perf > 0))) {
207 			pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n",
208 				__func__, cpu, highest_perf, nominal_perf,
209 				lowest_nonlinear_perf, lowest_perf);
210 			return -EINVAL;
211 		}
212 	}
213 
214 	return 0;
215 }
216 
217 /*
218  * Check if frequency values are reasonable.
219  * nominal_freq > lowest_nonlinear_freq >= min_freq > 0
220  * max_freq >= lowest_nonlinear_freq
221  *
222  * On most parts the boost frequency is the highest, i.e.
223  * max_freq >= nominal_freq. On heterogeneous designs (e.g. Zen6) a
224  * low-power core can have a maximum frequency below the shared nominal
225  * reference frequency, so only require the boost frequency to sit above
226  * the lowest nonlinear frequency here.
227  * check max freq when set support boost mode.
228  */
229 static int amd_pstate_ut_check_freq(u32 index)
230 {
231 	int cpu = 0;
232 
233 	for_each_online_cpu(cpu) {
234 		struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
235 		struct amd_cpudata *cpudata;
236 		union perf_cached perf;
237 
238 		policy = cpufreq_cpu_get(cpu);
239 		if (!policy)
240 			continue;
241 
242 		cpudata = policy->driver_data;
243 		perf = READ_ONCE(cpudata->perf);
244 
245 		if (!((policy->cpuinfo.max_freq >= cpudata->lowest_nonlinear_freq) &&
246 			(cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) &&
247 			(cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) &&
248 			(policy->cpuinfo.min_freq > 0))) {
249 			pr_err("%s cpu%d max=%d, nominal=%d, lowest_nonlinear=%d, min=%d, the formula is incorrect!\n",
250 				__func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq,
251 				cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq);
252 			return -EINVAL;
253 		}
254 
255 		if (perf.bios_min_perf) {
256 			u32 bios_min_freq = perf_to_freq(perf, cpudata->nominal_freq,
257 							 perf.bios_min_perf);
258 
259 			/*
260 			 * User set bios_min_freq cannot be trusted to
261 			 * be within the driver limits. Clamp it similar
262 			 * to cpufreq_verify_within_cpu_limits().
263 			 */
264 			bios_min_freq = clamp_t(u32, bios_min_freq,
265 						     policy->cpuinfo.min_freq,
266 						     policy->cpuinfo.max_freq);
267 
268 			if (bios_min_freq != policy->min) {
269 				pr_err("%s cpu%d bios_min_freq=%d policy_min=%d, they should be equal!\n",
270 					__func__, cpu, bios_min_freq, policy->min);
271 				return -EINVAL;
272 			}
273 		} else if (cpudata->lowest_nonlinear_freq != policy->min) {
274 			pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n",
275 				__func__, cpu, cpudata->lowest_nonlinear_freq, policy->min);
276 			return -EINVAL;
277 		}
278 
279 		if (cpudata->boost_supported) {
280 			if ((policy->max != policy->cpuinfo.max_freq) &&
281 			    (policy->max != cpudata->nominal_freq)) {
282 				pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n",
283 					__func__, cpu, policy->max, policy->cpuinfo.max_freq,
284 					cpudata->nominal_freq);
285 				return -EINVAL;
286 			}
287 		} else {
288 			pr_err("%s cpu%d must support boost!\n", __func__, cpu);
289 			return -EINVAL;
290 		}
291 	}
292 
293 	return 0;
294 }
295 
296 static int amd_pstate_set_mode(enum amd_pstate_mode mode)
297 {
298 	const char *mode_str = amd_pstate_get_mode_string(mode);
299 
300 	pr_debug("->setting mode to %s\n", mode_str);
301 
302 	return amd_pstate_update_status(mode_str, strlen(mode_str));
303 }
304 
305 static int amd_pstate_ut_epp(u32 index)
306 {
307 	enum energy_perf_value_index epp_modes[] = {
308 		EPP_INDEX_DYNAMIC,
309 		EPP_INDEX_POWERSAVE,
310 		EPP_INDEX_BALANCE_POWERSAVE,
311 		EPP_INDEX_BALANCE_PERFORMANCE,
312 		EPP_INDEX_PERFORMANCE,
313 	};
314 	char *buf __free(cleanup_page) = NULL;
315 	struct cpufreq_policy *policy = NULL;
316 	unsigned long orig_dynamic_epp = 0;
317 	enum amd_pstate_mode orig_mode;
318 	struct amd_cpudata *cpudata;
319 	unsigned long orig_policy;
320 	int ret, cpu = 0;
321 	u16 epp;
322 	int i;
323 
324 	policy = cpufreq_cpu_get(cpu);
325 	if (!policy)
326 		return -ENODEV;
327 
328 	orig_mode = amd_pstate_get_status();
329 	if (policy->driver_data) {
330 		cpudata = policy->driver_data;
331 		orig_dynamic_epp = cpudata->dynamic_epp;
332 	}
333 
334 	/* Drop reference before potential driver change. */
335 	cpufreq_cpu_put(policy);
336 	policy = NULL;
337 
338 	buf = (char *)__get_free_page(GFP_KERNEL);
339 	if (!buf)
340 		return -ENOMEM;
341 
342 	ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE);
343 	if (ret)
344 		goto out;
345 
346 	policy = cpufreq_cpu_get(cpu);
347 	if (!policy) {
348 		ret = -ENODEV;
349 		goto out;
350 	}
351 
352 	down_write(&policy->rwsem);
353 	cpudata = policy->driver_data;
354 	orig_policy = cpudata->policy;
355 	cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
356 
357 	for (epp = 0; epp <= U8_MAX; epp++) {
358 		u8 val;
359 
360 		/* write all EPP values */
361 		memset(buf, 0, PAGE_SIZE);
362 		snprintf(buf, PAGE_SIZE, "%d", epp);
363 		ret = store_energy_performance_preference(policy, buf, strlen(buf));
364 		if (ret < 0)
365 			goto out;
366 
367 		/* check if the EPP value reads back correctly for raw numbers */
368 		memset(buf, 0, PAGE_SIZE);
369 		ret = show_energy_performance_preference(policy, buf);
370 		if (ret < 0)
371 			goto out;
372 		strreplace(buf, '\n', '\0');
373 		ret = kstrtou8(buf, 0, &val);
374 		if (!ret && epp != val) {
375 			pr_err("Raw EPP value mismatch: %d != %d\n", epp, val);
376 			ret = -EINVAL;
377 			goto out;
378 		}
379 	}
380 
381 	for (i = 0; i < ARRAY_SIZE(epp_modes); i++) {
382 		memset(buf, 0, PAGE_SIZE);
383 		snprintf(buf, PAGE_SIZE, "%s", energy_perf_strings[epp_modes[i]]);
384 		ret = store_energy_performance_preference(policy, buf, strlen(buf));
385 		if (ret < 0)
386 			goto out;
387 
388 		memset(buf, 0, PAGE_SIZE);
389 		ret = show_energy_performance_preference(policy, buf);
390 		if (ret < 0)
391 			goto out;
392 		strreplace(buf, '\n', '\0');
393 		/*
394 		 * "dynamic" mode reports the EPP as "dynamic(profile:X)"
395 		 * Trim at "(" and just compare tie the epp string.
396 		 */
397 		strreplace(buf, '(', '\0');
398 
399 		if (strcmp(buf, energy_perf_strings[epp_modes[i]])) {
400 			u8 epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached);
401 
402 			/*
403 			 * The preference read back may legitimately differ from the one
404 			 * written: some platforms (e.g. Zen6) program the same raw EPP
405 			 * value for more than one named preference, so show() reports the
406 			 * first name that matches that value.
407 			 *
408 			 * If strings mismatch, confirm the CPU is programmed with the correct
409 			 * EPP value for the mode. This verifies hardware programming while
410 			 * tolerating such aliasing in driver.
411 			 */
412 			if (epp == amd_pstate_cpu_epp_values(cpudata->cpu_type)[epp_modes[i]])
413 				continue;
414 
415 			pr_err("String EPP value mismatch: %s != %s\n",
416 			       buf, energy_perf_strings[epp_modes[i]]);
417 			ret = -EINVAL;
418 			goto out;
419 		}
420 	}
421 
422 	ret = 0;
423 
424 out:
425 	if (policy) {
426 		cpudata->policy = orig_policy;
427 		/*
428 		 * If the driver had enabled dynamic_epp to begin with,
429 		 * restore it here before dropping policy reference.
430 		 */
431 		if (orig_dynamic_epp) {
432 			const char * const dynamic_string = energy_perf_strings[epp_modes[0]];
433 			int ret2;
434 
435 			ret2 = store_energy_performance_preference(policy,
436 								  dynamic_string,
437 								  strlen(dynamic_string));
438 			if (!ret && (ret2 < 0))
439 				ret = ret2;
440 		}
441 		up_write(&policy->rwsem);
442 		cpufreq_cpu_put(policy);
443 	}
444 
445 	if (orig_mode != amd_pstate_get_status()) {
446 		int ret2;
447 
448 		ret2 = amd_pstate_set_mode(orig_mode);
449 		if (!ret && ret2)
450 			ret = ret2;
451 	}
452 
453 	return ret;
454 }
455 
456 static int amd_pstate_ut_check_driver(u32 index)
457 {
458 	enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
459 	enum amd_pstate_mode orig_mode = amd_pstate_get_status();
460 	int ret;
461 
462 	for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
463 		ret = amd_pstate_set_mode(mode1);
464 		if (ret)
465 			return ret;
466 		for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) {
467 			if (mode1 == mode2)
468 				continue;
469 			ret = amd_pstate_set_mode(mode2);
470 			if (ret)
471 				goto out;
472 		}
473 	}
474 
475 out:
476 	if (ret)
477 		pr_warn("%s: failed to update status for %s->%s: %d\n", __func__,
478 			amd_pstate_get_mode_string(mode1),
479 			amd_pstate_get_mode_string(mode2), ret);
480 
481 	amd_pstate_set_mode(orig_mode);
482 	return ret;
483 }
484 
485 enum attr_category {
486 	ATTR_ALWAYS,
487 	ATTR_PREFCORE,
488 	ATTR_EPP,
489 	ATTR_FLOOR_FREQ,
490 };
491 
492 static const struct {
493 	const char	*name;
494 	enum attr_category category;
495 } expected_freq_attrs[] = {
496 	{"amd_pstate_max_freq",				ATTR_ALWAYS},
497 	{"amd_pstate_lowest_nonlinear_freq",		ATTR_ALWAYS},
498 	{"amd_pstate_highest_perf",			ATTR_ALWAYS},
499 	{"amd_pstate_prefcore_ranking",			ATTR_PREFCORE},
500 	{"amd_pstate_hw_prefcore",			ATTR_PREFCORE},
501 	{"energy_performance_preference",		ATTR_EPP},
502 	{"energy_performance_available_preferences",	ATTR_EPP},
503 	{"amd_pstate_floor_freq",			ATTR_FLOOR_FREQ},
504 	{"amd_pstate_floor_count",			ATTR_FLOOR_FREQ},
505 };
506 
507 static bool attr_in_driver(struct freq_attr **driver_attrs, const char *name)
508 {
509 	int j;
510 
511 	for (j = 0; driver_attrs[j]; j++) {
512 		if (!strcmp(driver_attrs[j]->attr.name, name))
513 			return true;
514 	}
515 	return false;
516 }
517 
518 /*
519  * Verify that for each mode the driver's live ->attr array contains exactly
520  * the attributes that should be visible.  Expected visibility is derived
521  * independently from hw_prefcore, cpu features, and the current mode —
522  * not from the driver's own visibility functions.
523  */
524 static int amd_pstate_ut_check_freq_attrs(u32 index)
525 {
526 	enum amd_pstate_mode orig_mode = amd_pstate_get_status();
527 	static const enum amd_pstate_mode modes[] = {
528 		AMD_PSTATE_PASSIVE, AMD_PSTATE_ACTIVE, AMD_PSTATE_GUIDED,
529 	};
530 	bool has_prefcore, has_floor_freq;
531 	int m, i, ret;
532 
533 	has_floor_freq = cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO);
534 
535 	/*
536 	 * Determine prefcore support from any online CPU's cpudata.
537 	 * hw_prefcore reflects the platform-wide decision made at init.
538 	 */
539 	has_prefcore = false;
540 	for_each_online_cpu(i) {
541 		struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
542 		struct amd_cpudata *cpudata;
543 
544 		policy = cpufreq_cpu_get(i);
545 		if (!policy)
546 			continue;
547 		cpudata = policy->driver_data;
548 		has_prefcore = cpudata->hw_prefcore;
549 		break;
550 	}
551 
552 	for (m = 0; m < ARRAY_SIZE(modes); m++) {
553 		struct freq_attr **driver_attrs;
554 
555 		ret = amd_pstate_set_mode(modes[m]);
556 		if (ret)
557 			goto out;
558 
559 		driver_attrs = amd_pstate_get_current_attrs();
560 		if (!driver_attrs) {
561 			pr_err("%s: no driver attrs in mode %s\n",
562 			       __func__, amd_pstate_get_mode_string(modes[m]));
563 			ret = -EINVAL;
564 			goto out;
565 		}
566 
567 		for (i = 0; i < ARRAY_SIZE(expected_freq_attrs); i++) {
568 			bool expected, found;
569 
570 			switch (expected_freq_attrs[i].category) {
571 			case ATTR_ALWAYS:
572 				expected = true;
573 				break;
574 			case ATTR_PREFCORE:
575 				expected = has_prefcore;
576 				break;
577 			case ATTR_EPP:
578 				expected = (modes[m] == AMD_PSTATE_ACTIVE);
579 				break;
580 			case ATTR_FLOOR_FREQ:
581 				expected = has_floor_freq;
582 				break;
583 			default:
584 				expected = false;
585 				break;
586 			}
587 
588 			found = attr_in_driver(driver_attrs,
589 					       expected_freq_attrs[i].name);
590 
591 			if (expected != found) {
592 				pr_err("%s: mode %s: attr %s expected %s but is %s\n",
593 				       __func__,
594 				       amd_pstate_get_mode_string(modes[m]),
595 				       expected_freq_attrs[i].name,
596 				       expected ? "visible" : "hidden",
597 				       found ? "visible" : "hidden");
598 				ret = -EINVAL;
599 				goto out;
600 			}
601 		}
602 	}
603 
604 	ret = 0;
605 out:
606 	amd_pstate_set_mode(orig_mode);
607 	return ret;
608 }
609 
610 static int amd_pstate_ut_check_floor_freq(u32 index)
611 {
612 	struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
613 	char *buf __free(cleanup_page) = NULL;
614 	unsigned int orig_floor_freq;
615 	unsigned int floor_freq;
616 	int ret, cpu = 0;
617 
618 	if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
619 		return -EOPNOTSUPP;
620 
621 	policy = cpufreq_cpu_get(cpu);
622 	if (!policy)
623 		return -ENODEV;
624 
625 	buf = (char *)__get_free_page(GFP_KERNEL);
626 	if (!buf)
627 		return -ENOMEM;
628 
629 	guard(rwsem_write)(&policy->rwsem);
630 
631 	if (!policy->driver_data)
632 		return -ENODEV;
633 
634 	/* Retrieve original floor frequency */
635 	memset(buf, 0, PAGE_SIZE);
636 	ret = show_amd_pstate_floor_freq(policy, buf);
637 	if (ret < 0)
638 		return ret;
639 
640 	ret = kstrtou32(buf, 0, &orig_floor_freq);
641 	if (ret)
642 		return ret;
643 
644 	memset(buf, 0, PAGE_SIZE);
645 	snprintf(buf, PAGE_SIZE, "%u", policy->cpuinfo.min_freq);
646 
647 	/* Set floor frequency to cpuinfo.min_freq */
648 	ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf));
649 	if (ret < 0) {
650 		pr_err("Failed to set floor frequency to %s\n", buf);
651 		return ret;
652 	}
653 
654 	memset(buf, 0, PAGE_SIZE);
655 	ret = show_amd_pstate_floor_freq(policy, buf);
656 	if (ret < 0)
657 		return ret;
658 
659 	strreplace(buf, '\n', '\0');
660 	ret = kstrtou32(buf, 0, &floor_freq);
661 	if (ret)
662 		return ret;
663 
664 	/* Confirm sysfs reflects the change correctly. */
665 	if (floor_freq != policy->cpuinfo.min_freq) {
666 		pr_err("Floor frequency value mismatch: %u != %u\n",
667 		       floor_freq, policy->cpuinfo.min_freq);
668 		return -EINVAL;
669 	}
670 
671 	memset(buf, 0, PAGE_SIZE);
672 	snprintf(buf, PAGE_SIZE, "%u", orig_floor_freq);
673 
674 	/* Restore the original value. */
675 	ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf));
676 	if (ret < 0) {
677 		pr_err("Failed to restore floor frequency to %s\n", buf);
678 		return ret;
679 	}
680 
681 	return 0;
682 }
683 
684 static int __init amd_pstate_ut_init(void)
685 {
686 	u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
687 	enum amd_pstate_mode mode = amd_pstate_get_status();
688 
689 	/* don't test if no running amd-pstate driver */
690 	if (mode == AMD_PSTATE_UNDEFINED || mode == AMD_PSTATE_DISABLE)
691 		return -EOPNOTSUPP;
692 
693 	for (i = 0; i < arr_size; i++) {
694 		int ret;
695 
696 		if (test_list && *test_list &&
697 		    !test_in_list(test_list, amd_pstate_ut_cases[i].name))
698 			continue;
699 
700 		ret = amd_pstate_ut_cases[i].func(i);
701 
702 		if (ret) {
703 			/* Platform does not support the feature being tested. */
704 			if (ret == -EOPNOTSUPP) {
705 				pr_err("%-4d %-20s\t skipped!\n", i+1, amd_pstate_ut_cases[i].name);
706 				continue;
707 			}
708 			pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret);
709 		} else {
710 			pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name);
711 		}
712 	}
713 
714 	return 0;
715 }
716 
717 static void __exit amd_pstate_ut_exit(void)
718 {
719 }
720 
721 module_init(amd_pstate_ut_init);
722 module_exit(amd_pstate_ut_exit);
723 
724 MODULE_AUTHOR("Meng Li <li.meng@amd.com>");
725 MODULE_DESCRIPTION("AMD P-state driver Test module");
726 MODULE_LICENSE("GPL");
727