[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 03/15] xen/x86: introduce new sub-hypercall to propagate CPPC data
In order to provide backward compatibility with existing governors that represent performance as frequency, like ondemand, the _CPC table can optionally provide processor frequency range values, Lowest frequency and Norminal frequency, to let OS use Lowest Frequency/ Performance and Nominal Frequency/Performance as anchor points to create linear mapping of CPPC abstract performance to CPU frequency. As Xen is uncapable of parsing the ACPI dynamic table, we'd like to introduce a new sub-hypercall "XEN_PM_CPPC" to propagate required CPPC data from dom0 kernel to Xen. In the according handler set_cppc_pminfo(), we do _CPC and _PSD sanitization check, as both _PSD and _CPC info are necessary for correctly initializing cpufreq cores in CPPC mode. Users shall be warned that if we failed at this point, no fallback scheme, like legacy P-state could be switched to. A new flag "XEN_CPPC_INIT" is also introduced to differentiate cpufreq core initialised in Px mode. Signed-off-by: Penny Zheng <Penny.Zheng@xxxxxxx> --- v1 -> v2: - Remove unnecessary figure braces - Pointer-to-const for print_CPPC and set_cppc_pminfo - Structure allocation shall use xvzalloc() - Unnecessary memcpy(), and change it to a (type safe) structure assignment - Add comment for struct xen_processor_cppc, and keep the chosen fields in the order _CPC has them - Obey to alphabetic sorting, and prefix compat structures with ? instead of ! --- v2 -> v3: - Trim too long line - Re-place set_cppc_pminfo() past set_px_pminfo() - Fix Misra violations: Declaration and definition ought to agree in parameter names - Introduce a new flag XEN_PM_CPPC to reflect processor initialised in CPPC mode --- v3 -> v4: - Refactor commit message - make "acpi_id" unsigned int - Add warning message when cpufreq_cpu_init() failed only under debug mode - Expand "struct xen_processor_cppc" to include _PSD and shared type - add sanity check for ACPI CPPC data --- xen/arch/x86/platform_hypercall.c | 5 + xen/drivers/cpufreq/cpufreq.c | 131 ++++++++++++++++++++-- xen/include/acpi/cpufreq/processor_perf.h | 4 +- xen/include/public/platform.h | 26 +++++ xen/include/xen/pmstat.h | 2 + xen/include/xlat.lst | 1 + 6 files changed, 161 insertions(+), 8 deletions(-) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 90abd3197f..49717e9ca9 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -572,6 +572,11 @@ ret_t do_platform_op( break; } + case XEN_PM_CPPC: + ret = set_cppc_pminfo(op->u.set_pminfo.id, + &op->u.set_pminfo.u.cppc_data); + break; + default: ret = -EINVAL; break; diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c index b020ccbcf7..e01acc0c2d 100644 --- a/xen/drivers/cpufreq/cpufreq.c +++ b/xen/drivers/cpufreq/cpufreq.c @@ -40,6 +40,7 @@ #include <xen/domain.h> #include <xen/cpu.h> #include <xen/pmstat.h> +#include <xen/xvmalloc.h> #include <asm/io.h> #include <asm/processor.h> @@ -205,6 +206,12 @@ static int get_psd_info(uint32_t init, unsigned int cpu, if ( domain_info ) *domain_info = processor_pminfo[cpu]->perf.domain_info; break; + case XEN_CPPC_INIT: + if ( shared_type ) + *shared_type = processor_pminfo[cpu]->cppc_data.shared_type; + if ( domain_info ) + *domain_info = processor_pminfo[cpu]->cppc_data.domain_info; + break; default: ret = -EINVAL; break; @@ -230,7 +237,7 @@ int cpufreq_add_cpu(unsigned int cpu) if ( !processor_pminfo[cpu] || !cpu_online(cpu) ) return -EINVAL; - if ( !(processor_pminfo[cpu]->init & XEN_PX_INIT) ) + if ( !(processor_pminfo[cpu]->init & (XEN_PX_INIT | XEN_CPPC_INIT)) ) return -EINVAL; if (!cpufreq_driver.init) @@ -401,7 +408,7 @@ int cpufreq_del_cpu(unsigned int cpu) if ( !processor_pminfo[cpu] || !cpu_online(cpu) ) return -EINVAL; - if ( !(processor_pminfo[cpu]->init & XEN_PX_INIT) ) + if ( !(processor_pminfo[cpu]->init & (XEN_PX_INIT | XEN_CPPC_INIT)) ) return -EINVAL; if (!per_cpu(cpufreq_cpu_policy, cpu)) @@ -497,12 +504,19 @@ static void print_PPC(unsigned int platform_limit) printk("\t_PPC: %d\n", platform_limit); } -static int check_psd_pminfo(const struct xen_processor_performance *perf) +static int check_psd_pminfo(const struct xen_processor_performance *perf, + const struct xen_processor_cppc *cppc_data) { + uint32_t shared_type; + + if ( !perf && !cppc_data ) + return -EINVAL; + + shared_type = perf ? perf->shared_type : cppc_data->shared_type; /* check domain coordination */ - if ( perf->shared_type != CPUFREQ_SHARED_TYPE_ALL && - perf->shared_type != CPUFREQ_SHARED_TYPE_ANY && - perf->shared_type != CPUFREQ_SHARED_TYPE_HW ) + if ( shared_type != CPUFREQ_SHARED_TYPE_ALL && + shared_type != CPUFREQ_SHARED_TYPE_ANY && + shared_type != CPUFREQ_SHARED_TYPE_HW ) return -EINVAL; return 0; @@ -589,7 +603,7 @@ int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf) if ( perf->flags & XEN_PX_PSD ) { - ret = check_psd_pminfo(perf); + ret = check_psd_pminfo(perf, NULL); if ( ret ) goto out; @@ -627,6 +641,109 @@ out: return ret; } +static void print_CPPC(const struct xen_processor_cppc *cppc_data) +{ + printk("\t_CPC: highest_perf=%u, lowest_perf=%u, " + "nominal_perf=%u, lowest_nonlinear_perf=%u, " + "nominal_mhz=%uMHz, lowest_mhz=%uMHz\n", + cppc_data->cpc.highest_perf, cppc_data->cpc.lowest_perf, + cppc_data->cpc.nominal_perf, cppc_data->cpc.lowest_nonlinear_perf, + cppc_data->cpc.nominal_mhz, cppc_data->cpc.lowest_mhz); +} + +int set_cppc_pminfo(unsigned int acpi_id, + const struct xen_processor_cppc *cppc_data) +{ + int ret = 0, cpuid; + struct processor_pminfo *pm_info; + + cpuid = get_cpu_id(acpi_id); + if ( cpuid < 0 || !cppc_data ) + { + ret = -EINVAL; + goto out; + } + if ( cpufreq_verbose ) + printk("Set CPU acpi_id(%u) cpuid(%d) CPPC State info:\n", + acpi_id, cpuid); + + pm_info = processor_pminfo[cpuid]; + if ( !pm_info ) + { + pm_info = xvzalloc(struct processor_pminfo); + if ( !pm_info ) + { + ret = -ENOMEM; + goto out; + } + processor_pminfo[cpuid] = pm_info; + } + pm_info->acpi_id = acpi_id; + pm_info->id = cpuid; + + if ( cppc_data->flags & XEN_CPPC_PSD ) + { + ret = check_psd_pminfo(NULL, cppc_data); + if ( ret ) + goto out; + } + + if ( cppc_data->flags & XEN_CPPC_CPC ) + { + if ( cppc_data->cpc.highest_perf == 0 || + cppc_data->cpc.highest_perf > UINT8_MAX || + cppc_data->cpc.nominal_perf == 0 || + cppc_data->cpc.nominal_perf > UINT8_MAX || + cppc_data->cpc.lowest_nonlinear_perf == 0 || + cppc_data->cpc.lowest_nonlinear_perf > UINT8_MAX || + cppc_data->cpc.lowest_perf == 0 || + cppc_data->cpc.lowest_perf > UINT8_MAX || + cppc_data->cpc.lowest_perf > + cppc_data->cpc.lowest_nonlinear_perf || + cppc_data->cpc.lowest_nonlinear_perf > + cppc_data->cpc.nominal_perf || + cppc_data->cpc.nominal_perf > cppc_data->cpc.highest_perf ) + /* + * Right now, Xen doesn't actually use perf values + * in ACPI _CPC table, warning is enough. + */ + printk(XENLOG_WARNING + "Broken CPPC perf values: lowest(%u), nonlinear_lowest(%u), nominal(%u), highest(%u)\n", + cppc_data->cpc.lowest_perf, + cppc_data->cpc.lowest_nonlinear_perf, + cppc_data->cpc.nominal_perf, + cppc_data->cpc.highest_perf); + + /* lowest_mhz and nominal_mhz are optional value */ + if ( (cppc_data->cpc.lowest_mhz && cppc_data->cpc.nominal_mhz) && + cppc_data->cpc.lowest_mhz > cppc_data->cpc.nominal_mhz ) + printk(XENLOG_WARNING + "Broken CPPC freq values: lowest(%u), nominal(%u)\n", + cppc_data->cpc.lowest_mhz, + cppc_data->cpc.nominal_mhz); + } + + if ( cppc_data->flags == (XEN_CPPC_PSD | XEN_CPPC_CPC) ) + { + pm_info->cppc_data = *cppc_data; + if ( cpufreq_verbose ) + { + print_PSD(&pm_info->cppc_data.domain_info); + print_CPPC(&pm_info->cppc_data); + } + + pm_info->init = XEN_CPPC_INIT; + ret = cpufreq_cpu_init(cpuid); +#ifndef NDEBUG + if ( ret ) + printk(XENLOG_WARNING "No fallback scheme could be replaced now"); +#endif + } + + out: + return ret; +} + static void cpufreq_cmdline_common_para(struct cpufreq_policy *new_policy) { if (usr_max_freq) diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h index 5f2612b15a..f1f4f3138d 100644 --- a/xen/include/acpi/cpufreq/processor_perf.h +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -5,7 +5,8 @@ #include <public/sysctl.h> #include <xen/acpi.h> -#define XEN_PX_INIT 0x80000000U +#define XEN_CPPC_INIT 0x40000000U +#define XEN_PX_INIT 0x80000000U unsigned int powernow_register_driver(void); unsigned int get_measured_perf(unsigned int cpu, unsigned int flag); @@ -35,6 +36,7 @@ struct processor_pminfo { uint32_t acpi_id; uint32_t id; struct processor_performance perf; + struct xen_processor_cppc cppc_data; uint32_t init; }; diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h index 67cf5eeabd..0e18a86ab4 100644 --- a/xen/include/public/platform.h +++ b/xen/include/public/platform.h @@ -363,6 +363,7 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t); #define XEN_PM_PX 1 #define XEN_PM_TX 2 #define XEN_PM_PDC 3 +#define XEN_PM_CPPC 4 /* Px sub info type */ #define XEN_PX_PCT 1 @@ -370,6 +371,10 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t); #define XEN_PX_PPC 4 #define XEN_PX_PSD 8 +/* CPPC sub info type */ +#define XEN_CPPC_PSD 1 +#define XEN_CPPC_CPC 2 + struct xen_power_register { uint32_t space_id; uint32_t bit_width; @@ -459,6 +464,26 @@ struct xen_processor_performance { typedef struct xen_processor_performance xen_processor_performance_t; DEFINE_XEN_GUEST_HANDLE(xen_processor_performance_t); +struct xen_processor_cppc { + uint8_t flags; /* flag for CPPC sub info type */ + /* + * Subset _CPC fields useful for CPPC-compatible cpufreq + * driver's initialization + */ + struct { + uint32_t highest_perf; + uint32_t nominal_perf; + uint32_t lowest_nonlinear_perf; + uint32_t lowest_perf; + uint32_t lowest_mhz; + uint32_t nominal_mhz; + } cpc; + struct xen_psd_package domain_info; /* _PSD */ + /* Coordination type of this processor */ + uint32_t shared_type; +}; +typedef struct xen_processor_cppc xen_processor_cppc_t; + struct xenpf_set_processor_pminfo { /* IN variables */ uint32_t id; /* ACPI CPU ID */ @@ -467,6 +492,7 @@ struct xenpf_set_processor_pminfo { struct xen_processor_power power;/* Cx: _CST/_CSD */ struct xen_processor_performance perf; /* Px: _PPC/_PCT/_PSS/_PSD */ XEN_GUEST_HANDLE(uint32) pdc; /* _PDC */ + xen_processor_cppc_t cppc_data; /* _CPC and _PSD */ } u; }; typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t; diff --git a/xen/include/xen/pmstat.h b/xen/include/xen/pmstat.h index 8350403e95..f30286d48e 100644 --- a/xen/include/xen/pmstat.h +++ b/xen/include/xen/pmstat.h @@ -7,6 +7,8 @@ int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf); long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power); +int set_cppc_pminfo(unsigned int acpi_id, + const struct xen_processor_cppc *cppc_data); #ifdef CONFIG_COMPAT struct compat_processor_performance; diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index 3c7b6c6830..d3f87c7cc2 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -168,6 +168,7 @@ ! processor_performance platform.h ! processor_power platform.h ? processor_px platform.h +? processor_cppc platform.h ! psd_package platform.h ? xenpf_enter_acpi_sleep platform.h ? xenpf_pcpu_version platform.h -- 2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |