xref: /linux/drivers/cpufreq/amd-pstate-ut.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
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  * max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0
220  * check max freq when set support boost mode.
221  */
222 static int amd_pstate_ut_check_freq(u32 index)
223 {
224 	int cpu = 0;
225 
226 	for_each_online_cpu(cpu) {
227 		struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
228 		struct amd_cpudata *cpudata;
229 
230 		policy = cpufreq_cpu_get(cpu);
231 		if (!policy)
232 			continue;
233 		cpudata = policy->driver_data;
234 
235 		if (!((policy->cpuinfo.max_freq >= cpudata->nominal_freq) &&
236 			(cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) &&
237 			(cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) &&
238 			(policy->cpuinfo.min_freq > 0))) {
239 			pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n",
240 				__func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq,
241 				cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq);
242 			return -EINVAL;
243 		}
244 
245 		if (cpudata->lowest_nonlinear_freq != policy->min) {
246 			pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n",
247 				__func__, cpu, cpudata->lowest_nonlinear_freq, policy->min);
248 			return -EINVAL;
249 		}
250 
251 		if (cpudata->boost_supported) {
252 			if ((policy->max != policy->cpuinfo.max_freq) &&
253 			    (policy->max != cpudata->nominal_freq)) {
254 				pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n",
255 					__func__, cpu, policy->max, policy->cpuinfo.max_freq,
256 					cpudata->nominal_freq);
257 				return -EINVAL;
258 			}
259 		} else {
260 			pr_err("%s cpu%d must support boost!\n", __func__, cpu);
261 			return -EINVAL;
262 		}
263 	}
264 
265 	return 0;
266 }
267 
268 static int amd_pstate_set_mode(enum amd_pstate_mode mode)
269 {
270 	const char *mode_str = amd_pstate_get_mode_string(mode);
271 
272 	pr_debug("->setting mode to %s\n", mode_str);
273 
274 	return amd_pstate_update_status(mode_str, strlen(mode_str));
275 }
276 
277 static int amd_pstate_ut_epp(u32 index)
278 {
279 	static const char * const epp_strings[] = {
280 		"dynamic",
281 		"power",
282 		"balance_power",
283 		"balance_performance",
284 		"performance",
285 	};
286 	char *buf __free(cleanup_page) = NULL;
287 	struct cpufreq_policy *policy = NULL;
288 	unsigned long orig_dynamic_epp = 0;
289 	enum amd_pstate_mode orig_mode;
290 	struct amd_cpudata *cpudata;
291 	unsigned long orig_policy;
292 	int ret, cpu = 0;
293 	u16 epp;
294 	int i;
295 
296 	policy = cpufreq_cpu_get(cpu);
297 	if (!policy)
298 		return -ENODEV;
299 
300 	orig_mode = amd_pstate_get_status();
301 	if (policy->driver_data) {
302 		cpudata = policy->driver_data;
303 		orig_dynamic_epp = cpudata->dynamic_epp;
304 	}
305 
306 	/* Drop reference before potential driver change. */
307 	cpufreq_cpu_put(policy);
308 	policy = NULL;
309 
310 	buf = (char *)__get_free_page(GFP_KERNEL);
311 	if (!buf)
312 		return -ENOMEM;
313 
314 	ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE);
315 	if (ret)
316 		goto out;
317 
318 	policy = cpufreq_cpu_get(cpu);
319 	if (!policy) {
320 		ret = -ENODEV;
321 		goto out;
322 	}
323 
324 	down_write(&policy->rwsem);
325 	cpudata = policy->driver_data;
326 	orig_policy = cpudata->policy;
327 	cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
328 
329 	for (epp = 0; epp <= U8_MAX; epp++) {
330 		u8 val;
331 
332 		/* write all EPP values */
333 		memset(buf, 0, PAGE_SIZE);
334 		snprintf(buf, PAGE_SIZE, "%d", epp);
335 		ret = store_energy_performance_preference(policy, buf, strlen(buf));
336 		if (ret < 0)
337 			goto out;
338 
339 		/* check if the EPP value reads back correctly for raw numbers */
340 		memset(buf, 0, PAGE_SIZE);
341 		ret = show_energy_performance_preference(policy, buf);
342 		if (ret < 0)
343 			goto out;
344 		strreplace(buf, '\n', '\0');
345 		ret = kstrtou8(buf, 0, &val);
346 		if (!ret && epp != val) {
347 			pr_err("Raw EPP value mismatch: %d != %d\n", epp, val);
348 			ret = -EINVAL;
349 			goto out;
350 		}
351 	}
352 
353 	for (i = 0; i < ARRAY_SIZE(epp_strings); i++) {
354 		memset(buf, 0, PAGE_SIZE);
355 		snprintf(buf, PAGE_SIZE, "%s", epp_strings[i]);
356 		ret = store_energy_performance_preference(policy, buf, strlen(buf));
357 		if (ret < 0)
358 			goto out;
359 
360 		memset(buf, 0, PAGE_SIZE);
361 		ret = show_energy_performance_preference(policy, buf);
362 		if (ret < 0)
363 			goto out;
364 		strreplace(buf, '\n', '\0');
365 		/*
366 		 * "dynamic" mode reports the EPP as "dynamic(profile:X)"
367 		 * Trim at "(" and just compare tie the epp string.
368 		 */
369 		strreplace(buf, '(', '\0');
370 
371 		if (strcmp(buf, epp_strings[i])) {
372 			pr_err("String EPP value mismatch: %s != %s\n", buf, epp_strings[i]);
373 			ret = -EINVAL;
374 			goto out;
375 		}
376 	}
377 
378 	ret = 0;
379 
380 out:
381 	if (policy) {
382 		cpudata->policy = orig_policy;
383 		/*
384 		 * If the driver had enabled dynamic_epp to begin with,
385 		 * restore it here before dropping policy reference.
386 		 */
387 		if (orig_dynamic_epp) {
388 			int ret2;
389 
390 			ret2 = store_energy_performance_preference(policy,
391 								  epp_strings[0],
392 								  strlen(epp_strings[0]));
393 			if (!ret && (ret2 < 0))
394 				ret = ret2;
395 		}
396 		up_write(&policy->rwsem);
397 		cpufreq_cpu_put(policy);
398 	}
399 
400 	if (orig_mode != amd_pstate_get_status()) {
401 		int ret2;
402 
403 		ret2 = amd_pstate_set_mode(orig_mode);
404 		if (!ret && ret2)
405 			ret = ret2;
406 	}
407 
408 	return ret;
409 }
410 
411 static int amd_pstate_ut_check_driver(u32 index)
412 {
413 	enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
414 	enum amd_pstate_mode orig_mode = amd_pstate_get_status();
415 	int ret;
416 
417 	for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
418 		ret = amd_pstate_set_mode(mode1);
419 		if (ret)
420 			return ret;
421 		for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) {
422 			if (mode1 == mode2)
423 				continue;
424 			ret = amd_pstate_set_mode(mode2);
425 			if (ret)
426 				goto out;
427 		}
428 	}
429 
430 out:
431 	if (ret)
432 		pr_warn("%s: failed to update status for %s->%s: %d\n", __func__,
433 			amd_pstate_get_mode_string(mode1),
434 			amd_pstate_get_mode_string(mode2), ret);
435 
436 	amd_pstate_set_mode(orig_mode);
437 	return ret;
438 }
439 
440 enum attr_category {
441 	ATTR_ALWAYS,
442 	ATTR_PREFCORE,
443 	ATTR_EPP,
444 	ATTR_FLOOR_FREQ,
445 };
446 
447 static const struct {
448 	const char	*name;
449 	enum attr_category category;
450 } expected_freq_attrs[] = {
451 	{"amd_pstate_max_freq",				ATTR_ALWAYS},
452 	{"amd_pstate_lowest_nonlinear_freq",		ATTR_ALWAYS},
453 	{"amd_pstate_highest_perf",			ATTR_ALWAYS},
454 	{"amd_pstate_prefcore_ranking",			ATTR_PREFCORE},
455 	{"amd_pstate_hw_prefcore",			ATTR_PREFCORE},
456 	{"energy_performance_preference",		ATTR_EPP},
457 	{"energy_performance_available_preferences",	ATTR_EPP},
458 	{"amd_pstate_floor_freq",			ATTR_FLOOR_FREQ},
459 	{"amd_pstate_floor_count",			ATTR_FLOOR_FREQ},
460 };
461 
462 static bool attr_in_driver(struct freq_attr **driver_attrs, const char *name)
463 {
464 	int j;
465 
466 	for (j = 0; driver_attrs[j]; j++) {
467 		if (!strcmp(driver_attrs[j]->attr.name, name))
468 			return true;
469 	}
470 	return false;
471 }
472 
473 /*
474  * Verify that for each mode the driver's live ->attr array contains exactly
475  * the attributes that should be visible.  Expected visibility is derived
476  * independently from hw_prefcore, cpu features, and the current mode —
477  * not from the driver's own visibility functions.
478  */
479 static int amd_pstate_ut_check_freq_attrs(u32 index)
480 {
481 	enum amd_pstate_mode orig_mode = amd_pstate_get_status();
482 	static const enum amd_pstate_mode modes[] = {
483 		AMD_PSTATE_PASSIVE, AMD_PSTATE_ACTIVE, AMD_PSTATE_GUIDED,
484 	};
485 	bool has_prefcore, has_floor_freq;
486 	int m, i, ret;
487 
488 	has_floor_freq = cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO);
489 
490 	/*
491 	 * Determine prefcore support from any online CPU's cpudata.
492 	 * hw_prefcore reflects the platform-wide decision made at init.
493 	 */
494 	has_prefcore = false;
495 	for_each_online_cpu(i) {
496 		struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
497 		struct amd_cpudata *cpudata;
498 
499 		policy = cpufreq_cpu_get(i);
500 		if (!policy)
501 			continue;
502 		cpudata = policy->driver_data;
503 		has_prefcore = cpudata->hw_prefcore;
504 		break;
505 	}
506 
507 	for (m = 0; m < ARRAY_SIZE(modes); m++) {
508 		struct freq_attr **driver_attrs;
509 
510 		ret = amd_pstate_set_mode(modes[m]);
511 		if (ret)
512 			goto out;
513 
514 		driver_attrs = amd_pstate_get_current_attrs();
515 		if (!driver_attrs) {
516 			pr_err("%s: no driver attrs in mode %s\n",
517 			       __func__, amd_pstate_get_mode_string(modes[m]));
518 			ret = -EINVAL;
519 			goto out;
520 		}
521 
522 		for (i = 0; i < ARRAY_SIZE(expected_freq_attrs); i++) {
523 			bool expected, found;
524 
525 			switch (expected_freq_attrs[i].category) {
526 			case ATTR_ALWAYS:
527 				expected = true;
528 				break;
529 			case ATTR_PREFCORE:
530 				expected = has_prefcore;
531 				break;
532 			case ATTR_EPP:
533 				expected = (modes[m] == AMD_PSTATE_ACTIVE);
534 				break;
535 			case ATTR_FLOOR_FREQ:
536 				expected = has_floor_freq;
537 				break;
538 			default:
539 				expected = false;
540 				break;
541 			}
542 
543 			found = attr_in_driver(driver_attrs,
544 					       expected_freq_attrs[i].name);
545 
546 			if (expected != found) {
547 				pr_err("%s: mode %s: attr %s expected %s but is %s\n",
548 				       __func__,
549 				       amd_pstate_get_mode_string(modes[m]),
550 				       expected_freq_attrs[i].name,
551 				       expected ? "visible" : "hidden",
552 				       found ? "visible" : "hidden");
553 				ret = -EINVAL;
554 				goto out;
555 			}
556 		}
557 	}
558 
559 	ret = 0;
560 out:
561 	amd_pstate_set_mode(orig_mode);
562 	return ret;
563 }
564 
565 static int amd_pstate_ut_check_floor_freq(u32 index)
566 {
567 	struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
568 	char *buf __free(cleanup_page) = NULL;
569 	unsigned int orig_floor_freq;
570 	unsigned int floor_freq;
571 	int ret, cpu = 0;
572 
573 	if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
574 		return -EOPNOTSUPP;
575 
576 	policy = cpufreq_cpu_get(cpu);
577 	if (!policy)
578 		return -ENODEV;
579 
580 	buf = (char *)__get_free_page(GFP_KERNEL);
581 	if (!buf)
582 		return -ENOMEM;
583 
584 	guard(rwsem_write)(&policy->rwsem);
585 
586 	if (!policy->driver_data)
587 		return -ENODEV;
588 
589 	/* Retrieve original floor frequency */
590 	memset(buf, 0, PAGE_SIZE);
591 	ret = show_amd_pstate_floor_freq(policy, buf);
592 	if (ret < 0)
593 		return ret;
594 
595 	ret = kstrtou32(buf, 0, &orig_floor_freq);
596 	if (ret)
597 		return ret;
598 
599 	memset(buf, 0, PAGE_SIZE);
600 	snprintf(buf, PAGE_SIZE, "%u", policy->cpuinfo.min_freq);
601 
602 	/* Set floor frequency to cpuinfo.min_freq */
603 	ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf));
604 	if (ret < 0) {
605 		pr_err("Failed to set floor frequency to %s\n", buf);
606 		return ret;
607 	}
608 
609 	memset(buf, 0, PAGE_SIZE);
610 	ret = show_amd_pstate_floor_freq(policy, buf);
611 	if (ret < 0)
612 		return ret;
613 
614 	strreplace(buf, '\n', '\0');
615 	ret = kstrtou32(buf, 0, &floor_freq);
616 	if (ret)
617 		return ret;
618 
619 	/* Confirm sysfs reflects the change correctly. */
620 	if (floor_freq != policy->cpuinfo.min_freq) {
621 		pr_err("Floor frequency value mismatch: %u != %u\n",
622 		       floor_freq, policy->cpuinfo.min_freq);
623 		return -EINVAL;
624 	}
625 
626 	memset(buf, 0, PAGE_SIZE);
627 	snprintf(buf, PAGE_SIZE, "%u", orig_floor_freq);
628 
629 	/* Restore the original value. */
630 	ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf));
631 	if (ret < 0) {
632 		pr_err("Failed to restore floor frequency to %s\n", buf);
633 		return ret;
634 	}
635 
636 	return 0;
637 }
638 
639 static int __init amd_pstate_ut_init(void)
640 {
641 	u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
642 	enum amd_pstate_mode mode = amd_pstate_get_status();
643 
644 	/* don't test if no running amd-pstate driver */
645 	if (mode == AMD_PSTATE_UNDEFINED || mode == AMD_PSTATE_DISABLE)
646 		return -EOPNOTSUPP;
647 
648 	for (i = 0; i < arr_size; i++) {
649 		int ret;
650 
651 		if (test_list && *test_list &&
652 		    !test_in_list(test_list, amd_pstate_ut_cases[i].name))
653 			continue;
654 
655 		ret = amd_pstate_ut_cases[i].func(i);
656 
657 		if (ret) {
658 			/* Platform does not support the feature being tested. */
659 			if (ret == -EOPNOTSUPP) {
660 				pr_err("%-4d %-20s\t skipped!\n", i+1, amd_pstate_ut_cases[i].name);
661 				continue;
662 			}
663 			pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret);
664 		} else {
665 			pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name);
666 		}
667 	}
668 
669 	return 0;
670 }
671 
672 static void __exit amd_pstate_ut_exit(void)
673 {
674 }
675 
676 module_init(amd_pstate_ut_init);
677 module_exit(amd_pstate_ut_exit);
678 
679 MODULE_AUTHOR("Meng Li <li.meng@amd.com>");
680 MODULE_DESCRIPTION("AMD P-state driver Test module");
681 MODULE_LICENSE("GPL");
682