[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 09/11] xen/x86: implement EPP support for the amd-cppc driver in active mode
On 06.02.2025 09:32, Penny Zheng wrote: > @@ -258,14 +259,27 @@ static void amd_cppc_write_request_msrs(void *info) > } > > static int cf_check amd_cppc_write_request(int cpu, uint8_t min_perf, > - uint8_t des_perf, uint8_t > max_perf) > + uint8_t des_perf, uint8_t > max_perf, > + int epp) > { > struct amd_cppc_drv_data *data = per_cpu(amd_cppc_drv_data, cpu); > uint64_t prev = data->req.raw; > > data->req.min_perf = min_perf; > data->req.max_perf = max_perf; > - data->req.des_perf = des_perf; > + if ( !opt_cpufreq_active ) > + data->req.des_perf = des_perf; > + else > + { > + data->req.des_perf = 0; > + /* Get pre-defined BIOS value */ > + if ( epp < 0 ) > + data->req.epp = epp_init; Instead of passing in a negative value, could't the caller pass epp_init, allowing the function parameter to be of an unsigned type? > @@ -292,7 +306,25 @@ static int cf_check amd_cppc_cpufreq_target(struct > cpufreq_policy *policy, > return res; > > return amd_cppc_write_request(policy->cpu, > data->caps.lowest_nonlinear_perf, > - des_perf, data->caps.highest_perf); > + des_perf, data->caps.highest_perf, -1); > +} > + > +static int read_epp_init_once(void) > +{ > + uint64_t val; > + static bool read_once = false; > + > + if ( !read_once ) > + { > + if ( rdmsr_safe(MSR_AMD_CPPC_REQ, val) ) > + return -EINVAL; > + epp_init = (val >> 24) & 0xFF; > + > + /* Read pre-defined BIOS value once */ > + read_once = true; > + } > + > + return 0; > } And all processors are (silently) assumed to have been configured the same? > @@ -381,7 +413,8 @@ static void cf_check amd_cppc_init_msrs(void *info) > data->nominal_freq = nominal_freq; > data->max_freq = max_freq; > > - return; > + if ( !read_epp_init_once() ) > + return; With this kind of a caller the function ought to return bool. If the function returns an error code, it should not be lost here. > @@ -443,6 +487,52 @@ static int cf_check amd_cppc_cpufreq_cpu_exit(struct > cpufreq_policy *policy) > return 0; > } > > +static int cf_check amd_cppc_epp_cpu_init(struct cpufreq_policy *policy) > +{ > + int ret; > + > + ret = amd_cppc_cpufreq_init_perf(policy); > + if ( ret ) > + return ret; > + > + policy->policy = cpufreq_parse_policy(policy->governor); > + > + amd_cppc_verbose("CPU %u initialized with amd-cppc active mode\n", > policy->cpu); > + > + return 0; > +} > + > +static int amd_cppc_epp_update_limit(const struct cpufreq_policy *policy) > +{ > + const struct amd_cppc_drv_data *data = per_cpu(amd_cppc_drv_data, > policy->cpu); > + uint8_t max_perf, min_perf, des_perf; > + int epp = -1; > + > + /* Initial min/max values for CPPC Performance Controls Register */ > + max_perf = data->caps.highest_perf; > + min_perf = data->caps.lowest_perf; > + > + /* CPPC EPP feature require to set zero to the desire perf bit */ > + des_perf = 0; Then why the local variable? Can't you pass ... > + if ( policy->policy == CPUFREQ_POLICY_PERFORMANCE ) > + { > + /* Force the epp value to be zero for performance policy */ > + epp = CPPC_ENERGY_PERF_MAX_PERFORMANCE; > + min_perf = max_perf; > + } > + else if ( policy->policy == CPUFREQ_POLICY_POWERSAVE ) > + /* Force the epp value to be 0xff for powersave policy */ > + epp = CPPC_ENERGY_PERF_MAX_POWERSAVE; > + > + return amd_cppc_write_request(policy->cpu, min_perf, des_perf, max_perf, > epp); ... 0 here (if need be with a /* des_perf */ comment)? The line (nit) is too long anyway, and hence needs wrapping no matter what. > @@ -452,10 +542,22 @@ static const struct cpufreq_driver > __initconst_cf_clobber amd_cppc_cpufreq_drive > .exit = amd_cppc_cpufreq_cpu_exit, > }; > > +static const struct cpufreq_driver __initconst_cf_clobber > amd_cppc_epp_driver = > +{ > + .name = XEN_AMD_CPPC_EPP_DRIVER_NAME, > + .verify = amd_cppc_cpufreq_verify, > + .setpolicy = amd_cppc_epp_set_policy, > + .init = amd_cppc_epp_cpu_init, > + .exit = amd_cppc_cpufreq_cpu_exit, > +}; > + > int __init amd_cppc_register_driver(void) > { > if ( !cpu_has_cppc ) > return -ENODEV; > > - return cpufreq_register_driver(&amd_cppc_cpufreq_driver); > + if ( !opt_cpufreq_active ) > + return cpufreq_register_driver(&amd_cppc_cpufreq_driver); > + else > + return cpufreq_register_driver(&amd_cppc_epp_driver); > } I'm personally opposed to this style of coding, and you ... > --- a/xen/drivers/cpufreq/utility.c > +++ b/xen/drivers/cpufreq/utility.c > @@ -484,3 +484,14 @@ int __cpufreq_set_policy(struct cpufreq_policy *data, > > return __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); > } > + > +unsigned int cpufreq_parse_policy(const struct cpufreq_governor *gov) > +{ > + if ( !strncasecmp(gov->name, "performance", CPUFREQ_NAME_LEN) ) > + return CPUFREQ_POLICY_PERFORMANCE; > + > + if ( !strncasecmp(gov->name, "powersave", CPUFREQ_NAME_LEN) ) > + return CPUFREQ_POLICY_POWERSAVE; > + > + return CPUFREQ_POLICY_UNKNOWN; > +} ... aren't doing that consistently anyway. May I ask that you drop the "else" there, or perhaps switch to using a conditional operator? > --- a/xen/include/acpi/cpufreq/cpufreq.h > +++ b/xen/include/acpi/cpufreq/cpufreq.h > @@ -83,6 +83,7 @@ struct cpufreq_policy { > int8_t turbo; /* tristate flag: 0 for unsupported > * -1 for disable, 1 for enabled > * See CPUFREQ_TURBO_* below for defines */ > + unsigned int policy; This new field wants connecting, by way of a comment perhaps, to ... > @@ -133,6 +134,17 @@ extern int cpufreq_register_governor(struct > cpufreq_governor *governor); > extern struct cpufreq_governor *__find_governor(const char *governor); > #define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs > > +#define CPUFREQ_POLICY_UNKNOWN 0 > +/* > + * If cpufreq_driver->target() exists, the ->governor decides what frequency > + * within the limits is used. If cpufreq_driver->setpolicy() exists, these > + * two generic policies are available: > + */ > +#define CPUFREQ_POLICY_POWERSAVE 1 > +#define CPUFREQ_POLICY_PERFORMANCE 2 ... the values to be put there, which - yes - ... > +unsigned int cpufreq_parse_policy(const struct cpufreq_governor *gov); ... are returned by this function. Such a comment could be as simple as /* CPUFREQ_POLICY_* */ Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |