diff options
-rw-r--r-- | xen/arch/x86/acpi/Makefile | 1 | ||||
-rw-r--r-- | xen/arch/x86/acpi/cpufreq/Makefile | 2 | ||||
-rw-r--r-- | xen/arch/x86/acpi/cpufreq/cpufreq.c | 153 | ||||
-rw-r--r-- | xen/drivers/Makefile | 1 | ||||
-rw-r--r-- | xen/drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | xen/drivers/acpi/pmstat.c (renamed from xen/arch/x86/acpi/pmstat.c) | 6 | ||||
-rw-r--r-- | xen/drivers/cpufreq/Makefile | 3 | ||||
-rw-r--r-- | xen/drivers/cpufreq/cpufreq.c | 188 | ||||
-rw-r--r-- | xen/drivers/cpufreq/cpufreq_ondemand.c (renamed from xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c) | 0 | ||||
-rw-r--r-- | xen/drivers/cpufreq/utility.c (renamed from xen/arch/x86/acpi/cpufreq/utility.c) | 18 | ||||
-rw-r--r-- | xen/include/acpi/cpufreq/cpufreq.h | 7 | ||||
-rw-r--r-- | xen/include/acpi/cpufreq/processor_perf.h | 10 |
12 files changed, 219 insertions, 171 deletions
diff --git a/xen/arch/x86/acpi/Makefile b/xen/arch/x86/acpi/Makefile index d98d77d654..f31302c368 100644 --- a/xen/arch/x86/acpi/Makefile +++ b/xen/arch/x86/acpi/Makefile @@ -2,4 +2,3 @@ subdir-y += cpufreq obj-y += boot.o obj-y += power.o suspend.o wakeup_prot.o cpu_idle.o cpuidle_menu.o -obj-y += pmstat.o diff --git a/xen/arch/x86/acpi/cpufreq/Makefile b/xen/arch/x86/acpi/cpufreq/Makefile index 5debfe7ccf..f75da9b9ca 100644 --- a/xen/arch/x86/acpi/cpufreq/Makefile +++ b/xen/arch/x86/acpi/cpufreq/Makefile @@ -1,4 +1,2 @@ obj-y += cpufreq.o -obj-y += utility.o -obj-y += cpufreq_ondemand.o obj-y += powernow.o diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c b/xen/arch/x86/acpi/cpufreq/cpufreq.c index 119d8ff86d..b706d113c9 100644 --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c @@ -45,9 +45,6 @@ #include <acpi/acpi.h> #include <acpi/cpufreq/cpufreq.h> -/* TODO: change to link list later as domain number may be sparse */ -static cpumask_t cpufreq_dom_map[NR_CPUS]; - enum { UNDEFINED_CAPABLE = 0, SYSTEM_INTEL_MSR_CAPABLE, @@ -57,13 +54,6 @@ enum { #define INTEL_MSR_RANGE (0xffff) #define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1) -struct acpi_cpufreq_data { - struct processor_performance *acpi_data; - struct cpufreq_frequency_table *freq_table; - unsigned int max_freq; - unsigned int cpu_feature; -}; - static struct acpi_cpufreq_data *drv_data[NR_CPUS]; static struct cpufreq_driver acpi_cpufreq_driver; @@ -342,7 +332,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, policy->resume = 0; } else { - printk(KERN_INFO "Already at target state (P%d)\n", + printk(KERN_DEBUG "Already at target state (P%d)\n", next_perf_state); return 0; } @@ -379,7 +369,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, if (!check_freqs(cmd.mask, freqs.new, data)) return -EAGAIN; - px_statistic_update(cmd.mask, perf->state, next_perf_state); + cpufreq_statistic_update(cmd.mask, perf->state, next_perf_state); perf->state = next_perf_state; policy->cur = freqs.new; @@ -581,145 +571,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .exit = acpi_cpufreq_cpu_exit, }; -int cpufreq_limit_change(unsigned int cpu) -{ - struct processor_performance *perf = &processor_pminfo[cpu]->perf; - struct cpufreq_policy *data = cpufreq_cpu_policy[cpu]; - struct cpufreq_policy policy; - - if (!cpu_online(cpu) || !data || !processor_pminfo[cpu]) - return -ENODEV; - - if ((perf->platform_limit < 0) || - (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; - unsigned int j; - 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)) - return 0; - - if (cpu_is_offline(cpu) || cpufreq_cpu_policy[cpu]) - return -EINVAL; - - ret = px_statistic_init(cpu); - if (ret) - return ret; - - dom = perf->domain_info.domain; - if (cpus_weight(cpufreq_dom_map[dom])) { - /* share policy with the first cpu since on same boat */ - firstcpu = first_cpu(cpufreq_dom_map[dom]); - policy = cpufreq_cpu_policy[firstcpu]; - - cpufreq_cpu_policy[cpu] = policy; - cpu_set(cpu, cpufreq_dom_map[dom]); - cpu_set(cpu, policy->cpus); - - printk(KERN_EMERG"adding CPU %u\n", cpu); - } else { - /* for the first cpu, setup policy and do init work */ - policy = xmalloc(struct cpufreq_policy); - if (!policy) { - px_statistic_exit(cpu); - return -ENOMEM; - } - memset(policy, 0, sizeof(struct cpufreq_policy)); - - cpufreq_cpu_policy[cpu] = policy; - cpu_set(cpu, cpufreq_dom_map[dom]); - cpu_set(cpu, policy->cpus); - - policy->cpu = cpu; - ret = cpufreq_driver->init(policy); - if (ret) - goto err1; - printk(KERN_EMERG"CPU %u initialization completed\n", cpu); - } - - /* - * After get full cpumap of the coordination domain, - * we can safely start gov here. - */ - if (cpus_weight(cpufreq_dom_map[dom]) == - perf->domain_info.num_processors) { - memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); - policy->governor = NULL; - ret = __cpufreq_set_policy(policy, &new_policy); - if (ret) - goto err2; - } - - return 0; - -err2: - cpufreq_driver->exit(policy); -err1: - for_each_cpu_mask(j, cpufreq_dom_map[dom]) { - cpufreq_cpu_policy[j] = NULL; - px_statistic_exit(j); - } - - cpus_clear(cpufreq_dom_map[dom]); - xfree(policy); - return ret; -} - -int cpufreq_del_cpu(unsigned int cpu) -{ - unsigned int dom; - 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)) - return 0; - - if (cpu_is_offline(cpu) || !cpufreq_cpu_policy[cpu]) - return -EINVAL; - - dom = perf->domain_info.domain; - policy = cpufreq_cpu_policy[cpu]; - - printk(KERN_EMERG"deleting CPU %u\n", cpu); - - /* for the first cpu of the domain, stop gov */ - if (cpus_weight(cpufreq_dom_map[dom]) == - perf->domain_info.num_processors) - __cpufreq_governor(policy, CPUFREQ_GOV_STOP); - - cpufreq_cpu_policy[cpu] = NULL; - cpu_clear(cpu, policy->cpus); - cpu_clear(cpu, cpufreq_dom_map[dom]); - px_statistic_exit(cpu); - - /* for the last cpu of the domain, clean room */ - /* It's safe here to free freq_table, drv_data and policy */ - if (!cpus_weight(cpufreq_dom_map[dom])) { - cpufreq_driver->exit(policy); - xfree(policy); - } - - return 0; -} - static int __init cpufreq_driver_init(void) { int ret = 0; diff --git a/xen/drivers/Makefile b/xen/drivers/Makefile index 805fe1f77b..e88cd2ffe8 100644 --- a/xen/drivers/Makefile +++ b/xen/drivers/Makefile @@ -1,4 +1,5 @@ subdir-y += char +subdir-y += cpufreq subdir-$(x86) += passthrough subdir-$(HAS_ACPI) += acpi subdir-$(HAS_VGA) += video diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile index cc6acbe5dd..7d108c43a9 100644 --- a/xen/drivers/acpi/Makefile +++ b/xen/drivers/acpi/Makefile @@ -4,6 +4,7 @@ subdir-y += utilities obj-y += tables.o obj-y += numa.o obj-y += osl.o +obj-y += pmstat.o obj-$(x86) += hwregs.o obj-$(x86) += reboot.o diff --git a/xen/arch/x86/acpi/pmstat.c b/xen/drivers/acpi/pmstat.c index e15b244b1b..1a0a052100 100644 --- a/xen/arch/x86/acpi/pmstat.c +++ b/xen/drivers/acpi/pmstat.c @@ -41,7 +41,7 @@ #include <public/sysctl.h> #include <acpi/cpufreq/cpufreq.h> -struct pm_px *__read_mostly px_statistic_data[NR_CPUS]; +struct pm_px *__read_mostly cpufreq_statistic_data[NR_CPUS]; extern uint32_t pmstat_get_cx_nr(uint32_t cpuid); extern int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat); @@ -84,7 +84,7 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op) uint64_t now, ct; uint64_t total_idle_ns; uint64_t tmp_idle_ns; - struct pm_px *pxpt = px_statistic_data[op->cpuid]; + struct pm_px *pxpt = cpufreq_statistic_data[op->cpuid]; if ( !pxpt ) return -ENODATA; @@ -122,7 +122,7 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op) case PMSTAT_reset_pxstat: { - px_statistic_reset(op->cpuid); + cpufreq_statistic_reset(op->cpuid); break; } diff --git a/xen/drivers/cpufreq/Makefile b/xen/drivers/cpufreq/Makefile new file mode 100644 index 0000000000..c91c25b715 --- /dev/null +++ b/xen/drivers/cpufreq/Makefile @@ -0,0 +1,3 @@ +obj-y += cpufreq.o +obj-y += cpufreq_ondemand.o +obj-y += utility.o diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c new file mode 100644 index 0000000000..d4dae5bfd3 --- /dev/null +++ b/xen/drivers/cpufreq/cpufreq.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> + * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> + * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> + * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com> + * + * Feb 2008 - Liu Jinsong <jinsong.liu@intel.com> + * 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/delay.h> +#include <xen/cpumask.h> +#include <xen/sched.h> +#include <xen/timer.h> +#include <xen/xmalloc.h> +#include <asm/bug.h> +#include <asm/msr.h> +#include <asm/io.h> +#include <asm/config.h> +#include <asm/processor.h> +#include <asm/percpu.h> +#include <asm/cpufeature.h> +#include <acpi/acpi.h> +#include <acpi/cpufreq/cpufreq.h> + +/* TODO: change to link list later as domain number may be sparse */ +static cpumask_t cpufreq_dom_map[NR_CPUS]; + +int cpufreq_limit_change(unsigned int cpu) +{ + struct processor_performance *perf = &processor_pminfo[cpu]->perf; + struct cpufreq_policy *data = cpufreq_cpu_policy[cpu]; + struct cpufreq_policy policy; + + if (!cpu_online(cpu) || !data || !processor_pminfo[cpu]) + return -ENODEV; + + if ((perf->platform_limit < 0) || + (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; + unsigned int j; + 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)) + return 0; + + if (cpu_is_offline(cpu) || cpufreq_cpu_policy[cpu]) + return -EINVAL; + + ret = cpufreq_statistic_init(cpu); + if (ret) + return ret; + + dom = perf->domain_info.domain; + if (cpus_weight(cpufreq_dom_map[dom])) { + /* share policy with the first cpu since on same boat */ + firstcpu = first_cpu(cpufreq_dom_map[dom]); + policy = cpufreq_cpu_policy[firstcpu]; + + cpufreq_cpu_policy[cpu] = policy; + cpu_set(cpu, cpufreq_dom_map[dom]); + cpu_set(cpu, policy->cpus); + + printk(KERN_EMERG"adding CPU %u\n", cpu); + } else { + /* for the first cpu, setup policy and do init work */ + policy = xmalloc(struct cpufreq_policy); + if (!policy) { + cpufreq_statistic_exit(cpu); + return -ENOMEM; + } + memset(policy, 0, sizeof(struct cpufreq_policy)); + + cpufreq_cpu_policy[cpu] = policy; + cpu_set(cpu, cpufreq_dom_map[dom]); + cpu_set(cpu, policy->cpus); + + policy->cpu = cpu; + ret = cpufreq_driver->init(policy); + if (ret) + goto err1; + printk(KERN_EMERG"CPU %u initialization completed\n", cpu); + } + + /* + * After get full cpumap of the coordination domain, + * we can safely start gov here. + */ + if (cpus_weight(cpufreq_dom_map[dom]) == + perf->domain_info.num_processors) { + memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); + policy->governor = NULL; + ret = __cpufreq_set_policy(policy, &new_policy); + if (ret) + goto err2; + } + + return 0; + +err2: + cpufreq_driver->exit(policy); +err1: + for_each_cpu_mask(j, cpufreq_dom_map[dom]) { + cpufreq_cpu_policy[j] = NULL; + cpufreq_statistic_exit(j); + } + + cpus_clear(cpufreq_dom_map[dom]); + xfree(policy); + return ret; +} + +int cpufreq_del_cpu(unsigned int cpu) +{ + unsigned int dom; + 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)) + return 0; + + if (cpu_is_offline(cpu) || !cpufreq_cpu_policy[cpu]) + return -EINVAL; + + dom = perf->domain_info.domain; + policy = cpufreq_cpu_policy[cpu]; + + printk(KERN_EMERG"deleting CPU %u\n", cpu); + + /* for the first cpu of the domain, stop gov */ + if (cpus_weight(cpufreq_dom_map[dom]) == + perf->domain_info.num_processors) + __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + + cpufreq_cpu_policy[cpu] = NULL; + cpu_clear(cpu, policy->cpus); + cpu_clear(cpu, cpufreq_dom_map[dom]); + cpufreq_statistic_exit(cpu); + + /* for the last cpu of the domain, clean room */ + /* It's safe here to free freq_table, drv_data and policy */ + if (!cpus_weight(cpufreq_dom_map[dom])) { + cpufreq_driver->exit(policy); + xfree(policy); + } + + return 0; +} + diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c b/xen/drivers/cpufreq/cpufreq_ondemand.c index f1b676c2f4..f1b676c2f4 100644 --- a/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c +++ b/xen/drivers/cpufreq/cpufreq_ondemand.c diff --git a/xen/arch/x86/acpi/cpufreq/utility.c b/xen/drivers/cpufreq/utility.c index 96606f17c0..eaf8ab8d33 100644 --- a/xen/arch/x86/acpi/cpufreq/utility.c +++ b/xen/drivers/cpufreq/utility.c @@ -39,7 +39,7 @@ struct cpufreq_policy *__read_mostly cpufreq_cpu_policy[NR_CPUS]; * Px STATISTIC INFO * *********************************************************************/ -void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to) +void cpufreq_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to) { uint32_t i; uint64_t now; @@ -47,7 +47,7 @@ void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to) now = NOW(); for_each_cpu_mask(i, cpumask) { - struct pm_px *pxpt = px_statistic_data[i]; + struct pm_px *pxpt = cpufreq_statistic_data[i]; struct processor_pminfo *pmpt = processor_pminfo[i]; uint64_t total_idle_ns; uint64_t tmp_idle_ns; @@ -71,10 +71,10 @@ void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to) } } -int px_statistic_init(unsigned int cpuid) +int cpufreq_statistic_init(unsigned int cpuid) { uint32_t i, count; - struct pm_px *pxpt = px_statistic_data[cpuid]; + struct pm_px *pxpt = cpufreq_statistic_data[cpuid]; const struct processor_pminfo *pmpt = processor_pminfo[cpuid]; count = pmpt->perf.state_count; @@ -88,7 +88,7 @@ int px_statistic_init(unsigned int cpuid) if ( !pxpt ) return -ENOMEM; memset(pxpt, 0, sizeof(*pxpt)); - px_statistic_data[cpuid] = pxpt; + cpufreq_statistic_data[cpuid] = pxpt; } pxpt->u.trans_pt = xmalloc_array(uint64_t, count * count); @@ -116,9 +116,9 @@ int px_statistic_init(unsigned int cpuid) return 0; } -void px_statistic_exit(unsigned int cpuid) +void cpufreq_statistic_exit(unsigned int cpuid) { - struct pm_px *pxpt = px_statistic_data[cpuid]; + struct pm_px *pxpt = cpufreq_statistic_data[cpuid]; if (!pxpt) return; @@ -127,10 +127,10 @@ void px_statistic_exit(unsigned int cpuid) memset(pxpt, 0, sizeof(struct pm_px)); } -void px_statistic_reset(unsigned int cpuid) +void cpufreq_statistic_reset(unsigned int cpuid) { uint32_t i, j, count; - struct pm_px *pxpt = px_statistic_data[cpuid]; + struct pm_px *pxpt = cpufreq_statistic_data[cpuid]; const struct processor_pminfo *pmpt = processor_pminfo[cpuid]; if ( !pxpt || !pmpt ) diff --git a/xen/include/acpi/cpufreq/cpufreq.h b/xen/include/acpi/cpufreq/cpufreq.h index 59ceac34f5..77824417ed 100644 --- a/xen/include/acpi/cpufreq/cpufreq.h +++ b/xen/include/acpi/cpufreq/cpufreq.h @@ -21,6 +21,13 @@ struct cpufreq_governor; +struct acpi_cpufreq_data { + struct processor_performance *acpi_data; + struct cpufreq_frequency_table *freq_table; + unsigned int max_freq; + unsigned int cpu_feature; +}; + struct cpufreq_cpuinfo { unsigned int max_freq; unsigned int min_freq; diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h index 75afcf3f23..1bec3c43e3 100644 --- a/xen/include/acpi/cpufreq/processor_perf.h +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -9,10 +9,10 @@ int get_cpu_id(u8); int powernow_cpufreq_init(void); -void px_statistic_update(cpumask_t, uint8_t, uint8_t); -int px_statistic_init(unsigned int); -void px_statistic_exit(unsigned int); -void px_statistic_reset(unsigned int); +void cpufreq_statistic_update(cpumask_t, uint8_t, uint8_t); +int cpufreq_statistic_init(unsigned int); +void cpufreq_statistic_exit(unsigned int); +void cpufreq_statistic_reset(unsigned int); int cpufreq_limit_change(unsigned int); @@ -58,6 +58,6 @@ struct pm_px { uint64_t prev_idle_wall; }; -extern struct pm_px *px_statistic_data[NR_CPUS]; +extern struct pm_px *cpufreq_statistic_data[NR_CPUS]; #endif /* __XEN_PROCESSOR_PM_H__ */ |