Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cpufreq/amd-pstate-ut: Add a unit test for raw EPP

Ensure that all supported raw EPP values work properly.

Export the driver helpers used by the test module so the test can drive
raw EPP writes and temporarily disable dynamic EPP while it runs.

Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>

+120 -4
+109
drivers/cpufreq/amd-pstate-ut.c
··· 28 28 #include <linux/kernel.h> 29 29 #include <linux/module.h> 30 30 #include <linux/moduleparam.h> 31 + #include <linux/mm.h> 31 32 #include <linux/fs.h> 32 33 #include <linux/cleanup.h> 33 34 ··· 42 41 module_param(test_list, charp, 0444); 43 42 MODULE_PARM_DESC(test_list, 44 43 "Comma-delimited list of tests to run (empty means run all tests)"); 44 + DEFINE_FREE(cleanup_page, void *, if (_T) free_page((unsigned long)_T)) 45 45 46 46 struct amd_pstate_ut_struct { 47 47 const char *name; ··· 56 54 static int amd_pstate_ut_check_enabled(u32 index); 57 55 static int amd_pstate_ut_check_perf(u32 index); 58 56 static int amd_pstate_ut_check_freq(u32 index); 57 + static int amd_pstate_ut_epp(u32 index); 59 58 static int amd_pstate_ut_check_driver(u32 index); 60 59 static int amd_pstate_ut_check_freq_attrs(u32 index); 61 60 ··· 65 62 {"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled }, 66 63 {"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf }, 67 64 {"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }, 65 + {"amd_pstate_ut_epp", amd_pstate_ut_epp }, 68 66 {"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }, 69 67 {"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs }, 70 68 }; ··· 270 266 pr_debug("->setting mode to %s\n", mode_str); 271 267 272 268 return amd_pstate_update_status(mode_str, strlen(mode_str)); 269 + } 270 + 271 + static int amd_pstate_ut_epp(u32 index) 272 + { 273 + struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 274 + char *buf __free(cleanup_page) = NULL; 275 + static const char * const epp_strings[] = { 276 + "performance", 277 + "balance_performance", 278 + "balance_power", 279 + "power", 280 + }; 281 + struct amd_cpudata *cpudata; 282 + enum amd_pstate_mode orig_mode; 283 + bool orig_dynamic_epp; 284 + int ret, cpu = 0; 285 + int i; 286 + u16 epp; 287 + 288 + policy = cpufreq_cpu_get(cpu); 289 + if (!policy) 290 + return -ENODEV; 291 + 292 + cpudata = policy->driver_data; 293 + orig_mode = amd_pstate_get_status(); 294 + orig_dynamic_epp = cpudata->dynamic_epp; 295 + 296 + /* disable dynamic EPP before running test */ 297 + if (cpudata->dynamic_epp) { 298 + pr_debug("Dynamic EPP is enabled, disabling it\n"); 299 + amd_pstate_clear_dynamic_epp(policy); 300 + } 301 + 302 + buf = (char *)__get_free_page(GFP_KERNEL); 303 + if (!buf) 304 + return -ENOMEM; 305 + 306 + ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE); 307 + if (ret) 308 + goto out; 309 + 310 + for (epp = 0; epp <= U8_MAX; epp++) { 311 + u8 val; 312 + 313 + /* write all EPP values */ 314 + memset(buf, 0, PAGE_SIZE); 315 + snprintf(buf, PAGE_SIZE, "%d", epp); 316 + ret = store_energy_performance_preference(policy, buf, strlen(buf)); 317 + if (ret < 0) 318 + goto out; 319 + 320 + /* check if the EPP value reads back correctly for raw numbers */ 321 + memset(buf, 0, PAGE_SIZE); 322 + ret = show_energy_performance_preference(policy, buf); 323 + if (ret < 0) 324 + goto out; 325 + strreplace(buf, '\n', '\0'); 326 + ret = kstrtou8(buf, 0, &val); 327 + if (!ret && epp != val) { 328 + pr_err("Raw EPP value mismatch: %d != %d\n", epp, val); 329 + ret = -EINVAL; 330 + goto out; 331 + } 332 + } 333 + 334 + for (i = 0; i < ARRAY_SIZE(epp_strings); i++) { 335 + memset(buf, 0, PAGE_SIZE); 336 + snprintf(buf, PAGE_SIZE, "%s", epp_strings[i]); 337 + ret = store_energy_performance_preference(policy, buf, strlen(buf)); 338 + if (ret < 0) 339 + goto out; 340 + 341 + memset(buf, 0, PAGE_SIZE); 342 + ret = show_energy_performance_preference(policy, buf); 343 + if (ret < 0) 344 + goto out; 345 + strreplace(buf, '\n', '\0'); 346 + 347 + if (strcmp(buf, epp_strings[i])) { 348 + pr_err("String EPP value mismatch: %s != %s\n", buf, epp_strings[i]); 349 + ret = -EINVAL; 350 + goto out; 351 + } 352 + } 353 + 354 + ret = 0; 355 + 356 + out: 357 + if (orig_dynamic_epp) { 358 + int ret2; 359 + 360 + ret2 = amd_pstate_set_mode(AMD_PSTATE_DISABLE); 361 + if (!ret && ret2) 362 + ret = ret2; 363 + } 364 + 365 + if (orig_mode != amd_pstate_get_status()) { 366 + int ret2; 367 + 368 + ret2 = amd_pstate_set_mode(orig_mode); 369 + if (!ret && ret2) 370 + ret = ret2; 371 + } 372 + 373 + return ret; 273 374 } 274 375 275 376 static int amd_pstate_ut_check_driver(u32 index)
+7 -4
drivers/cpufreq/amd-pstate.c
··· 1257 1257 .profile_get = amd_pstate_profile_get, 1258 1258 }; 1259 1259 1260 - static void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy) 1260 + void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy) 1261 1261 { 1262 1262 struct amd_cpudata *cpudata = policy->driver_data; 1263 1263 ··· 1270 1270 kfree(cpudata->profile_name); 1271 1271 cpudata->dynamic_epp = false; 1272 1272 } 1273 + EXPORT_SYMBOL_GPL(amd_pstate_clear_dynamic_epp); 1273 1274 1274 1275 static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy) 1275 1276 { ··· 1407 1406 return offset; 1408 1407 } 1409 1408 1410 - static ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, 1411 - const char *buf, size_t count) 1409 + ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, 1410 + const char *buf, size_t count) 1412 1411 { 1413 1412 struct amd_cpudata *cpudata = policy->driver_data; 1414 1413 ssize_t ret; ··· 1449 1448 1450 1449 return count; 1451 1450 } 1451 + EXPORT_SYMBOL_GPL(store_energy_performance_preference); 1452 1452 1453 - static ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf) 1453 + ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf) 1454 1454 { 1455 1455 struct amd_cpudata *cpudata = policy->driver_data; 1456 1456 u8 preference, epp; ··· 1480 1478 1481 1479 return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]); 1482 1480 } 1481 + EXPORT_SYMBOL_GPL(show_energy_performance_preference); 1483 1482 1484 1483 static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, 1485 1484 const char *buf, size_t count)
+4
drivers/cpufreq/amd-pstate.h
··· 150 150 const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode); 151 151 int amd_pstate_get_status(void); 152 152 int amd_pstate_update_status(const char *buf, size_t size); 153 + ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, 154 + const char *buf, size_t count); 155 + ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf); 156 + void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy); 153 157 154 158 struct freq_attr; 155 159