[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH] cpufreq: make cpufreq driver more generalizable
First implementation of the cpufreq infrastructure has been written with x86 in mind. This patch makes possible the cpufreq driver be working on both x86 and arm architecture. Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@xxxxxxxxxxxxxxx> --- xen/arch/arm/cpufreq/cpufreq_ops.c | 248 ++++++++++++++++ xen/arch/x86/acpi/cpu_idle.c | 2 +- xen/arch/x86/acpi/cpufreq/Makefile | 1 + xen/arch/x86/acpi/cpufreq/cpufreq.c | 2 +- xen/arch/x86/acpi/cpufreq/cpufreq_ops.c | 424 +++++++++++++++++++++++++++ xen/arch/x86/acpi/cpufreq/powernow.c | 2 +- xen/arch/x86/acpi/power.c | 2 +- xen/arch/x86/cpu/mwait-idle.c | 2 +- xen/drivers/acpi/pmstat.c | 2 +- xen/drivers/cpufreq/cpufreq.c | 421 +------------------------- xen/drivers/cpufreq/cpufreq_misc_governors.c | 2 +- xen/drivers/cpufreq/cpufreq_ondemand.c | 9 +- xen/drivers/cpufreq/utility.c | 21 +- xen/include/acpi/cpufreq/cpufreq.h | 258 ---------------- xen/include/acpi/cpufreq/processor_perf.h | 3 - xen/include/xen/cpufreq.h | 285 ++++++++++++++++++ 16 files changed, 1000 insertions(+), 684 deletions(-) create mode 100644 xen/arch/arm/cpufreq/cpufreq_ops.c create mode 100644 xen/arch/x86/acpi/cpufreq/cpufreq_ops.c delete mode 100644 xen/include/acpi/cpufreq/cpufreq.h create mode 100644 xen/include/xen/cpufreq.h diff --git a/xen/arch/arm/cpufreq/cpufreq_ops.c b/xen/arch/arm/cpufreq/cpufreq_ops.c new file mode 100644 index 0000000..fe9a3b5 --- /dev/null +++ b/xen/arch/arm/cpufreq/cpufreq_ops.c @@ -0,0 +1,248 @@ +/* + * cpufreq_ops.c - most of the code derived from Linux + * + * Copyright (C) 2001 Russell King + * (C) 2002 - 2003 Dominik Brodowski <linux@xxxxxxxx> + * + * Oct 2005 - Ashok Raj <ashok.raj@xxxxxxxxx> + * Added handling for CPU hotplug + * Feb 2006 - Jacob Shin <jacob.shin@xxxxxxx> + * Fix handling for CPU hotplug -- affected CPUs + * + * Copyright (C) 2014 GlobalLogic Inc. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include <xen/types.h> +#include <xen/errno.h> +#include <xen/xmalloc.h> +#include <xen/cpumask.h> +#include <xen/percpu.h> +#include <xen/cpufreq.h> +#include <xen/string.h> + +#ifdef CONFIG_HOTPLUG_CPU +/* This one keeps track of the previously set governor of a removed CPU */ +static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); +#endif + +/* + * Returns: + * Negative: Failure + * 0: Success + * Positive: When we have a managed CPU + */ +static int cpufreq_add_dev_policy(unsigned int cpu, + struct cpufreq_policy *policy) +{ + int ret = 0; +#ifdef CONFIG_SMP + unsigned int j; +#ifdef CONFIG_HOTPLUG_CPU + struct cpufreq_governor *gov; + + gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); + if ( gov ) + { + policy->governor = gov; + pr_cpufreq("Restoring governor %s for cpu %d\n", + policy->governor->name, cpu); + } +#endif + + for_each_cpu(j, policy->cpus) { + struct cpufreq_policy *managed_policy; + + if ( cpu == j ) + continue; + + /* Check for existing affected CPUs. + * They may not be aware of it due to CPU Hotplug. + * cpufreq_cpu_put is called when the device is removed + * in __cpufreq_remove_dev() + */ + managed_policy = per_cpu(cpufreq_cpu_policy, j); + if ( unlikely(managed_policy != NULL) ) + { + cpumask_copy(managed_policy->cpus, policy->cpus); + per_cpu(cpufreq_cpu_policy, cpu) = managed_policy; + + pr_cpufreq("CPU already managed\n"); + /* + * Success. We only needed to be added to the mask. + * Call driver->exit() because only the cpu parent + * needed to call init(). + */ + if ( cpufreq_driver->exit ) + cpufreq_driver->exit(policy); + + if ( !ret ) + return 1; + else + return ret; + } + } +#endif + return ret; +} + +int cpufreq_add_cpu(unsigned int cpu) +{ + int ret; + unsigned int j; + struct cpufreq_policy *policy; + + if ( !cpu_online(cpu) ) + return 0; + + pr_cpufreq("adding CPU %u\n", cpu); + + if (!cpufreq_driver) + return 0; + + if ( per_cpu(cpufreq_cpu_policy, cpu) ) + return 0; + + ret = -ENOMEM; + policy = xzalloc(struct cpufreq_policy); + if ( !policy ) + goto nomem_out; + + if ( !zalloc_cpumask_var(&policy->cpus) ) + goto err_free_policy; + + policy->cpu = cpu; + cpumask_copy(policy->cpus, cpumask_of(cpu)); + + policy->governor = cpufreq_opt_governor ? : CPUFREQ_DEFAULT_GOVERNOR; + + /* call driver. From then on the cpufreq must be able + * to accept all calls to ->verify and ->setpolicy for this CPU + */ + ret = cpufreq_driver->init(policy); + if ( ret ) + { + pr_cpufreq("initialization failed\n"); + goto err_free_cpumask; + } + + ret = cpufreq_add_dev_policy(cpu, policy); + if ( ret ) + { + if (ret > 0) + /* This is a managed cpu, exit with 0 */ + ret = 0; + goto err_drv_init; + } + + for_each_cpu(j, policy->cpus) { + if (!cpu_online(j)) + continue; + per_cpu(cpufreq_cpu_policy, j) = policy; + } + + ret = cpufreq_set_default_policy(policy); + if ( ret ) + { + pr_cpufreq("setting policy failed\n"); + goto err_out_unregister; + } + + pr_cpufreq("initialization complete\n"); + return 0; + +err_out_unregister: + for_each_cpu(j, policy->cpus) + per_cpu(cpufreq_cpu_policy, j) = NULL; +err_drv_init: + if (cpufreq_driver->exit) + cpufreq_driver->exit(policy); +err_free_cpumask: + free_cpumask_var(policy->cpus); +err_free_policy: + xfree(policy); +nomem_out: + return ret; +} + +int cpufreq_del_cpu(unsigned int cpu) +{ + int ret = 0; + struct cpufreq_policy *data; +#ifdef CONFIG_SMP + unsigned int j; +#endif + + if ( !cpu_online(cpu) ) + return -EINVAL; + + pr_cpufreq("unregistering CPU %u\n", cpu); + + data = per_cpu(cpufreq_cpu_policy, cpu); + + if ( !data ) + return 0; + + per_cpu(cpufreq_cpu_policy, cpu) = NULL; + +#ifdef CONFIG_SMP + /* if this isn't the CPU which is the parent, we + * only need clear mask and exit + */ + if ( unlikely(cpu != data->cpu) ) + { + pr_cpufreq("clear mask\n"); + cpumask_clear_cpu(cpu, data->cpus); + return 0; + } + +#ifdef CONFIG_HOTPLUG_CPU + strlcpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name, + CPUFREQ_NAME_LEN); +#endif + + /* if we have other CPUs still registered, we need to unlink them. + * Clean the per_cpu(cpufreq_cpu_policy). + */ + if ( unlikely(cpumask_weight(data->cpus) > 1) ) + { + for_each_cpu(j, data->cpus) { + if ( j == cpu ) + continue; + per_cpu(cpufreq_cpu_policy, j) = NULL; +#ifdef CONFIG_HOTPLUG_CPU + strlcpy(per_cpu(cpufreq_cpu_governor, j), + data->governor->name, CPUFREQ_NAME_LEN); +#endif + } + } +#endif + + if (cpufreq_driver->target) + __cpufreq_governor(data, CPUFREQ_GOV_STOP); + + if (cpufreq_driver->exit) + cpufreq_driver->exit(data); + + free_cpumask_var(data->cpus); + xfree(data); + + return ret; +} diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index b05fb39..85c7e58 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -51,7 +51,7 @@ #include <xen/softirq.h> #include <public/platform.h> #include <public/sysctl.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> #include <asm/apic.h> #include <asm/cpuidle.h> #include <asm/mwait.h> diff --git a/xen/arch/x86/acpi/cpufreq/Makefile b/xen/arch/x86/acpi/cpufreq/Makefile index f75da9b..6c8464b 100644 --- a/xen/arch/x86/acpi/cpufreq/Makefile +++ b/xen/arch/x86/acpi/cpufreq/Makefile @@ -1,2 +1,3 @@ obj-y += cpufreq.o obj-y += powernow.o +obj-y += cpufreq_ops.o diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c b/xen/arch/x86/acpi/cpufreq/cpufreq.c index fa3678d..aeda0a3 100644 --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c @@ -42,7 +42,7 @@ #include <asm/percpu.h> #include <asm/cpufeature.h> #include <acpi/acpi.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> enum { UNDEFINED_CAPABLE = 0, diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq_ops.c b/xen/arch/x86/acpi/cpufreq/cpufreq_ops.c new file mode 100644 index 0000000..3a1a823 --- /dev/null +++ b/xen/arch/x86/acpi/cpufreq/cpufreq_ops.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@xxxxxxxxx> + * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@xxxxxxxxx> + * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@xxxxxxxx> + * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@xxxxxxxxx> + * + * Feb 2008 - Liu Jinsong <jinsong.liu@xxxxxxxxx> + * Add cpufreq limit change handle and per-cpu cpufreq add/del + * to cope with cpu hotplug + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include <xen/types.h> +#include <xen/errno.h> +#include <xen/xmalloc.h> +#include <xen/guest_access.h> + +#include <xen/acpi.h> +#include <xen/cpufreq.h> + +int cpufreq_add_cpu(unsigned int cpu) +{ + int ret = 0; + unsigned int firstcpu; + unsigned int dom, domexist = 0; + unsigned int hw_all = 0; + struct list_head *pos; + struct cpufreq_dom *cpufreq_dom = NULL; + struct cpufreq_policy *policy; + struct processor_performance *perf = &processor_pminfo[cpu]->perf; + + /* to protect the case when Px was not controlled by xen */ + if (!processor_pminfo[cpu] || + !(perf->init & XEN_PX_INIT) || + !cpu_online(cpu)) + return -EINVAL; + + if (!cpufreq_driver) + return 0; + + if (per_cpu(cpufreq_cpu_policy, cpu)) + return 0; + + if (perf->shared_type == CPUFREQ_SHARED_TYPE_HW) + hw_all = 1; + + dom = perf->domain_info.domain; + + list_for_each(pos, &cpufreq_dom_list_head) { + cpufreq_dom = list_entry(pos, struct cpufreq_dom, node); + if (dom == cpufreq_dom->dom) { + domexist = 1; + break; + } + } + + if (!domexist) { + cpufreq_dom = xzalloc(struct cpufreq_dom); + if (!cpufreq_dom) + return -ENOMEM; + + if (!zalloc_cpumask_var(&cpufreq_dom->map)) { + xfree(cpufreq_dom); + return -ENOMEM; + } + + cpufreq_dom->dom = dom; + list_add(&cpufreq_dom->node, &cpufreq_dom_list_head); + } else { + /* domain sanity check under whatever coordination type */ + firstcpu = cpumask_first(cpufreq_dom->map); + if ((perf->domain_info.coord_type != + processor_pminfo[firstcpu]->perf.domain_info.coord_type) || + (perf->domain_info.num_processors != + processor_pminfo[firstcpu]->perf.domain_info.num_processors)) { + + printk(KERN_WARNING "cpufreq fail to add CPU%d:" + "incorrect _PSD(%"PRIu64":%"PRIu64"), " + "expect(%"PRIu64"/%"PRIu64")\n", + cpu, perf->domain_info.coord_type, + perf->domain_info.num_processors, + processor_pminfo[firstcpu]->perf.domain_info.coord_type, + processor_pminfo[firstcpu]->perf.domain_info.num_processors + ); + return -EINVAL; + } + } + + if (!domexist || hw_all) { + policy = xzalloc(struct cpufreq_policy); + if (!policy) { + ret = -ENOMEM; + goto err0; + } + + if (!zalloc_cpumask_var(&policy->cpus)) { + xfree(policy); + ret = -ENOMEM; + goto err0; + } + + policy->cpu = cpu; + per_cpu(cpufreq_cpu_policy, cpu) = policy; + + ret = cpufreq_driver->init(policy); + if (ret) { + free_cpumask_var(policy->cpus); + xfree(policy); + per_cpu(cpufreq_cpu_policy, cpu) = NULL; + goto err0; + } + pr_cpufreq("CPU %u initialization completed\n", cpu); + } else { + firstcpu = cpumask_first(cpufreq_dom->map); + policy = per_cpu(cpufreq_cpu_policy, firstcpu); + + per_cpu(cpufreq_cpu_policy, cpu) = policy; + pr_cpufreq("adding CPU %u\n", cpu); + } + + cpumask_set_cpu(cpu, policy->cpus); + cpumask_set_cpu(cpu, cpufreq_dom->map); + + ret = cpufreq_statistic_init(cpu); + if (ret) + goto err1; + + if (hw_all || (cpumask_weight(cpufreq_dom->map) == + perf->domain_info.num_processors)) { + ret = cpufreq_set_default_policy(policy); + if ( ret ) + goto err2; + } + + return 0; + +err2: + cpufreq_statistic_exit(cpu); +err1: + per_cpu(cpufreq_cpu_policy, cpu) = NULL; + cpumask_clear_cpu(cpu, policy->cpus); + cpumask_clear_cpu(cpu, cpufreq_dom->map); + + if (cpumask_empty(policy->cpus)) { + cpufreq_driver->exit(policy); + free_cpumask_var(policy->cpus); + xfree(policy); + } +err0: + if (cpumask_empty(cpufreq_dom->map)) { + list_del(&cpufreq_dom->node); + free_cpumask_var(cpufreq_dom->map); + xfree(cpufreq_dom); + } + return ret; +} + +int cpufreq_del_cpu(unsigned int cpu) +{ + unsigned int dom, domexist = 0; + unsigned int hw_all = 0; + struct list_head *pos; + struct cpufreq_dom *cpufreq_dom = NULL; + struct cpufreq_policy *policy; + struct processor_performance *perf = &processor_pminfo[cpu]->perf; + + /* to protect the case when Px was not controlled by xen */ + if (!processor_pminfo[cpu] || + !(perf->init & XEN_PX_INIT) || + !cpu_online(cpu)) + return -EINVAL; + + if (!per_cpu(cpufreq_cpu_policy, cpu)) + return 0; + + if (perf->shared_type == CPUFREQ_SHARED_TYPE_HW) + hw_all = 1; + + dom = perf->domain_info.domain; + policy = per_cpu(cpufreq_cpu_policy, cpu); + + list_for_each(pos, &cpufreq_dom_list_head) { + cpufreq_dom = list_entry(pos, struct cpufreq_dom, node); + if (dom == cpufreq_dom->dom) { + domexist = 1; + break; + } + } + + if (!domexist) + return -EINVAL; + + /* for HW_ALL, stop gov for each core of the _PSD domain */ + /* for SW_ALL & SW_ANY, stop gov for the 1st core of the _PSD domain */ + if (hw_all || (cpumask_weight(cpufreq_dom->map) == + perf->domain_info.num_processors)) + __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + + cpufreq_statistic_exit(cpu); + per_cpu(cpufreq_cpu_policy, cpu) = NULL; + cpumask_clear_cpu(cpu, policy->cpus); + cpumask_clear_cpu(cpu, cpufreq_dom->map); + + if (cpumask_empty(policy->cpus)) { + cpufreq_driver->exit(policy); + free_cpumask_var(policy->cpus); + xfree(policy); + } + + /* for the last cpu of the domain, clean room */ + /* It's safe here to free freq_table, drv_data and policy */ + if (cpumask_empty(cpufreq_dom->map)) { + list_del(&cpufreq_dom->node); + free_cpumask_var(cpufreq_dom->map); + xfree(cpufreq_dom); + } + + pr_cpufreq("deleting CPU %u\n", cpu); + return 0; +} + +int cpufreq_limit_change(unsigned int cpu) +{ + struct processor_performance *perf = &processor_pminfo[cpu]->perf; + struct cpufreq_policy *data; + struct cpufreq_policy policy; + + if (!cpu_online(cpu) || !(data = per_cpu(cpufreq_cpu_policy, cpu)) || + !processor_pminfo[cpu]) + return -ENODEV; + + if (perf->platform_limit >= perf->state_count) + return -EINVAL; + + memcpy(&policy, data, sizeof(struct cpufreq_policy)); + + policy.max = + perf->states[perf->platform_limit].core_frequency * 1000; + + return __cpufreq_set_policy(data, &policy); +} + +static void print_PCT(struct xen_pct_register *ptr) +{ + printk("\t_PCT: descriptor=%d, length=%d, space_id=%d, " + "bit_width=%d, bit_offset=%d, reserved=%d, address=%"PRId64"\n", + ptr->descriptor, ptr->length, ptr->space_id, ptr->bit_width, + ptr->bit_offset, ptr->reserved, ptr->address); +} + +static void print_PSS(struct xen_processor_px *ptr, int count) +{ + int i; + printk("\t_PSS: state_count=%d\n", count); + for (i=0; i<count; i++){ + printk("\tState%d: %"PRId64"MHz %"PRId64"mW %"PRId64"us " + "%"PRId64"us %#"PRIx64" %#"PRIx64"\n", + i, + ptr[i].core_frequency, + ptr[i].power, + ptr[i].transition_latency, + ptr[i].bus_master_latency, + ptr[i].control, + ptr[i].status); + } +} + +static void print_PSD( struct xen_psd_package *ptr) +{ + printk("\t_PSD: num_entries=%"PRId64" rev=%"PRId64 + " domain=%"PRId64" coord_type=%"PRId64" num_processors=%"PRId64"\n", + ptr->num_entries, ptr->revision, ptr->domain, ptr->coord_type, + ptr->num_processors); +} + +static void print_PPC(unsigned int platform_limit) +{ + printk("\t_PPC: %d\n", platform_limit); +} + +int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *dom0_px_info) +{ + int ret=0, cpuid; + struct processor_pminfo *pmpt; + struct processor_performance *pxpt; + + cpuid = get_cpu_id(acpi_id); + if ( cpuid < 0 || !dom0_px_info) + { + ret = -EINVAL; + goto out; + } + pr_cpufreq("Set CPU acpi_id(%d) cpuid(%d) Px State info:\n", + acpi_id, cpuid); + + pmpt = processor_pminfo[cpuid]; + if ( !pmpt ) + { + pmpt = xzalloc(struct processor_pminfo); + if ( !pmpt ) + { + ret = -ENOMEM; + goto out; + } + processor_pminfo[cpuid] = pmpt; + } + pxpt = &pmpt->perf; + pmpt->acpi_id = acpi_id; + pmpt->id = cpuid; + + if ( dom0_px_info->flags & XEN_PX_PCT ) + { + /* space_id check */ + if (dom0_px_info->control_register.space_id != + dom0_px_info->status_register.space_id) + { + ret = -EINVAL; + goto out; + } + + 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 ( cpufreq_verbose ) + { + print_PCT(&pxpt->control_register); + print_PCT(&pxpt->status_register); + } + } + + if ( dom0_px_info->flags & XEN_PX_PSS ) + { + /* capability check */ + if (dom0_px_info->state_count <= 1) + { + ret = -EINVAL; + goto out; + } + + if ( !(pxpt->states = xmalloc_array(struct xen_processor_px, + dom0_px_info->state_count)) ) + { + ret = -ENOMEM; + goto out; + } + if ( copy_from_guest(pxpt->states, dom0_px_info->states, + dom0_px_info->state_count) ) + { + ret = -EFAULT; + goto out; + } + pxpt->state_count = dom0_px_info->state_count; + + if ( cpufreq_verbose ) + print_PSS(pxpt->states,pxpt->state_count); + } + + if ( dom0_px_info->flags & XEN_PX_PSD ) + { + /* check domain coordination */ + if (dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_ALL && + dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_ANY && + dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_HW) + { + ret = -EINVAL; + goto out; + } + + pxpt->shared_type = dom0_px_info->shared_type; + memcpy ((void *)&pxpt->domain_info, + (void *)&dom0_px_info->domain_info, + sizeof(struct xen_psd_package)); + + if ( cpufreq_verbose ) + print_PSD(&pxpt->domain_info); + } + + if ( dom0_px_info->flags & XEN_PX_PPC ) + { + pxpt->platform_limit = dom0_px_info->platform_limit; + + if ( cpufreq_verbose ) + print_PPC(pxpt->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; + + ret = cpufreq_cpu_init(cpuid); + goto out; + } + +out: + return ret; +} diff --git a/xen/arch/x86/acpi/cpufreq/powernow.c b/xen/arch/x86/acpi/cpufreq/powernow.c index 2c9fea2..4961d55 100644 --- a/xen/arch/x86/acpi/cpufreq/powernow.c +++ b/xen/arch/x86/acpi/cpufreq/powernow.c @@ -36,7 +36,7 @@ #include <asm/percpu.h> #include <asm/cpufeature.h> #include <acpi/acpi.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> #define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1) #define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 diff --git a/xen/arch/x86/acpi/power.c b/xen/arch/x86/acpi/power.c index f41f0de..f4a87e3 100644 --- a/xen/arch/x86/acpi/power.c +++ b/xen/arch/x86/acpi/power.c @@ -29,7 +29,7 @@ #include <asm/tboot.h> #include <asm/apic.h> #include <asm/io_apic.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> uint32_t system_reset_counter = 1; diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c index c2c8889..35771b1 100644 --- a/xen/arch/x86/cpu/mwait-idle.c +++ b/xen/arch/x86/cpu/mwait-idle.c @@ -59,7 +59,7 @@ #include <asm/hpet.h> #include <asm/mwait.h> #include <asm/msr.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> #define MWAIT_IDLE_VERSION "0.4" #undef PREFIX diff --git a/xen/drivers/acpi/pmstat.c b/xen/drivers/acpi/pmstat.c index daac2da..3486148 100644 --- a/xen/drivers/acpi/pmstat.c +++ b/xen/drivers/acpi/pmstat.c @@ -40,7 +40,7 @@ #include <xen/acpi.h> #include <public/sysctl.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> #include <xen/pmstat.h> DEFINE_PER_CPU_READ_MOSTLY(struct pm_px *, cpufreq_statistic_data); diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c index ab66884..5f92162 100644 --- a/xen/drivers/cpufreq/cpufreq.c +++ b/xen/drivers/cpufreq/cpufreq.c @@ -36,15 +36,13 @@ #include <xen/string.h> #include <xen/timer.h> #include <xen/xmalloc.h> -#include <xen/guest_access.h> #include <xen/domain.h> #include <xen/cpu.h> #include <asm/bug.h> #include <asm/io.h> #include <asm/processor.h> #include <asm/percpu.h> -#include <acpi/acpi.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> static unsigned int __read_mostly usr_min_freq; static unsigned int __read_mostly usr_max_freq; @@ -119,414 +117,25 @@ int __init cpufreq_register_governor(struct cpufreq_governor *governor) return 0; } -int cpufreq_limit_change(unsigned int cpu) +int cpufreq_set_default_policy(struct cpufreq_policy *policy) { - struct processor_performance *perf = &processor_pminfo[cpu]->perf; - struct cpufreq_policy *data; - struct cpufreq_policy policy; - - if (!cpu_online(cpu) || !(data = per_cpu(cpufreq_cpu_policy, cpu)) || - !processor_pminfo[cpu]) - return -ENODEV; - - if (perf->platform_limit >= perf->state_count) - return -EINVAL; - - memcpy(&policy, data, sizeof(struct cpufreq_policy)); - - policy.max = - perf->states[perf->platform_limit].core_frequency * 1000; - - return __cpufreq_set_policy(data, &policy); -} - -int cpufreq_add_cpu(unsigned int cpu) -{ - int ret = 0; - unsigned int firstcpu; - unsigned int dom, domexist = 0; - unsigned int hw_all = 0; - struct list_head *pos; - struct cpufreq_dom *cpufreq_dom = NULL; struct cpufreq_policy new_policy; - struct cpufreq_policy *policy; - struct processor_performance *perf = &processor_pminfo[cpu]->perf; - - /* to protect the case when Px was not controlled by xen */ - if (!processor_pminfo[cpu] || - !(perf->init & XEN_PX_INIT) || - !cpu_online(cpu)) - return -EINVAL; - - if (!cpufreq_driver) - return 0; - - if (per_cpu(cpufreq_cpu_policy, cpu)) - return 0; - - if (perf->shared_type == CPUFREQ_SHARED_TYPE_HW) - hw_all = 1; - - dom = perf->domain_info.domain; + int ret; - list_for_each(pos, &cpufreq_dom_list_head) { - cpufreq_dom = list_entry(pos, struct cpufreq_dom, node); - if (dom == cpufreq_dom->dom) { - domexist = 1; - break; - } - } - - if (!domexist) { - cpufreq_dom = xzalloc(struct cpufreq_dom); - if (!cpufreq_dom) - return -ENOMEM; - - if (!zalloc_cpumask_var(&cpufreq_dom->map)) { - xfree(cpufreq_dom); - return -ENOMEM; - } - - cpufreq_dom->dom = dom; - list_add(&cpufreq_dom->node, &cpufreq_dom_list_head); - } else { - /* domain sanity check under whatever coordination type */ - firstcpu = cpumask_first(cpufreq_dom->map); - if ((perf->domain_info.coord_type != - processor_pminfo[firstcpu]->perf.domain_info.coord_type) || - (perf->domain_info.num_processors != - processor_pminfo[firstcpu]->perf.domain_info.num_processors)) { - - printk(KERN_WARNING "cpufreq fail to add CPU%d:" - "incorrect _PSD(%"PRIu64":%"PRIu64"), " - "expect(%"PRIu64"/%"PRIu64")\n", - cpu, perf->domain_info.coord_type, - perf->domain_info.num_processors, - processor_pminfo[firstcpu]->perf.domain_info.coord_type, - processor_pminfo[firstcpu]->perf.domain_info.num_processors - ); - return -EINVAL; - } - } + memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); + policy->governor = NULL; - if (!domexist || hw_all) { - policy = xzalloc(struct cpufreq_policy); - if (!policy) { - ret = -ENOMEM; - goto err0; - } - - if (!zalloc_cpumask_var(&policy->cpus)) { - xfree(policy); - ret = -ENOMEM; - goto err0; - } - - policy->cpu = cpu; - per_cpu(cpufreq_cpu_policy, cpu) = policy; - - ret = cpufreq_driver->init(policy); - if (ret) { - free_cpumask_var(policy->cpus); - xfree(policy); - per_cpu(cpufreq_cpu_policy, cpu) = NULL; - goto err0; - } - if (cpufreq_verbose) - printk("CPU %u initialization completed\n", cpu); - } else { - firstcpu = cpumask_first(cpufreq_dom->map); - policy = per_cpu(cpufreq_cpu_policy, firstcpu); - - per_cpu(cpufreq_cpu_policy, cpu) = policy; - if (cpufreq_verbose) - printk("adding CPU %u\n", cpu); - } + cpufreq_cmdline_common_para(&new_policy); - cpumask_set_cpu(cpu, policy->cpus); - cpumask_set_cpu(cpu, cpufreq_dom->map); - - ret = cpufreq_statistic_init(cpu); - if (ret) - goto err1; - - if (hw_all || (cpumask_weight(cpufreq_dom->map) == - perf->domain_info.num_processors)) { + ret = __cpufreq_set_policy(policy, &new_policy); + if ( ret && new_policy.governor != CPUFREQ_DEFAULT_GOVERNOR ) + { + /* grub option governor fail */ + /* give one more chance to default gov */ memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); - policy->governor = NULL; - - cpufreq_cmdline_common_para(&new_policy); - + new_policy.governor = CPUFREQ_DEFAULT_GOVERNOR; ret = __cpufreq_set_policy(policy, &new_policy); - if (ret) { - if (new_policy.governor == CPUFREQ_DEFAULT_GOVERNOR) - /* if default governor fail, cpufreq really meet troubles */ - goto err2; - else { - /* grub option governor fail */ - /* give one more chance to default gov */ - memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); - new_policy.governor = CPUFREQ_DEFAULT_GOVERNOR; - ret = __cpufreq_set_policy(policy, &new_policy); - if (ret) - goto err2; - } - } - } - - return 0; - -err2: - cpufreq_statistic_exit(cpu); -err1: - per_cpu(cpufreq_cpu_policy, cpu) = NULL; - cpumask_clear_cpu(cpu, policy->cpus); - cpumask_clear_cpu(cpu, cpufreq_dom->map); - - if (cpumask_empty(policy->cpus)) { - cpufreq_driver->exit(policy); - free_cpumask_var(policy->cpus); - xfree(policy); - } -err0: - if (cpumask_empty(cpufreq_dom->map)) { - list_del(&cpufreq_dom->node); - free_cpumask_var(cpufreq_dom->map); - xfree(cpufreq_dom); - } - - return ret; -} - -int cpufreq_del_cpu(unsigned int cpu) -{ - unsigned int dom, domexist = 0; - unsigned int hw_all = 0; - struct list_head *pos; - struct cpufreq_dom *cpufreq_dom = NULL; - struct cpufreq_policy *policy; - struct processor_performance *perf = &processor_pminfo[cpu]->perf; - - /* to protect the case when Px was not controlled by xen */ - if (!processor_pminfo[cpu] || - !(perf->init & XEN_PX_INIT) || - !cpu_online(cpu)) - return -EINVAL; - - if (!per_cpu(cpufreq_cpu_policy, cpu)) - return 0; - - if (perf->shared_type == CPUFREQ_SHARED_TYPE_HW) - hw_all = 1; - - dom = perf->domain_info.domain; - policy = per_cpu(cpufreq_cpu_policy, cpu); - - list_for_each(pos, &cpufreq_dom_list_head) { - cpufreq_dom = list_entry(pos, struct cpufreq_dom, node); - if (dom == cpufreq_dom->dom) { - domexist = 1; - break; - } - } - - if (!domexist) - return -EINVAL; - - /* for HW_ALL, stop gov for each core of the _PSD domain */ - /* for SW_ALL & SW_ANY, stop gov for the 1st core of the _PSD domain */ - if (hw_all || (cpumask_weight(cpufreq_dom->map) == - perf->domain_info.num_processors)) - __cpufreq_governor(policy, CPUFREQ_GOV_STOP); - - cpufreq_statistic_exit(cpu); - per_cpu(cpufreq_cpu_policy, cpu) = NULL; - cpumask_clear_cpu(cpu, policy->cpus); - cpumask_clear_cpu(cpu, cpufreq_dom->map); - - if (cpumask_empty(policy->cpus)) { - cpufreq_driver->exit(policy); - free_cpumask_var(policy->cpus); - xfree(policy); - } - - /* for the last cpu of the domain, clean room */ - /* It's safe here to free freq_table, drv_data and policy */ - if (cpumask_empty(cpufreq_dom->map)) { - list_del(&cpufreq_dom->node); - free_cpumask_var(cpufreq_dom->map); - xfree(cpufreq_dom); - } - - if (cpufreq_verbose) - printk("deleting CPU %u\n", cpu); - return 0; -} - -static void print_PCT(struct xen_pct_register *ptr) -{ - printk("\t_PCT: descriptor=%d, length=%d, space_id=%d, " - "bit_width=%d, bit_offset=%d, reserved=%d, address=%"PRId64"\n", - ptr->descriptor, ptr->length, ptr->space_id, ptr->bit_width, - ptr->bit_offset, ptr->reserved, ptr->address); -} - -static void print_PSS(struct xen_processor_px *ptr, int count) -{ - int i; - printk("\t_PSS: state_count=%d\n", count); - for (i=0; i<count; i++){ - printk("\tState%d: %"PRId64"MHz %"PRId64"mW %"PRId64"us " - "%"PRId64"us %#"PRIx64" %#"PRIx64"\n", - i, - ptr[i].core_frequency, - ptr[i].power, - ptr[i].transition_latency, - ptr[i].bus_master_latency, - ptr[i].control, - ptr[i].status); - } -} - -static void print_PSD( struct xen_psd_package *ptr) -{ - printk("\t_PSD: num_entries=%"PRId64" rev=%"PRId64 - " domain=%"PRId64" coord_type=%"PRId64" num_processors=%"PRId64"\n", - ptr->num_entries, ptr->revision, ptr->domain, ptr->coord_type, - ptr->num_processors); -} - -static void print_PPC(unsigned int platform_limit) -{ - printk("\t_PPC: %d\n", platform_limit); -} - -int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *dom0_px_info) -{ - int ret=0, cpuid; - struct processor_pminfo *pmpt; - struct processor_performance *pxpt; - - cpuid = get_cpu_id(acpi_id); - if ( cpuid < 0 || !dom0_px_info) - { - ret = -EINVAL; - goto out; } - if ( cpufreq_verbose ) - printk("Set CPU acpi_id(%d) cpuid(%d) Px State info:\n", - acpi_id, cpuid); - - pmpt = processor_pminfo[cpuid]; - if ( !pmpt ) - { - pmpt = xzalloc(struct processor_pminfo); - if ( !pmpt ) - { - ret = -ENOMEM; - goto out; - } - processor_pminfo[cpuid] = pmpt; - } - pxpt = &pmpt->perf; - pmpt->acpi_id = acpi_id; - pmpt->id = cpuid; - - if ( dom0_px_info->flags & XEN_PX_PCT ) - { - /* space_id check */ - if (dom0_px_info->control_register.space_id != - dom0_px_info->status_register.space_id) - { - ret = -EINVAL; - goto out; - } - - 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 ( cpufreq_verbose ) - { - print_PCT(&pxpt->control_register); - print_PCT(&pxpt->status_register); - } - } - - if ( dom0_px_info->flags & XEN_PX_PSS ) - { - /* capability check */ - if (dom0_px_info->state_count <= 1) - { - ret = -EINVAL; - goto out; - } - - if ( !(pxpt->states = xmalloc_array(struct xen_processor_px, - dom0_px_info->state_count)) ) - { - ret = -ENOMEM; - goto out; - } - if ( copy_from_guest(pxpt->states, dom0_px_info->states, - dom0_px_info->state_count) ) - { - ret = -EFAULT; - goto out; - } - pxpt->state_count = dom0_px_info->state_count; - - if ( cpufreq_verbose ) - print_PSS(pxpt->states,pxpt->state_count); - } - - if ( dom0_px_info->flags & XEN_PX_PSD ) - { - /* check domain coordination */ - if (dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_ALL && - dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_ANY && - dom0_px_info->shared_type != CPUFREQ_SHARED_TYPE_HW) - { - ret = -EINVAL; - goto out; - } - - pxpt->shared_type = dom0_px_info->shared_type; - memcpy ((void *)&pxpt->domain_info, - (void *)&dom0_px_info->domain_info, - sizeof(struct xen_psd_package)); - - if ( cpufreq_verbose ) - print_PSD(&pxpt->domain_info); - } - - if ( dom0_px_info->flags & XEN_PX_PPC ) - { - pxpt->platform_limit = dom0_px_info->platform_limit; - - if ( cpufreq_verbose ) - print_PPC(pxpt->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; - - ret = cpufreq_cpu_init(cpuid); - goto out; - } - -out: return ret; } @@ -630,12 +239,14 @@ static struct notifier_block cpu_nfb = { .notifier_call = cpu_callback }; -static int __init cpufreq_presmp_init(void) +int __init cpufreq_presmp_init(void) { void *cpu = (void *)(long)smp_processor_id(); cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); register_cpu_notifier(&cpu_nfb); return 0; } -presmp_initcall(cpufreq_presmp_init); +#ifndef CONFIG_ARM +presmp_initcall(cpufreq_presmp_init); +#endif diff --git a/xen/drivers/cpufreq/cpufreq_misc_governors.c b/xen/drivers/cpufreq/cpufreq_misc_governors.c index 746bbcd..4a5510c 100644 --- a/xen/drivers/cpufreq/cpufreq_misc_governors.c +++ b/xen/drivers/cpufreq/cpufreq_misc_governors.c @@ -18,7 +18,7 @@ #include <xen/init.h> #include <xen/percpu.h> #include <xen/sched.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> /* * cpufreq userspace governor diff --git a/xen/drivers/cpufreq/cpufreq_ondemand.c b/xen/drivers/cpufreq/cpufreq_ondemand.c index 7fdba03..be69499 100644 --- a/xen/drivers/cpufreq/cpufreq_ondemand.c +++ b/xen/drivers/cpufreq/cpufreq_ondemand.c @@ -1,5 +1,5 @@ /* - * xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c + * xen/drivers/cpufreq/cpufreq_ondemand.c * * Copyright (C) 2001 Russell King * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@xxxxxxxxx>. @@ -18,7 +18,7 @@ #include <xen/types.h> #include <xen/sched.h> #include <xen/timer.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> #define DEF_FREQUENCY_UP_THRESHOLD (80) #define MIN_FREQUENCY_UP_THRESHOLD (11) @@ -193,12 +193,11 @@ static void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) (void *)dbs_info, dbs_info->cpu); set_timer(&per_cpu(dbs_timer, dbs_info->cpu), NOW()+dbs_tuners_ins.sampling_rate); - +#ifdef CONFIG_X86 if ( processor_pminfo[dbs_info->cpu]->perf.shared_type == CPUFREQ_SHARED_TYPE_HW ) - { +#endif dbs_info->stoppable = 1; - } } static void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) diff --git a/xen/drivers/cpufreq/utility.c b/xen/drivers/cpufreq/utility.c index 519f862..e5bc8c4 100644 --- a/xen/drivers/cpufreq/utility.c +++ b/xen/drivers/cpufreq/utility.c @@ -28,13 +28,15 @@ #include <xen/sched.h> #include <xen/timer.h> #include <xen/trace.h> -#include <acpi/cpufreq/cpufreq.h> +#include <xen/cpufreq.h> #include <public/sysctl.h> struct cpufreq_driver *cpufreq_driver; -struct processor_pminfo *__read_mostly processor_pminfo[NR_CPUS]; DEFINE_PER_CPU_READ_MOSTLY(struct cpufreq_policy *, cpufreq_cpu_policy); +#ifdef HAS_ACPI +struct processor_pminfo *__read_mostly processor_pminfo[NR_CPUS]; + DEFINE_PER_CPU(spinlock_t, cpufreq_statistic_lock); /********************************************************************* @@ -198,7 +200,7 @@ void cpufreq_statistic_reset(unsigned int cpuid) spin_unlock(cpufreq_statistic_lock); } - +#endif /* HAS_ACPI */ /********************************************************************* * FREQUENCY TABLE HELPERS * @@ -209,7 +211,9 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, { unsigned int min_freq = ~0; unsigned int max_freq = 0; +#ifdef CONFIG_X86 unsigned int second_max_freq = 0; +#endif unsigned int i; for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { @@ -225,18 +229,21 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, unsigned int freq = table[i].frequency; if (freq == CPUFREQ_ENTRY_INVALID || freq == max_freq) continue; +#ifdef CONFIG_X86 if (freq > second_max_freq) second_max_freq = freq; +#endif } +#ifdef CONFIG_X86 if (second_max_freq == 0) second_max_freq = max_freq; - if (cpufreq_verbose) - printk("max_freq: %u second_max_freq: %u\n", + pr_cpufreq("max_freq: %u second_max_freq: %u\n", max_freq, second_max_freq); + policy->cpuinfo.second_max_freq = second_max_freq; +#endif policy->min = policy->cpuinfo.min_freq = min_freq; policy->max = policy->cpuinfo.max_freq = max_freq; - policy->cpuinfo.second_max_freq = second_max_freq; if (policy->min == ~0) return -EINVAL; @@ -390,6 +397,7 @@ int cpufreq_driver_getavg(unsigned int cpu, unsigned int flag) return policy->cur; } +#ifdef CONFIG_X86 int cpufreq_update_turbo(int cpuid, int new_state) { struct cpufreq_policy *policy; @@ -430,6 +438,7 @@ int cpufreq_get_turbo_status(int cpuid) policy = per_cpu(cpufreq_cpu_policy, cpuid); return policy && policy->turbo == CPUFREQ_TURBO_ENABLED; } +#endif /* CONFIG_X86 */ /********************************************************************* * POLICY * diff --git a/xen/include/acpi/cpufreq/cpufreq.h b/xen/include/acpi/cpufreq/cpufreq.h deleted file mode 100644 index f96c3e4..0000000 --- a/xen/include/acpi/cpufreq/cpufreq.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * xen/include/acpi/cpufreq/cpufreq.h - * - * Copyright (C) 2001 Russell King - * (C) 2002 - 2003 Dominik Brodowski <linux@xxxxxxxx> - * - * $Id: cpufreq.h,v 1.36 2003/01/20 17:31:48 db Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __XEN_CPUFREQ_PM_H__ -#define __XEN_CPUFREQ_PM_H__ - -#include <xen/types.h> -#include <xen/list.h> -#include <xen/cpumask.h> - -#include "processor_perf.h" - -DECLARE_PER_CPU(spinlock_t, cpufreq_statistic_lock); - -extern bool_t cpufreq_verbose; - -struct cpufreq_governor; - -struct acpi_cpufreq_data { - struct processor_performance *acpi_data; - struct cpufreq_frequency_table *freq_table; - unsigned int arch_cpu_flags; -}; - -extern struct acpi_cpufreq_data *cpufreq_drv_data[NR_CPUS]; - -struct cpufreq_cpuinfo { - unsigned int max_freq; - unsigned int second_max_freq; /* P1 if Turbo Mode is on */ - unsigned int min_freq; - unsigned int transition_latency; /* in 10^(-9) s = nanoseconds */ -}; - -struct cpufreq_policy { - cpumask_var_t cpus; /* affected CPUs */ - unsigned int shared_type; /* ANY or ALL affected CPUs - should set cpufreq */ - unsigned int cpu; /* cpu nr of registered CPU */ - struct cpufreq_cpuinfo cpuinfo; - - unsigned int min; /* in kHz */ - unsigned int max; /* in kHz */ - unsigned int cur; /* in kHz, only needed if cpufreq - * governors are used */ - struct cpufreq_governor *governor; - - bool_t resume; /* flag for cpufreq 1st run - * S3 wakeup, hotplug cpu, etc */ - s8 turbo; /* tristate flag: 0 for unsupported - * -1 for disable, 1 for enabled - * See CPUFREQ_TURBO_* below for defines */ - bool_t aperf_mperf; /* CPU has APERF/MPERF MSRs */ -}; -DECLARE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_policy); - -extern int __cpufreq_set_policy(struct cpufreq_policy *data, - struct cpufreq_policy *policy); - -void cpufreq_cmdline_parse(char *); - -#define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ -#define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ -#define CPUFREQ_SHARED_TYPE_ALL (2) /* All dependent CPUs should set freq */ -#define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/ - -/******************** cpufreq transition notifiers *******************/ - -struct cpufreq_freqs { - unsigned int cpu; /* cpu nr */ - unsigned int old; - unsigned int new; - u8 flags; /* flags of cpufreq_driver, see below. */ -}; - - -/********************************************************************* - * CPUFREQ GOVERNORS * - *********************************************************************/ - -#define CPUFREQ_GOV_START 1 -#define CPUFREQ_GOV_STOP 2 -#define CPUFREQ_GOV_LIMITS 3 - -struct cpufreq_governor { - char name[CPUFREQ_NAME_LEN]; - int (*governor)(struct cpufreq_policy *policy, - unsigned int event); - bool_t (*handle_option)(const char *name, const char *value); - struct list_head governor_list; -}; - -extern struct cpufreq_governor *cpufreq_opt_governor; -extern struct cpufreq_governor cpufreq_gov_dbs; -extern struct cpufreq_governor cpufreq_gov_userspace; -extern struct cpufreq_governor cpufreq_gov_performance; -extern struct cpufreq_governor cpufreq_gov_powersave; - -extern struct list_head cpufreq_governor_list; - -extern int cpufreq_register_governor(struct cpufreq_governor *governor); -extern struct cpufreq_governor *__find_governor(const char *governor); -#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs - -/* pass a target to the cpufreq driver */ -extern int __cpufreq_driver_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation); - -#define GOV_GETAVG 1 -#define USR_GETAVG 2 -extern int cpufreq_driver_getavg(unsigned int cpu, unsigned int flag); - -#define CPUFREQ_TURBO_DISABLED -1 -#define CPUFREQ_TURBO_UNSUPPORTED 0 -#define CPUFREQ_TURBO_ENABLED 1 - -extern int cpufreq_update_turbo(int cpuid, int new_state); -extern int cpufreq_get_turbo_status(int cpuid); - -static __inline__ int -__cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) -{ - return policy->governor->governor(policy, event); -} - - -/********************************************************************* - * CPUFREQ DRIVER INTERFACE * - *********************************************************************/ - -#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ -#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ - -struct cpufreq_driver { - char name[CPUFREQ_NAME_LEN]; - int (*init)(struct cpufreq_policy *policy); - int (*verify)(struct cpufreq_policy *policy); - int (*update)(int cpuid, struct cpufreq_policy *policy); - int (*target)(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation); - unsigned int (*get)(unsigned int cpu); - unsigned int (*getavg)(unsigned int cpu, unsigned int flag); - int (*exit)(struct cpufreq_policy *policy); -}; - -extern struct cpufreq_driver *cpufreq_driver; - -static __inline__ -int cpufreq_register_driver(struct cpufreq_driver *driver_data) -{ - if (!driver_data || - !driver_data->init || - !driver_data->exit || - !driver_data->verify || - !driver_data->target) - return -EINVAL; - - if (cpufreq_driver) - return -EBUSY; - - cpufreq_driver = driver_data; - return 0; -} - -static __inline__ -int cpufreq_unregister_driver(struct cpufreq_driver *driver) -{ - if (!cpufreq_driver || (driver != cpufreq_driver)) - return -EINVAL; - - cpufreq_driver = NULL; - return 0; -} - -static __inline__ -void cpufreq_verify_within_limits(struct cpufreq_policy *policy, - unsigned int min, unsigned int max) -{ - if (policy->min < min) - policy->min = min; - if (policy->max < min) - policy->max = min; - if (policy->min > max) - policy->min = max; - if (policy->max > max) - policy->max = max; - if (policy->min > policy->max) - policy->min = policy->max; - return; -} - - -/********************************************************************* - * FREQUENCY TABLE HELPERS * - *********************************************************************/ - -#define CPUFREQ_ENTRY_INVALID ~0 -#define CPUFREQ_TABLE_END ~1 - -struct cpufreq_frequency_table { - unsigned int index; /* any */ - unsigned int frequency; /* kHz - doesn't need to be in ascending - * order */ -}; - -int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table); - -int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table); - -int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table, - unsigned int target_freq, - unsigned int relation, - unsigned int *index); - - -/********************************************************************* - * UNIFIED DEBUG HELPERS * - *********************************************************************/ - -struct cpu_dbs_info_s { - uint64_t prev_cpu_idle; - uint64_t prev_cpu_wall; - struct cpufreq_policy *cur_policy; - struct cpufreq_frequency_table *freq_table; - int cpu; - unsigned int enable:1; - unsigned int stoppable:1; - unsigned int turbo_enabled:1; -}; - -int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event); -int get_cpufreq_ondemand_para(uint32_t *sampling_rate_max, - uint32_t *sampling_rate_min, - uint32_t *sampling_rate, - uint32_t *up_threshold); -int write_ondemand_sampling_rate(unsigned int sampling_rate); -int write_ondemand_up_threshold(unsigned int up_threshold); - -int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq); - -void cpufreq_dbs_timer_suspend(void); -void cpufreq_dbs_timer_resume(void); - -#endif /* __XEN_CPUFREQ_PM_H__ */ diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h index d8a1ba6..42c1932 100644 --- a/xen/include/acpi/cpufreq/processor_perf.h +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -18,9 +18,6 @@ void cpufreq_statistic_reset(unsigned int); int cpufreq_limit_change(unsigned int); -int cpufreq_add_cpu(unsigned int); -int cpufreq_del_cpu(unsigned int); - struct processor_performance { uint32_t state; uint32_t platform_limit; diff --git a/xen/include/xen/cpufreq.h b/xen/include/xen/cpufreq.h new file mode 100644 index 0000000..2974ff8 --- /dev/null +++ b/xen/include/xen/cpufreq.h @@ -0,0 +1,285 @@ +/* + * xen/include/xen/cpufreq.h + * + * Copyright (C) 2001 Russell King + * (C) 2002 - 2003 Dominik Brodowski <linux@xxxxxxxx> + * + * $Id: cpufreq.h,v 1.36 2003/01/20 17:31:48 db Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XEN_CPUFREQ_PM_H__ +#define __XEN_CPUFREQ_PM_H__ + +#include <xen/types.h> +#include <xen/list.h> +#include <xen/cpumask.h> +#include <xen/percpu.h> +#include <xen/spinlock.h> +#include <xen/init.h> +#include <public/platform.h> +#include <public/sysctl.h> + +#ifdef CONFIG_X86 +#include <acpi/cpufreq/processor_perf.h> +#endif + +DECLARE_PER_CPU(spinlock_t, cpufreq_statistic_lock); + +extern bool_t cpufreq_verbose; + +#define pr_cpufreq(fmt, ...) \ + do \ + { \ + if ( cpufreq_verbose ) \ + printk(KERN_WARNING "cpufreq: " fmt, ##__VA_ARGS__); \ + } while (0) + +struct cpufreq_governor; + +#ifdef CONFIG_X86 +struct acpi_cpufreq_data { + struct processor_performance *acpi_data; + struct cpufreq_frequency_table *freq_table; + unsigned int arch_cpu_flags; +}; + +extern struct acpi_cpufreq_data *cpufreq_drv_data[NR_CPUS]; +#endif + +struct cpufreq_cpuinfo { + unsigned int max_freq; +#ifdef CONFIG_X86 + unsigned int second_max_freq; /* P1 if Turbo Mode is on */ +#endif + unsigned int min_freq; + unsigned int transition_latency; /* in 10^(-9) s = nanoseconds */ +}; + +struct cpufreq_policy { + cpumask_var_t cpus; /* affected CPUs */ + unsigned int shared_type; /* ANY or ALL affected CPUs + should set cpufreq */ + unsigned int cpu; /* cpu nr of registered CPU */ + struct cpufreq_cpuinfo cpuinfo; + + unsigned int min; /* in kHz */ + unsigned int max; /* in kHz */ + unsigned int cur; /* in kHz, only needed if cpufreq + * governors are used */ + struct cpufreq_governor *governor; + + bool_t resume; /* flag for cpufreq 1st run + * S3 wakeup, hotplug cpu, etc */ +#ifdef CONFIG_X86 + s8 turbo; /* tristate flag: 0 for unsupported + * -1 for disable, 1 for enabled + * See CPUFREQ_TURBO_* below for defines */ + bool_t aperf_mperf; /* CPU has APERF/MPERF MSRs */ +#endif +}; +DECLARE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_policy); + +extern int __cpufreq_set_policy(struct cpufreq_policy *data, + struct cpufreq_policy *policy); + +void cpufreq_cmdline_parse(char *); + +#define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ +#define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ +#define CPUFREQ_SHARED_TYPE_ALL (2) /* All dependent CPUs should set freq */ +#define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/ + +/******************** cpufreq transition notifiers *******************/ + +struct cpufreq_freqs { + unsigned int cpu; /* cpu nr */ + unsigned int old; + unsigned int new; + u8 flags; /* flags of cpufreq_driver, see below. */ +}; + + +/********************************************************************* + * CPUFREQ GOVERNORS * + *********************************************************************/ + +#define CPUFREQ_GOV_START 1 +#define CPUFREQ_GOV_STOP 2 +#define CPUFREQ_GOV_LIMITS 3 + +struct cpufreq_governor { + char name[CPUFREQ_NAME_LEN]; + int (*governor)(struct cpufreq_policy *policy, + unsigned int event); + bool_t (*handle_option)(const char *name, const char *value); + struct list_head governor_list; +}; + +extern struct cpufreq_governor *cpufreq_opt_governor; +extern struct cpufreq_governor cpufreq_gov_dbs; +extern struct cpufreq_governor cpufreq_gov_userspace; +extern struct cpufreq_governor cpufreq_gov_performance; +extern struct cpufreq_governor cpufreq_gov_powersave; + +extern struct list_head cpufreq_governor_list; + +extern int cpufreq_register_governor(struct cpufreq_governor *governor); +extern struct cpufreq_governor *__find_governor(const char *governor); +#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs + +/* pass a target to the cpufreq driver */ +extern int __cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); + +#define GOV_GETAVG 1 +#define USR_GETAVG 2 +extern int cpufreq_driver_getavg(unsigned int cpu, unsigned int flag); + +#define CPUFREQ_TURBO_DISABLED -1 +#define CPUFREQ_TURBO_UNSUPPORTED 0 +#define CPUFREQ_TURBO_ENABLED 1 + +#ifdef CONFIG_X86 +extern int cpufreq_update_turbo(int cpuid, int new_state); +extern int cpufreq_get_turbo_status(int cpuid); +#endif + +static __inline__ int +__cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) +{ + return policy->governor->governor(policy, event); +} + + +/********************************************************************* + * CPUFREQ DRIVER INTERFACE * + *********************************************************************/ + +#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ +#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ + +struct cpufreq_driver { + char name[CPUFREQ_NAME_LEN]; + int (*init)(struct cpufreq_policy *policy); + int (*verify)(struct cpufreq_policy *policy); + int (*update)(int cpuid, struct cpufreq_policy *policy); + int (*target)(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); + unsigned int (*get)(unsigned int cpu); + unsigned int (*getavg)(unsigned int cpu, unsigned int flag); + int (*exit)(struct cpufreq_policy *policy); +}; + +extern struct cpufreq_driver *cpufreq_driver; + +static __inline__ +int cpufreq_register_driver(struct cpufreq_driver *driver_data) +{ + if (!driver_data || + !driver_data->init || + !driver_data->exit || + !driver_data->verify || + !driver_data->target) + return -EINVAL; + + if (cpufreq_driver) + return -EBUSY; + + cpufreq_driver = driver_data; + return 0; +} + +static __inline__ +int cpufreq_unregister_driver(struct cpufreq_driver *driver) +{ + if (!cpufreq_driver || (driver != cpufreq_driver)) + return -EINVAL; + + cpufreq_driver = NULL; + return 0; +} + +static __inline__ +void cpufreq_verify_within_limits(struct cpufreq_policy *policy, + unsigned int min, unsigned int max) +{ + if (policy->min < min) + policy->min = min; + if (policy->max < min) + policy->max = min; + if (policy->min > max) + policy->min = max; + if (policy->max > max) + policy->max = max; + if (policy->min > policy->max) + policy->min = policy->max; + return; +} + +int cpufreq_add_cpu(unsigned int); +int cpufreq_del_cpu(unsigned int); +int cpufreq_set_default_policy(struct cpufreq_policy *policy); + +int __init cpufreq_presmp_init(void); + +/********************************************************************* + * FREQUENCY TABLE HELPERS * + *********************************************************************/ + +#define CPUFREQ_ENTRY_INVALID ~0 +#define CPUFREQ_TABLE_END ~1 + +struct cpufreq_frequency_table { + unsigned int index; /* any */ + unsigned int frequency; /* kHz - doesn't need to be in ascending + * order */ +}; + +int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table); + +int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table); + +int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table, + unsigned int target_freq, + unsigned int relation, + unsigned int *index); + + +/********************************************************************* + * UNIFIED DEBUG HELPERS * + *********************************************************************/ + +struct cpu_dbs_info_s { + uint64_t prev_cpu_idle; + uint64_t prev_cpu_wall; + struct cpufreq_policy *cur_policy; + struct cpufreq_frequency_table *freq_table; + int cpu; + unsigned int enable:1; + unsigned int stoppable:1; + unsigned int turbo_enabled:1; +}; + +int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event); +int get_cpufreq_ondemand_para(uint32_t *sampling_rate_max, + uint32_t *sampling_rate_min, + uint32_t *sampling_rate, + uint32_t *up_threshold); +int write_ondemand_sampling_rate(unsigned int sampling_rate); +int write_ondemand_up_threshold(unsigned int up_threshold); + +int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq); + +void cpufreq_dbs_timer_suspend(void); +void cpufreq_dbs_timer_resume(void); + +#endif /* __XEN_CPUFREQ_PM_H__ */ -- 1.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |