From b43a7ffbf33be7e4d3b10b7714ee663ea2c52fe2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sun, 24 Mar 2013 11:56:43 +0530 Subject: cpufreq: Notify all policy->cpus in cpufreq_notify_transition() policy->cpus contains all online cpus that have single shared clock line. And their frequencies are always updated together. Many SMP system's cpufreq drivers take care of this in individual drivers but the best place for this code is in cpufreq core. This patch modifies cpufreq_notify_transition() to notify frequency change for all cpus in policy->cpus and hence updates all users of this API. Signed-off-by: Viresh Kumar Acked-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Rafael J. Wysocki --- arch/sh/kernel/cpufreq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/sh') diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index e68b45b6f3f9..2c7bd94f95ee 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c @@ -69,15 +69,14 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); - freqs.cpu = cpu; freqs.old = sh_cpufreq_get(cpu); freqs.new = (freq + 500) / 1000; freqs.flags = 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); set_cpus_allowed_ptr(current, &cpus_allowed); clk_set_rate(cpuclk, freq); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); dev_dbg(dev, "set frequency %lu Hz\n", freq); -- cgit v1.2.3 From e9f51837c97d199dfa06ef448797c584755837a8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 1 Apr 2013 12:57:46 +0000 Subject: cpufreq: Don't check if cpu is online/offline for cpufreq callbacks cpufreq layer doesn't call cpufreq driver's callback for any offline CPU and so checking that isn't useful. Lets get rid of it. Signed-off-by: Viresh Kumar Acked-by: David S. Miller Signed-off-by: Rafael J. Wysocki --- arch/mips/kernel/cpufreq/loongson2_cpufreq.c | 6 ------ arch/sh/kernel/cpufreq.c | 6 ------ arch/sparc/kernel/us2e_cpufreq.c | 6 ------ arch/sparc/kernel/us3_cpufreq.c | 6 ------ drivers/cpufreq/p4-clockmod.c | 3 +-- drivers/cpufreq/powernow-k8.c | 3 --- drivers/cpufreq/speedstep-centrino.c | 4 ---- 7 files changed, 1 insertion(+), 33 deletions(-) (limited to 'arch/sh') diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c index bafda7063f03..84889573b566 100644 --- a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c +++ b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c @@ -61,9 +61,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, struct cpufreq_freqs freqs; unsigned int freq; - if (!cpu_online(cpu)) - return -ENODEV; - cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -109,9 +106,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) unsigned long rate; int ret; - if (!cpu_online(policy->cpu)) - return -ENODEV; - cpuclk = clk_get(NULL, "cpu_clk"); if (IS_ERR(cpuclk)) { printk(KERN_ERR "cpufreq: couldn't get CPU clk\n"); diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index 2c7bd94f95ee..0fdf64b759c8 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c @@ -51,9 +51,6 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, struct device *dev; long freq; - if (!cpu_online(cpu)) - return -ENODEV; - cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -111,9 +108,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) struct cpufreq_frequency_table *freq_table; struct device *dev; - if (!cpu_online(cpu)) - return -ENODEV; - dev = get_cpu_device(cpu); cpuclk = clk_get(dev, "cpu_clk"); diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/arch/sparc/kernel/us2e_cpufreq.c index abe963d7b87c..306ae462bba6 100644 --- a/arch/sparc/kernel/us2e_cpufreq.c +++ b/arch/sparc/kernel/us2e_cpufreq.c @@ -234,9 +234,6 @@ static unsigned int us2e_freq_get(unsigned int cpu) cpumask_t cpus_allowed; unsigned long clock_tick, estar; - if (!cpu_online(cpu)) - return 0; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -257,9 +254,6 @@ static void us2e_set_cpu_divider_index(struct cpufreq_policy *policy, cpumask_t cpus_allowed; struct cpufreq_freqs freqs; - if (!cpu_online(cpu)) - return; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); diff --git a/arch/sparc/kernel/us3_cpufreq.c b/arch/sparc/kernel/us3_cpufreq.c index 7ceb9c8458f0..c71ee142347a 100644 --- a/arch/sparc/kernel/us3_cpufreq.c +++ b/arch/sparc/kernel/us3_cpufreq.c @@ -82,9 +82,6 @@ static unsigned int us3_freq_get(unsigned int cpu) unsigned long reg; unsigned int ret; - if (!cpu_online(cpu)) - return 0; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -104,9 +101,6 @@ static void us3_set_cpu_divider_index(struct cpufreq_policy *policy, cpumask_t cpus_allowed; struct cpufreq_freqs freqs; - if (!cpu_online(cpu)) - return; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index 4b2e7737b939..421ef37d0bb3 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -58,8 +58,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) { u32 l, h; - if (!cpu_online(cpu) || - (newstate > DC_DISABLE) || (newstate == DC_RESV)) + if ((newstate > DC_DISABLE) || (newstate == DC_RESV)) return -EINVAL; rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 52137a323965..b828efe4b2f8 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1102,9 +1102,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) struct init_on_cpu init_on_cpu; int rc; - if (!cpu_online(pol->cpu)) - return -ENODEV; - smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); if (rc) return -ENODEV; diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 3dbbcc3519af..618e6f417b1c 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -481,10 +481,6 @@ static int centrino_target (struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { int good_cpu; - /* cpufreq holds the hotplug lock, so we are safe here */ - if (!cpu_online(j)) - continue; - /* * Support for SMP systems. * Make sure we are running on CPU that wants to change freq -- cgit v1.2.3 From eb2f50ff93f08c8001d0d7e1148948ba80989aaf Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 1 Apr 2013 12:57:48 +0000 Subject: cpufreq: drivers: Remove unnecessary assignments of policy-> members Some assignments of policy-> min/max/cur/cpuinfo.min_freq/cpuinfo.max_freq aren't required as part of it is done by cpufreq driver or cpufreq core. Remove them. At some places we merge multiple lines together too. Signed-off-by: Viresh Kumar Acked-by: Sekhar Nori Signed-off-by: Rafael J. Wysocki --- Documentation/cpu-freq/cpu-drivers.txt | 5 +++-- arch/arm/mach-davinci/cpufreq.c | 21 ++++++++------------- arch/arm/mach-imx/cpufreq.c | 3 --- arch/sh/kernel/cpufreq.c | 9 +++------ drivers/cpufreq/cpufreq-nforce2.c | 6 ++---- drivers/cpufreq/omap-cpufreq.c | 4 +--- 6 files changed, 17 insertions(+), 31 deletions(-) (limited to 'arch/sh') diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 7c7721d042ff..a3585eac83b6 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -108,8 +108,9 @@ policy->governor must contain the "default policy" for cpufreq_driver.target is called with these values. -For setting some of these values, the frequency table helpers might be -helpful. See the section 2 for more information on them. +For setting some of these values (cpuinfo.min[max]_freq, policy->min[max]), the +frequency table helpers might be helpful. See the section 2 for more information +on them. SMP systems normally have same clock source for a group of cpus. For these the .init() would be called only once for the first online cpu. Here the .init() diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c index 8fb0c2ac227e..7c2e943c5500 100644 --- a/arch/arm/mach-davinci/cpufreq.c +++ b/arch/arm/mach-davinci/cpufreq.c @@ -137,21 +137,16 @@ static int davinci_cpu_init(struct cpufreq_policy *policy) return result; } - policy->cur = policy->min = policy->max = davinci_getspeed(0); - - if (freq_table) { - result = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (!result) - cpufreq_frequency_table_get_attr(freq_table, - policy->cpu); - } else { - policy->cpuinfo.min_freq = policy->min; - policy->cpuinfo.max_freq = policy->max; + policy->cur = davinci_getspeed(0); + + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (result) { + pr_err("%s: cpufreq_frequency_table_cpuinfo() failed", + __func__); + return result; } - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - policy->cur = davinci_getspeed(0); + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); /* * Time measurement across the target() function yields ~1500-1800us diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c index cfce5e3f67f5..387dc4cceca2 100644 --- a/arch/arm/mach-imx/cpufreq.c +++ b/arch/arm/mach-imx/cpufreq.c @@ -144,14 +144,11 @@ static int mxc_cpufreq_init(struct cpufreq_policy *policy) imx_freq_table[i].frequency = CPUFREQ_TABLE_END; policy->cur = clk_get_rate(cpu_clk) / 1000; - policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min; - policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max; /* Manual states, that PLL stabilizes in two CLK32 periods */ policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ; ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); - if (ret < 0) { printk(KERN_ERR "%s: failed to register i.MXC CPUfreq with error code %d\n", __func__, ret); diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index 0fdf64b759c8..88c8feedf785 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c @@ -116,7 +116,7 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) return PTR_ERR(cpuclk); } - policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu); + policy->cur = sh_cpufreq_get(cpu); freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; if (freq_table) { @@ -129,15 +129,12 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) dev_notice(dev, "no frequency table found, falling back " "to rate rounding.\n"); - policy->cpuinfo.min_freq = + policy->min = policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; - policy->cpuinfo.max_freq = + policy->max = policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; } - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index 224a4787ecc2..af1542d41440 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -359,12 +359,10 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) min_fsb = NFORCE2_MIN_FSB; /* cpuinfo and default policy values */ - policy->cpuinfo.min_freq = min_fsb * fid * 100; - policy->cpuinfo.max_freq = max_fsb * fid * 100; + policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100; + policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = nforce2_get(policy->cpu); - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; return 0; } diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index b610edd820b1..ad7549c13ed2 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -177,7 +177,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) goto fail_ck; } - policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); + policy->cur = omap_getspeed(policy->cpu); if (!freq_table) result = opp_init_cpufreq_table(mpu_dev, &freq_table); @@ -196,8 +196,6 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; policy->cur = omap_getspeed(policy->cpu); /* -- cgit v1.2.3 From 7258267e56325d41f468eb650b6c23f697201645 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 4 Apr 2013 12:54:22 +0000 Subject: cpufreq: sh: move cpufreq driver to drivers/cpufreq This patch moves cpufreq driver of SUPERH architecture to drivers/cpufreq. Signed-off-by: Viresh Kumar Acked-by: Paul Mundt Signed-off-by: Rafael J. Wysocki --- arch/sh/Kconfig | 18 ---- arch/sh/kernel/Makefile | 1 - arch/sh/kernel/cpufreq.c | 191 ------------------------------------------- drivers/cpufreq/Kconfig | 18 ++++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/sh-cpufreq.c | 189 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 208 insertions(+), 210 deletions(-) delete mode 100644 arch/sh/kernel/cpufreq.c create mode 100644 drivers/cpufreq/sh-cpufreq.c (limited to 'arch/sh') diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5e859633ce69..06e3163bdc11 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -624,25 +624,7 @@ config SH_CLK_CPG_LEGACY endmenu menu "CPU Frequency scaling" - source "drivers/cpufreq/Kconfig" - -config SH_CPU_FREQ - tristate "SuperH CPU Frequency driver" - depends on CPU_FREQ - select CPU_FREQ_TABLE - help - This adds the cpufreq driver for SuperH. Any CPU that supports - clock rate rounding through the clock framework can use this - driver. While it will make the kernel slightly larger, this is - harmless for CPUs that don't support rate rounding. The driver - will also generate a notice in the boot log before disabling - itself if the CPU in question is not capable of rate rounding. - - For details, take a look at . - - If unsure, say N. - endmenu source "arch/sh/drivers/Kconfig" diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index f259b37874e9..261c8bfd75ce 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o obj-$(CONFIG_KGDB) += kgdb.o -obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c deleted file mode 100644 index 88c8feedf785..000000000000 --- a/arch/sh/kernel/cpufreq.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * arch/sh/kernel/cpufreq.c - * - * cpufreq driver for the SuperH processors. - * - * Copyright (C) 2002 - 2012 Paul Mundt - * Copyright (C) 2002 M. R. Brown - * - * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c - * - * Copyright (C) 2004-2007 Atmel Corporation - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#define pr_fmt(fmt) "cpufreq: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* set_cpus_allowed() */ -#include -#include -#include - -static DEFINE_PER_CPU(struct clk, sh_cpuclk); - -static unsigned int sh_cpufreq_get(unsigned int cpu) -{ - return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000; -} - -/* - * Here we notify other drivers of the proposed change and the final change. - */ -static int sh_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int cpu = policy->cpu; - struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); - cpumask_t cpus_allowed; - struct cpufreq_freqs freqs; - struct device *dev; - long freq; - - cpus_allowed = current->cpus_allowed; - set_cpus_allowed_ptr(current, cpumask_of(cpu)); - - BUG_ON(smp_processor_id() != cpu); - - dev = get_cpu_device(cpu); - - /* Convert target_freq from kHz to Hz */ - freq = clk_round_rate(cpuclk, target_freq * 1000); - - if (freq < (policy->min * 1000) || freq > (policy->max * 1000)) - return -EINVAL; - - dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); - - freqs.old = sh_cpufreq_get(cpu); - freqs.new = (freq + 500) / 1000; - freqs.flags = 0; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - set_cpus_allowed_ptr(current, &cpus_allowed); - clk_set_rate(cpuclk, freq); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - dev_dbg(dev, "set frequency %lu Hz\n", freq); - - return 0; -} - -static int sh_cpufreq_verify(struct cpufreq_policy *policy) -{ - struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu); - struct cpufreq_frequency_table *freq_table; - - freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; - if (freq_table) - return cpufreq_frequency_table_verify(policy, freq_table); - - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - - policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000; - policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; - - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - - return 0; -} - -static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int cpu = policy->cpu; - struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); - struct cpufreq_frequency_table *freq_table; - struct device *dev; - - dev = get_cpu_device(cpu); - - cpuclk = clk_get(dev, "cpu_clk"); - if (IS_ERR(cpuclk)) { - dev_err(dev, "couldn't get CPU clk\n"); - return PTR_ERR(cpuclk); - } - - policy->cur = sh_cpufreq_get(cpu); - - freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; - if (freq_table) { - int result; - - result = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (!result) - cpufreq_frequency_table_get_attr(freq_table, cpu); - } else { - dev_notice(dev, "no frequency table found, falling back " - "to rate rounding.\n"); - - policy->min = policy->cpuinfo.min_freq = - (clk_round_rate(cpuclk, 1) + 500) / 1000; - policy->max = policy->cpuinfo.max_freq = - (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; - } - - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - - dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " - "Maximum %u.%03u MHz.\n", - policy->min / 1000, policy->min % 1000, - policy->max / 1000, policy->max % 1000); - - return 0; -} - -static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - unsigned int cpu = policy->cpu; - struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); - - cpufreq_frequency_table_put_attr(cpu); - clk_put(cpuclk); - - return 0; -} - -static struct freq_attr *sh_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver sh_cpufreq_driver = { - .owner = THIS_MODULE, - .name = "sh", - .get = sh_cpufreq_get, - .target = sh_cpufreq_target, - .verify = sh_cpufreq_verify, - .init = sh_cpufreq_cpu_init, - .exit = sh_cpufreq_cpu_exit, - .attr = sh_freq_attr, -}; - -static int __init sh_cpufreq_module_init(void) -{ - pr_notice("SuperH CPU frequency driver.\n"); - return cpufreq_register_driver(&sh_cpufreq_driver); -} - -static void __exit sh_cpufreq_module_exit(void) -{ - cpufreq_unregister_driver(&sh_cpufreq_driver); -} - -module_init(sh_cpufreq_module_init); -module_exit(sh_cpufreq_module_exit); - -MODULE_AUTHOR("Paul Mundt "); -MODULE_DESCRIPTION("cpufreq driver for SuperH"); -MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 5030df5cd3eb..602d5dbc4345 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -258,5 +258,23 @@ depends on PPC32 || PPC64 source "drivers/cpufreq/Kconfig.powerpc" endmenu +menu "SH CPU Frequency scaling" +depends on SUPERH +config SH_CPU_FREQ + tristate "SuperH CPU Frequency driver" + select CPU_FREQ_TABLE + help + This adds the cpufreq driver for SuperH. Any CPU that supports + clock rate rounding through the clock framework can use this + driver. While it will make the kernel slightly larger, this is + harmless for CPUs that don't support rate rounding. The driver + will also generate a notice in the boot log before disabling + itself if the CPU in question is not capable of rate rounding. + + For details, take a look at . + + If unsure, say N. +endmenu + endif endmenu diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 9659cbbad25e..3930d2e6a664 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -83,3 +83,4 @@ obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o +obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c new file mode 100644 index 000000000000..73adb64651e8 --- /dev/null +++ b/drivers/cpufreq/sh-cpufreq.c @@ -0,0 +1,189 @@ +/* + * cpufreq driver for the SuperH processors. + * + * Copyright (C) 2002 - 2012 Paul Mundt + * Copyright (C) 2002 M. R. Brown + * + * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c + * + * Copyright (C) 2004-2007 Atmel Corporation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#define pr_fmt(fmt) "cpufreq: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* set_cpus_allowed() */ +#include +#include +#include + +static DEFINE_PER_CPU(struct clk, sh_cpuclk); + +static unsigned int sh_cpufreq_get(unsigned int cpu) +{ + return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000; +} + +/* + * Here we notify other drivers of the proposed change and the final change. + */ +static int sh_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int cpu = policy->cpu; + struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); + cpumask_t cpus_allowed; + struct cpufreq_freqs freqs; + struct device *dev; + long freq; + + cpus_allowed = current->cpus_allowed; + set_cpus_allowed_ptr(current, cpumask_of(cpu)); + + BUG_ON(smp_processor_id() != cpu); + + dev = get_cpu_device(cpu); + + /* Convert target_freq from kHz to Hz */ + freq = clk_round_rate(cpuclk, target_freq * 1000); + + if (freq < (policy->min * 1000) || freq > (policy->max * 1000)) + return -EINVAL; + + dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); + + freqs.old = sh_cpufreq_get(cpu); + freqs.new = (freq + 500) / 1000; + freqs.flags = 0; + + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + set_cpus_allowed_ptr(current, &cpus_allowed); + clk_set_rate(cpuclk, freq); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + + dev_dbg(dev, "set frequency %lu Hz\n", freq); + + return 0; +} + +static int sh_cpufreq_verify(struct cpufreq_policy *policy) +{ + struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu); + struct cpufreq_frequency_table *freq_table; + + freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; + if (freq_table) + return cpufreq_frequency_table_verify(policy, freq_table); + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000; + policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + return 0; +} + +static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); + struct cpufreq_frequency_table *freq_table; + struct device *dev; + + dev = get_cpu_device(cpu); + + cpuclk = clk_get(dev, "cpu_clk"); + if (IS_ERR(cpuclk)) { + dev_err(dev, "couldn't get CPU clk\n"); + return PTR_ERR(cpuclk); + } + + policy->cur = sh_cpufreq_get(cpu); + + freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; + if (freq_table) { + int result; + + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!result) + cpufreq_frequency_table_get_attr(freq_table, cpu); + } else { + dev_notice(dev, "no frequency table found, falling back " + "to rate rounding.\n"); + + policy->min = policy->cpuinfo.min_freq = + (clk_round_rate(cpuclk, 1) + 500) / 1000; + policy->max = policy->cpuinfo.max_freq = + (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; + } + + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + + dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " + "Maximum %u.%03u MHz.\n", + policy->min / 1000, policy->min % 1000, + policy->max / 1000, policy->max % 1000); + + return 0; +} + +static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); + + cpufreq_frequency_table_put_attr(cpu); + clk_put(cpuclk); + + return 0; +} + +static struct freq_attr *sh_freq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver sh_cpufreq_driver = { + .owner = THIS_MODULE, + .name = "sh", + .get = sh_cpufreq_get, + .target = sh_cpufreq_target, + .verify = sh_cpufreq_verify, + .init = sh_cpufreq_cpu_init, + .exit = sh_cpufreq_cpu_exit, + .attr = sh_freq_attr, +}; + +static int __init sh_cpufreq_module_init(void) +{ + pr_notice("SuperH CPU frequency driver.\n"); + return cpufreq_register_driver(&sh_cpufreq_driver); +} + +static void __exit sh_cpufreq_module_exit(void) +{ + cpufreq_unregister_driver(&sh_cpufreq_driver); +} + +module_init(sh_cpufreq_module_init); +module_exit(sh_cpufreq_module_exit); + +MODULE_AUTHOR("Paul Mundt "); +MODULE_DESCRIPTION("cpufreq driver for SuperH"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3