@@ -572,6 +572,12 @@ 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;
@@ -54,3 +54,21 @@ int compat_set_px_pminfo(uint32_t acpi_id,
return set_px_pminfo(acpi_id, xen_perf);
}
+
+int compat_set_cppc_pminfo(uint32_t acpi_id,
+ struct compat_processor_cppc *cppc_data)
+{
+ struct xen_processor_cppc *xen_cppc;
+ unsigned long xlat_page_current;
+
+ xlat_malloc_init(xlat_page_current);
+
+ xen_cppc = xlat_malloc_array(xlat_page_current,
+ struct xen_processor_cppc, 1);
+ if ( unlikely(xen_cppc == NULL) )
+ return -EFAULT;
+
+ XLAT_processor_cppc(xen_cppc, cppc_data);
+
+ return set_cppc_pminfo(acpi_id, xen_cppc);
+}
@@ -20,6 +20,9 @@ EMIT_FILE;
#define xen_processor_power compat_processor_power
#define set_cx_pminfo compat_set_cx_pminfo
+#define xen_processor_cppc compat_processor_cppc
+#define set_cppc_pminfo compat_set_cppc_pminfo
+
#define xen_pf_pcpuinfo xenpf_pcpuinfo
CHECK_pf_pcpuinfo;
#undef xen_pf_pcpuinfo
@@ -458,6 +458,56 @@ static void print_PPC(unsigned int platform_limit)
printk("\t_PPC: %d\n", platform_limit);
}
+static void print_CPPC(struct xen_processor_cppc *cppc_data)
+{
+ printk("\t_CPC: highest_perf=%u, lowest_perf=%u, "
+ "nominal_perf=%u, lowest_nonlinear_perf=%u, "
+ "nominal_freq=%uMhz, lowest_freq=%uMhz\n",
+ cppc_data->highest_perf, cppc_data->lowest_perf,
+ cppc_data->nominal_perf, cppc_data->lowest_nonlinear_perf,
+ cppc_data->nominal_freq, cppc_data->lowest_freq);
+}
+
+int set_cppc_pminfo(uint32_t acpi_id, 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];
+ if ( !pm_info )
+ {
+ pm_info = xzalloc(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;
+
+ memcpy ((void *)&pm_info->cppc_data,
+ (void *)cppc_data,
+ sizeof(struct xen_processor_cppc));
+
+ if ( cpufreq_verbose )
+ print_CPPC(&pm_info->cppc_data);
+
+ out:
+ return ret;
+}
+
int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf)
{
int ret = 0, cpu;
@@ -37,6 +37,7 @@ struct processor_pminfo {
uint32_t acpi_id;
uint32_t id;
struct processor_performance perf;
+ struct xen_processor_cppc cppc_data;
};
extern struct processor_pminfo *processor_pminfo[NR_CPUS];
@@ -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
@@ -432,6 +433,15 @@ struct xen_processor_px {
typedef struct xen_processor_px xen_processor_px_t;
DEFINE_XEN_GUEST_HANDLE(xen_processor_px_t);
+struct xen_processor_cppc {
+ uint32_t highest_perf;
+ uint32_t nominal_perf;
+ uint32_t lowest_perf;
+ uint32_t lowest_nonlinear_perf;
+ uint32_t lowest_freq;
+ uint32_t nominal_freq;
+};
+
struct xen_psd_package {
uint64_t num_entries;
uint64_t revision;
@@ -465,6 +475,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 */
+ struct xen_processor_cppc cppc_data; /*_CPC */
} u;
};
typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t;
@@ -5,6 +5,7 @@
#include <public/platform.h> /* for struct xen_processor_power */
#include <public/sysctl.h> /* for struct pm_cx_stat */
+int set_cppc_pminfo(uint32_t cpu, struct xen_processor_cppc *cppc_data);
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);
@@ -13,6 +14,8 @@ struct compat_processor_performance;
int compat_set_px_pminfo(uint32_t acpi_id, struct compat_processor_performance *perf);
struct compat_processor_power;
long compat_set_cx_pminfo(uint32_t acpi_id, struct compat_processor_power *power);
+struct compat_processor_cppc;
+int compat_set_cppc_pminfo(uint32_t acpi_id, struct compat_processor_cppc *cppc);
#endif
uint32_t pmstat_get_cx_nr(unsigned int cpu);
@@ -166,6 +166,7 @@
! processor_cx platform.h
! processor_flags platform.h
! processor_performance platform.h
+! processor_cppc platform.h
! processor_power platform.h
? processor_px platform.h
! psd_package 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 get required CPPC data from dom0 kernel. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- xen/arch/x86/platform_hypercall.c | 6 +++ xen/arch/x86/x86_64/cpufreq.c | 18 ++++++++ xen/arch/x86/x86_64/platform_hypercall.c | 3 ++ xen/drivers/cpufreq/cpufreq.c | 50 +++++++++++++++++++++++ xen/include/acpi/cpufreq/processor_perf.h | 1 + xen/include/public/platform.h | 11 +++++ xen/include/xen/pmstat.h | 3 ++ xen/include/xlat.lst | 1 + 8 files changed, 93 insertions(+)