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

Configure Feed

Select the types of activity you want to include in your feed.

amd-pstate-ut: Add a testcase to validate the visibility of driver attributes

amd-pstate driver has per-attribute visibility functions to
dynamically control which sysfs freq_attrs are exposed based on the
platform capabilities and the current amd_pstate mode. However, there
is no test coverage to validate that the driver's live attribute list
matches the expected visibility for each mode.

Add amd_pstate_ut_check_freq_attrs() to the amd-pstate unit test
module. For each enabled mode (passive, active, guided), the test
independently derives the expected visibility of each attribute:
- Core attributes (max_freq, lowest_nonlinear_freq, highest_perf)
are always expected.
- Prefcore attributes (prefcore_ranking, hw_prefcore) are expected
only when cpudata->hw_prefcore indicates platform support.
- EPP attributes (energy_performance_preference,
energy_performance_available_preferences) are expected only in
active mode.
- Floor frequency attributes (floor_freq, floor_count) are expected
only when X86_FEATURE_CPPC_PERF_PRIO is present.

Compare these independent expectations against the live driver's attr
array, catching bugs such as attributes leaking into wrong modes or
visibility functions checking incorrect conditions.

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

authored by

Gautham R. Shenoy and committed by
Mario Limonciello (AMD)
3b90e5a4 c6a2b750

