diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-03-30 11:36:25 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-03-30 11:36:25 +0800 |
commit | 88f08b421c91f2d4db3a110e5e3a86d64e2b40c9 (patch) | |
tree | e3af9f0bf2a355fd69119ae9b680371d39012a2d /drivers/cpufreq | |
parent | 6cf2f136f3df6fad82ddabd89d93c53181564274 (diff) | |
parent | f53c766e85d69add6a26d6f3e233dec6dc98de1e (diff) |
Merge remote branch 'fsl-linux-sdk/imx_3.0.15' into imx_3.0.15_4.6.6
Conflicts:
arch/arm/configs/imx6_defconfig
arch/arm/configs/imx6_updater_defconfig
arch/arm/mach-mx6/board-mx6q_sabreauto.c
arch/arm/mach-mx6/board-mx6q_sabresd.c
arch/arm/mach-mx6/clock.c
arch/arm/mach-mx6/localtimer.c
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq_interactive.c
drivers/input/keyboard/gpio_keys.c
drivers/media/video/mxc/capture/Kconfig
drivers/media/video/mxc/capture/mxc_v4l2_capture.c
drivers/mmc/card/block.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
drivers/usb/otg/fsl_otg.c
drivers/video/mxc/mxc_ipuv3_fb.c
include/linux/fsl_devices.h
include/linux/mmc/host.h
sound/soc/imx/Kconfig
sound/soc/imx/Makefile
sound/soc/imx/imx-hdmi-dma.c
sound/soc/imx/imx-wm8958.c
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/cpufreq_interactive.c | 137 |
1 files changed, 133 insertions, 4 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 45266d5b6cd5..1fa2889d4dbc 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -2,6 +2,7 @@ * drivers/cpufreq/cpufreq_interactive.c * * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2012 Freescale Semiconductor, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -27,6 +28,7 @@ #include <linux/workqueue.h> #include <linux/kthread.h> #include <linux/mutex.h> +#include <linux/kernel_stat.h> #include <asm/cputime.h> @@ -69,13 +71,15 @@ static unsigned long go_hispeed_load; /* * The minimum amount of time to spend at a frequency before we can ramp down. */ -#define DEFAULT_MIN_SAMPLE_TIME 20 * USEC_PER_MSEC +#define DEFAULT_MIN_SAMPLE_TIME (20 * USEC_PER_MSEC) static unsigned long min_sample_time; /* * The sample rate of the timer used to increase frequency */ -#define DEFAULT_TIMER_RATE 20 * USEC_PER_MSEC +#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC) +#define CPUFREQ_IRQ_LEN 60 +#define CPUFREQ_NOTE_LEN 120 static unsigned long timer_rate; static int cpufreq_governor_interactive(struct cpufreq_policy *policy, @@ -91,6 +95,45 @@ struct cpufreq_governor cpufreq_gov_interactive = { .owner = THIS_MODULE, }; +static struct irq_tuner irq_tuner_ins[MAX_CPUFREQ_IRQ_NUMBER]; +static struct irq_desc *cpufreq_irq_desc[MAX_CPUFREQ_IRQ_NUMBER]; + +static bool cpufreq_interactive_check_irq(void) +{ + bool val; + unsigned int irq_count = 0, i; + static unsigned int irq_count_start[MAX_CPUFREQ_IRQ_NUMBER]; + static unsigned int irq_count_end[MAX_CPUFREQ_IRQ_NUMBER]; + + val = false; + for (i = 0; i < MAX_CPUFREQ_IRQ_NUMBER; i++) { + if (irq_tuner_ins[i].irq_number == 0) + break; + if (!irq_tuner_ins[i].enable) + continue; + if (irq_count_start[i] == 0) + irq_count_start[i] = cpufreq_irq_desc[i] && + cpufreq_irq_desc[i]->kstat_irqs ? + *per_cpu_ptr(cpufreq_irq_desc[i]->kstat_irqs, 0) : 0; + else if (irq_count_end[i] == 0) + irq_count_end[i] = cpufreq_irq_desc[i] && + cpufreq_irq_desc[i]->kstat_irqs ? + *per_cpu_ptr(cpufreq_irq_desc[i]->kstat_irqs, 0) : 0; + else { + irq_count = irq_count_end[i] - irq_count_start[i]; + irq_count_start[i] = irq_count_end[i]; + irq_count_end[i] = 0; + } + if (irq_count > irq_tuner_ins[i].up_threshold) { + irq_count = 0; + val = true; + break; + } + } + + return val; +} + static void cpufreq_interactive_timer(unsigned long data) { unsigned int delta_idle; @@ -105,6 +148,7 @@ static void cpufreq_interactive_timer(unsigned long data) unsigned int new_freq; unsigned int index; unsigned long flags; + bool irq_load; smp_rmb(); @@ -163,11 +207,14 @@ static void cpufreq_interactive_timer(unsigned long data) if (load_since_change > cpu_load) cpu_load = load_since_change; - if (cpu_load >= go_hispeed_load) { + irq_load = cpufreq_interactive_check_irq(); + if (cpu_load >= go_hispeed_load || irq_load) { if (pcpu->policy->cur == pcpu->policy->min) new_freq = hispeed_freq; else new_freq = pcpu->policy->max * cpu_load / 100; + if (irq_load) + new_freq = hispeed_freq; } else { new_freq = pcpu->policy->cur * cpu_load / 100; } @@ -521,11 +568,55 @@ static ssize_t store_timer_rate(struct kobject *kobj, static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644, show_timer_rate, store_timer_rate); +static ssize_t show_irq_param(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + int i, j = 0; + j += scnprintf(&buf[j], CPUFREQ_NOTE_LEN, "Change irq setting by echo a data, format: 0xAABBBC, AA:irq number, BBB:up_threshold, C:enable\n"); + for (i = 0; i < MAX_CPUFREQ_IRQ_NUMBER; i++) { + if (irq_tuner_ins[i].irq_number != 0) + j += scnprintf(&buf[j], CPUFREQ_IRQ_LEN, "irq number: %d, up_threshold %d, %s\n", irq_tuner_ins[i].irq_number, irq_tuner_ins[i].up_threshold, irq_tuner_ins[i].enable ? "enabled" : "disabled"); + } + + return j; +} + +static ssize_t store_irq_param(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + int ret, i; + unsigned long val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + + for (i = 0; i < MAX_CPUFREQ_IRQ_NUMBER; i++) { + if (irq_tuner_ins[i].irq_number == val >> 16) + break; + } + + if (i >= MAX_CPUFREQ_IRQ_NUMBER) { + printk(KERN_WARNING "Invalid irq number!\n"); + return -EINVAL; + } + irq_tuner_ins[i].irq_number = val >> 16; + irq_tuner_ins[i].up_threshold = (val & 0xFFF0) >> 4; + irq_tuner_ins[i].enable = (val & 0xF) ? true : false; + + return count; +} + + +static struct global_attr irq_param_attr = __ATTR(irq_scaling, 0644, + show_irq_param, store_irq_param); + static struct attribute *interactive_attributes[] = { &hispeed_freq_attr.attr, &go_hispeed_load_attr.attr, &min_sample_time_attr.attr, &timer_rate_attr.attr, + &irq_param_attr.attr, NULL, }; @@ -664,7 +755,7 @@ static int __init cpufreq_interactive_init(void) /* No rescuer thread, bind to CPU queuing the work for possibly warm cache (probably doesn't matter much). */ - down_wq = alloc_workqueue("knteractive_down", 0, 1); + down_wq = alloc_workqueue("kinteractive_down", 0, 1); if (!down_wq) goto err_freeuptask; @@ -685,6 +776,44 @@ err_freeuptask: return -ENOMEM; } +int cpufreq_gov_irq_tuner_register(struct irq_tuner dbs_irq_tuner) +{ + int i, ret = 0; + static bool init_flag; + + /* Init the global irq_tuner_ins structure */ + if (!init_flag) { + for (i = 0; i < MAX_CPUFREQ_IRQ_NUMBER; i++) { + irq_tuner_ins[i].irq_number = 0; + irq_tuner_ins[i].up_threshold = 0; + irq_tuner_ins[i].enable = 0; + } + init_flag = true; + } + + if (dbs_irq_tuner.irq_number == 0) + return -EINVAL; + /* Find an unused struct */ + for (i = 0; i < MAX_CPUFREQ_IRQ_NUMBER; i++) { + if (irq_tuner_ins[i].irq_number != 0) + continue; + else + break; + } + /* Check index */ + if (i >= MAX_CPUFREQ_IRQ_NUMBER) { + printk(KERN_WARNING "Too many irq number requested!\n"); + return -EINVAL; + } + + irq_tuner_ins[i].irq_number = dbs_irq_tuner.irq_number; + irq_tuner_ins[i].up_threshold = dbs_irq_tuner.up_threshold; + irq_tuner_ins[i].enable = dbs_irq_tuner.enable; + cpufreq_irq_desc[i] = irq_to_desc(irq_tuner_ins[i].irq_number); + + return ret; +} +EXPORT_SYMBOL_GPL(cpufreq_gov_irq_tuner_register); #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE fs_initcall(cpufreq_interactive_init); #else |