Skip to content

Commit 7e173bc

Browse files
committed
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>
1 parent 6927f21 commit 7e173bc

3 files changed

Lines changed: 120 additions & 4 deletions

File tree

drivers/cpufreq/amd-pstate-ut.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/kernel.h>
2929
#include <linux/module.h>
3030
#include <linux/moduleparam.h>
31+
#include <linux/mm.h>
3132
#include <linux/fs.h>
3233
#include <linux/cleanup.h>
3334

@@ -41,6 +42,7 @@ static char *test_list;
4142
module_param(test_list, charp, 0444);
4243
MODULE_PARM_DESC(test_list,
4344
"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))
4446

4547
struct amd_pstate_ut_struct {
4648
const char *name;
@@ -54,6 +56,7 @@ static int amd_pstate_ut_acpi_cpc_valid(u32 index);
5456
static int amd_pstate_ut_check_enabled(u32 index);
5557
static int amd_pstate_ut_check_perf(u32 index);
5658
static int amd_pstate_ut_check_freq(u32 index);
59+
static int amd_pstate_ut_epp(u32 index);
5760
static int amd_pstate_ut_check_driver(u32 index);
5861
static int amd_pstate_ut_check_freq_attrs(u32 index);
5962

@@ -62,6 +65,7 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
6265
{"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled },
6366
{"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf },
6467
{"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq },
68+
{"amd_pstate_ut_epp", amd_pstate_ut_epp },
6569
{"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver },
6670
{"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs },
6771
};
@@ -268,6 +272,111 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
268272
return amd_pstate_update_status(mode_str, strlen(mode_str));
269273
}
270274

275+
static int amd_pstate_ut_epp(u32 index)
276+
{
277+
struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
278+
char *buf __free(cleanup_page) = NULL;
279+
static const char * const epp_strings[] = {
280+
"performance",
281+
"balance_performance",
282+
"balance_power",
283+
"power",
284+
};
285+
struct amd_cpudata *cpudata;
286+
enum amd_pstate_mode orig_mode;
287+
bool orig_dynamic_epp;
288+
int ret, cpu = 0;
289+
int i;
290+
u16 epp;
291+
292+
policy = cpufreq_cpu_get(cpu);
293+
if (!policy)
294+
return -ENODEV;
295+
296+
cpudata = policy->driver_data;
297+
orig_mode = amd_pstate_get_status();
298+
orig_dynamic_epp = cpudata->dynamic_epp;
299+
300+
/* disable dynamic EPP before running test */
301+
if (cpudata->dynamic_epp) {
302+
pr_debug("Dynamic EPP is enabled, disabling it\n");
303+
amd_pstate_clear_dynamic_epp(policy);
304+
}
305+
306+
buf = (char *)__get_free_page(GFP_KERNEL);
307+
if (!buf)
308+
return -ENOMEM;
309+
310+
ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE);
311+
if (ret)
312+
goto out;
313+
314+
for (epp = 0; epp <= U8_MAX; epp++) {
315+
u8 val;
316+
317+
/* write all EPP values */
318+
memset(buf, 0, PAGE_SIZE);
319+
snprintf(buf, PAGE_SIZE, "%d", epp);
320+
ret = store_energy_performance_preference(policy, buf, strlen(buf));
321+
if (ret < 0)
322+
goto out;
323+
324+
/* check if the EPP value reads back correctly for raw numbers */
325+
memset(buf, 0, PAGE_SIZE);
326+
ret = show_energy_performance_preference(policy, buf);
327+
if (ret < 0)
328+
goto out;
329+
strreplace(buf, '\n', '\0');
330+
ret = kstrtou8(buf, 0, &val);
331+
if (!ret && epp != val) {
332+
pr_err("Raw EPP value mismatch: %d != %d\n", epp, val);
333+
ret = -EINVAL;
334+
goto out;
335+
}
336+
}
337+
338+
for (i = 0; i < ARRAY_SIZE(epp_strings); i++) {
339+
memset(buf, 0, PAGE_SIZE);
340+
snprintf(buf, PAGE_SIZE, "%s", epp_strings[i]);
341+
ret = store_energy_performance_preference(policy, buf, strlen(buf));
342+
if (ret < 0)
343+
goto out;
344+
345+
memset(buf, 0, PAGE_SIZE);
346+
ret = show_energy_performance_preference(policy, buf);
347+
if (ret < 0)
348+
goto out;
349+
strreplace(buf, '\n', '\0');
350+
351+
if (strcmp(buf, epp_strings[i])) {
352+
pr_err("String EPP value mismatch: %s != %s\n", buf, epp_strings[i]);
353+
ret = -EINVAL;
354+
goto out;
355+
}
356+
}
357+
358+
ret = 0;
359+
360+
out:
361+
if (orig_dynamic_epp) {
362+
int ret2;
363+
364+
ret2 = amd_pstate_set_mode(AMD_PSTATE_DISABLE);
365+
if (!ret && ret2)
366+
ret = ret2;
367+
}
368+
369+
if (orig_mode != amd_pstate_get_status()) {
370+
int ret2;
371+
372+
ret2 = amd_pstate_set_mode(orig_mode);
373+
if (!ret && ret2)
374+
ret = ret2;
375+
}
376+
377+
return ret;
378+
}
379+
271380
static int amd_pstate_ut_check_driver(u32 index)
272381
{
273382
enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;

drivers/cpufreq/amd-pstate.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ static const struct platform_profile_ops amd_pstate_profile_ops = {
12571257
.profile_get = amd_pstate_profile_get,
12581258
};
12591259

1260-
static void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
1260+
void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
12611261
{
12621262
struct amd_cpudata *cpudata = policy->driver_data;
12631263

@@ -1270,6 +1270,7 @@ static void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
12701270
kfree(cpudata->profile_name);
12711271
cpudata->dynamic_epp = false;
12721272
}
1273+
EXPORT_SYMBOL_GPL(amd_pstate_clear_dynamic_epp);
12731274

12741275
static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
12751276
{
@@ -1406,8 +1407,8 @@ static ssize_t show_energy_performance_available_preferences(
14061407
return offset;
14071408
}
14081409

1409-
static ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
1410-
const char *buf, size_t count)
1410+
ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
1411+
const char *buf, size_t count)
14111412
{
14121413
struct amd_cpudata *cpudata = policy->driver_data;
14131414
ssize_t ret;
@@ -1448,8 +1449,9 @@ static ssize_t store_energy_performance_preference(struct cpufreq_policy *policy
14481449

14491450
return count;
14501451
}
1452+
EXPORT_SYMBOL_GPL(store_energy_performance_preference);
14511453

1452-
static ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf)
1454+
ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf)
14531455
{
14541456
struct amd_cpudata *cpudata = policy->driver_data;
14551457
u8 preference, epp;
@@ -1478,6 +1480,7 @@ static ssize_t show_energy_performance_preference(struct cpufreq_policy *policy,
14781480

14791481
return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
14801482
}
1483+
EXPORT_SYMBOL_GPL(show_energy_performance_preference);
14811484

14821485
static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy,
14831486
const char *buf, size_t count)

drivers/cpufreq/amd-pstate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ enum amd_pstate_mode {
150150
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
151151
int amd_pstate_get_status(void);
152152
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);
153157

154158
struct freq_attr;
155159

0 commit comments

Comments
 (0)