+146 -5
+134 -5
drivers/cpufreq/amd-pstate-ut.c
··· 23 23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 24 24 25 25 #include <linux/bitfield.h> 26 + #include <linux/cpufeature.h> 27 + #include <linux/cpufreq.h> 26 28 #include <linux/kernel.h> 27 29 #include <linux/module.h> 28 30 #include <linux/moduleparam.h> ··· 55 53 static int amd_pstate_ut_check_perf(u32 index); 56 54 static int amd_pstate_ut_check_freq(u32 index); 57 55 static int amd_pstate_ut_check_driver(u32 index); 56 + static int amd_pstate_ut_check_freq_attrs(u32 index); 58 57 59 58 static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = { 60 - {"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid }, 61 - {"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled }, 62 - {"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf }, 63 - {"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }, 64 - {"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver } 59 + {"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid }, 60 + {"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled }, 61 + {"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf }, 62 + {"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }, 63 + {"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }, 64 + {"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs }, 65 65 }; 66 66 67 67 static bool test_in_list(const char *list, const char *name) ··· 293 289 amd_pstate_get_mode_string(mode1), 294 290 amd_pstate_get_mode_string(mode2), ret); 295 291 292 + amd_pstate_set_mode(orig_mode); 293 + return ret; 294 + } 295 + 296 + enum attr_category { 297 + ATTR_ALWAYS, 298 + ATTR_PREFCORE, 299 + ATTR_EPP, 300 + ATTR_FLOOR_FREQ, 301 + }; 302 + 303 + static const struct { 304 + const char *name; 305 + enum attr_category category; 306 + } expected_freq_attrs[] = { 307 + {"amd_pstate_max_freq", ATTR_ALWAYS}, 308 + {"amd_pstate_lowest_nonlinear_freq", ATTR_ALWAYS}, 309 + {"amd_pstate_highest_perf", ATTR_ALWAYS}, 310 + {"amd_pstate_prefcore_ranking", ATTR_PREFCORE}, 311 + {"amd_pstate_hw_prefcore", ATTR_PREFCORE}, 312 + {"energy_performance_preference", ATTR_EPP}, 313 + {"energy_performance_available_preferences", ATTR_EPP}, 314 + {"amd_pstate_floor_freq", ATTR_FLOOR_FREQ}, 315 + {"amd_pstate_floor_count", ATTR_FLOOR_FREQ}, 316 + }; 317 + 318 + static bool attr_in_driver(struct freq_attr **driver_attrs, const char *name) 319 + { 320 + int j; 321 + 322 + for (j = 0; driver_attrs[j]; j++) { 323 + if (!strcmp(driver_attrs[j]->attr.name, name)) 324 + return true; 325 + } 326 + return false; 327 + } 328 + 329 + /* 330 + * Verify that for each mode the driver's live ->attr array contains exactly 331 + * the attributes that should be visible. Expected visibility is derived 332 + * independently from hw_prefcore, cpu features, and the current mode — 333 + * not from the driver's own visibility functions. 334 + */ 335 + static int amd_pstate_ut_check_freq_attrs(u32 index) 336 + { 337 + enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 338 + static const enum amd_pstate_mode modes[] = { 339 + AMD_PSTATE_PASSIVE, AMD_PSTATE_ACTIVE, AMD_PSTATE_GUIDED, 340 + }; 341 + bool has_prefcore, has_floor_freq; 342 + int m, i, ret; 343 + 344 + has_floor_freq = cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO); 345 + 346 + /* 347 + * Determine prefcore support from any online CPU's cpudata. 348 + * hw_prefcore reflects the platform-wide decision made at init. 349 + */ 350 + has_prefcore = false; 351 + for_each_online_cpu(i) { 352 + struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 353 + struct amd_cpudata *cpudata; 354 + 355 + policy = cpufreq_cpu_get(i); 356 + if (!policy) 357 + continue; 358 + cpudata = policy->driver_data; 359 + has_prefcore = cpudata->hw_prefcore; 360 + break; 361 + } 362 + 363 + for (m = 0; m < ARRAY_SIZE(modes); m++) { 364 + struct freq_attr **driver_attrs; 365 + 366 + ret = amd_pstate_set_mode(modes[m]); 367 + if (ret) 368 + goto out; 369 + 370 + driver_attrs = amd_pstate_get_current_attrs(); 371 + if (!driver_attrs) { 372 + pr_err("%s: no driver attrs in mode %s\n", 373 + __func__, amd_pstate_get_mode_string(modes[m])); 374 + ret = -EINVAL; 375 + goto out; 376 + } 377 + 378 + for (i = 0; i < ARRAY_SIZE(expected_freq_attrs); i++) { 379 + bool expected, found; 380 + 381 + switch (expected_freq_attrs[i].category) { 382 + case ATTR_ALWAYS: 383 + expected = true; 384 + break; 385 + case ATTR_PREFCORE: 386 + expected = has_prefcore; 387 + break; 388 + case ATTR_EPP: 389 + expected = (modes[m] == AMD_PSTATE_ACTIVE); 390 + break; 391 + case ATTR_FLOOR_FREQ: 392 + expected = has_floor_freq; 393 + break; 394 + default: 395 + expected = false; 396 + break; 397 + } 398 + 399 + found = attr_in_driver(driver_attrs, 400 + expected_freq_attrs[i].name); 401 + 402 + if (expected != found) { 403 + pr_err("%s: mode %s: attr %s expected %s but is %s\n", 404 + __func__, 405 + amd_pstate_get_mode_string(modes[m]), 406 + expected_freq_attrs[i].name, 407 + expected ? "visible" : "hidden", 408 + found ? "visible" : "hidden"); 409 + ret = -EINVAL; 410 + goto out; 411 + } 412 + } 413 + } 414 + 415 + ret = 0; 416 + out: 296 417 amd_pstate_set_mode(orig_mode); 297 418 return ret; 298 419 }
+8
drivers/cpufreq/amd-pstate.c
··· 1390 1390 {&amd_pstate_floor_count, floor_freq_visibility}, 1391 1391 }; 1392 1392 1393 + struct freq_attr **amd_pstate_get_current_attrs(void) 1394 + { 1395 + if (!current_pstate_driver) 1396 + return NULL; 1397 + return current_pstate_driver->attr; 1398 + } 1399 + EXPORT_SYMBOL_GPL(amd_pstate_get_current_attrs); 1400 + 1393 1401 static struct freq_attr **get_freq_attrs(void) 1394 1402 { 1395 1403 bool attr_visible[ARRAY_SIZE(amd_pstate_attr_visibility)];
+4
drivers/cpufreq/amd-pstate.h
··· 134 134 int amd_pstate_get_status(void); 135 135 int amd_pstate_update_status(const char *buf, size_t size); 136 136 137 + struct freq_attr; 138 + 139 + struct freq_attr **amd_pstate_get_current_attrs(void); 140 + 137 141 #endif /* _LINUX_AMD_PSTATE_H */