[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v8 8/8] xen/cpufreq: Adapt SET/GET_CPUFREQ_CPPC xen_sysctl_pm_op for amd-cppc driver
Introduce helper set_amd_cppc_para() and get_amd_cppc_para() to SET/GET CPPC-related para for amd-cppc/amd-cppc-epp driver. In get_cpufreq_cppc()/set_cpufreq_cppc(), we include "processor_pminfo[cpuid]->init & XEN_CPPC_INIT" condition check to deal with cpufreq driver in amd-cppc. We also borrow governor field to indicate policy info for CPPC active mode. Signed-off-by: Penny Zheng <Penny.Zheng@xxxxxxx> Acked-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> --- v1 -> v2: - Give the variable des_perf an initializer of 0 - Use the strncmp()s directly in the if() --- v3 -> v4 - refactor comments - remove double blank lines - replace amd_cppc_in_use flag with XEN_PROCESSOR_PM_CPPC --- v4 -> v5: - add new field "policy" in "struct xen_cppc_para" - add new performamce policy XEN_CPUFREQ_POLICY_BALANCE - drop string comparisons with "processor_pminfo[cpuid]->init & XEN_CPPC_INIT" and "cpufreq.setpolicy == NULL" - Blank line ahead of the main "return" of a function - refactor comments, commit message and title --- v5 -> v6: - remove duplicated manifest constants, and just move it to public header - use "else if" to avoid confusion that it looks as if both paths could be taken - add check for legitimate perf values - use "unknown" instead of "none" - introduce "CPUFREQ_POLICY_END" for array overrun check in user space tools --- v6 -> v7: - use ARRAY_SIZE() instead - ->policy print is avoided in passive mode and print "unknown" in invalid cases - let cpufreq_is_governorless() being the variable's initializer - refactor with the conditional operator to increase readability - move duplicated defination ahead and use local variable - avoid using "else-condition" to bring "dead code" in Misra's nomeclature - move the comment out of public header and into the respective internal struct field - wrap set{,get}_amd_cppc_para() with CONFIG_PM_OP - add symmetry scenario for maximum check --- v7 -> v8: - change function name to amd_cppc_get{,set}_para() - fix too deep indentation, and indent according to pending open parentheses - missing -EINVAL when no flag is set at all - use new helper amd_cppc_prepare_policy() to reduce redundancy - borrow governor field to indicate policy info --- tools/misc/xenpm.c | 13 ++- xen/arch/x86/acpi/cpufreq/amd-cppc.c | 164 +++++++++++++++++++++++++++ xen/drivers/acpi/pm-op.c | 28 +++-- xen/include/acpi/cpufreq/cpufreq.h | 4 + 4 files changed, 196 insertions(+), 13 deletions(-) diff --git a/tools/misc/xenpm.c b/tools/misc/xenpm.c index 893a0afe11..bda9c62aa0 100644 --- a/tools/misc/xenpm.c +++ b/tools/misc/xenpm.c @@ -832,11 +832,14 @@ static void print_cppc_para(unsigned int cpuid, /* print out parameters about cpu frequency */ static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para *p_cpufreq) { - bool is_governor_less = false; + bool is_governor_less = false, is_cppc_active = false; int i; - if ( !strcmp(p_cpufreq->scaling_driver, XEN_HWP_DRIVER_NAME) || - !strcmp(p_cpufreq->scaling_driver, XEN_AMD_CPPC_EPP_DRIVER_NAME) ) + if ( !strcmp(p_cpufreq->scaling_driver, XEN_AMD_CPPC_EPP_DRIVER_NAME) ) + is_cppc_active = true; + + if ( is_cppc_active || + !strcmp(p_cpufreq->scaling_driver, XEN_HWP_DRIVER_NAME) ) is_governor_less = true; printf("cpu id : %d\n", cpuid); @@ -899,6 +902,10 @@ static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para *p_cpufreq) p_cpufreq->u.s.scaling_cur_freq); } + /* Translate governor info to policy info in CPPC active mode */ + if ( is_cppc_active ) + printf("policy : %s\n", p_cpufreq->u.s.scaling_governor); + printf("turbo mode : %s\n", p_cpufreq->turbo_enabled ? "enabled" : "disabled or n/a"); printf("\n"); diff --git a/xen/arch/x86/acpi/cpufreq/amd-cppc.c b/xen/arch/x86/acpi/cpufreq/amd-cppc.c index bb7f4e4a9e..eca455240f 100644 --- a/xen/arch/x86/acpi/cpufreq/amd-cppc.c +++ b/xen/arch/x86/acpi/cpufreq/amd-cppc.c @@ -566,6 +566,170 @@ static int cf_check amd_cppc_epp_set_policy(struct cpufreq_policy *policy) return 0; } +#ifdef CONFIG_PM_OP +int amd_cppc_get_para(const struct cpufreq_policy *policy, + struct xen_get_cppc_para *cppc_para) +{ + const struct amd_cppc_drv_data *data = per_cpu(amd_cppc_drv_data, + policy->cpu); + + if ( data == NULL ) + return -ENODATA; + + cppc_para->lowest = data->caps.lowest_perf; + cppc_para->lowest_nonlinear = data->caps.lowest_nonlinear_perf; + cppc_para->nominal = data->caps.nominal_perf; + cppc_para->highest = data->caps.highest_perf; + cppc_para->minimum = data->req.min_perf; + cppc_para->maximum = data->req.max_perf; + cppc_para->desired = data->req.des_perf; + cppc_para->energy_perf = data->req.epp; + + return 0; +} + +int amd_cppc_set_para(struct cpufreq_policy *policy, + const struct xen_set_cppc_para *set_cppc) +{ + unsigned int cpu = policy->cpu; + struct amd_cppc_drv_data *data = per_cpu(amd_cppc_drv_data, cpu); + uint8_t max_perf, min_perf, des_perf, epp; + bool active_mode = cpufreq_is_governorless(cpu); + + if ( data == NULL ) + return -ENOENT; + + /* Only allow values if params bit is set. */ + if ( (!(set_cppc->set_params & XEN_SYSCTL_CPPC_SET_DESIRED) && + set_cppc->desired) || + (!(set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MINIMUM) && + set_cppc->minimum) || + (!(set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MAXIMUM) && + set_cppc->maximum) || + (!(set_cppc->set_params & XEN_SYSCTL_CPPC_SET_ENERGY_PERF) && + set_cppc->energy_perf) ) + return -EINVAL; + + /* Return if there is nothing to do. */ + if ( set_cppc->set_params == 0 ) + return 0; + + /* + * Validate all parameters + * Maximum performance may be set to any performance value in the range + * [Nonlinear Lowest Performance, Highest Performance], inclusive but must + * be set to a value that is larger than or equal to minimum Performance. + */ + if ( (set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MAXIMUM) && + (set_cppc->maximum > data->caps.highest_perf || + (set_cppc->maximum < + (set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MINIMUM + ? set_cppc->minimum + : data->req.min_perf))) ) + return -EINVAL; + /* + * Minimum performance may be set to any performance value in the range + * [Nonlinear Lowest Performance, Highest Performance], inclusive but must + * be set to a value that is less than or equal to Maximum Performance. + */ + if ( (set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MINIMUM) && + (set_cppc->minimum < data->caps.lowest_nonlinear_perf || + (set_cppc->minimum > + (set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MAXIMUM + ? set_cppc->maximum + : data->req.max_perf))) ) + return -EINVAL; + /* + * Desired performance may be set to any performance value in the range + * [Minimum Performance, Maximum Performance], inclusive. + */ + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_DESIRED ) + { + if ( active_mode ) + return -EOPNOTSUPP; + + if ( (set_cppc->desired > + (set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MAXIMUM + ? set_cppc->maximum + : data->req.max_perf)) || + (set_cppc->desired < + (set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MINIMUM + ? set_cppc->minimum + : data->req.min_perf)) ) + return -EINVAL; + } + /* + * Energy Performance Preference may be set with a range of values + * from 0 to 0xFF + */ + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_ENERGY_PERF ) + { + if ( !active_mode ) + return -EOPNOTSUPP; + + if ( set_cppc->energy_perf > UINT8_MAX ) + return -EINVAL; + } + + /* Activity window not supported in MSR */ + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_ACT_WINDOW ) + return -EOPNOTSUPP; + + des_perf = data->req.des_perf; + /* + * Apply presets: + * XEN_SYSCTL_CPPC_SET_PRESET_POWERSAVE/PERFORMANCE/ONDEMAND are + * only available when CPPC in active mode + */ + switch ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_PRESET_MASK ) + { + case XEN_SYSCTL_CPPC_SET_PRESET_POWERSAVE: + if ( !active_mode ) + return -EINVAL; + policy->policy = CPUFREQ_POLICY_POWERSAVE; + break; + + case XEN_SYSCTL_CPPC_SET_PRESET_PERFORMANCE: + if ( !active_mode ) + return -EINVAL; + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + break; + + case XEN_SYSCTL_CPPC_SET_PRESET_ONDEMAND: + if ( !active_mode ) + return -EINVAL; + policy->policy = CPUFREQ_POLICY_ONDEMAND; + break; + + case XEN_SYSCTL_CPPC_SET_PRESET_NONE: + if ( active_mode ) + policy->policy = CPUFREQ_POLICY_UNKNOWN; + break; + + default: + return -EINVAL; + } + amd_cppc_prepare_policy(policy, &max_perf, &min_perf, &epp); + + /* Further customize presets if needed */ + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MINIMUM ) + min_perf = set_cppc->minimum; + + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_MAXIMUM ) + max_perf = set_cppc->maximum; + + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_ENERGY_PERF ) + epp = set_cppc->energy_perf; + + if ( set_cppc->set_params & XEN_SYSCTL_CPPC_SET_DESIRED ) + des_perf = set_cppc->desired; + + amd_cppc_write_request(cpu, min_perf, des_perf, max_perf, epp); + + return 0; +} +#endif /* CONFIG_PM_OP */ + static const struct cpufreq_driver __initconst_cf_clobber amd_cppc_cpufreq_driver = { diff --git a/xen/drivers/acpi/pm-op.c b/xen/drivers/acpi/pm-op.c index 371deaf678..bcb3b9b2a7 100644 --- a/xen/drivers/acpi/pm-op.c +++ b/xen/drivers/acpi/pm-op.c @@ -84,6 +84,8 @@ static int get_cpufreq_cppc(unsigned int cpu, if ( hwp_active() ) ret = get_hwp_para(cpu, cppc_para); + else if ( processor_pminfo[cpu]->init & XEN_CPPC_INIT ) + ret = amd_cppc_get_para(per_cpu(cpufreq_cpu_policy, cpu), cppc_para); return ret; } @@ -154,6 +156,17 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op) else strlcpy(op->u.get_para.scaling_driver, "Unknown", CPUFREQ_NAME_LEN); + /* + * In CPPC active mode, we are borrowing governor field to indicate + * policy info. + */ + if ( policy->governor->name[0] ) + strlcpy(op->u.get_para.u.s.scaling_governor, + policy->governor->name, CPUFREQ_NAME_LEN); + else + strlcpy(op->u.get_para.u.s.scaling_governor, "Unknown", + CPUFREQ_NAME_LEN); + if ( !cpufreq_is_governorless(op->cpuid) ) { if ( !(scaling_available_governors = @@ -178,13 +191,6 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op) op->u.get_para.u.s.scaling_max_freq = policy->max; op->u.get_para.u.s.scaling_min_freq = policy->min; - if ( policy->governor->name[0] ) - strlcpy(op->u.get_para.u.s.scaling_governor, - policy->governor->name, CPUFREQ_NAME_LEN); - else - strlcpy(op->u.get_para.u.s.scaling_governor, "Unknown", - CPUFREQ_NAME_LEN); - /* governor specific para */ if ( !strncasecmp(op->u.get_para.u.s.scaling_governor, "userspace", CPUFREQ_NAME_LEN) ) @@ -321,10 +327,12 @@ static int set_cpufreq_cppc(struct xen_sysctl_pm_op *op) if ( !policy || !policy->governor ) return -ENOENT; - if ( !hwp_active() ) - return -EOPNOTSUPP; + if ( hwp_active() ) + return set_hwp_para(policy, &op->u.set_cppc); + if ( processor_pminfo[op->cpuid]->init & XEN_CPPC_INIT ) + return amd_cppc_set_para(policy, &op->u.set_cppc); - return set_hwp_para(policy, &op->u.set_cppc); + return -EOPNOTSUPP; } int do_pm_op(struct xen_sysctl_pm_op *op) diff --git a/xen/include/acpi/cpufreq/cpufreq.h b/xen/include/acpi/cpufreq/cpufreq.h index 7caeae26cf..e8b4e955a2 100644 --- a/xen/include/acpi/cpufreq/cpufreq.h +++ b/xen/include/acpi/cpufreq/cpufreq.h @@ -293,6 +293,10 @@ int acpi_cpufreq_register(void); int amd_cppc_cmdline_parse(const char *s, const char *e); int amd_cppc_register_driver(void); +int amd_cppc_get_para(const struct cpufreq_policy *policy, + struct xen_get_cppc_para *cppc_para); +int amd_cppc_set_para(struct cpufreq_policy *policy, + const struct xen_set_cppc_para *set_cppc); /* * Governor-less cpufreq driver indicates the driver doesn't rely on Xen -- 2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |