diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c b/xen/arch/x86/acpi/cpufreq/cpufreq.c index 0798a4c9b1..45a0a53094 100644 --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c @@ -584,3 +584,21 @@ static int __init cpufreq_driver_init(void) return ret; } __initcall(cpufreq_driver_init); + +int cpufreq_cpu_init(unsigned int cpuid) +{ + static int cpu_count=0; + int ret; + + cpu_count++; + + /* Currently we only handle Intel and AMD processor */ + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + ret = cpufreq_add_cpu(cpuid); + else if ( (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (cpu_count == num_online_cpus()) ) + ret = powernow_cpufreq_init(); + else + ret = -EFAULT; + return ret; +} diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 72c6648deb..99060a0d56 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -45,6 +45,7 @@ extern spinlock_t xenpf_lock; static DEFINE_PER_CPU(uint64_t, freq); +extern int set_px_pminfo(uint32_t cpu, struct xen_processor_performance *perf); extern long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power); static long cpu_frequency_change_helper(void *data) @@ -52,6 +53,15 @@ static long cpu_frequency_change_helper(void *data) return cpu_frequency_change(this_cpu(freq)); } +int xenpf_copy_px_states(struct processor_performance *pxpt, + struct xen_processor_performance *dom0_px_info) +{ + if (!pxpt || !dom0_px_info) + return -EINVAL; + return copy_from_compat(pxpt->states, dom0_px_info->states, + dom0_px_info->state_count); +} + ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) { ret_t ret = 0; @@ -363,99 +373,9 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) { case XEN_PM_PX: { - static int cpu_count = 0; - struct xenpf_set_processor_pminfo *xenpmpt = &op->u.set_pminfo; - struct xen_processor_performance *xenpxpt = &op->u.set_pminfo.perf; - int cpuid = get_cpu_id(xenpmpt->id); - struct processor_pminfo *pmpt; - struct processor_performance *pxpt; - - if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) ) - { - ret = -ENOSYS; - break; - } - if ( cpuid < 0 ) - { - ret = -EINVAL; - break; - } - pmpt = processor_pminfo[cpuid]; - if ( !pmpt ) - { - pmpt = xmalloc(struct processor_pminfo); - if ( !pmpt ) - { - ret = -ENOMEM; - break; - } - memset(pmpt, 0, sizeof(*pmpt)); - processor_pminfo[cpuid] = pmpt; - } - pxpt = &pmpt->perf; - pmpt->acpi_id = xenpmpt->id; - pmpt->id = cpuid; - - if ( xenpxpt->flags & XEN_PX_PCT ) - { - memcpy ((void *)&pxpt->control_register, - (void *)&xenpxpt->control_register, - sizeof(struct xen_pct_register)); - memcpy ((void *)&pxpt->status_register, - (void *)&xenpxpt->status_register, - sizeof(struct xen_pct_register)); - } - if ( xenpxpt->flags & XEN_PX_PSS ) - { - if ( !(pxpt->states = xmalloc_array(struct xen_processor_px, - xenpxpt->state_count)) ) - { - ret = -ENOMEM; - break; - } - if ( copy_from_compat(pxpt->states, xenpxpt->states, - xenpxpt->state_count) ) - { - xfree(pxpt->states); - ret = -EFAULT; - break; - } - pxpt->state_count = xenpxpt->state_count; - } - if ( xenpxpt->flags & XEN_PX_PSD ) - { - pxpt->shared_type = xenpxpt->shared_type; - memcpy ((void *)&pxpt->domain_info, - (void *)&xenpxpt->domain_info, - sizeof(struct xen_psd_package)); - } - if ( xenpxpt->flags & XEN_PX_PPC ) - { - pxpt->platform_limit = xenpxpt->platform_limit; - - if ( pxpt->init == XEN_PX_INIT ) - { - ret = cpufreq_limit_change(cpuid); - break; - } - } - - if ( xenpxpt->flags == ( XEN_PX_PCT | XEN_PX_PSS | - XEN_PX_PSD | XEN_PX_PPC ) ) - { - pxpt->init = XEN_PX_INIT; - cpu_count++; - - /* Currently we only handle Intel and AMD processor */ - if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) - ret = cpufreq_add_cpu(cpuid); - else if ( (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && - (cpu_count == num_online_cpus()) ) - ret = powernow_cpufreq_init(); - else - break; - } + ret = set_px_pminfo(op->u.set_pminfo.id, + &op->u.set_pminfo.perf); break; } diff --git a/xen/arch/x86/x86_64/platform_hypercall.c b/xen/arch/x86/x86_64/platform_hypercall.c index 037ab4f4af..02364c4535 100644 --- a/xen/arch/x86/x86_64/platform_hypercall.c +++ b/xen/arch/x86/x86_64/platform_hypercall.c @@ -11,6 +11,8 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_op_t); #define xen_platform_op_t compat_platform_op_t #define do_platform_op(x) compat_platform_op(_##x) +#define xenpf_copy_px_states compat_xenpf_copy_px_states + #define xen_processor_px compat_processor_px #define xen_processor_px_t compat_processor_px_t #define xen_processor_performance compat_processor_performance diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c index d4dae5bfd3..156adfca50 100644 --- a/xen/drivers/cpufreq/cpufreq.c +++ b/xen/drivers/cpufreq/cpufreq.c @@ -34,13 +34,12 @@ #include #include #include +#include #include -#include #include #include #include #include -#include #include #include @@ -82,7 +81,7 @@ int cpufreq_add_cpu(unsigned int cpu) if (!processor_pminfo[cpu] || !(perf->init & XEN_PX_INIT)) return 0; - if (cpu_is_offline(cpu) || cpufreq_cpu_policy[cpu]) + if (!cpu_online(cpu) || cpufreq_cpu_policy[cpu]) return -EINVAL; ret = cpufreq_statistic_init(cpu); @@ -158,7 +157,7 @@ int cpufreq_del_cpu(unsigned int cpu) if (!processor_pminfo[cpu] || !(perf->init & XEN_PX_INIT)) return 0; - if (cpu_is_offline(cpu) || !cpufreq_cpu_policy[cpu]) + if (!cpu_online(cpu) || !cpufreq_cpu_policy[cpu]) return -EINVAL; dom = perf->domain_info.domain; @@ -186,3 +185,123 @@ int cpufreq_del_cpu(unsigned int cpu) return 0; } +static void print_PSS(struct xen_processor_px *ptr, int count) +{ + int i; + printk(KERN_INFO "\t_PSS:\n"); + for (i=0; inum_entries, ptr->revision, ptr->domain, ptr->coord_type, + ptr->num_processors); +} + +int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *dom0_px_info) +{ + int cpu_count = 0, ret=0, cpuid; + struct processor_pminfo *pmpt; + struct processor_performance *pxpt; + + if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) ) + { + ret = -ENOSYS; + goto out; + } + + cpuid = get_cpu_id(acpi_id); + if ( cpuid < 0 ) + { + ret = -EINVAL; + goto out; + } + printk(KERN_INFO "Set CPU acpi_id(%d) cpuid(%d) Px State info:\n", + acpi_id, cpuid); + + pmpt = processor_pminfo[cpuid]; + if ( !pmpt ) + { + pmpt = xmalloc(struct processor_pminfo); + if ( !pmpt ) + { + ret = -ENOMEM; + goto out; + } + memset(pmpt, 0, sizeof(*pmpt)); + processor_pminfo[cpuid] = pmpt; + } + pxpt = &pmpt->perf; + pmpt->acpi_id = acpi_id; + pmpt->id = cpuid; + + if ( dom0_px_info->flags & XEN_PX_PCT ) + { + memcpy ((void *)&pxpt->control_register, + (void *)&dom0_px_info->control_register, + sizeof(struct xen_pct_register)); + memcpy ((void *)&pxpt->status_register, + (void *)&dom0_px_info->status_register, + sizeof(struct xen_pct_register)); + } + if ( dom0_px_info->flags & XEN_PX_PSS ) + { + if ( !(pxpt->states = xmalloc_array(struct xen_processor_px, + dom0_px_info->state_count)) ) + { + ret = -ENOMEM; + goto out; + } + if ( xenpf_copy_px_states(pxpt, dom0_px_info) ) + { + xfree(pxpt->states); + ret = -EFAULT; + goto out; + } + pxpt->state_count = dom0_px_info->state_count; + print_PSS(pxpt->states,pxpt->state_count); + } + if ( dom0_px_info->flags & XEN_PX_PSD ) + { + pxpt->shared_type = dom0_px_info->shared_type; + memcpy ((void *)&pxpt->domain_info, + (void *)&dom0_px_info->domain_info, + sizeof(struct xen_psd_package)); + print_PSD(&pxpt->domain_info); + } + if ( dom0_px_info->flags & XEN_PX_PPC ) + { + pxpt->platform_limit = dom0_px_info->platform_limit; + + if ( pxpt->init == XEN_PX_INIT ) + { + + ret = cpufreq_limit_change(cpuid); + goto out; + } + } + + if ( dom0_px_info->flags == ( XEN_PX_PCT | XEN_PX_PSS | + XEN_PX_PSD | XEN_PX_PPC ) ) + { + pxpt->init = XEN_PX_INIT; + cpu_count++; + + ret = cpufreq_cpu_init(cpuid); + goto out; + } + +out: + return ret; +} + diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h index b9c934da51..7821aeffb1 100644 --- a/xen/include/acpi/cpufreq/processor_perf.h +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -60,4 +60,8 @@ struct pm_px { extern struct pm_px *cpufreq_statistic_data[NR_CPUS]; +int xenpf_copy_px_states(struct processor_performance *pxpt, + struct xen_processor_performance *dom0_px_info); + +int cpufreq_cpu_init(unsigned int cpuid); #endif /* __XEN_PROCESSOR_PM_H__ */