@@ -583,6 +583,11 @@ ret_t do_platform_op(
&op->u.set_pminfo.u.domain_info);
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;
@@ -26,6 +26,8 @@
#include <xen/pmstat.h>
#include <compat/platform.h>
+CHECK_processor_cppc;
+
CHECK_processor_px;
CHECK_psd_package;
@@ -68,7 +68,7 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
return -ENODEV;
if ( hwp_active() )
return -EOPNOTSUPP;
- if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
+ if ( !pmpt || !(pmpt->init & XEN_PX_INIT) )
return -EINVAL;
break;
default:
@@ -467,7 +467,7 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
case CPUFREQ_PARA:
if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
return -ENODEV;
- if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
+ if ( !pmpt || !(pmpt->init & (XEN_PX_INIT | XEN_CPPC_INIT)) )
return -EINVAL;
break;
}
@@ -210,7 +210,7 @@ int cpufreq_add_cpu(unsigned int cpu)
pmpt = processor_pminfo[cpu];
- if ( !(pmpt->perf.init & XEN_PX_INIT) )
+ if ( !(pmpt->init & (XEN_PX_INIT | XEN_CPPC_INIT)) )
return -EINVAL;
if (!cpufreq_driver.init)
@@ -368,7 +368,7 @@ int cpufreq_del_cpu(unsigned int cpu)
pmpt = processor_pminfo[cpu];
- if ( !(pmpt->perf.init & XEN_PX_INIT) )
+ if ( !(pmpt->init & (XEN_PX_INIT | XEN_CPPC_INIT)) )
return -EINVAL;
if (!per_cpu(cpufreq_cpu_policy, cpu))
@@ -459,6 +459,16 @@ static void print_PPC(unsigned int platform_limit)
printk("\t_PPC: %d\n", platform_limit);
}
+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->highest_perf, cppc_data->lowest_perf,
+ cppc_data->nominal_perf, cppc_data->lowest_nonlinear_perf,
+ cppc_data->nominal_mhz, cppc_data->lowest_mhz);
+}
+
int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf)
{
int ret = 0, cpu;
@@ -539,7 +549,7 @@ int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf)
if ( cpufreq_verbose )
print_PPC(pxpt->platform_limit);
- if ( pxpt->init == XEN_PX_INIT )
+ if ( pmpt->init == XEN_PX_INIT )
{
ret = cpufreq_limit_change(cpu);
goto out;
@@ -548,7 +558,7 @@ int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf)
if ( perf->flags == ( XEN_PX_PCT | XEN_PX_PSS | XEN_PX_PPC ) )
{
- pxpt->init = XEN_PX_INIT;
+ pmpt->init = XEN_PX_INIT;
ret = cpufreq_cpu_init(cpu);
goto out;
@@ -606,6 +616,41 @@ int set_psd_pminfo(uint32_t acpi_id, uint32_t shared_type,
return ret;
}
+int set_cppc_pminfo(uint32_t 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(%d) cpuid(%d) CPPC State info:\n",
+ acpi_id, cpuid);
+
+ pm_info = processor_pminfo[cpuid];
+ /* Must already allocated in set_psd_pminfo */
+ if ( !pm_info )
+ {
+ ret = -EINVAL;
+ goto out;
+ }
+ pm_info->cppc_data = *cppc_data;
+
+ if ( cpufreq_verbose )
+ print_CPPC(&pm_info->cppc_data);
+
+ pm_info->init = XEN_CPPC_INIT;
+ ret = cpufreq_cpu_init(cpuid);
+
+ out:
+ return ret;
+}
+
static void cpufreq_cmdline_common_para(struct cpufreq_policy *new_policy)
{
if (usr_max_freq)
@@ -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);
@@ -27,8 +28,6 @@ struct processor_performance {
struct xen_pct_register status_register;
uint32_t state_count;
struct xen_processor_px *states;
-
- uint32_t init;
};
struct processor_pminfo {
@@ -37,6 +36,9 @@ struct processor_pminfo {
struct xen_psd_package domain_info;
uint32_t shared_type;
struct processor_performance perf;
+ struct xen_processor_cppc cppc_data;
+
+ uint32_t init;
};
extern struct processor_pminfo *processor_pminfo[NR_CPUS];
@@ -364,6 +364,7 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t);
#define XEN_PM_TX 2
#define XEN_PM_PDC 3
#define XEN_PM_PSD 4
+#define XEN_PM_CPPC 5
/* Px sub info type */
#define XEN_PX_PCT 1
@@ -432,6 +433,20 @@ struct xen_processor_px {
typedef struct xen_processor_px xen_processor_px_t;
DEFINE_XEN_GUEST_HANDLE(xen_processor_px_t);
+/*
+ * Subset _CPC fields useful for CPPC-compatible cpufreq
+ * driver's initialization
+ */
+struct xen_processor_cppc {
+ 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;
+};
+typedef struct xen_processor_cppc xen_processor_cppc_t;
+
struct xen_psd_package {
uint64_t num_entries;
uint64_t revision;
@@ -461,6 +476,7 @@ struct xenpf_set_processor_pminfo {
xen_psd_package_t domain_info; /* _PSD */
struct xen_processor_performance perf; /* Px: _PPC/_PCT/_PSS/ */
XEN_GUEST_HANDLE(uint32) pdc; /* _PDC */
+ xen_processor_cppc_t cppc_data; /*_CPC */
} u;
/* Coordination type of this processor */
#define XEN_CPUPERF_SHARED_TYPE_HW 1 /* HW does needed coordination */
@@ -8,6 +8,8 @@
int set_psd_pminfo(uint32_t acpi_id, uint32_t shared_type,
const struct xen_psd_package *psd_data);
int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf);
+int set_cppc_pminfo(uint32_t acpi_id,
+ const struct xen_processor_cppc *cppc_data);
long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power);
#ifdef CONFIG_COMPAT
@@ -162,6 +162,7 @@
! pct_register platform.h
! power_register platform.h
+? processor_cppc platform.h
? processor_csd platform.h
! processor_cx platform.h
! processor_flags platform.h
In order to provide backward compatibility with existing governors that represent performance as frequencies, 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, this commit introduces a new sub-hypercall to propagate required CPPC data from dom0 kernel. If the platform supports CPPC, the _CPC object must exist under all processor objects. That is, Xen is not expected to support mixed mode (CPPC & legacy PSS, _PCT, _PPC) operation, either advanced CPPC, or legacy P-states. This commit also introduces a new flag XEN_PM_CPPC to reflect processor initialised in CPPC mode. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- 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 --- xen/arch/x86/platform_hypercall.c | 5 +++ xen/arch/x86/x86_64/cpufreq.c | 2 + xen/drivers/acpi/pmstat.c | 4 +- xen/drivers/cpufreq/cpufreq.c | 53 +++++++++++++++++++++-- xen/include/acpi/cpufreq/processor_perf.h | 8 ++-- xen/include/public/platform.h | 16 +++++++ xen/include/xen/pmstat.h | 2 + xen/include/xlat.lst | 1 + 8 files changed, 82 insertions(+), 9 deletions(-)