Hi Charles, At first I did looked in the hrtimers API to do so, but it seems that significant hacking would be required to provide what is needed for vcpufreq to work; That is:
1) Steering of the timer interrupt to a given CPU 2) Making sure that the timer callback is called in an interrupt context. I am specifically interested in getting vcpufreq to work on TI SoCs anyway, and using dm timers was painless comparatively. However if someone wants to take stab at implementing this in a portable manner shouldn't be too hard, since the platform glue is nicely abstracted with just 3 functions to implement. Regards -- Pantelis On Jun 20, 2012, at 10:56 AM, Charles Garcia-Tobin wrote: > Hi > > This is exactly the sort of technique I was proposing, but I was wondering > whether there is a generic timer API that could be used. I was thinking > hrtimer but profess no knowledge here. Such an approach would make it usable > on all boards. > > Cheers > > Charles > > >> -----Original Message----- >> From: Amit Kucheria [mailto:amit.kuche...@linaro.org] >> Sent: 20 June 2012 06:30 >> To: Pantelis Antoniou >> Cc: santosh.shilim...@ti.com; linaro-dev@lists.linaro.org; >> vbars...@dev.rtsoft.ru; Rob Lee; Charles Garcia-Tobin >> Subject: Re: [PATCH] [CPUFREQ] VCPUfreq: Virtual CPU frequency driver. >> >> Panto, >> >> This looks interesting. cc'ing Rob and Charles who were interested in >> this at Connect. >> >> /Amit >> >> On Thu, Jun 21, 2012 at 3:15 AM, Pantelis Antoniou >> <pa...@antoniou-consulting.com> wrote: >>> Many current interesting systems have no ability to simulate the upcoming >>> bigLITTLE machines, since their cores have to be clocked at the same speeds. >>> >>> Using this driver it is possible to simulate a bigLITTLE system by means >>> of a standard (virtual) cpufreq driver. >>> >>> By using a timer per core & irq affinity it is possible to do something >>> like this: >>> >>> $ cpucycle cpu0 >>> 90403235 >>> $ cpucycle cpu1 >>> 89810456 >>> $ cd /sys/devices/system/cpu/cpu0/cpufreq >>> $ cat scaling_available_frequencies >>> 233325 466651 699977 >>> $ echo 466651 > scaling_setspeed >>> $ cpucycle cpu0 >>> 58936083 >>> >>> Note that the ratios are about the same so it is somewhat accurate. >>> 4666651 / 699977 =~ 0.666 >>> 58936083 / 90403235 =~ 0.652 >>> >>> The available tunables available as module parameters are: >>> >>> freq: >>> Normal maximum CPU frequency in kHz >>> When 0, then the platform glue layer should probe for it. >>> default 0 >>> >>> hogtime: >>> Amount of time in usecs that the timer interrupt handler will hog >>> the CPU. Note this is time spend spinning in an IRQ handler, so >>> it should be as low as possible. A higher value result in more >>> accurate simulation. >>> Default 100 >>> >>> latency: >>> Simulated latency in usecs of cpu freq change. >>> Default 500 >>> >>> splits: >>> Number of splits in the frequency value. For example when freq is >>> 1000000 and splits is 2 then two frequency OPPs will be generated, >>> one in 500000 and one in 1000000. >>> >>> Only one glue layer for omap2plus is provided, but it should be trivial to >>> add more for other platforms. >>> --- >>> drivers/cpufreq/Kconfig | 26 ++++ >>> drivers/cpufreq/Makefile | 5 + >>> drivers/cpufreq/vcpufreq-omap.c | 251 >> +++++++++++++++++++++++++++++++++++++++ >>> drivers/cpufreq/vcpufreq.c | 216 +++++++++++++++++++++++++++++++++ >>> drivers/cpufreq/vcpufreq.h | 25 ++++ >>> 5 files changed, 523 insertions(+), 0 deletions(-) >>> create mode 100644 drivers/cpufreq/vcpufreq-omap.c >>> create mode 100644 drivers/cpufreq/vcpufreq.c >>> create mode 100644 drivers/cpufreq/vcpufreq.h >>> >>> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig >>> index e24a2a1..1fef0ad 100644 >>> --- a/drivers/cpufreq/Kconfig >>> +++ b/drivers/cpufreq/Kconfig >>> @@ -194,5 +194,31 @@ depends on PPC32 || PPC64 >>> source "drivers/cpufreq/Kconfig.powerpc" >>> endmenu >>> >>> +config VCPUFREQ >>> + bool "Virtual CPU freq driver" >>> + depends on CPU_FREQ >>> + select CPU_FREQ_TABLE >>> + help >>> + This driver implements a cycle-soaker cpufreq driver. >>> + >>> + To compile this driver as a module, choose M here: the >>> + module will be called vcpufreq. >>> + >>> + If in doubt, say N. >>> + >>> +if VCPUFREQ >>> + >>> +choice >>> + prompt "VCPUFREQ Platform glue Layer" >>> + >>> +config VCPUFREQ_OMAP2PLUS >>> + bool "OMAP VCPUFREQ driver" >>> + depends on ARCH_OMAP2PLUS >>> + >>> +endchoice >>> + >>> +endif >>> + >>> endif >>> + >>> endmenu >>> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile >>> index 9531fc2..97d3011 100644 >>> --- a/drivers/cpufreq/Makefile >>> +++ b/drivers/cpufreq/Makefile >>> @@ -52,3 +52,8 @@ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o >>> >> ############################################################################# >> ##### >>> # PowerPC platform drivers >>> obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o >>> + >>> >> +############################################################################# >> ##### >>> +# Virtual driver >>> +obj-$(CONFIG_VCPUFREQ) += vcpufreq.o >>> +obj-$(CONFIG_VCPUFREQ_OMAP2PLUS) += vcpufreq-omap.o >>> diff --git a/drivers/cpufreq/vcpufreq-omap.c b/drivers/cpufreq/vcpufreq- >> omap.c >>> new file mode 100644 >>> index 0000000..fd789c4 >>> --- /dev/null >>> +++ b/drivers/cpufreq/vcpufreq-omap.c >>> @@ -0,0 +1,251 @@ >>> +/* >>> + * Copyright 2012 Pantelis Antoniou <pa...@antoniou-consulting.com> >>> + * >>> + * Virtual CPUFreq glue driver for OMAP2PLUS >>> + * >>> + * 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. >>> + */ >>> + >>> +#define pr_fmt(fmt) "cpufreq: " fmt >>> + >>> +#include <linux/kernel.h> >>> +#include <linux/types.h> >>> +#include <linux/init.h> >>> +#include <linux/cpufreq.h> >>> +#include <linux/clk.h> >>> +#include <linux/err.h> >>> +#include <linux/module.h> >>> +#include <linux/slab.h> >>> +#include <linux/interrupt.h> >>> +#include <linux/irq.h> >>> +#include <linux/math64.h> >>> +#include <linux/delay.h> >>> + >>> +#include <asm/smp_plat.h> >>> +#include <asm/cpu.h> >>> +#include <plat/cpu.h> >>> +#include <plat/dmtimer.h> >>> + >>> +#include "vcpufreq.h" >>> + >>> +struct omap_timer_info { >>> + unsigned int cpu; >>> + struct omap_dm_timer *dm_timer; >>> + unsigned int irq; >>> + uint64_t counter; >>> + char irqname[16]; /* vcpufreq%d */ >>> + unsigned int hwtimer_rate; >>> + unsigned int hog_delta; >>> +}; >>> + >>> +static DEFINE_PER_CPU(struct omap_timer_info, omap_timer); >>> + >>> +static irqreturn_t dm_timer_handler(int irq, void *dev_id) >>> +{ >>> + struct omap_timer_info *oti = dev_id; >>> + unsigned int status; >>> + unsigned int start; >>> + >>> + BUG_ON(oti == NULL); >>> + BUG_ON(oti->dm_timer == NULL); >>> + >>> + status = omap_dm_timer_read_status(oti->dm_timer); >>> + if (status & OMAP_TIMER_INT_OVERFLOW) { >>> + omap_dm_timer_write_status(oti->dm_timer, >>> + OMAP_TIMER_INT_OVERFLOW); >>> + omap_dm_timer_read_status(oti->dm_timer); >>> + oti->counter++; >>> + >>> + /* >>> + * udelay is really crap for this; no accuracy whatsoever >>> + * so use the nice hardware counter and be happy >>> + */ >>> + start = omap_dm_timer_read_counter(oti->dm_timer); >>> + while ((omap_dm_timer_read_counter(oti->dm_timer) - start) >>> + < oti->hog_delta) >>> + ; /* do nothing */ >>> + >>> + return IRQ_HANDLED; >>> + } >>> + >>> + return IRQ_NONE; >>> +} >>> + >>> +int vcpufreq_glue_set_freq(unsigned int cpu, unsigned int new_freq, >>> + unsigned int old_freq) >>> +{ >>> + struct omap_timer_info __percpu *oti = &per_cpu(omap_timer, cpu); >>> + int ret = 0; >>> + uint32_t rate; >>> + unsigned int hog_timer_rate; >>> + unsigned int freq = vcpufreq_get_maxspeed(); >>> + unsigned int hogtime = vcpufreq_get_hogtime(); >>> + >>> + /* should never happen; checked before */ >>> + BUG_ON(new_freq == old_freq); >>> + >>> + /* max freq; stop the timer */ >>> + if (new_freq == freq) { >>> + pr_debug("#%d: shut down timer\n", cpu); >>> + /* no error */ >>> + ret = 0; >>> + goto omap_stop_timer; >>> + >>> + } >>> + >>> + /* timer was stopped, we should start it */ >>> + if (old_freq == freq) { >>> + >>> + oti->cpu = cpu; >>> + >>> + /* get any omap timer */ >>> + oti->dm_timer = omap_dm_timer_request(); >>> + if (oti->dm_timer == NULL) { >>> + pr_err("#%d: No available omap timers\n", cpu); >>> + ret = -ENODEV; >>> + goto omap_stop_timer; >>> + } >>> + >>> + pr_debug("#%d: got omap timer with id %d\n", cpu, oti- >>> dm_timer->id); >>> + >>> + /* source it from SYS_CLK */ >>> + ret = omap_dm_timer_set_source(oti->dm_timer, >> OMAP_TIMER_SRC_SYS_CLK); >>> + if (ret != 0) { >>> + pr_err("#%d: omap_dm_timer_set_source() failed\n", >> cpu); >>> + goto omap_stop_timer; >>> + } >>> + >>> + /* set the prescaler to 0 (need a fast timer) */ >>> + ret = omap_dm_timer_set_prescaler(oti->dm_timer, 0); >>> + if (ret != 0) { >>> + pr_err("#%d: omap_dm_timer_set_prescaler() >> failed\n", cpu); >>> + goto omap_stop_timer; >>> + } >>> + >>> + /* get the irq */ >>> + ret = omap_dm_timer_get_irq(oti->dm_timer); >>> + if (ret < 0) { >>> + pr_err("#%d: omap_dm_timer_get_irq() failed\n", >> cpu); >>> + goto omap_stop_timer; >>> + } >>> + oti->irq = ret; >>> + >>> + snprintf(oti->irqname, sizeof(oti->irqname), "vcpufreq%u", >> cpu); >>> + ret = request_irq(oti->irq, dm_timer_handler, >>> + IRQF_DISABLED | IRQF_TIMER, oti->irqname, >> oti); >>> + if (ret < 0) { >>> + pr_err("#%d: failed to request percpu irq %d >> (%d)\n", cpu, >>> + oti->irq, ret); >>> + goto omap_stop_timer; >>> + } >>> + } else >>> + omap_dm_timer_stop(oti->dm_timer); >>> + >>> + /* common in either case */ >>> + oti->hwtimer_rate = clk_get_rate(omap_dm_timer_get_fclk(oti- >>> dm_timer)); >>> + if (oti->hwtimer_rate == 0) { >>> + pr_err("#%d: illegal timer fclk rate\n", cpu); >>> + goto omap_stop_timer; >>> + } >>> + pr_debug("#%d: hwtimer_rate=%u/sec (period %uns)", cpu, >>> + oti->hwtimer_rate, 1000000000 / oti->hwtimer_rate); >>> + >>> + oti->hog_delta = div_u64((u64)oti->hwtimer_rate * (u64)hogtime, >> 1000000); >>> + pr_debug("#%d: hog_delta = %u\n", cpu, oti->hog_delta); >>> + >>> + /* rate of hog timer */ >>> + hog_timer_rate = div_u64((u64)(freq - new_freq) * 1000000, freq * >> hogtime); >>> + pr_debug("#%d: hog timer rate = %u\n", cpu, hog_timer_rate); >>> + >>> + rate = (oti->hwtimer_rate + (hog_timer_rate / 2)) / hog_timer_rate; >>> + pr_debug("#%d: hw timer rate = %u\n", cpu, rate); >>> + >>> + omap_dm_timer_set_load(oti->dm_timer, 1, 0xFFFFFFFF - rate); >>> + >>> + /* first start */ >>> + if (old_freq == freq) { >>> + /* enable the interrupt on overflow */ >>> + omap_dm_timer_set_int_enable(oti->dm_timer, >>> + OMAP_TIMER_INT_OVERFLOW); >>> + /* route the interrupt to a given cpu */ >>> + irq_set_affinity(oti->irq, cpumask_of(cpu)); >>> + } >>> + >>> + omap_dm_timer_start(oti->dm_timer); >>> + >>> + vcpufreq_set_speed(cpu, new_freq); >>> + return 0; >>> + >>> +omap_stop_timer: >>> + /* clear everything */ >>> + if (oti->dm_timer) { >>> + >>> + omap_dm_timer_stop(oti->dm_timer); >>> + if (oti->irq != (unsigned int)-1) { >>> + free_irq(oti->irq, oti); >>> + oti->irq = -1; >>> + } >>> + omap_dm_timer_free(oti->dm_timer); >>> + >>> + /* clean up */ >>> + memset(oti, 0, sizeof(*oti)); >>> + oti->irq = (unsigned int)-1; >>> + } >>> + >>> + /* always return to max speed here */ >>> + vcpufreq_set_speed(cpu, freq); >>> + return ret; >>> +} >>> + >>> +int vcpufreq_glue_init(struct cpufreq_policy *policy, int *freq) >>> +{ >>> + struct omap_timer_info __percpu *oti; >>> + int ret = 0; >>> + struct clk *mpu_clk; >>> + const char *mpu_clk_name = NULL; >>> + >>> + BUG_ON(freq == NULL); >>> + >>> + /* if no freq was provided, probe */ >>> + if (*freq == 0) { >>> + if (cpu_is_omap24xx()) >>> + mpu_clk_name = "virt_prcm_set"; >>> + else if (cpu_is_omap34xx()) >>> + mpu_clk_name = "dpll1_ck"; >>> + else if (cpu_is_omap44xx()) >>> + mpu_clk_name = "dpll_mpu_ck"; >>> + >>> + if (mpu_clk_name == NULL) { >>> + pr_err("%s: Unknown mpu_clk_name (unsupported)\n", >>> + __func__); >>> + ret = -EINVAL; >>> + goto error_out; >>> + } >>> + mpu_clk = clk_get(NULL, mpu_clk_name); >>> + if (IS_ERR(mpu_clk)) { >>> + ret = PTR_ERR(mpu_clk); >>> + pr_err("%s: clk_get for '%s' failed\n", __func__, >>> + mpu_clk_name); >>> + goto error_out; >>> + } >>> + /* update freq */ >>> + *freq = clk_get_rate(mpu_clk) / 1000; >>> + } >>> + >>> + /* initialize per cpu structure */ >>> + oti = &per_cpu(omap_timer, policy->cpu); >>> + memset(oti, 0, sizeof(*oti)); >>> + oti->irq = (unsigned int)-1; >>> + >>> + ret = 0; >>> + >>> +error_out: >>> + return ret; >>> +} >>> + >>> +int vcpufreq_glue_exit(struct cpufreq_policy *policy) >>> +{ >>> + return 0; >>> +} >>> diff --git a/drivers/cpufreq/vcpufreq.c b/drivers/cpufreq/vcpufreq.c >>> new file mode 100644 >>> index 0000000..b5ded3f >>> --- /dev/null >>> +++ b/drivers/cpufreq/vcpufreq.c >>> @@ -0,0 +1,216 @@ >>> +/* >>> + * Copyright 2012 Pantelis Antoniou <pa...@antoniou-consulting.com> >>> + * >>> + * Virtual CPUFreq driver; allows usage of normal SMP systems for >>> + * asymmetric processing evaluation. >>> + * >>> + * 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. >>> + */ >>> + >>> +#define pr_fmt(fmt) "cpufreq: " fmt >>> + >>> +#include <linux/kernel.h> >>> +#include <linux/types.h> >>> +#include <linux/init.h> >>> +#include <linux/cpufreq.h> >>> +#include <linux/clk.h> >>> +#include <linux/err.h> >>> +#include <linux/module.h> >>> +#include <linux/slab.h> >>> +#include <linux/interrupt.h> >>> +#include <linux/irq.h> >>> +#include <linux/math64.h> >>> +#include <linux/delay.h> >>> + >>> +#include "vcpufreq.h" >>> + >>> +static struct cpufreq_frequency_table *vfreq_table = NULL; >>> + >>> +static unsigned int latency = 500; >>> +static unsigned int splits = 3; >>> +static unsigned int freq = 0; /* default 1GHz */ >>> +static unsigned int hogtime = 100; >>> + >>> +static DEFINE_PER_CPU(unsigned int, curfreq); >>> + >>> +static int vcpufreq_verify_speed(struct cpufreq_policy *policy) >>> +{ >>> + BUG_ON(vfreq_table == NULL); >>> + return cpufreq_frequency_table_verify(policy, vfreq_table); >>> +} >>> + >>> +unsigned int vcpufreq_get_speed(unsigned int cpu) >>> +{ >>> + return per_cpu(curfreq, cpu); >>> +} >>> + >>> +void vcpufreq_set_speed(unsigned int cpu, unsigned int new_freq) >>> +{ >>> + per_cpu(curfreq, cpu) = new_freq; >>> +} >>> + >>> +unsigned int vcpufreq_get_maxspeed(void) >>> +{ >>> + return freq; >>> +} >>> + >>> +unsigned int vcpufreq_get_hogtime(void) >>> +{ >>> + return hogtime; >>> +} >>> + >>> +static int vcpufreq_set_target(struct cpufreq_policy *policy, >>> + unsigned int target_freq, >>> + unsigned int relation) >>> +{ >>> + int ret; >>> + unsigned int i; >>> + struct cpufreq_freqs freqs; >>> + >>> + BUG_ON(vfreq_table == NULL); >>> + >>> + ret = cpufreq_frequency_table_target(policy, vfreq_table, >>> + target_freq, relation, &i); >>> + if (ret != 0) >>> + return ret; >>> + >>> + memset(&freqs, 0, sizeof(freqs)); >>> + freqs.cpu = policy->cpu; >>> + freqs.old = vcpufreq_get_speed(policy->cpu); >>> + freqs.new = vfreq_table[i].frequency; >>> + >>> + if (freqs.old == freqs.new && policy->cur == freqs.new) >>> + return 0; >>> + >>> + /* the CPUs are free-clocked */ >>> + freqs.cpu = policy->cpu; >>> + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); >>> + >>> + pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new); >>> + >>> + /* nothing */ >>> + if (freqs.new == freqs.old) { >>> + pr_err("#%d: same freq %u\n", policy->cpu, freqs.new); >>> + ret = -EAGAIN; >>> + goto error_out; >>> + } >>> + >>> + ret = vcpufreq_glue_set_freq(policy->cpu, freqs.new, freqs.old); >>> + >>> +error_out: >>> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); >>> + >>> + return ret; >>> +} >>> + >>> +static int __cpuinit vcpufreq_driver_init(struct cpufreq_policy *policy) >>> +{ >>> + int ret; >>> + unsigned int i; >>> + >>> + ret = vcpufreq_glue_init(policy, &freq); >>> + if (ret != 0) { >>> + pr_err("%s: vcpufreq_glue_init() failed\n", __func__); >>> + goto error_out; >>> + } >>> + >>> + if (splits < 1) { >>> + pr_err("%s: Illegal splits value (%u)\n", __func__, splits); >>> + ret = -EINVAL; >>> + goto error_out; >>> + } >>> + >>> + vfreq_table = kmalloc(sizeof(*vfreq_table) * (splits + 1), >> GFP_KERNEL); >>> + if (vfreq_table == NULL) { >>> + pr_err("Failed to allocate frequency table: %d\n", >>> + ret); >>> + ret = -ENOMEM; >>> + goto error_out; >>> + } >>> + >>> + /* 0 .. splits-1 */ >>> + for (i = 0; i < splits; i++) { >>> + vfreq_table[i].index = i; >>> + vfreq_table[i].frequency = (freq * (i + 1)) / splits; >>> + } >>> + /* splits-1 */ >>> + vfreq_table[i].index = i; >>> + vfreq_table[i].frequency = freq; >>> + >>> + /* ends */ >>> + vfreq_table[i].index = i; >>> + vfreq_table[i].frequency = CPUFREQ_TABLE_END; >>> + >>> + ret = cpufreq_frequency_table_cpuinfo(policy, vfreq_table); >>> + if (ret != 0) { >>> + pr_err("Failed to configure frequency table: %d\n", >>> + ret); >>> + goto error_out; >>> + } >>> + >>> + cpufreq_frequency_table_get_attr(vfreq_table, policy->cpu); >>> + >>> + policy->min = policy->cpuinfo.min_freq; >>> + policy->max = policy->cpuinfo.max_freq; >>> + >>> + /* always start at the max */ >>> + per_cpu(curfreq, policy->cpu) = freq; >>> + >>> + policy->cur = per_cpu(curfreq, policy->cpu); >>> + policy->cpuinfo.transition_latency = latency; >>> + >>> + pr_info("#%d: Virtual CPU frequency driver initialized\n", policy- >>> cpu); >>> + >>> + return 0; >>> + >>> +error_out: >>> + kfree(vfreq_table); >>> + vfreq_table = NULL; >>> + return ret; >>> +} >>> + >>> +static int __cpuexit vcpufreq_driver_exit(struct cpufreq_policy *policy) >>> +{ >>> + kfree(vfreq_table); >>> + vfreq_table = NULL; >>> + vcpufreq_glue_exit(policy); >>> + >>> + return 0; >>> +} >>> + >>> +static struct freq_attr *vcpufreq_attr[] = { >>> + &cpufreq_freq_attr_scaling_available_freqs, >>> + NULL, >>> +}; >>> + >>> +static struct cpufreq_driver vcpufreq_driver = { >>> + .owner = THIS_MODULE, >>> + .flags = CPUFREQ_CONST_LOOPS, >>> + .verify = vcpufreq_verify_speed, >>> + .target = vcpufreq_set_target, >>> + .get = vcpufreq_get_speed, >>> + .init = vcpufreq_driver_init, >>> + .exit = vcpufreq_driver_exit, >>> + .name = "vcpufreq", >>> + .attr = vcpufreq_attr, >>> +}; >>> + >>> +static int __init vcpufreq_init(void) >>> +{ >>> + return cpufreq_register_driver(&vcpufreq_driver); >>> +} >>> +module_init(vcpufreq_init); >>> + >>> +module_param(latency, uint, 0644); >>> +MODULE_PARM_DESC(latency, "Transition latency in usecs (default 500)"); >>> + >>> +module_param(splits, uint, 0644); >>> +MODULE_PARM_DESC(splits, "Number of frequency splits (default 2)"); >>> + >>> +module_param(freq, uint, 0644); >>> +MODULE_PARM_DESC(freq, "Maximum frequency in kHz (0 means platform >> detect)"); >>> + >>> +module_param(hogtime, uint, 0644); >>> +MODULE_PARM_DESC(hogtime, "Time spend hogging the CPU in the IRQ handle in >> usec (default 10)"); >>> diff --git a/drivers/cpufreq/vcpufreq.h b/drivers/cpufreq/vcpufreq.h >>> new file mode 100644 >>> index 0000000..6135b23 >>> --- /dev/null >>> +++ b/drivers/cpufreq/vcpufreq.h >>> @@ -0,0 +1,25 @@ >>> +#ifndef __VCPUFREQ_H >>> +#define __VCPUFREQ_H >>> + >>> +/* >>> + * Copyright 2012 Pantelis Antoniou <pa...@antoniou-consulting.com> >>> + * >>> + * Virtual CPUFreq driver header. >>> + * >>> + * 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. >>> + */ >>> + >>> +/* provided by the glue layer */ >>> +int vcpufreq_glue_set_freq(unsigned int cpu, unsigned int new_freq, >>> + unsigned int old_freq); >>> +int vcpufreq_glue_init(struct cpufreq_policy *policy, int *freq); >>> +int vcpufreq_glue_exit(struct cpufreq_policy *policy); >>> + >>> +/* provided by the core */ >>> +unsigned int vcpufreq_get_maxspeed(void); >>> +unsigned int vcpufreq_get_hogtime(void); >>> +void vcpufreq_set_speed(unsigned int cpu, unsigned int new_freq); >>> + >>> +#endif >>> -- >>> 1.7.1 >>> >>> >>> _______________________________________________ >>> linaro-dev mailing list >>> linaro-dev@lists.linaro.org >>> http://lists.linaro.org/mailman/listinfo/linaro-dev > > > -- IMPORTANT NOTICE: The contents of this email and any attachments are > confidential and may also be privileged. If you are not the intended > recipient, please notify the sender immediately and do not disclose the > contents to any other person, use it for any purpose, or store or copy the > information in any medium. Thank you. > _______________________________________________ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev