[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH v2 10/12] cpufreq: add dom0-cpufreq driver
This driver uses Dom0 to change frequencies on CPUs Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@xxxxxxxxxxxxxxx> --- xen/Rules.mk | 1 + xen/drivers/cpufreq/Makefile | 1 + xen/drivers/cpufreq/dom0-cpufreq.c | 241 +++++++++++++++++++++++++++++++++++++ xen/include/public/xen.h | 1 + 4 files changed, 244 insertions(+) create mode 100644 xen/drivers/cpufreq/dom0-cpufreq.c diff --git a/xen/Rules.mk b/xen/Rules.mk index 3b0b89b..8104f7b 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -56,6 +56,7 @@ CFLAGS-$(perfc_arrays) += -DPERF_ARRAYS CFLAGS-$(lock_profile) += -DLOCK_PROFILE CFLAGS-$(HAS_ACPI) += -DHAS_ACPI CFLAGS-$(HAS_CPUFREQ) += -DHAS_CPUFREQ +CFLAGS-$(HAS_DOM0_CPUFREQ) += -DHAS_DOM0_CPUFREQ CFLAGS-$(HAS_PM) += -DHAS_PM CFLAGS-$(HAS_CPU_TURBO) += -DHAS_CPU_TURBO CFLAGS-$(HAS_GDBSX) += -DHAS_GDBSX diff --git a/xen/drivers/cpufreq/Makefile b/xen/drivers/cpufreq/Makefile index b87d127..172bd51 100644 --- a/xen/drivers/cpufreq/Makefile +++ b/xen/drivers/cpufreq/Makefile @@ -2,3 +2,4 @@ obj-y += cpufreq.o obj-y += cpufreq_ondemand.o obj-y += cpufreq_misc_governors.o obj-y += utility.o +obj-$(HAS_DOM0_CPUFREQ) += dom0-cpufreq.o diff --git a/xen/drivers/cpufreq/dom0-cpufreq.c b/xen/drivers/cpufreq/dom0-cpufreq.c new file mode 100644 index 0000000..f4274d7 --- /dev/null +++ b/xen/drivers/cpufreq/dom0-cpufreq.c @@ -0,0 +1,241 @@ +/* + * 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/sched.h> +#include <xen/event.h> +#include <xen/irq.h> +#include <xen/spinlock.h> +#include <xen/cpufreq.h> +#include <asm/current.h> + +struct acpi_cpufreq_data *cpufreq_drv_data[NR_CPUS]; +static DEFINE_SPINLOCK(sysctl_cpufreq_lock); + +struct sysctl_cpufreq_data { + uint32_t cpu; + uint32_t freq; + uint32_t relation; + int32_t result; +}; + +static struct sysctl_cpufreq_data sysctl_cpufreq_data; + +int cpufreq_cpu_init(unsigned int cpuid) +{ + return cpufreq_add_cpu(cpuid); +} + +static void notify_cpufreq_domains(void) +{ + send_global_virq(VIRQ_CPUFREQ); +} + +static int dom0_cpufreq_verify(struct cpufreq_policy *policy) +{ + struct acpi_cpufreq_data *data; + struct processor_performance *perf; + + if ( !policy || !(data = cpufreq_drv_data[policy->cpu]) || + !processor_pminfo[policy->cpu] ) + return -EINVAL; + + perf = &processor_pminfo[policy->cpu]->perf; + + cpufreq_verify_within_limits(policy, 0, + perf->states[perf->platform_limit].core_frequency * 1000); + + return cpufreq_frequency_table_verify(policy, data->freq_table); +} + +static int dom0_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct acpi_cpufreq_data *data = cpufreq_drv_data[policy->cpu]; + struct processor_performance *perf; + struct cpufreq_freqs freqs; + cpumask_t online_policy_cpus; + unsigned int next_state = 0; /* Index into freq_table */ + unsigned int next_perf_state = 0; /* Index into perf table */ + unsigned int j; + int ret = 0; + + if ( unlikely(data == NULL || + data->acpi_data == NULL || data->freq_table == NULL) ) + { + return -ENODEV; + } + + perf = data->acpi_data; + ret = cpufreq_frequency_table_target(policy, + data->freq_table, + target_freq, + relation, &next_state); + if ( unlikely(ret) ) + return -ENODEV; + + cpumask_and(&online_policy_cpus, &cpu_online_map, policy->cpus); + + next_perf_state = data->freq_table[next_state].index; + if ( perf->state == next_perf_state ) + { + if ( unlikely(policy->resume) ) + policy->resume = 0; + else + return 0; + } + + freqs.old = perf->states[perf->state].core_frequency * 1000; + freqs.new = data->freq_table[next_state].frequency; + + /* Do send cmd for Dom0 */ + spin_lock(&sysctl_cpufreq_lock); + /* return previous result */ + ret = sysctl_cpufreq_data.result; + + sysctl_cpufreq_data.cpu = policy->cpu; + sysctl_cpufreq_data.freq = freqs.new; + sysctl_cpufreq_data.relation = (uint32_t)relation; + spin_unlock(&sysctl_cpufreq_lock); + notify_cpufreq_domains(); + + for_each_cpu( j, &online_policy_cpus ) + cpufreq_statistic_update(j, perf->state, next_perf_state); + + perf->state = next_perf_state; + policy->cur = freqs.new; + + return ret; +} + +static int +dom0_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + struct processor_performance *perf; + struct acpi_cpufreq_data *data; + unsigned int cpu = policy->cpu; + unsigned int valid_states = 0; + int i; + int ret = 0; + + data = xzalloc(struct acpi_cpufreq_data); + if ( !data ) + return -ENOMEM; + + cpufreq_drv_data[cpu] = data; + + data->acpi_data = &processor_pminfo[cpu]->perf; + + perf = data->acpi_data; + policy->shared_type = perf->shared_type; + + data->freq_table = xmalloc_array(struct cpufreq_frequency_table, + (perf->state_count+1)); + if ( !data->freq_table ) + { + ret = -ENOMEM; + goto err_unreg; + } + + /* detect transition latency */ + policy->cpuinfo.transition_latency = 0; + for ( i=0; i<perf->state_count; i++ ) + { + if ( (perf->states[i].transition_latency * 1000) > + policy->cpuinfo.transition_latency ) + policy->cpuinfo.transition_latency = + perf->states[i].transition_latency * 1000; + } + + policy->governor = cpufreq_opt_governor ? : CPUFREQ_DEFAULT_GOVERNOR; + + /* table init */ + for ( i=0; i<perf->state_count; i++ ) + { + if ( i>0 && perf->states[i].core_frequency >= + data->freq_table[valid_states-1].frequency / 1000 ) + continue; + + data->freq_table[valid_states].index = i; + data->freq_table[valid_states].frequency = + perf->states[i].core_frequency * 1000; + valid_states++; + } + data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END; + perf->state = 0; + + ret = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); + if ( ret ) + goto err_freqfree; + + + /* + * the first call to ->target() should result in us actually + * send command to the Dom0 to set frequency. + */ + policy->resume = 1; + + /* Set the minimal frequency */ + return dom0_cpufreq_target(policy, policy->min, CPUFREQ_RELATION_L); + +err_freqfree: + xfree(data->freq_table); +err_unreg: + xfree(data); + cpufreq_drv_data[cpu] = NULL; + + return ret; +} + +static int dom0_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + struct acpi_cpufreq_data *data = cpufreq_drv_data[policy->cpu]; + + if ( data ) + { + cpufreq_drv_data[policy->cpu] = NULL; + xfree(data->freq_table); + xfree(data); + } + + return 0; +} + +static struct cpufreq_driver dom0_cpufreq_driver = { + .name = "dom0-cpufreq", + .verify = dom0_cpufreq_verify, + .target = dom0_cpufreq_target, + .init = dom0_cpufreq_cpu_init, + .exit = dom0_cpufreq_cpu_exit, +}; + +int __init dom0_cpufreq_driver_init(void) +{ + int ret = 0; + + if ( cpufreq_controller == FREQCTL_xen ) + ret = cpufreq_register_driver(&dom0_cpufreq_driver); + + return ret; +} + +__initcall(dom0_cpufreq_driver_init); diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 8c5697e..14a593d 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -160,6 +160,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); #define VIRQ_MEM_EVENT 10 /* G. (DOM0) A memory event has occured */ #define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient */ #define VIRQ_ENOMEM 12 /* G. (DOM0) Low on heap memory */ +#define VIRQ_CPUFREQ 13 /* G. (DOM0) Notify dom0-cpufreq driver. */ /* Architecture-specific VIRQ definitions. */ #define VIRQ_ARCH_0 16 -- 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 |