diff options
Diffstat (limited to 'drivers/cpufreq')
72 files changed, 1633 insertions, 3011 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 534fcb825153..38093e272377 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -17,15 +17,11 @@ config CPU_FREQ if CPU_FREQ -config CPU_FREQ_TABLE - tristate - config CPU_FREQ_GOV_COMMON bool config CPU_FREQ_STAT tristate "CPU frequency translation statistics" - select CPU_FREQ_TABLE default y help This driver exports CPU frequency statistics information through sysfs @@ -143,7 +139,6 @@ config CPU_FREQ_GOV_USERSPACE config CPU_FREQ_GOV_ONDEMAND tristate "'ondemand' cpufreq policy governor" - select CPU_FREQ_TABLE select CPU_FREQ_GOV_COMMON help 'ondemand' - This driver adds a dynamic cpufreq policy governor. @@ -187,7 +182,6 @@ config CPU_FREQ_GOV_CONSERVATIVE config GENERIC_CPUFREQ_CPU0 tristate "Generic CPU0 cpufreq driver" depends on HAVE_CLK && REGULATOR && PM_OPP && OF - select CPU_FREQ_TABLE help This adds a generic cpufreq driver for CPU0 frequency management. It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) @@ -223,7 +217,6 @@ depends on IA64 config IA64_ACPI_CPUFREQ tristate "ACPI Processor P-States driver" - select CPU_FREQ_TABLE depends on ACPI_PROCESSOR help This driver adds a CPUFreq driver which utilizes the ACPI @@ -240,7 +233,6 @@ depends on MIPS config LOONGSON2_CPUFREQ tristate "Loongson2 CPUFreq Driver" - select CPU_FREQ_TABLE help This option adds a CPUFreq driver for loongson processors which support software configurable cpu frequency. @@ -262,7 +254,6 @@ menu "SPARC CPU frequency scaling drivers" depends on SPARC64 config SPARC_US3_CPUFREQ tristate "UltraSPARC-III CPU Frequency driver" - select CPU_FREQ_TABLE help This adds the CPUFreq driver for UltraSPARC-III processors. @@ -272,7 +263,6 @@ config SPARC_US3_CPUFREQ config SPARC_US2E_CPUFREQ tristate "UltraSPARC-IIe CPU Frequency driver" - select CPU_FREQ_TABLE help This adds the CPUFreq driver for UltraSPARC-IIe processors. @@ -285,7 +275,6 @@ 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 diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0fa204b244bd..ce52ed949249 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -5,7 +5,6 @@ config ARM_BIG_LITTLE_CPUFREQ tristate "Generic ARM big LITTLE CPUfreq driver" depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK - select CPU_FREQ_TABLE help This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. @@ -18,7 +17,6 @@ config ARM_DT_BL_CPUFREQ config ARM_EXYNOS_CPUFREQ bool - select CPU_FREQ_TABLE config ARM_EXYNOS4210_CPUFREQ bool "SAMSUNG EXYNOS4210" @@ -58,7 +56,6 @@ config ARM_EXYNOS5440_CPUFREQ depends on SOC_EXYNOS5440 depends on HAVE_CLK && PM_OPP && OF default y - select CPU_FREQ_TABLE help This adds the CPUFreq driver for Samsung EXYNOS5440 SoC. The nature of exynos5440 clock controller is @@ -85,7 +82,6 @@ config ARM_IMX6Q_CPUFREQ tristate "Freescale i.MX6Q cpufreq support" depends on SOC_IMX6Q depends on REGULATOR_ANATOP - select CPU_FREQ_TABLE help This adds cpufreq driver support for Freescale i.MX6Q SOC. @@ -101,7 +97,6 @@ config ARM_INTEGRATOR config ARM_KIRKWOOD_CPUFREQ def_bool ARCH_KIRKWOOD && OF - select CPU_FREQ_TABLE help This adds the CPUFreq driver for Marvell Kirkwood SoCs. @@ -110,7 +105,6 @@ config ARM_OMAP2PLUS_CPUFREQ bool "TI OMAP2+" depends on ARCH_OMAP2PLUS default ARCH_OMAP2PLUS - select CPU_FREQ_TABLE config ARM_S3C_CPUFREQ bool @@ -165,7 +159,6 @@ config ARM_S3C2412_CPUFREQ config ARM_S3C2416_CPUFREQ bool "S3C2416 CPU Frequency scaling support" depends on CPU_S3C2416 - select CPU_FREQ_TABLE help This adds the CPUFreq driver for the Samsung S3C2416 and S3C2450 SoC. The S3C2416 supports changing the rate of the @@ -196,7 +189,6 @@ config ARM_S3C2440_CPUFREQ config ARM_S3C64XX_CPUFREQ bool "Samsung S3C64XX" depends on CPU_S3C6410 - select CPU_FREQ_TABLE default y help This adds the CPUFreq driver for Samsung S3C6410 SoC. @@ -206,7 +198,6 @@ config ARM_S3C64XX_CPUFREQ config ARM_S5PV210_CPUFREQ bool "Samsung S5PV210 and S5PC110" depends on CPU_S5PV210 - select CPU_FREQ_TABLE default y help This adds the CPUFreq driver for Samsung S5PV210 and @@ -223,7 +214,6 @@ config ARM_SA1110_CPUFREQ config ARM_SPEAR_CPUFREQ bool "SPEAr CPUFreq support" depends on PLAT_SPEAR - select CPU_FREQ_TABLE default y help This adds the CPUFreq driver support for SPEAr SOCs. @@ -231,7 +221,14 @@ config ARM_SPEAR_CPUFREQ config ARM_TEGRA_CPUFREQ bool "TEGRA CPUFreq support" depends on ARCH_TEGRA - select CPU_FREQ_TABLE default y help This adds the CPUFreq driver support for TEGRA SOCs. + +config ARM_VEXPRESS_SPC_CPUFREQ + tristate "Versatile Express SPC based CPUfreq driver" + select ARM_BIG_LITTLE_CPUFREQ + depends on ARCH_VEXPRESS_SPC + help + This add the CPUfreq driver support for Versatile Express + big.LITTLE platforms using SPC for power management. diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc index 25ca9db62e09..ca0021a96e19 100644 --- a/drivers/cpufreq/Kconfig.powerpc +++ b/drivers/cpufreq/Kconfig.powerpc @@ -1,7 +1,6 @@ config CPU_FREQ_CBE tristate "CBE frequency scaling" depends on CBE_RAS && PPC_CELL - select CPU_FREQ_TABLE default m help This adds the cpufreq driver for Cell BE processors. @@ -20,7 +19,6 @@ config CPU_FREQ_CBE_PMI config CPU_FREQ_MAPLE bool "Support for Maple 970FX Evaluation Board" depends on PPC_MAPLE - select CPU_FREQ_TABLE help This adds support for frequency switching on Maple 970FX Evaluation Board and compatible boards (IBM JS2x blades). @@ -28,7 +26,6 @@ config CPU_FREQ_MAPLE config PPC_CORENET_CPUFREQ tristate "CPU frequency scaling driver for Freescale E500MC SoCs" depends on PPC_E500MC && OF && COMMON_CLK - select CPU_FREQ_TABLE select CLK_PPC_CORENET help This adds the CPUFreq driver support for Freescale e500mc, @@ -38,7 +35,6 @@ config PPC_CORENET_CPUFREQ config CPU_FREQ_PMAC bool "Support for Apple PowerBooks" depends on ADB_PMU && PPC32 - select CPU_FREQ_TABLE help This adds support for frequency switching on Apple PowerBooks, this currently includes some models of iBook & Titanium @@ -47,7 +43,6 @@ config CPU_FREQ_PMAC config CPU_FREQ_PMAC64 bool "Support for some Apple G5s" depends on PPC_PMAC && PPC64 - select CPU_FREQ_TABLE help This adds support for frequency switching on Apple iMac G5, and some of the more recent desktop G5 machines as well. @@ -55,7 +50,6 @@ config CPU_FREQ_PMAC64 config PPC_PASEMI_CPUFREQ bool "Support for PA Semi PWRficient" depends on PPC_PASEMI - select CPU_FREQ_TABLE default y help This adds the support for frequency switching on PA Semi diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index e2b6eabef221..d369349eeaab 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -31,7 +31,6 @@ config X86_PCC_CPUFREQ config X86_ACPI_CPUFREQ tristate "ACPI Processor P-States driver" - select CPU_FREQ_TABLE depends on ACPI_PROCESSOR help This driver adds a CPUFreq driver which utilizes the ACPI @@ -60,7 +59,6 @@ config X86_ACPI_CPUFREQ_CPB config ELAN_CPUFREQ tristate "AMD Elan SC400 and SC410" - select CPU_FREQ_TABLE depends on MELAN ---help--- This adds the CPUFreq driver for AMD Elan SC400 and SC410 @@ -76,7 +74,6 @@ config ELAN_CPUFREQ config SC520_CPUFREQ tristate "AMD Elan SC520" - select CPU_FREQ_TABLE depends on MELAN ---help--- This adds the CPUFreq driver for AMD Elan SC520 processor. @@ -88,7 +85,6 @@ config SC520_CPUFREQ config X86_POWERNOW_K6 tristate "AMD Mobile K6-2/K6-3 PowerNow!" - select CPU_FREQ_TABLE depends on X86_32 help This adds the CPUFreq driver for mobile AMD K6-2+ and mobile @@ -100,7 +96,6 @@ config X86_POWERNOW_K6 config X86_POWERNOW_K7 tristate "AMD Mobile Athlon/Duron PowerNow!" - select CPU_FREQ_TABLE depends on X86_32 help This adds the CPUFreq driver for mobile AMD K7 mobile processors. @@ -118,7 +113,6 @@ config X86_POWERNOW_K7_ACPI config X86_POWERNOW_K8 tristate "AMD Opteron/Athlon64 PowerNow!" - select CPU_FREQ_TABLE depends on ACPI && ACPI_PROCESSOR && X86_ACPI_CPUFREQ help This adds the CPUFreq driver for K8/early Opteron/Athlon64 processors. @@ -132,11 +126,10 @@ config X86_POWERNOW_K8 config X86_AMD_FREQ_SENSITIVITY tristate "AMD frequency sensitivity feedback powersave bias" depends on CPU_FREQ_GOV_ONDEMAND && X86_ACPI_CPUFREQ && CPU_SUP_AMD - select CPU_FREQ_TABLE help This adds AMD-specific powersave bias function to the ondemand governor, which allows it to make more power-conscious frequency - change decisions based on feedback from hardware (availble on AMD + change decisions based on feedback from hardware (available on AMD Family 16h and above). Hardware feedback tells software how "sensitive" to frequency changes @@ -160,7 +153,6 @@ config X86_GX_SUSPMOD config X86_SPEEDSTEP_CENTRINO tristate "Intel Enhanced SpeedStep (deprecated)" - select CPU_FREQ_TABLE select X86_SPEEDSTEP_CENTRINO_TABLE if X86_32 depends on X86_32 || (X86_64 && ACPI_PROCESSOR) help @@ -190,7 +182,6 @@ config X86_SPEEDSTEP_CENTRINO_TABLE config X86_SPEEDSTEP_ICH tristate "Intel Speedstep on ICH-M chipsets (ioport interface)" - select CPU_FREQ_TABLE depends on X86_32 help This adds the CPUFreq driver for certain mobile Intel Pentium III @@ -204,7 +195,6 @@ config X86_SPEEDSTEP_ICH config X86_SPEEDSTEP_SMI tristate "Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)" - select CPU_FREQ_TABLE depends on X86_32 help This adds the CPUFreq driver for certain mobile Intel Pentium III @@ -217,7 +207,6 @@ config X86_SPEEDSTEP_SMI config X86_P4_CLOCKMOD tristate "Intel Pentium 4 clock modulation" - select CPU_FREQ_TABLE help This adds the CPUFreq driver for Intel Pentium 4 / XEON processors. When enabled it will lower CPU temperature by skipping @@ -259,7 +248,6 @@ config X86_LONGRUN config X86_LONGHAUL tristate "VIA Cyrix III Longhaul" - select CPU_FREQ_TABLE depends on X86_32 && ACPI_PROCESSOR help This adds the CPUFreq driver for VIA Samuel/CyrixIII, @@ -272,7 +260,6 @@ config X86_LONGHAUL config X86_E_POWERSAVER tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)" - select CPU_FREQ_TABLE depends on X86_32 && ACPI_PROCESSOR help This adds the CPUFreq driver for VIA C7 processors. However, this driver diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ad5866c2ada0..74945652dd7a 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -1,5 +1,5 @@ # CPUfreq core -obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o @@ -11,9 +11,6 @@ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o -# CPUfreq cross-arch helpers -obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o - obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o ################################################################################## @@ -77,6 +74,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o +obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ################################################################################## # PowerPC platform drivers diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 506fd23c7550..caf41ebea184 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -424,34 +424,21 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, } static int acpi_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) + unsigned int index) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); struct acpi_processor_performance *perf; - struct cpufreq_freqs freqs; struct drv_cmd cmd; - unsigned int next_state = 0; /* Index into freq_table */ unsigned int next_perf_state = 0; /* Index into perf table */ int result = 0; - pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); - if (unlikely(data == NULL || data->acpi_data == NULL || data->freq_table == NULL)) { return -ENODEV; } perf = data->acpi_data; - result = cpufreq_frequency_table_target(policy, - data->freq_table, - target_freq, - relation, &next_state); - if (unlikely(result)) { - result = -ENODEV; - goto out; - } - - next_perf_state = data->freq_table[next_state].driver_data; + next_perf_state = data->freq_table[index].driver_data; if (perf->state == next_perf_state) { if (unlikely(data->resume)) { pr_debug("Called after resume, resetting to P%d\n", @@ -492,23 +479,17 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, else cmd.mask = cpumask_of(policy->cpu); - freqs.old = perf->states[perf->state].core_frequency * 1000; - freqs.new = data->freq_table[next_state].frequency; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - drv_write(&cmd); if (acpi_pstate_strict) { - if (!check_freqs(cmd.mask, freqs.new, data)) { + if (!check_freqs(cmd.mask, data->freq_table[index].frequency, + data)) { pr_debug("acpi_cpufreq_target failed (%d)\n", policy->cpu); result = -EAGAIN; - freqs.new = freqs.old; } } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - if (!result) perf->state = next_perf_state; @@ -516,15 +497,6 @@ out: return result; } -static int acpi_cpufreq_verify(struct cpufreq_policy *policy) -{ - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - - pr_debug("acpi_cpufreq_verify\n"); - - return cpufreq_frequency_table_verify(policy, data->freq_table); -} - static unsigned long acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) { @@ -837,7 +809,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END; perf->state = 0; - result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); + result = cpufreq_table_validate_and_show(policy, data->freq_table); if (result) goto err_freqfree; @@ -846,12 +818,16 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) switch (perf->control_register.space_id) { case ACPI_ADR_SPACE_SYSTEM_IO: - /* Current speed is unknown and not detectable by IO port */ + /* + * The core will not set policy->cur, because + * cpufreq_driver->get is NULL, so we need to set it here. + * However, we have to guess it, because the current speed is + * unknown and not detectable via IO ports. + */ policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); break; case ACPI_ADR_SPACE_FIXED_HARDWARE: acpi_cpufreq_driver.get = get_cur_freq_on_cpu; - policy->cur = get_cur_freq_on_cpu(cpu); break; default: break; @@ -868,8 +844,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) (u32) perf->states[i].power, (u32) perf->states[i].transition_latency); - cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); - /* * the first call to ->target() should result in us actually * writing something to the appropriate registers. @@ -929,8 +903,8 @@ static struct freq_attr *acpi_cpufreq_attr[] = { }; static struct cpufreq_driver acpi_cpufreq_driver = { - .verify = acpi_cpufreq_verify, - .target = acpi_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = acpi_cpufreq_target, .bios_limit = acpi_processor_get_bios_limit, .init = acpi_cpufreq_cpu_init, .exit = acpi_cpufreq_cpu_exit, diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index 3549f0784af1..5519933813ea 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -24,110 +24,323 @@ #include <linux/cpufreq.h> #include <linux/cpumask.h> #include <linux/export.h> +#include <linux/mutex.h> #include <linux/of_platform.h> -#include <linux/opp.h> +#include <linux/pm_opp.h> #include <linux/slab.h> #include <linux/topology.h> #include <linux/types.h> +#include <asm/bL_switcher.h> #include "arm_big_little.h" /* Currently we support only two clusters */ +#define A15_CLUSTER 0 +#define A7_CLUSTER 1 #define MAX_CLUSTERS 2 +#ifdef CONFIG_BL_SWITCHER +static bool bL_switching_enabled; +#define is_bL_switching_enabled() bL_switching_enabled +#define set_switching_enabled(x) (bL_switching_enabled = (x)) +#else +#define is_bL_switching_enabled() false +#define set_switching_enabled(x) do { } while (0) +#endif + +#define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq) +#define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) + static struct cpufreq_arm_bL_ops *arm_bL_ops; static struct clk *clk[MAX_CLUSTERS]; -static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS]; -static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)}; +static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; +static atomic_t cluster_usage[MAX_CLUSTERS + 1]; + +static unsigned int clk_big_min; /* (Big) clock frequencies */ +static unsigned int clk_little_max; /* Maximum clock frequency (Little) */ + +static DEFINE_PER_CPU(unsigned int, physical_cluster); +static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq); -static unsigned int bL_cpufreq_get(unsigned int cpu) +static struct mutex cluster_lock[MAX_CLUSTERS]; + +static inline int raw_cpu_to_cluster(int cpu) { - u32 cur_cluster = cpu_to_cluster(cpu); + return topology_physical_package_id(cpu); +} - return clk_get_rate(clk[cur_cluster]) / 1000; +static inline int cpu_to_cluster(int cpu) +{ + return is_bL_switching_enabled() ? + MAX_CLUSTERS : raw_cpu_to_cluster(cpu); } -/* Validate policy frequency range */ -static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy) +static unsigned int find_cluster_maxfreq(int cluster) { - u32 cur_cluster = cpu_to_cluster(policy->cpu); + int j; + u32 max_freq = 0, cpu_freq; + + for_each_online_cpu(j) { + cpu_freq = per_cpu(cpu_last_req_freq, j); + + if ((cluster == per_cpu(physical_cluster, j)) && + (max_freq < cpu_freq)) + max_freq = cpu_freq; + } + + pr_debug("%s: cluster: %d, max freq: %d\n", __func__, cluster, + max_freq); + + return max_freq; +} + +static unsigned int clk_get_cpu_rate(unsigned int cpu) +{ + u32 cur_cluster = per_cpu(physical_cluster, cpu); + u32 rate = clk_get_rate(clk[cur_cluster]) / 1000; + + /* For switcher we use virtual A7 clock rates */ + if (is_bL_switching_enabled()) + rate = VIRT_FREQ(cur_cluster, rate); + + pr_debug("%s: cpu: %d, cluster: %d, freq: %u\n", __func__, cpu, + cur_cluster, rate); + + return rate; +} + +static unsigned int bL_cpufreq_get_rate(unsigned int cpu) +{ + if (is_bL_switching_enabled()) { + pr_debug("%s: freq: %d\n", __func__, per_cpu(cpu_last_req_freq, + cpu)); + + return per_cpu(cpu_last_req_freq, cpu); + } else { + return clk_get_cpu_rate(cpu); + } +} + +static unsigned int +bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) +{ + u32 new_rate, prev_rate; + int ret; + bool bLs = is_bL_switching_enabled(); + + mutex_lock(&cluster_lock[new_cluster]); - return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]); + if (bLs) { + prev_rate = per_cpu(cpu_last_req_freq, cpu); + per_cpu(cpu_last_req_freq, cpu) = rate; + per_cpu(physical_cluster, cpu) = new_cluster; + + new_rate = find_cluster_maxfreq(new_cluster); + new_rate = ACTUAL_FREQ(new_cluster, new_rate); + } else { + new_rate = rate; + } + + pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d, freq: %d\n", + __func__, cpu, old_cluster, new_cluster, new_rate); + + ret = clk_set_rate(clk[new_cluster], new_rate * 1000); + if (WARN_ON(ret)) { + pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret, + new_cluster); + if (bLs) { + per_cpu(cpu_last_req_freq, cpu) = prev_rate; + per_cpu(physical_cluster, cpu) = old_cluster; + } + + mutex_unlock(&cluster_lock[new_cluster]); + + return ret; + } + + mutex_unlock(&cluster_lock[new_cluster]); + + /* Recalc freq for old cluster when switching clusters */ + if (old_cluster != new_cluster) { + pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d\n", + __func__, cpu, old_cluster, new_cluster); + + /* Switch cluster */ + bL_switch_request(cpu, new_cluster); + + mutex_lock(&cluster_lock[old_cluster]); + + /* Set freq of old cluster if there are cpus left on it */ + new_rate = find_cluster_maxfreq(old_cluster); + new_rate = ACTUAL_FREQ(old_cluster, new_rate); + + if (new_rate) { + pr_debug("%s: Updating rate of old cluster: %d, to freq: %d\n", + __func__, old_cluster, new_rate); + + if (clk_set_rate(clk[old_cluster], new_rate * 1000)) + pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n", + __func__, ret, old_cluster); + } + mutex_unlock(&cluster_lock[old_cluster]); + } + + return 0; } /* Set clock frequency */ static int bL_cpufreq_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) + unsigned int index) { - struct cpufreq_freqs freqs; - u32 cpu = policy->cpu, freq_tab_idx, cur_cluster; - int ret = 0; + u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster; + unsigned int freqs_new; + + cur_cluster = cpu_to_cluster(cpu); + new_cluster = actual_cluster = per_cpu(physical_cluster, cpu); + + freqs_new = freq_table[cur_cluster][index].frequency; + + if (is_bL_switching_enabled()) { + if ((actual_cluster == A15_CLUSTER) && + (freqs_new < clk_big_min)) { + new_cluster = A7_CLUSTER; + } else if ((actual_cluster == A7_CLUSTER) && + (freqs_new > clk_little_max)) { + new_cluster = A15_CLUSTER; + } + } - cur_cluster = cpu_to_cluster(policy->cpu); + return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new); +} - freqs.old = bL_cpufreq_get(policy->cpu); +static inline u32 get_table_count(struct cpufreq_frequency_table *table) +{ + int count; - /* Determine valid target frequency using freq_table */ - cpufreq_frequency_table_target(policy, freq_table[cur_cluster], - target_freq, relation, &freq_tab_idx); - freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency; + for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++) + ; - pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n", - __func__, cpu, cur_cluster, freqs.old, target_freq, - freqs.new); + return count; +} - if (freqs.old == freqs.new) - return 0; +/* get the minimum frequency in the cpufreq_frequency_table */ +static inline u32 get_table_min(struct cpufreq_frequency_table *table) +{ + int i; + uint32_t min_freq = ~0; + for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) + if (table[i].frequency < min_freq) + min_freq = table[i].frequency; + return min_freq; +} - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); +/* get the maximum frequency in the cpufreq_frequency_table */ +static inline u32 get_table_max(struct cpufreq_frequency_table *table) +{ + int i; + uint32_t max_freq = 0; + for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) + if (table[i].frequency > max_freq) + max_freq = table[i].frequency; + return max_freq; +} - ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000); - if (ret) { - pr_err("clk_set_rate failed: %d\n", ret); - freqs.new = freqs.old; +static int merge_cluster_tables(void) +{ + int i, j, k = 0, count = 1; + struct cpufreq_frequency_table *table; + + for (i = 0; i < MAX_CLUSTERS; i++) + count += get_table_count(freq_table[i]); + + table = kzalloc(sizeof(*table) * count, GFP_KERNEL); + if (!table) + return -ENOMEM; + + freq_table[MAX_CLUSTERS] = table; + + /* Add in reverse order to get freqs in increasing order */ + for (i = MAX_CLUSTERS - 1; i >= 0; i--) { + for (j = 0; freq_table[i][j].frequency != CPUFREQ_TABLE_END; + j++) { + table[k].frequency = VIRT_FREQ(i, + freq_table[i][j].frequency); + pr_debug("%s: index: %d, freq: %d\n", __func__, k, + table[k].frequency); + k++; + } } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + table[k].driver_data = k; + table[k].frequency = CPUFREQ_TABLE_END; - return ret; + pr_debug("%s: End, table: %p, count: %d\n", __func__, table, k); + + return 0; +} + +static void _put_cluster_clk_and_freq_table(struct device *cpu_dev) +{ + u32 cluster = raw_cpu_to_cluster(cpu_dev->id); + + if (!freq_table[cluster]) + return; + + clk_put(clk[cluster]); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); + dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster); } static void put_cluster_clk_and_freq_table(struct device *cpu_dev) { u32 cluster = cpu_to_cluster(cpu_dev->id); + int i; + + if (atomic_dec_return(&cluster_usage[cluster])) + return; + + if (cluster < MAX_CLUSTERS) + return _put_cluster_clk_and_freq_table(cpu_dev); - if (!atomic_dec_return(&cluster_usage[cluster])) { - clk_put(clk[cluster]); - opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); - dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster); + for_each_present_cpu(i) { + struct device *cdev = get_cpu_device(i); + if (!cdev) { + pr_err("%s: failed to get cpu%d device\n", __func__, i); + return; + } + + _put_cluster_clk_and_freq_table(cdev); } + + /* free virtual table */ + kfree(freq_table[cluster]); } -static int get_cluster_clk_and_freq_table(struct device *cpu_dev) +static int _get_cluster_clk_and_freq_table(struct device *cpu_dev) { - u32 cluster = cpu_to_cluster(cpu_dev->id); + u32 cluster = raw_cpu_to_cluster(cpu_dev->id); char name[14] = "cpu-cluster."; int ret; - if (atomic_inc_return(&cluster_usage[cluster]) != 1) + if (freq_table[cluster]) return 0; ret = arm_bL_ops->init_opp_table(cpu_dev); if (ret) { dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n", __func__, cpu_dev->id, ret); - goto atomic_dec; + goto out; } - ret = opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]); + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]); if (ret) { dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n", __func__, cpu_dev->id, ret); - goto atomic_dec; + goto out; } name[12] = cluster + '0'; - clk[cluster] = clk_get_sys(name, NULL); + clk[cluster] = clk_get(cpu_dev, name); if (!IS_ERR(clk[cluster])) { dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n", __func__, clk[cluster], freq_table[cluster], @@ -138,15 +351,74 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev) dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n", __func__, cpu_dev->id, cluster); ret = PTR_ERR(clk[cluster]); - opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); -atomic_dec: - atomic_dec(&cluster_usage[cluster]); +out: dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__, cluster); return ret; } +static int get_cluster_clk_and_freq_table(struct device *cpu_dev) +{ + u32 cluster = cpu_to_cluster(cpu_dev->id); + int i, ret; + + if (atomic_inc_return(&cluster_usage[cluster]) != 1) + return 0; + + if (cluster < MAX_CLUSTERS) { + ret = _get_cluster_clk_and_freq_table(cpu_dev); + if (ret) + atomic_dec(&cluster_usage[cluster]); + return ret; + } + + /* + * Get data for all clusters and fill virtual cluster with a merge of + * both + */ + for_each_present_cpu(i) { + struct device *cdev = get_cpu_device(i); + if (!cdev) { + pr_err("%s: failed to get cpu%d device\n", __func__, i); + return -ENODEV; + } + + ret = _get_cluster_clk_and_freq_table(cdev); + if (ret) + goto put_clusters; + } + + ret = merge_cluster_tables(); + if (ret) + goto put_clusters; + + /* Assuming 2 cluster, set clk_big_min and clk_little_max */ + clk_big_min = get_table_min(freq_table[0]); + clk_little_max = VIRT_FREQ(1, get_table_max(freq_table[1])); + + pr_debug("%s: cluster: %d, clk_big_min: %d, clk_little_max: %d\n", + __func__, cluster, clk_big_min, clk_little_max); + + return 0; + +put_clusters: + for_each_present_cpu(i) { + struct device *cdev = get_cpu_device(i); + if (!cdev) { + pr_err("%s: failed to get cpu%d device\n", __func__, i); + return -ENODEV; + } + + _put_cluster_clk_and_freq_table(cdev); + } + + atomic_dec(&cluster_usage[cluster]); + + return ret; +} + /* Per-CPU initialization */ static int bL_cpufreq_init(struct cpufreq_policy *policy) { @@ -165,7 +437,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) if (ret) return ret; - ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster]); + ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]); if (ret) { dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n", policy->cpu, cur_cluster); @@ -173,7 +445,14 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) return ret; } - cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu); + if (cur_cluster < MAX_CLUSTERS) { + cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); + + per_cpu(physical_cluster, policy->cpu) = cur_cluster; + } else { + /* Assumption: during init, we are always running on A15 */ + per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER; + } if (arm_bL_ops->get_transition_latency) policy->cpuinfo.transition_latency = @@ -181,9 +460,8 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) else policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = bL_cpufreq_get(policy->cpu); - - cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); + if (is_bL_switching_enabled()) + per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu); dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); return 0; @@ -200,33 +478,60 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy) return -ENODEV; } + cpufreq_frequency_table_put_attr(policy->cpu); put_cluster_clk_and_freq_table(cpu_dev); dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu); return 0; } -/* Export freq_table to sysfs */ -static struct freq_attr *bL_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver bL_cpufreq_driver = { .name = "arm-big-little", - .flags = CPUFREQ_STICKY, - .verify = bL_cpufreq_verify_policy, - .target = bL_cpufreq_set_target, - .get = bL_cpufreq_get, + .flags = CPUFREQ_STICKY | + CPUFREQ_HAVE_GOVERNOR_PER_POLICY, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = bL_cpufreq_set_target, + .get = bL_cpufreq_get_rate, .init = bL_cpufreq_init, .exit = bL_cpufreq_exit, - .have_governor_per_policy = true, - .attr = bL_cpufreq_attr, + .attr = cpufreq_generic_attr, +}; + +static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb, + unsigned long action, void *_arg) +{ + pr_debug("%s: action: %ld\n", __func__, action); + + switch (action) { + case BL_NOTIFY_PRE_ENABLE: + case BL_NOTIFY_PRE_DISABLE: + cpufreq_unregister_driver(&bL_cpufreq_driver); + break; + + case BL_NOTIFY_POST_ENABLE: + set_switching_enabled(true); + cpufreq_register_driver(&bL_cpufreq_driver); + break; + + case BL_NOTIFY_POST_DISABLE: + set_switching_enabled(false); + cpufreq_register_driver(&bL_cpufreq_driver); + break; + + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block bL_switcher_notifier = { + .notifier_call = bL_cpufreq_switcher_notifier, }; int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) { - int ret; + int ret, i; if (arm_bL_ops) { pr_debug("%s: Already registered: %s, exiting\n", __func__, @@ -241,16 +546,29 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) arm_bL_ops = ops; + ret = bL_switcher_get_enabled(); + set_switching_enabled(ret); + + for (i = 0; i < MAX_CLUSTERS; i++) + mutex_init(&cluster_lock[i]); + ret = cpufreq_register_driver(&bL_cpufreq_driver); if (ret) { pr_info("%s: Failed registering platform driver: %s, err: %d\n", __func__, ops->name, ret); arm_bL_ops = NULL; } else { - pr_info("%s: Registered platform driver: %s\n", __func__, - ops->name); + ret = bL_switcher_register_notifier(&bL_switcher_notifier); + if (ret) { + cpufreq_unregister_driver(&bL_cpufreq_driver); + arm_bL_ops = NULL; + } else { + pr_info("%s: Registered platform driver: %s\n", + __func__, ops->name); + } } + bL_switcher_put_enabled(); return ret; } EXPORT_SYMBOL_GPL(bL_cpufreq_register); @@ -263,7 +581,10 @@ void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops) return; } + bL_switcher_get_enabled(); + bL_switcher_unregister_notifier(&bL_switcher_notifier); cpufreq_unregister_driver(&bL_cpufreq_driver); + bL_switcher_put_enabled(); pr_info("%s: Un-registered platform driver: %s\n", __func__, arm_bL_ops->name); arm_bL_ops = NULL; diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h index 79b2ce17884d..70f18fc12d4a 100644 --- a/drivers/cpufreq/arm_big_little.h +++ b/drivers/cpufreq/arm_big_little.h @@ -34,11 +34,6 @@ struct cpufreq_arm_bL_ops { int (*init_opp_table)(struct device *cpu_dev); }; -static inline int cpu_to_cluster(int cpu) -{ - return topology_physical_package_id(cpu); -} - int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops); diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c index 480c0bd0468d..8d9d59108906 100644 --- a/drivers/cpufreq/arm_big_little_dt.c +++ b/drivers/cpufreq/arm_big_little_dt.c @@ -24,7 +24,7 @@ #include <linux/export.h> #include <linux/module.h> #include <linux/of_device.h> -#include <linux/opp.h> +#include <linux/pm_opp.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c index e0c38d938997..7c03dd84f66a 100644 --- a/drivers/cpufreq/at32ap-cpufreq.c +++ b/drivers/cpufreq/at32ap-cpufreq.c @@ -19,18 +19,10 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/export.h> +#include <linux/slab.h> static struct clk *cpuclk; - -static int at32_verify_speed(struct cpufreq_policy *policy) -{ - if (policy->cpu != 0) - return -EINVAL; - - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - return 0; -} +static struct cpufreq_frequency_table *freq_table; static unsigned int at32_get_speed(unsigned int cpu) { @@ -43,74 +35,94 @@ static unsigned int at32_get_speed(unsigned int cpu) static unsigned int ref_freq; static unsigned long loops_per_jiffy_ref; -static int at32_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) { - struct cpufreq_freqs freqs; - long freq; - - /* Convert target_freq from kHz to Hz */ - freq = clk_round_rate(cpuclk, target_freq * 1000); - - /* Check if policy->min <= new_freq <= policy->max */ - if(freq < (policy->min * 1000) || freq > (policy->max * 1000)) - return -EINVAL; - - pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000); + unsigned int old_freq, new_freq; - freqs.old = at32_get_speed(0); - freqs.new = (freq + 500) / 1000; - freqs.flags = 0; + old_freq = at32_get_speed(0); + new_freq = freq_table[index].frequency; if (!ref_freq) { - ref_freq = freqs.old; + ref_freq = old_freq; loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy; } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - if (freqs.old < freqs.new) + if (old_freq < new_freq) boot_cpu_data.loops_per_jiffy = cpufreq_scale( - loops_per_jiffy_ref, ref_freq, freqs.new); - clk_set_rate(cpuclk, freq); - if (freqs.new < freqs.old) + loops_per_jiffy_ref, ref_freq, new_freq); + clk_set_rate(cpuclk, new_freq * 1000); + if (new_freq < old_freq) boot_cpu_data.loops_per_jiffy = cpufreq_scale( - loops_per_jiffy_ref, ref_freq, freqs.new); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - pr_debug("cpufreq: set frequency %lu Hz\n", freq); + loops_per_jiffy_ref, ref_freq, new_freq); return 0; } -static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy) +static int at32_cpufreq_driver_init(struct cpufreq_policy *policy) { + unsigned int frequency, rate, min_freq; + int retval, steps, i; + if (policy->cpu != 0) return -EINVAL; cpuclk = clk_get(NULL, "cpu"); if (IS_ERR(cpuclk)) { pr_debug("cpufreq: could not get CPU clk\n"); - return PTR_ERR(cpuclk); + retval = PTR_ERR(cpuclk); + goto out_err; } - policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; - policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; + min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; + frequency = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; policy->cpuinfo.transition_latency = 0; - policy->cur = at32_get_speed(0); - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - printk("cpufreq: AT32AP CPU frequency driver\n"); + /* + * AVR32 CPU frequency rate scales in power of two between maximum and + * minimum, also add space for the table end marker. + * + * Further validate that the frequency is usable, and append it to the + * frequency table. + */ + steps = fls(frequency / min_freq) + 1; + freq_table = kzalloc(steps * sizeof(struct cpufreq_frequency_table), + GFP_KERNEL); + if (!freq_table) { + retval = -ENOMEM; + goto out_err_put_clk; + } - return 0; + for (i = 0; i < (steps - 1); i++) { + rate = clk_round_rate(cpuclk, frequency * 1000) / 1000; + + if (rate != frequency) + freq_table[i].frequency = CPUFREQ_ENTRY_INVALID; + else + freq_table[i].frequency = frequency; + + frequency /= 2; + } + + freq_table[steps - 1].frequency = CPUFREQ_TABLE_END; + + retval = cpufreq_table_validate_and_show(policy, freq_table); + if (!retval) { + printk("cpufreq: AT32AP CPU frequency driver\n"); + return 0; + } + + kfree(freq_table); +out_err_put_clk: + clk_put(cpuclk); +out_err: + return retval; } static struct cpufreq_driver at32_driver = { .name = "at32ap", .init = at32_cpufreq_driver_init, - .verify = at32_verify_speed, - .target = at32_set_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = at32_set_target, .get = at32_get_speed, .flags = CPUFREQ_STICKY, }; diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c index ef05978a7237..e9e63fc9c2c9 100644 --- a/drivers/cpufreq/blackfin-cpufreq.c +++ b/drivers/cpufreq/blackfin-cpufreq.c @@ -127,41 +127,28 @@ unsigned long cpu_set_cclk(int cpu, unsigned long new) } #endif -static int bfin_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) +static int bfin_target(struct cpufreq_policy *policy, unsigned int index) { #ifndef CONFIG_BF60x unsigned int plldiv; #endif - unsigned int index; - unsigned long cclk_hz; - struct cpufreq_freqs freqs; static unsigned long lpj_ref; static unsigned int lpj_ref_freq; + unsigned int old_freq, new_freq; int ret = 0; #if defined(CONFIG_CYCLES_CLOCKSOURCE) cycles_t cycles; #endif - if (cpufreq_frequency_table_target(policy, bfin_freq_table, target_freq, - relation, &index)) - return -EINVAL; + old_freq = bfin_getfreq_khz(0); + new_freq = bfin_freq_table[index].frequency; - cclk_hz = bfin_freq_table[index].frequency; - - freqs.old = bfin_getfreq_khz(0); - freqs.new = cclk_hz; - - pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n", - cclk_hz, target_freq, freqs.old); - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); #ifndef CONFIG_BF60x plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; bfin_write_PLL_DIV(plldiv); #else - ret = cpu_set_cclk(policy->cpu, freqs.new * 1000); + ret = cpu_set_cclk(policy->cpu, new_freq * 1000); if (ret != 0) { WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret); return ret; @@ -177,25 +164,16 @@ static int bfin_target(struct cpufreq_policy *policy, #endif if (!lpj_ref_freq) { lpj_ref = loops_per_jiffy; - lpj_ref_freq = freqs.old; + lpj_ref_freq = old_freq; } - if (freqs.new != freqs.old) { + if (new_freq != old_freq) { loops_per_jiffy = cpufreq_scale(lpj_ref, - lpj_ref_freq, freqs.new); + lpj_ref_freq, new_freq); } - /* TODO: just test case for cycles clock source, remove later */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - pr_debug("cpufreq: done\n"); return ret; } -static int bfin_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, bfin_freq_table); -} - static int __bfin_cpu_init(struct cpufreq_policy *policy) { @@ -209,23 +187,17 @@ static int __bfin_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 50000; /* 50us assumed */ - policy->cur = cclk; - cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu); - return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table); + return cpufreq_table_validate_and_show(policy, bfin_freq_table); } -static struct freq_attr *bfin_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver bfin_driver = { - .verify = bfin_verify_speed, - .target = bfin_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = bfin_target, .get = bfin_getfreq_khz, .init = __bfin_cpu_init, + .exit = cpufreq_generic_exit, .name = "bfin cpufreq", - .attr = bfin_freq_attr, + .attr = cpufreq_generic_attr, }; static int __init bfin_cpu_init(void) diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index c522a95c0e16..d4585ce2346c 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -17,7 +17,7 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/opp.h> +#include <linux/pm_opp.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -30,73 +30,51 @@ static struct clk *cpu_clk; static struct regulator *cpu_reg; static struct cpufreq_frequency_table *freq_table; -static int cpu0_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, freq_table); -} - static unsigned int cpu0_get_speed(unsigned int cpu) { return clk_get_rate(cpu_clk) / 1000; } -static int cpu0_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) +static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) { - struct cpufreq_freqs freqs; - struct opp *opp; + struct dev_pm_opp *opp; unsigned long volt = 0, volt_old = 0, tol = 0; + unsigned int old_freq, new_freq; long freq_Hz, freq_exact; - unsigned int index; int ret; - ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, - relation, &index); - if (ret) { - pr_err("failed to match target freqency %d: %d\n", - target_freq, ret); - return ret; - } - freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); if (freq_Hz < 0) freq_Hz = freq_table[index].frequency * 1000; - freq_exact = freq_Hz; - freqs.new = freq_Hz / 1000; - freqs.old = clk_get_rate(cpu_clk) / 1000; - if (freqs.old == freqs.new) - return 0; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + freq_exact = freq_Hz; + new_freq = freq_Hz / 1000; + old_freq = clk_get_rate(cpu_clk) / 1000; if (!IS_ERR(cpu_reg)) { rcu_read_lock(); - opp = opp_find_freq_ceil(cpu_dev, &freq_Hz); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); if (IS_ERR(opp)) { rcu_read_unlock(); pr_err("failed to find OPP for %ld\n", freq_Hz); - freqs.new = freqs.old; - ret = PTR_ERR(opp); - goto post_notify; + return PTR_ERR(opp); } - volt = opp_get_voltage(opp); + volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); tol = volt * voltage_tolerance / 100; volt_old = regulator_get_voltage(cpu_reg); } pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", - freqs.old / 1000, volt_old ? volt_old / 1000 : -1, - freqs.new / 1000, volt ? volt / 1000 : -1); + old_freq / 1000, volt_old ? volt_old / 1000 : -1, + new_freq / 1000, volt ? volt / 1000 : -1); /* scaling up? scale voltage before frequency */ - if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) { + if (!IS_ERR(cpu_reg) && new_freq > old_freq) { ret = regulator_set_voltage_tol(cpu_reg, volt, tol); if (ret) { pr_err("failed to scale voltage up: %d\n", ret); - freqs.new = freqs.old; - goto post_notify; + return ret; } } @@ -105,72 +83,35 @@ static int cpu0_set_target(struct cpufreq_policy *policy, pr_err("failed to set clock rate: %d\n", ret); if (!IS_ERR(cpu_reg)) regulator_set_voltage_tol(cpu_reg, volt_old, tol); - freqs.new = freqs.old; - goto post_notify; + return ret; } /* scaling down? scale voltage after frequency */ - if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) { + if (!IS_ERR(cpu_reg) && new_freq < old_freq) { ret = regulator_set_voltage_tol(cpu_reg, volt, tol); if (ret) { pr_err("failed to scale voltage down: %d\n", ret); - clk_set_rate(cpu_clk, freqs.old * 1000); - freqs.new = freqs.old; + clk_set_rate(cpu_clk, old_freq * 1000); } } -post_notify: - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - return ret; } static int cpu0_cpufreq_init(struct cpufreq_policy *policy) { - int ret; - - ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (ret) { - pr_err("invalid frequency table: %d\n", ret); - return ret; - } - - policy->cpuinfo.transition_latency = transition_latency; - policy->cur = clk_get_rate(cpu_clk) / 1000; - - /* - * The driver only supports the SMP configuartion where all processors - * share the clock and voltage and clock. Use cpufreq affected_cpus - * interface to have all CPUs scaled together. - */ - cpumask_setall(policy->cpus); - - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - - return 0; + return cpufreq_generic_init(policy, freq_table, transition_latency); } -static int cpu0_cpufreq_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - - return 0; -} - -static struct freq_attr *cpu0_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver cpu0_cpufreq_driver = { .flags = CPUFREQ_STICKY, - .verify = cpu0_verify_speed, - .target = cpu0_set_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = cpu0_set_target, .get = cpu0_get_speed, .init = cpu0_cpufreq_init, - .exit = cpu0_cpufreq_exit, + .exit = cpufreq_generic_exit, .name = "generic_cpu0", - .attr = cpu0_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int cpu0_cpufreq_probe(struct platform_device *pdev) @@ -218,7 +159,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) goto out_put_node; } - ret = opp_init_cpufreq_table(cpu_dev, &freq_table); + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); if (ret) { pr_err("failed to init cpufreq table: %d\n", ret); goto out_put_node; @@ -230,7 +171,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) transition_latency = CPUFREQ_ETERNAL; if (!IS_ERR(cpu_reg)) { - struct opp *opp; + struct dev_pm_opp *opp; unsigned long min_uV, max_uV; int i; @@ -242,12 +183,12 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) ; rcu_read_lock(); - opp = opp_find_freq_exact(cpu_dev, + opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[0].frequency * 1000, true); - min_uV = opp_get_voltage(opp); - opp = opp_find_freq_exact(cpu_dev, + min_uV = dev_pm_opp_get_voltage(opp); + opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[i-1].frequency * 1000, true); - max_uV = opp_get_voltage(opp); + max_uV = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); if (ret > 0) @@ -264,7 +205,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) return 0; out_free_table: - opp_free_cpufreq_table(cpu_dev, &freq_table); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); out_put_node: of_node_put(np); return ret; @@ -273,7 +214,7 @@ out_put_node: static int cpu0_cpufreq_remove(struct platform_device *pdev) { cpufreq_unregister_driver(&cpu0_cpufreq_driver); - opp_free_cpufreq_table(cpu_dev, &freq_table); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); return 0; } diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index b83d45f68574..a05b876f375e 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -303,9 +303,7 @@ static int nforce2_verify(struct cpufreq_policy *policy) if (policy->min < (fsb_pol_max * fid * 100)) policy->max = (fsb_pol_max + 1) * fid * 100; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); return 0; } @@ -362,7 +360,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) 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); return 0; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 04548f7023af..8d19f7c06010 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -47,49 +47,11 @@ static LIST_HEAD(cpufreq_policy_list); static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); #endif -/* - * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure - * all cpufreq/hotplug/workqueue/etc related lock issues. - * - * The rules for this semaphore: - * - Any routine that wants to read from the policy structure will - * do a down_read on this semaphore. - * - Any routine that will write to the policy structure and/or may take away - * the policy altogether (eg. CPU hotplug), will hold this lock in write - * mode before doing so. - * - * Additional rules: - * - Governor routines that can be called in cpufreq hotplug path should not - * take this sem as top level hotplug notifier handler takes this. - * - Lock should not be held across - * __cpufreq_governor(data, CPUFREQ_GOV_STOP); - */ -static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); - -#define lock_policy_rwsem(mode, cpu) \ -static int lock_policy_rwsem_##mode(int cpu) \ -{ \ - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); \ - BUG_ON(!policy); \ - down_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu)); \ - \ - return 0; \ -} - -lock_policy_rwsem(read, cpu); -lock_policy_rwsem(write, cpu); - -#define unlock_policy_rwsem(mode, cpu) \ -static void unlock_policy_rwsem_##mode(int cpu) \ -{ \ - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); \ - BUG_ON(!policy); \ - up_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu)); \ +static inline bool has_target(void) +{ + return cpufreq_driver->target_index || cpufreq_driver->target; } -unlock_policy_rwsem(read, cpu); -unlock_policy_rwsem(write, cpu); - /* * rwsem to guarantee that cpufreq driver module doesn't unload during critical * sections @@ -135,7 +97,7 @@ static DEFINE_MUTEX(cpufreq_governor_mutex); bool have_governor_per_policy(void) { - return cpufreq_driver->have_governor_per_policy; + return !!(cpufreq_driver->flags & CPUFREQ_HAVE_GOVERNOR_PER_POLICY); } EXPORT_SYMBOL_GPL(have_governor_per_policy); @@ -183,6 +145,37 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) } EXPORT_SYMBOL_GPL(get_cpu_idle_time); +/* + * This is a generic cpufreq init() routine which can be used by cpufreq + * drivers of SMP systems. It will do following: + * - validate & show freq table passed + * - set policies transition latency + * - policy->cpus with all possible CPUs + */ +int cpufreq_generic_init(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table, + unsigned int transition_latency) +{ + int ret; + + ret = cpufreq_table_validate_and_show(policy, table); + if (ret) { + pr_err("%s: invalid frequency table: %d\n", __func__, ret); + return ret; + } + + policy->cpuinfo.transition_latency = transition_latency; + + /* + * The driver only supports the SMP configuartion where all processors + * share the clock and voltage and clock. + */ + cpumask_setall(policy->cpus); + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_generic_init); + struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) { struct cpufreq_policy *policy = NULL; @@ -363,7 +356,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, *policy = CPUFREQ_POLICY_POWERSAVE; err = 0; } - } else if (cpufreq_driver->target) { + } else if (has_target()) { struct cpufreq_governor *t; mutex_lock(&cpufreq_governor_mutex); @@ -414,7 +407,7 @@ show_one(scaling_min_freq, min); show_one(scaling_max_freq, max); show_one(scaling_cur_freq, cur); -static int __cpufreq_set_policy(struct cpufreq_policy *policy, +static int cpufreq_set_policy(struct cpufreq_policy *policy, struct cpufreq_policy *new_policy); /** @@ -435,7 +428,7 @@ static ssize_t store_##file_name \ if (ret != 1) \ return -EINVAL; \ \ - ret = __cpufreq_set_policy(policy, &new_policy); \ + ret = cpufreq_set_policy(policy, &new_policy); \ policy->user_policy.object = policy->object; \ \ return ret ? ret : count; \ @@ -493,11 +486,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, &new_policy.governor)) return -EINVAL; - /* - * Do not use cpufreq_set_policy here or the user_policy.max - * will be wrongly overridden - */ - ret = __cpufreq_set_policy(policy, &new_policy); + ret = cpufreq_set_policy(policy, &new_policy); policy->user_policy.policy = policy->policy; policy->user_policy.governor = policy->governor; @@ -525,7 +514,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, ssize_t i = 0; struct cpufreq_governor *t; - if (!cpufreq_driver->target) { + if (!has_target()) { i += sprintf(buf, "performance powersave"); goto out; } @@ -653,24 +642,21 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) { struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); - ssize_t ret = -EINVAL; + ssize_t ret; if (!down_read_trylock(&cpufreq_rwsem)) - goto exit; + return -EINVAL; - if (lock_policy_rwsem_read(policy->cpu) < 0) - goto up_read; + down_read(&policy->rwsem); if (fattr->show) ret = fattr->show(policy, buf); else ret = -EIO; - unlock_policy_rwsem_read(policy->cpu); - -up_read: + up_read(&policy->rwsem); up_read(&cpufreq_rwsem); -exit: + return ret; } @@ -689,17 +675,15 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, if (!down_read_trylock(&cpufreq_rwsem)) goto unlock; - if (lock_policy_rwsem_write(policy->cpu) < 0) - goto up_read; + down_write(&policy->rwsem); if (fattr->store) ret = fattr->store(policy, buf, count); else ret = -EIO; - unlock_policy_rwsem_write(policy->cpu); + up_write(&policy->rwsem); -up_read: up_read(&cpufreq_rwsem); unlock: put_online_cpus(); @@ -815,7 +799,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, if (ret) goto err_out_kobj_put; } - if (cpufreq_driver->target) { + if (has_target()) { ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); if (ret) goto err_out_kobj_put; @@ -844,14 +828,17 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) int ret = 0; memcpy(&new_policy, policy, sizeof(*policy)); - /* assure that the starting sequence is run in __cpufreq_set_policy */ + + /* Use the default policy if its valid. */ + if (cpufreq_driver->setpolicy) + cpufreq_parse_governor(policy->governor->name, + &new_policy.policy, NULL); + + /* assure that the starting sequence is run in cpufreq_set_policy */ policy->governor = NULL; /* set default policy */ - ret = __cpufreq_set_policy(policy, &new_policy); - policy->user_policy.policy = policy->policy; - policy->user_policy.governor = policy->governor; - + ret = cpufreq_set_policy(policy, &new_policy); if (ret) { pr_debug("setting policy failed\n"); if (cpufreq_driver->exit) @@ -861,13 +848,12 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) #ifdef CONFIG_HOTPLUG_CPU static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, - unsigned int cpu, struct device *dev, - bool frozen) + unsigned int cpu, struct device *dev) { - int ret = 0, has_target = !!cpufreq_driver->target; + int ret = 0; unsigned long flags; - if (has_target) { + if (has_target()) { ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); if (ret) { pr_err("%s: Failed to stop governor\n", __func__); @@ -875,7 +861,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, } } - lock_policy_rwsem_write(policy->cpu); + down_write(&policy->rwsem); write_lock_irqsave(&cpufreq_driver_lock, flags); @@ -883,9 +869,9 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, per_cpu(cpufreq_cpu_data, cpu) = policy; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - unlock_policy_rwsem_write(policy->cpu); + up_write(&policy->rwsem); - if (has_target) { + if (has_target()) { if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) || (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) { pr_err("%s: Failed to start governor\n", __func__); @@ -893,11 +879,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, } } - /* Don't touch sysfs links during light-weight init */ - if (!frozen) - ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); - - return ret; + return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); } #endif @@ -930,6 +912,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void) goto err_free_cpumask; INIT_LIST_HEAD(&policy->policy_list); + init_rwsem(&policy->rwsem); + return policy; err_free_cpumask: @@ -940,6 +924,27 @@ err_free_policy: return NULL; } +static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy) +{ + struct kobject *kobj; + struct completion *cmp; + + down_read(&policy->rwsem); + kobj = &policy->kobj; + cmp = &policy->kobj_unregister; + up_read(&policy->rwsem); + kobject_put(kobj); + + /* + * We need to make sure that the underlying kobj is + * actually not referenced anymore by anybody before we + * proceed with unloading. + */ + pr_debug("waiting for dropping of refcount\n"); + wait_for_completion(cmp); + pr_debug("wait complete\n"); +} + static void cpufreq_policy_free(struct cpufreq_policy *policy) { free_cpumask_var(policy->related_cpus); @@ -949,26 +954,17 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) { - if (cpu == policy->cpu) + if (WARN_ON(cpu == policy->cpu)) return; - /* - * Take direct locks as lock_policy_rwsem_write wouldn't work here. - * Also lock for last cpu is enough here as contention will happen only - * after policy->cpu is changed and after it is changed, other threads - * will try to acquire lock for new cpu. And policy is already updated - * by then. - */ - down_write(&per_cpu(cpu_policy_rwsem, policy->cpu)); + down_write(&policy->rwsem); policy->last_cpu = policy->cpu; policy->cpu = cpu; - up_write(&per_cpu(cpu_policy_rwsem, policy->last_cpu)); + up_write(&policy->rwsem); -#ifdef CONFIG_CPU_FREQ_TABLE cpufreq_frequency_table_update_policy_cpu(policy); -#endif blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_UPDATE_POLICY_CPU, policy); } @@ -1009,7 +1005,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen); + ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev); up_read(&cpufreq_rwsem); return ret; } @@ -1017,15 +1013,17 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, read_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif - if (frozen) - /* Restore the saved policy when doing light-weight init */ - policy = cpufreq_policy_restore(cpu); - else + /* + * Restore the saved policy when doing light-weight init and fall back + * to the full init if that fails. + */ + policy = frozen ? cpufreq_policy_restore(cpu) : NULL; + if (!policy) { + frozen = false; policy = cpufreq_policy_alloc(); - - if (!policy) - goto nomem_out; - + if (!policy) + goto nomem_out; + } /* * In the resume path, since we restore a saved policy, the assignment @@ -1053,6 +1051,14 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, goto err_set_policy_cpu; } + if (cpufreq_driver->get) { + policy->cur = cpufreq_driver->get(policy->cpu); + if (!policy->cur) { + pr_err("%s: ->get() failed\n", __func__); + goto err_get_freq; + } + } + /* related cpus should atleast have policy->cpus */ cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); @@ -1062,8 +1068,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, */ cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); - policy->user_policy.min = policy->min; - policy->user_policy.max = policy->max; + if (!frozen) { + policy->user_policy.min = policy->min; + policy->user_policy.max = policy->max; + } blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_START, policy); @@ -1094,6 +1102,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, cpufreq_init_policy(policy); + if (!frozen) { + policy->user_policy.policy = policy->policy; + policy->user_policy.governor = policy->governor; + } + kobject_uevent(&policy->kobj, KOBJ_ADD); up_read(&cpufreq_rwsem); @@ -1107,8 +1120,17 @@ err_out_unregister: per_cpu(cpufreq_cpu_data, j) = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); +err_get_freq: + if (cpufreq_driver->exit) + cpufreq_driver->exit(policy); err_set_policy_cpu: + if (frozen) { + /* Do not leave stale fallback data behind. */ + per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL; + cpufreq_policy_put_kobj(policy); + } cpufreq_policy_free(policy); + nomem_out: up_read(&cpufreq_rwsem); @@ -1130,7 +1152,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) } static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, - unsigned int old_cpu, bool frozen) + unsigned int old_cpu) { struct device *cpu_dev; int ret; @@ -1138,18 +1160,14 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, /* first sibling now owns the new sysfs dir */ cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); - /* Don't touch sysfs files during light-weight tear-down */ - if (frozen) - return cpu_dev->id; - sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); ret = kobject_move(&policy->kobj, &cpu_dev->kobj); if (ret) { pr_err("%s: Failed to move kobj: %d", __func__, ret); - WARN_ON(lock_policy_rwsem_write(old_cpu)); + down_write(&policy->rwsem); cpumask_set_cpu(old_cpu, policy->cpus); - unlock_policy_rwsem_write(old_cpu); + up_write(&policy->rwsem); ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq"); @@ -1186,7 +1204,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, return -EINVAL; } - if (cpufreq_driver->target) { + if (has_target()) { ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); if (ret) { pr_err("%s: Failed to stop governor\n", __func__); @@ -1200,22 +1218,21 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, policy->governor->name, CPUFREQ_NAME_LEN); #endif - lock_policy_rwsem_read(cpu); + down_read(&policy->rwsem); cpus = cpumask_weight(policy->cpus); - unlock_policy_rwsem_read(cpu); + up_read(&policy->rwsem); if (cpu != policy->cpu) { if (!frozen) sysfs_remove_link(&dev->kobj, "cpufreq"); } else if (cpus > 1) { - - new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); + new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu); if (new_cpu >= 0) { update_policy_cpu(policy, new_cpu); if (!frozen) { - pr_debug("%s: policy Kobject moved to cpu: %d " - "from: %d\n",__func__, new_cpu, cpu); + pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", + __func__, new_cpu, cpu); } } } @@ -1231,8 +1248,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev, int ret; unsigned long flags; struct cpufreq_policy *policy; - struct kobject *kobj; - struct completion *cmp; read_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); @@ -1243,16 +1258,16 @@ static int __cpufreq_remove_dev_finish(struct device *dev, return -EINVAL; } - WARN_ON(lock_policy_rwsem_write(cpu)); + down_write(&policy->rwsem); cpus = cpumask_weight(policy->cpus); if (cpus > 1) cpumask_clear_cpu(cpu, policy->cpus); - unlock_policy_rwsem_write(cpu); + up_write(&policy->rwsem); /* If cpu is last user of policy, free policy */ if (cpus == 1) { - if (cpufreq_driver->target) { + if (has_target()) { ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); if (ret) { @@ -1262,22 +1277,8 @@ static int __cpufreq_remove_dev_finish(struct device *dev, } } - if (!frozen) { - lock_policy_rwsem_read(cpu); - kobj = &policy->kobj; - cmp = &policy->kobj_unregister; - unlock_policy_rwsem_read(cpu); - kobject_put(kobj); - - /* - * We need to make sure that the underlying kobj is - * actually not referenced anymore by anybody before we - * proceed with unloading. - */ - pr_debug("waiting for dropping of refcount\n"); - wait_for_completion(cmp); - pr_debug("wait complete\n"); - } + if (!frozen) + cpufreq_policy_put_kobj(policy); /* * Perform the ->exit() even during light-weight tear-down, @@ -1295,7 +1296,7 @@ static int __cpufreq_remove_dev_finish(struct device *dev, if (!frozen) cpufreq_policy_free(policy); } else { - if (cpufreq_driver->target) { + if (has_target()) { if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) || (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) { pr_err("%s: Failed to start governor\n", @@ -1310,36 +1311,24 @@ static int __cpufreq_remove_dev_finish(struct device *dev, } /** - * __cpufreq_remove_dev - remove a CPU device + * cpufreq_remove_dev - remove a CPU device * * Removes the cpufreq interface for a CPU device. - * Caller should already have policy_rwsem in write mode for this CPU. - * This routine frees the rwsem before returning. */ -static inline int __cpufreq_remove_dev(struct device *dev, - struct subsys_interface *sif, - bool frozen) -{ - int ret; - - ret = __cpufreq_remove_dev_prepare(dev, sif, frozen); - - if (!ret) - ret = __cpufreq_remove_dev_finish(dev, sif, frozen); - - return ret; -} - static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) { unsigned int cpu = dev->id; - int retval; + int ret; if (cpu_is_offline(cpu)) return 0; - retval = __cpufreq_remove_dev(dev, sif, false); - return retval; + ret = __cpufreq_remove_dev_prepare(dev, sif, false); + + if (!ret) + ret = __cpufreq_remove_dev_finish(dev, sif, false); + + return ret; } static void handle_update(struct work_struct *work) @@ -1458,22 +1447,22 @@ static unsigned int __cpufreq_get(unsigned int cpu) */ unsigned int cpufreq_get(unsigned int cpu) { + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); unsigned int ret_freq = 0; if (cpufreq_disabled() || !cpufreq_driver) return -ENOENT; + BUG_ON(!policy); + if (!down_read_trylock(&cpufreq_rwsem)) return 0; - if (unlikely(lock_policy_rwsem_read(cpu))) - goto out_policy; + down_read(&policy->rwsem); ret_freq = __cpufreq_get(cpu); - unlock_policy_rwsem_read(cpu); - -out_policy: + up_read(&policy->rwsem); up_read(&cpufreq_rwsem); return ret_freq; @@ -1681,12 +1670,75 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", policy->cpu, target_freq, relation, old_target_freq); + /* + * This might look like a redundant call as we are checking it again + * after finding index. But it is left intentionally for cases where + * exactly same freq is called again and so we can save on few function + * calls. + */ if (target_freq == policy->cur) return 0; if (cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); + else if (cpufreq_driver->target_index) { + struct cpufreq_frequency_table *freq_table; + struct cpufreq_freqs freqs; + bool notify; + int index; + + freq_table = cpufreq_frequency_get_table(policy->cpu); + if (unlikely(!freq_table)) { + pr_err("%s: Unable to find freq_table\n", __func__); + goto out; + } + + retval = cpufreq_frequency_table_target(policy, freq_table, + target_freq, relation, &index); + if (unlikely(retval)) { + pr_err("%s: Unable to find matching freq\n", __func__); + goto out; + } + + if (freq_table[index].frequency == policy->cur) { + retval = 0; + goto out; + } + + notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); + + if (notify) { + freqs.old = policy->cur; + freqs.new = freq_table[index].frequency; + freqs.flags = 0; + + pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", + __func__, policy->cpu, freqs.old, + freqs.new); + cpufreq_notify_transition(policy, &freqs, + CPUFREQ_PRECHANGE); + } + + retval = cpufreq_driver->target_index(policy, index); + if (retval) + pr_err("%s: Failed to change cpu frequency: %d\n", + __func__, retval); + + if (notify) { + /* + * Notify with old freq in case we failed to change + * frequency + */ + if (retval) + freqs.new = freqs.old; + + cpufreq_notify_transition(policy, &freqs, + CPUFREQ_POSTCHANGE); + } + } + +out: return retval; } EXPORT_SYMBOL_GPL(__cpufreq_driver_target); @@ -1697,14 +1749,12 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, { int ret = -EINVAL; - if (unlikely(lock_policy_rwsem_write(policy->cpu))) - goto fail; + down_write(&policy->rwsem); ret = __cpufreq_driver_target(policy, target_freq, relation); - unlock_policy_rwsem_write(policy->cpu); + up_write(&policy->rwsem); -fail: return ret; } EXPORT_SYMBOL_GPL(cpufreq_driver_target); @@ -1871,10 +1921,10 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) EXPORT_SYMBOL(cpufreq_get_policy); /* - * data : current policy. - * policy : policy to be set. + * policy : current policy. + * new_policy: policy to be set. */ -static int __cpufreq_set_policy(struct cpufreq_policy *policy, +static int cpufreq_set_policy(struct cpufreq_policy *policy, struct cpufreq_policy *new_policy) { int ret = 0, failed = 1; @@ -1934,10 +1984,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *policy, /* end old governor */ if (policy->governor) { __cpufreq_governor(policy, CPUFREQ_GOV_STOP); - unlock_policy_rwsem_write(new_policy->cpu); + up_write(&policy->rwsem); __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); - lock_policy_rwsem_write(new_policy->cpu); + down_write(&policy->rwsem); } /* start new governor */ @@ -1946,10 +1996,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *policy, if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) { failed = 0; } else { - unlock_policy_rwsem_write(new_policy->cpu); + up_write(&policy->rwsem); __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); - lock_policy_rwsem_write(new_policy->cpu); + down_write(&policy->rwsem); } } @@ -1995,10 +2045,7 @@ int cpufreq_update_policy(unsigned int cpu) goto no_policy; } - if (unlikely(lock_policy_rwsem_write(cpu))) { - ret = -EINVAL; - goto fail; - } + down_write(&policy->rwsem); pr_debug("updating policy for CPU %u\n", cpu); memcpy(&new_policy, policy, sizeof(*policy)); @@ -2017,17 +2064,16 @@ int cpufreq_update_policy(unsigned int cpu) pr_debug("Driver did not initialize current freq"); policy->cur = new_policy.cur; } else { - if (policy->cur != new_policy.cur && cpufreq_driver->target) + if (policy->cur != new_policy.cur && has_target()) cpufreq_out_of_sync(cpu, policy->cur, new_policy.cur); } } - ret = __cpufreq_set_policy(policy, &new_policy); + ret = cpufreq_set_policy(policy, &new_policy); - unlock_policy_rwsem_write(cpu); + up_write(&policy->rwsem); -fail: cpufreq_cpu_put(policy); no_policy: return ret; @@ -2096,7 +2142,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) return -ENODEV; if (!driver_data || !driver_data->verify || !driver_data->init || - ((!driver_data->setpolicy) && (!driver_data->target))) + !(driver_data->setpolicy || driver_data->target_index || + driver_data->target)) return -EINVAL; pr_debug("trying to register driver %s\n", driver_data->name); @@ -2183,14 +2230,9 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); static int __init cpufreq_core_init(void) { - int cpu; - if (cpufreq_disabled()) return -ENODEV; - for_each_possible_cpu(cpu) - init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); - cpufreq_global_kobject = kobject_create(); BUG_ON(!cpufreq_global_kobject); register_syscore_ops(&cpufreq_syscore_ops); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index f62d822048e6..25a70d06c5bf 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -68,6 +68,9 @@ static void cs_check_cpu(int cpu, unsigned int load) dbs_info->requested_freq += get_freq_target(cs_tuners, policy); + if (dbs_info->requested_freq > policy->max) + dbs_info->requested_freq = policy->max; + __cpufreq_driver_target(policy, dbs_info->requested_freq, CPUFREQ_RELATION_H); return; @@ -80,13 +83,18 @@ static void cs_check_cpu(int cpu, unsigned int load) /* Check for frequency decrease */ if (load < cs_tuners->down_threshold) { + unsigned int freq_target; /* * if we cannot reduce the frequency anymore, break out early */ if (policy->cur == policy->min) return; - dbs_info->requested_freq -= get_freq_target(cs_tuners, policy); + freq_target = get_freq_target(cs_tuners, policy); + if (dbs_info->requested_freq > freq_target) + dbs_info->requested_freq -= freq_target; + else + dbs_info->requested_freq = policy->min; __cpufreq_driver_target(policy, dbs_info->requested_freq, CPUFREQ_RELATION_L); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 0806c31e5764..e6be63561fa6 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -328,10 +328,6 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, dbs_data->cdata->gov_dbs_timer); } - /* - * conservative does not implement micro like ondemand - * governor, thus we are bound to jiffes/HZ - */ if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { cs_dbs_info->down_skip = 0; cs_dbs_info->enable = 1; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 88cd39f7b0e9..b5f2b8618949 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -191,7 +191,10 @@ struct common_dbs_data { struct attribute_group *attr_group_gov_sys; /* one governor - system */ struct attribute_group *attr_group_gov_pol; /* one governor - policy */ - /* Common data for platforms that don't set have_governor_per_policy */ + /* + * Common data for platforms that don't set + * CPUFREQ_HAVE_GOVERNOR_PER_POLICY + */ struct dbs_data *gdbs_data; struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 32f26f6e17c5..18d409189092 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -168,7 +168,6 @@ static void od_check_cpu(int cpu, unsigned int load) dbs_info->rate_mult = od_tuners->sampling_down_factor; dbs_freq_increase(policy, policy->max); - return; } else { /* Calculate the next frequency proportional to load */ unsigned int freq_next; diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 03078090b5f7..4dbf1db16aca 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -38,18 +38,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) if (!per_cpu(cpu_is_managed, policy->cpu)) goto err; - /* - * We're safe from concurrent calls to ->target() here - * as we hold the userspace_mutex lock. If we were calling - * cpufreq_driver_target, a deadlock situation might occur: - * A: cpufreq_set (lock userspace_mutex) -> - * cpufreq_driver_target(lock policy->lock) - * B: cpufreq_set_policy(lock policy->lock) -> - * __cpufreq_governor -> - * cpufreq_governor_userspace (lock userspace_mutex) - */ ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); - err: mutex_unlock(&userspace_mutex); return ret; diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c index cb8276dd19ca..86559040c54c 100644 --- a/drivers/cpufreq/cris-artpec3-cpufreq.c +++ b/drivers/cpufreq/cris-artpec3-cpufreq.c @@ -27,18 +27,11 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) return clk_ctrl.pll ? 200000 : 6000; } -static void cris_freq_set_cpu_state(struct cpufreq_policy *policy, - unsigned int state) +static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) { - struct cpufreq_freqs freqs; reg_clkgen_rw_clk_ctrl clk_ctrl; clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); - freqs.old = cris_freq_get_cpu_frequency(policy->cpu); - freqs.new = cris_freq_table[state].frequency; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - local_irq_disable(); /* Even though we may be SMP they will share the same clock @@ -51,67 +44,22 @@ static void cris_freq_set_cpu_state(struct cpufreq_policy *policy, local_irq_enable(); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); -}; - -static int cris_freq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]); -} - -static int cris_freq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, cris_freq_table, - target_freq, relation, &newstate)) - return -EINVAL; - - cris_freq_set_cpu_state(policy, newstate); - return 0; } static int cris_freq_cpu_init(struct cpufreq_policy *policy) { - int result; - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 1000000; /* 1ms */ - policy->cur = cris_freq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table); - if (result) - return (result); - - cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu); - - return 0; -} - - -static int cris_freq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_generic_init(policy, cris_freq_table, 1000000); } - -static struct freq_attr *cris_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver cris_freq_driver = { .get = cris_freq_get_cpu_frequency, - .verify = cris_freq_verify, - .target = cris_freq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = cris_freq_target, .init = cris_freq_cpu_init, - .exit = cris_freq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "cris_freq", - .attr = cris_freq_attr, + .attr = cpufreq_generic_attr, }; static int __init cris_freq_init(void) diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c index 72328f77dc53..26d940d40b1d 100644 --- a/drivers/cpufreq/cris-etraxfs-cpufreq.c +++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c @@ -27,18 +27,11 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) return clk_ctrl.pll ? 200000 : 6000; } -static void cris_freq_set_cpu_state(struct cpufreq_policy *policy, - unsigned int state) +static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) { - struct cpufreq_freqs freqs; reg_config_rw_clk_ctrl clk_ctrl; clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); - freqs.old = cris_freq_get_cpu_frequency(policy->cpu); - freqs.new = cris_freq_table[state].frequency; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - local_irq_disable(); /* Even though we may be SMP they will share the same clock @@ -51,64 +44,22 @@ static void cris_freq_set_cpu_state(struct cpufreq_policy *policy, local_irq_enable(); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); -}; - -static int cris_freq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]); -} - -static int cris_freq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target - (policy, cris_freq_table, target_freq, relation, &newstate)) - return -EINVAL; - - cris_freq_set_cpu_state(policy, newstate); - return 0; } static int cris_freq_cpu_init(struct cpufreq_policy *policy) { - int result; - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 1000000; /* 1ms */ - policy->cur = cris_freq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table); - if (result) - return (result); - - cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu); - - return 0; + return cpufreq_generic_init(policy, cris_freq_table, 1000000); } -static int cris_freq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static struct freq_attr *cris_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver cris_freq_driver = { .get = cris_freq_get_cpu_frequency, - .verify = cris_freq_verify, - .target = cris_freq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = cris_freq_target, .init = cris_freq_cpu_init, - .exit = cris_freq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "cris_freq", - .attr = cris_freq_attr, + .attr = cpufreq_generic_attr, }; static int __init cris_freq_init(void) diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 551dd655c6f2..5e8a854381b7 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c @@ -50,9 +50,7 @@ static int davinci_verify_speed(struct cpufreq_policy *policy) if (policy->cpu) return -EINVAL; - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - + cpufreq_verify_within_cpu_limits(policy); policy->min = clk_round_rate(armclk, policy->min * 1000) / 1000; policy->max = clk_round_rate(armclk, policy->max * 1000) / 1000; cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, @@ -68,58 +66,38 @@ static unsigned int davinci_getspeed(unsigned int cpu) return clk_get_rate(cpufreq.armclk) / 1000; } -static int davinci_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) +static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) { - int ret = 0; - unsigned int idx; - struct cpufreq_freqs freqs; struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data; struct clk *armclk = cpufreq.armclk; + unsigned int old_freq, new_freq; + int ret = 0; - freqs.old = davinci_getspeed(0); - freqs.new = clk_round_rate(armclk, target_freq * 1000) / 1000; - - if (freqs.old == freqs.new) - return ret; - - dev_dbg(cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new); - - ret = cpufreq_frequency_table_target(policy, pdata->freq_table, - freqs.new, relation, &idx); - if (ret) - return -EINVAL; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + old_freq = davinci_getspeed(0); + new_freq = pdata->freq_table[idx].frequency; /* if moving to higher frequency, up the voltage beforehand */ - if (pdata->set_voltage && freqs.new > freqs.old) { + if (pdata->set_voltage && new_freq > old_freq) { ret = pdata->set_voltage(idx); if (ret) - goto out; + return ret; } ret = clk_set_rate(armclk, idx); if (ret) - goto out; + return ret; if (cpufreq.asyncclk) { ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate); if (ret) - goto out; + return ret; } /* if moving to lower freq, lower the voltage after lowering freq */ - if (pdata->set_voltage && freqs.new < freqs.old) + if (pdata->set_voltage && new_freq < old_freq) pdata->set_voltage(idx); -out: - if (ret) - freqs.new = freqs.old; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - return ret; + return 0; } static int davinci_cpu_init(struct cpufreq_policy *policy) @@ -138,47 +116,24 @@ static int davinci_cpu_init(struct cpufreq_policy *policy) return result; } - 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; - } - - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - /* * Time measurement across the target() function yields ~1500-1800us * time taken with no drivers on notification list. * Setting the latency to 2000 us to accommodate addition of drivers * to pre/post change notification list. */ - policy->cpuinfo.transition_latency = 2000 * 1000; - return 0; + return cpufreq_generic_init(policy, freq_table, 2000 * 1000); } -static int davinci_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static struct freq_attr *davinci_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver davinci_driver = { .flags = CPUFREQ_STICKY, .verify = davinci_verify_speed, - .target = davinci_target, + .target_index = davinci_target, .get = davinci_getspeed, .init = davinci_cpu_init, - .exit = davinci_cpu_exit, + .exit = cpufreq_generic_exit, .name = "davinci", - .attr = davinci_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int __init davinci_cpufreq_probe(struct platform_device *pdev) diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 26321cdc1946..0e67ab96321a 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c @@ -19,51 +19,11 @@ static struct cpufreq_frequency_table *freq_table; static struct clk *armss_clk; -static struct freq_attr *dbx500_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static int dbx500_cpufreq_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, freq_table); -} - static int dbx500_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int index) { - struct cpufreq_freqs freqs; - unsigned int idx; - int ret; - - /* Lookup the next frequency */ - if (cpufreq_frequency_table_target(policy, freq_table, target_freq, - relation, &idx)) - return -EINVAL; - - freqs.old = policy->cur; - freqs.new = freq_table[idx].frequency; - - if (freqs.old == freqs.new) - return 0; - - /* pre-change notification */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* update armss clk frequency */ - ret = clk_set_rate(armss_clk, freqs.new * 1000); - - if (ret) { - pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n", - freqs.new * 1000, ret); - freqs.new = freqs.old; - } - - /* post change notification */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - return ret; + return clk_set_rate(armss_clk, freq_table[index].frequency * 1000); } static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu) @@ -84,43 +44,17 @@ static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu) static int dbx500_cpufreq_init(struct cpufreq_policy *policy) { - int res; - - /* get policy fields based on the table */ - res = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (!res) - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - else { - pr_err("dbx500-cpufreq: Failed to read policy table\n"); - return res; - } - - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - policy->cur = dbx500_cpufreq_getspeed(policy->cpu); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - - /* - * FIXME : Need to take time measurement across the target() - * function with no/some/all drivers in the notification - * list. - */ - policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */ - - /* policy sharing between dual CPUs */ - cpumask_setall(policy->cpus); - - return 0; + return cpufreq_generic_init(policy, freq_table, 20 * 1000); } static struct cpufreq_driver dbx500_cpufreq_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS, - .verify = dbx500_cpufreq_verify_speed, - .target = dbx500_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = dbx500_cpufreq_target, .get = dbx500_cpufreq_getspeed, .init = dbx500_cpufreq_init, .name = "DBX500", - .attr = dbx500_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int dbx500_cpufreq_probe(struct platform_device *pdev) diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index 09f64cc83019..9012b8bb6b64 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -107,15 +107,9 @@ static int eps_set_state(struct eps_cpu_data *centaur, struct cpufreq_policy *policy, u32 dest_state) { - struct cpufreq_freqs freqs; u32 lo, hi; - int err = 0; int i; - freqs.old = eps_get(policy->cpu); - freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* Wait while CPU is busy */ rdmsr(MSR_IA32_PERF_STATUS, lo, hi); i = 0; @@ -124,8 +118,7 @@ static int eps_set_state(struct eps_cpu_data *centaur, rdmsr(MSR_IA32_PERF_STATUS, lo, hi); i++; if (unlikely(i > 64)) { - err = -ENODEV; - goto postchange; + return -ENODEV; } } /* Set new multiplier and voltage */ @@ -137,16 +130,10 @@ static int eps_set_state(struct eps_cpu_data *centaur, rdmsr(MSR_IA32_PERF_STATUS, lo, hi); i++; if (unlikely(i > 64)) { - err = -ENODEV; - goto postchange; + return -ENODEV; } } while (lo & ((1 << 16) | (1 << 17))); - /* Return current frequency */ -postchange: - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - freqs.new = centaur->fsb * ((lo >> 8) & 0xff); - #ifdef DEBUG { u8 current_multiplier, current_voltage; @@ -161,19 +148,12 @@ postchange: current_multiplier); } #endif - if (err) - freqs.new = freqs.old; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - return err; + return 0; } -static int eps_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int eps_target(struct cpufreq_policy *policy, unsigned int index) { struct eps_cpu_data *centaur; - unsigned int newstate = 0; unsigned int cpu = policy->cpu; unsigned int dest_state; int ret; @@ -182,28 +162,14 @@ static int eps_target(struct cpufreq_policy *policy, return -ENODEV; centaur = eps_cpu[cpu]; - if (unlikely(cpufreq_frequency_table_target(policy, - &eps_cpu[cpu]->freq_table[0], - target_freq, - relation, - &newstate))) { - return -EINVAL; - } - /* Make frequency transition */ - dest_state = centaur->freq_table[newstate].driver_data & 0xffff; + dest_state = centaur->freq_table[index].driver_data & 0xffff; ret = eps_set_state(centaur, policy, dest_state); if (ret) printk(KERN_ERR "eps: Timeout!\n"); return ret; } -static int eps_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - &eps_cpu[policy->cpu]->freq_table[0]); -} - static int eps_cpu_init(struct cpufreq_policy *policy) { unsigned int i; @@ -401,15 +367,13 @@ static int eps_cpu_init(struct cpufreq_policy *policy) } policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ - policy->cur = fsb * current_multiplier; - ret = cpufreq_frequency_table_cpuinfo(policy, ¢aur->freq_table[0]); + ret = cpufreq_table_validate_and_show(policy, ¢aur->freq_table[0]); if (ret) { kfree(centaur); return ret; } - cpufreq_frequency_table_get_attr(¢aur->freq_table[0], policy->cpu); return 0; } @@ -424,19 +388,14 @@ static int eps_cpu_exit(struct cpufreq_policy *policy) return 0; } -static struct freq_attr *eps_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver eps_driver = { - .verify = eps_verify, - .target = eps_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = eps_target, .init = eps_cpu_init, .exit = eps_cpu_exit, .get = eps_get, .name = "e_powersaver", - .attr = eps_attr, + .attr = cpufreq_generic_attr, }; diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c index 823a400d98fd..de08acff5101 100644 --- a/drivers/cpufreq/elanfreq.c +++ b/drivers/cpufreq/elanfreq.c @@ -105,32 +105,9 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) } -/** - * elanfreq_set_cpu_frequency: Change the CPU core frequency - * @cpu: cpu number - * @freq: frequency in kHz - * - * This function takes a frequency value and changes the CPU frequency - * according to this. Note that the frequency has to be checked by - * elanfreq_validatespeed() for correctness! - * - * There is no return value. - */ - -static void elanfreq_set_cpu_state(struct cpufreq_policy *policy, - unsigned int state) +static int elanfreq_target(struct cpufreq_policy *policy, + unsigned int state) { - struct cpufreq_freqs freqs; - - freqs.old = elanfreq_get_cpu_frequency(0); - freqs.new = elan_multiplier[state].clock; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n", - elan_multiplier[state].clock); - - /* * Access to the Elan's internal registers is indexed via * 0x22: Chip Setup & Control Register Index Register (CSCI) @@ -161,39 +138,8 @@ static void elanfreq_set_cpu_state(struct cpufreq_policy *policy, udelay(10000); local_irq_enable(); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); -}; - - -/** - * elanfreq_validatespeed: test if frequency range is valid - * @policy: the policy to validate - * - * This function checks if a given frequency range in kHz is valid - * for the hardware supported by the driver. - */ - -static int elanfreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]); -} - -static int elanfreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], - target_freq, relation, &newstate)) - return -EINVAL; - - elanfreq_set_cpu_state(policy, newstate); - return 0; } - - /* * Module init and exit code */ @@ -202,7 +148,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = &cpu_data(0); unsigned int i; - int result; /* capability check */ if ((c->x86_vendor != X86_VENDOR_AMD) || @@ -221,21 +166,8 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = elanfreq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table); - if (result) - return result; - cpufreq_frequency_table_get_attr(elanfreq_table, policy->cpu); - return 0; -} - - -static int elanfreq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_table_validate_and_show(policy, elanfreq_table); } @@ -261,20 +193,14 @@ __setup("elanfreq=", elanfreq_setup); #endif -static struct freq_attr *elanfreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - static struct cpufreq_driver elanfreq_driver = { .get = elanfreq_get_cpu_frequency, - .verify = elanfreq_verify, - .target = elanfreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = elanfreq_target, .init = elanfreq_cpu_init, - .exit = elanfreq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "elanfreq", - .attr = elanfreq_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id elan_id[] = { diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 0fac34439e31..f3c22874da75 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -25,18 +25,11 @@ static struct exynos_dvfs_info *exynos_info; static struct regulator *arm_regulator; -static struct cpufreq_freqs freqs; static unsigned int locking_frequency; static bool frequency_locked; static DEFINE_MUTEX(cpufreq_lock); -static int exynos_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - exynos_info->freq_table); -} - static unsigned int exynos_getspeed(unsigned int cpu) { return clk_get_rate(exynos_info->cpu_clk) / 1000; @@ -65,21 +58,18 @@ static int exynos_cpufreq_scale(unsigned int target_freq) struct cpufreq_policy *policy = cpufreq_cpu_get(0); unsigned int arm_volt, safe_arm_volt = 0; unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; + unsigned int old_freq; int index, old_index; int ret = 0; - freqs.old = policy->cur; - freqs.new = target_freq; - - if (freqs.new == freqs.old) - goto out; + old_freq = policy->cur; /* * The policy max have been changed so that we cannot get proper * old_index with cpufreq_frequency_table_target(). Thus, ignore - * policy and get the index from the raw freqeuncy table. + * policy and get the index from the raw frequency table. */ - old_index = exynos_cpufreq_get_index(freqs.old); + old_index = exynos_cpufreq_get_index(old_freq); if (old_index < 0) { ret = old_index; goto out; @@ -104,17 +94,14 @@ static int exynos_cpufreq_scale(unsigned int target_freq) } arm_volt = volt_table[index]; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* When the new frequency is higher than current frequency */ - if ((freqs.new > freqs.old) && !safe_arm_volt) { + if ((target_freq > old_freq) && !safe_arm_volt) { /* Firstly, voltage up to increase frequency */ ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); if (ret) { pr_err("%s: failed to set cpu voltage to %d\n", __func__, arm_volt); - freqs.new = freqs.old; - goto post_notify; + return ret; } } @@ -124,24 +111,17 @@ static int exynos_cpufreq_scale(unsigned int target_freq) if (ret) { pr_err("%s: failed to set cpu voltage to %d\n", __func__, safe_arm_volt); - freqs.new = freqs.old; - goto post_notify; + return ret; } } exynos_info->set_freq(old_index, index); -post_notify: - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - if (ret) - goto out; - /* When the new frequency is lower than current frequency */ - if ((freqs.new < freqs.old) || - ((freqs.new > freqs.old) && safe_arm_volt)) { + if ((target_freq < old_freq) || + ((target_freq > old_freq) && safe_arm_volt)) { /* down the voltage after frequency change */ - regulator_set_voltage(arm_regulator, arm_volt, + ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); if (ret) { pr_err("%s: failed to set cpu voltage to %d\n", @@ -151,19 +131,14 @@ post_notify: } out: - cpufreq_cpu_put(policy); return ret; } -static int exynos_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int exynos_target(struct cpufreq_policy *policy, unsigned int index) { struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; - unsigned int index; - unsigned int new_freq; int ret = 0; mutex_lock(&cpufreq_lock); @@ -171,15 +146,7 @@ static int exynos_target(struct cpufreq_policy *policy, if (frequency_locked) goto out; - if (cpufreq_frequency_table_target(policy, freq_table, - target_freq, relation, &index)) { - ret = -EINVAL; - goto out; - } - - new_freq = freq_table[index].frequency; - - ret = exynos_cpufreq_scale(new_freq); + ret = exynos_cpufreq_scale(freq_table[index].frequency); out: mutex_unlock(&cpufreq_lock); @@ -247,38 +214,18 @@ static struct notifier_block exynos_cpufreq_nb = { static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) { - policy->cur = policy->min = policy->max = exynos_getspeed(policy->cpu); - - cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu); - - /* set the transition latency value */ - policy->cpuinfo.transition_latency = 100000; - - cpumask_setall(policy->cpus); - - return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table); -} - -static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_generic_init(policy, exynos_info->freq_table, 100000); } -static struct freq_attr *exynos_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver exynos_driver = { .flags = CPUFREQ_STICKY, - .verify = exynos_verify_speed, - .target = exynos_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = exynos_target, .get = exynos_getspeed, .init = exynos_cpufreq_cpu_init, - .exit = exynos_cpufreq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "exynos_cpufreq", - .attr = exynos_cpufreq_attr, + .attr = cpufreq_generic_attr, #ifdef CONFIG_PM .suspend = exynos_cpufreq_suspend, .resume = exynos_cpufreq_resume, diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c index add7fbec4fc9..dfd1643b0b2f 100644 --- a/drivers/cpufreq/exynos4210-cpufreq.c +++ b/drivers/cpufreq/exynos4210-cpufreq.c @@ -81,9 +81,9 @@ static void exynos4210_set_clkdiv(unsigned int div_index) static void exynos4210_set_apll(unsigned int index) { - unsigned int tmp; + unsigned int tmp, freq = apll_freq_4210[index].freq; - /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ + /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ clk_set_parent(moutcore, mout_mpll); do { @@ -92,21 +92,9 @@ static void exynos4210_set_apll(unsigned int index) tmp &= 0x7; } while (tmp != 0x2); - /* 2. Set APLL Lock time */ - __raw_writel(EXYNOS4_APLL_LOCKTIME, EXYNOS4_APLL_LOCK); - - /* 3. Change PLL PMS values */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0)); - tmp |= apll_freq_4210[index].mps; - __raw_writel(tmp, EXYNOS4_APLL_CON0); + clk_set_rate(mout_apll, freq * 1000); - /* 4. wait_lock_time */ - do { - tmp = __raw_readl(EXYNOS4_APLL_CON0); - } while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT))); - - /* 5. MUX_CORE_SEL = APLL */ + /* MUX_CORE_SEL = APLL */ clk_set_parent(moutcore, mout_apll); do { @@ -115,53 +103,15 @@ static void exynos4210_set_apll(unsigned int index) } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)); } -static bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index) -{ - unsigned int old_pm = apll_freq_4210[old_index].mps >> 8; - unsigned int new_pm = apll_freq_4210[new_index].mps >> 8; - - return (old_pm == new_pm) ? 0 : 1; -} - static void exynos4210_set_frequency(unsigned int old_index, unsigned int new_index) { - unsigned int tmp; - if (old_index > new_index) { - if (!exynos4210_pms_change(old_index, new_index)) { - /* 1. Change the system clock divider values */ - exynos4210_set_clkdiv(new_index); - - /* 2. Change just s value in apll m,p,s value */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp &= ~(0x7 << 0); - tmp |= apll_freq_4210[new_index].mps & 0x7; - __raw_writel(tmp, EXYNOS4_APLL_CON0); - } else { - /* Clock Configuration Procedure */ - /* 1. Change the system clock divider values */ - exynos4210_set_clkdiv(new_index); - /* 2. Change the apll m,p,s value */ - exynos4210_set_apll(new_index); - } + exynos4210_set_clkdiv(new_index); + exynos4210_set_apll(new_index); } else if (old_index < new_index) { - if (!exynos4210_pms_change(old_index, new_index)) { - /* 1. Change just s value in apll m,p,s value */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp &= ~(0x7 << 0); - tmp |= apll_freq_4210[new_index].mps & 0x7; - __raw_writel(tmp, EXYNOS4_APLL_CON0); - - /* 2. Change the system clock divider values */ - exynos4210_set_clkdiv(new_index); - } else { - /* Clock Configuration Procedure */ - /* 1. Change the apll m,p,s value */ - exynos4210_set_apll(new_index); - /* 2. Change the system clock divider values */ - exynos4210_set_clkdiv(new_index); - } + exynos4210_set_apll(new_index); + exynos4210_set_clkdiv(new_index); } } @@ -194,7 +144,6 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info) info->volt_table = exynos4210_volt_table; info->freq_table = exynos4210_freq_table; info->set_freq = exynos4210_set_frequency; - info->need_apll_change = exynos4210_pms_change; return 0; @@ -208,4 +157,3 @@ err_moutcore: pr_debug("%s: failed initialization\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(exynos4210_cpufreq_init); diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index 08b7477b0aa2..efad5e657f6f 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c @@ -128,9 +128,9 @@ static void exynos4x12_set_clkdiv(unsigned int div_index) static void exynos4x12_set_apll(unsigned int index) { - unsigned int tmp, pdiv; + unsigned int tmp, freq = apll_freq_4x12[index].freq; - /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ + /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ clk_set_parent(moutcore, mout_mpll); do { @@ -140,24 +140,9 @@ static void exynos4x12_set_apll(unsigned int index) tmp &= 0x7; } while (tmp != 0x2); - /* 2. Set APLL Lock time */ - pdiv = ((apll_freq_4x12[index].mps >> 8) & 0x3f); + clk_set_rate(mout_apll, freq * 1000); - __raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK); - - /* 3. Change PLL PMS values */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0)); - tmp |= apll_freq_4x12[index].mps; - __raw_writel(tmp, EXYNOS4_APLL_CON0); - - /* 4. wait_lock_time */ - do { - cpu_relax(); - tmp = __raw_readl(EXYNOS4_APLL_CON0); - } while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT))); - - /* 5. MUX_CORE_SEL = APLL */ + /* MUX_CORE_SEL = APLL */ clk_set_parent(moutcore, mout_apll); do { @@ -167,52 +152,15 @@ static void exynos4x12_set_apll(unsigned int index) } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)); } -static bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index) -{ - unsigned int old_pm = apll_freq_4x12[old_index].mps >> 8; - unsigned int new_pm = apll_freq_4x12[new_index].mps >> 8; - - return (old_pm == new_pm) ? 0 : 1; -} - static void exynos4x12_set_frequency(unsigned int old_index, unsigned int new_index) { - unsigned int tmp; - if (old_index > new_index) { - if (!exynos4x12_pms_change(old_index, new_index)) { - /* 1. Change the system clock divider values */ - exynos4x12_set_clkdiv(new_index); - /* 2. Change just s value in apll m,p,s value */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp &= ~(0x7 << 0); - tmp |= apll_freq_4x12[new_index].mps & 0x7; - __raw_writel(tmp, EXYNOS4_APLL_CON0); - - } else { - /* Clock Configuration Procedure */ - /* 1. Change the system clock divider values */ - exynos4x12_set_clkdiv(new_index); - /* 2. Change the apll m,p,s value */ - exynos4x12_set_apll(new_index); - } + exynos4x12_set_clkdiv(new_index); + exynos4x12_set_apll(new_index); } else if (old_index < new_index) { - if (!exynos4x12_pms_change(old_index, new_index)) { - /* 1. Change just s value in apll m,p,s value */ - tmp = __raw_readl(EXYNOS4_APLL_CON0); - tmp &= ~(0x7 << 0); - tmp |= apll_freq_4x12[new_index].mps & 0x7; - __raw_writel(tmp, EXYNOS4_APLL_CON0); - /* 2. Change the system clock divider values */ - exynos4x12_set_clkdiv(new_index); - } else { - /* Clock Configuration Procedure */ - /* 1. Change the apll m,p,s value */ - exynos4x12_set_apll(new_index); - /* 2. Change the system clock divider values */ - exynos4x12_set_clkdiv(new_index); - } + exynos4x12_set_apll(new_index); + exynos4x12_set_clkdiv(new_index); } } @@ -250,7 +198,6 @@ int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info) info->volt_table = exynos4x12_volt_table; info->freq_table = exynos4x12_freq_table; info->set_freq = exynos4x12_set_frequency; - info->need_apll_change = exynos4x12_pms_change; return 0; @@ -264,4 +211,3 @@ err_moutcore: pr_debug("%s: failed initialization\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(exynos4x12_cpufreq_init); diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c index 9fae466d7746..8feda86fe42c 100644 --- a/drivers/cpufreq/exynos5250-cpufreq.c +++ b/drivers/cpufreq/exynos5250-cpufreq.c @@ -236,4 +236,3 @@ err_moutcore: pr_err("%s: failed initialization\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(exynos5250_cpufreq_init); diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index be5380ecdcd4..76bef8b078cb 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -20,7 +20,7 @@ #include <linux/module.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/opp.h> +#include <linux/pm_opp.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -118,12 +118,12 @@ static int init_div_table(void) struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table; unsigned int tmp, clk_div, ema_div, freq, volt_id; int i = 0; - struct opp *opp; + struct dev_pm_opp *opp; rcu_read_lock(); for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) { - opp = opp_find_freq_exact(dvfs_info->dev, + opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, freq_tbl[i].frequency * 1000, true); if (IS_ERR(opp)) { rcu_read_unlock(); @@ -142,7 +142,7 @@ static int init_div_table(void) << P0_7_CSCLKDEV_SHIFT; /* Calculate EMA */ - volt_id = opp_get_voltage(opp); + volt_id = dev_pm_opp_get_voltage(opp); volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP; if (volt_id < PMIC_HIGH_VOLT) { ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) | @@ -209,38 +209,22 @@ static void exynos_enable_dvfs(void) dvfs_info->base + XMU_DVFS_CTRL); } -static int exynos_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - dvfs_info->freq_table); -} - static unsigned int exynos_getspeed(unsigned int cpu) { return dvfs_info->cur_frequency; } -static int exynos_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int exynos_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int index, tmp; - int ret = 0, i; + unsigned int tmp; + int i; struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; mutex_lock(&cpufreq_lock); - ret = cpufreq_frequency_table_target(policy, freq_table, - target_freq, relation, &index); - if (ret) - goto out; - freqs.old = dvfs_info->cur_frequency; freqs.new = freq_table[index].frequency; - if (freqs.old == freqs.new) - goto out; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); /* Set the target frequency in all C0_3_PSTATE register */ @@ -251,9 +235,8 @@ static int exynos_target(struct cpufreq_policy *policy, __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4); } -out: mutex_unlock(&cpufreq_lock); - return ret; + return 0; } static void exynos_cpufreq_work(struct work_struct *work) @@ -324,30 +307,19 @@ static void exynos_sort_descend_freq_table(void) static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) { - int ret; - - ret = cpufreq_frequency_table_cpuinfo(policy, dvfs_info->freq_table); - if (ret) { - dev_err(dvfs_info->dev, "Invalid frequency table: %d\n", ret); - return ret; - } - - policy->cur = dvfs_info->cur_frequency; - policy->cpuinfo.transition_latency = dvfs_info->latency; - cpumask_setall(policy->cpus); - - cpufreq_frequency_table_get_attr(dvfs_info->freq_table, policy->cpu); - - return 0; + return cpufreq_generic_init(policy, dvfs_info->freq_table, + dvfs_info->latency); } static struct cpufreq_driver exynos_driver = { - .flags = CPUFREQ_STICKY, - .verify = exynos_verify_speed, - .target = exynos_target, + .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = exynos_target, .get = exynos_getspeed, .init = exynos_cpufreq_cpu_init, + .exit = cpufreq_generic_exit, .name = CPUFREQ_NAME, + .attr = cpufreq_generic_attr, }; static const struct of_device_id exynos_cpufreq_match[] = { @@ -399,13 +371,14 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_put_node; } - ret = opp_init_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); + ret = dev_pm_opp_init_cpufreq_table(dvfs_info->dev, + &dvfs_info->freq_table); if (ret) { dev_err(dvfs_info->dev, "failed to init cpufreq table: %d\n", ret); goto err_put_node; } - dvfs_info->freq_count = opp_get_opp_count(dvfs_info->dev); + dvfs_info->freq_count = dev_pm_opp_get_opp_count(dvfs_info->dev); exynos_sort_descend_freq_table(); if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency)) @@ -454,7 +427,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) return 0; err_free_table: - opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); + dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); err_put_node: of_node_put(np); dev_err(&pdev->dev, "%s: failed initialization\n", __func__); @@ -464,7 +437,7 @@ err_put_node: static int exynos_cpufreq_remove(struct platform_device *pdev) { cpufreq_unregister_driver(&exynos_driver); - opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); + dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); return 0; } diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index f111454a7aea..3458d27f63b4 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -54,31 +54,30 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { - unsigned int next_larger = ~0; - unsigned int i; - unsigned int count = 0; + unsigned int next_larger = ~0, freq, i = 0; + bool found = false; pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); - for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { - unsigned int freq = table[i].frequency; + for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) { if (freq == CPUFREQ_ENTRY_INVALID) continue; - if ((freq >= policy->min) && (freq <= policy->max)) - count++; - else if ((next_larger > freq) && (freq > policy->max)) + if ((freq >= policy->min) && (freq <= policy->max)) { + found = true; + break; + } + + if ((next_larger > freq) && (freq > policy->max)) next_larger = freq; } - if (!count) + if (!found) { policy->max = next_larger; - - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); + } pr_debug("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); @@ -87,6 +86,20 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); +/* + * Generic routine to verify policy & frequency table, requires driver to call + * cpufreq_frequency_table_get_attr() prior to it. + */ +int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *table = + cpufreq_frequency_get_table(policy->cpu); + if (!table) + return -ENODEV; + + return cpufreq_frequency_table_verify(policy, table); +} +EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); int cpufreq_frequency_table_target(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, @@ -200,6 +213,12 @@ struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { }; EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); +struct freq_attr *cpufreq_generic_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; +EXPORT_SYMBOL_GPL(cpufreq_generic_attr); + /* * if you use these, you must assure that the frequency table is valid * all the time between get_attr and put_attr! @@ -219,6 +238,18 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu) } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); +int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table) +{ + int ret = cpufreq_frequency_table_cpuinfo(policy, table); + + if (!ret) + cpufreq_frequency_table_get_attr(table, policy->cpu); + + return ret; +} +EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); + void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy) { pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n", diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index 70442c7b5e71..d83e8266a58e 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -401,7 +401,7 @@ static int cpufreq_gx_target(struct cpufreq_policy *policy, static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) { - unsigned int maxfreq, curfreq; + unsigned int maxfreq; if (!policy || policy->cpu != 0) return -ENODEV; @@ -415,10 +415,8 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; stock_freq = maxfreq; - curfreq = gx_get_cpuspeed(0); pr_debug("cpu max frequency is %d.\n", maxfreq); - pr_debug("cpu current frequency is %dkHz.\n", curfreq); /* setup basic struct for cpufreq API */ policy->cpu = 0; @@ -428,7 +426,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) else policy->min = maxfreq / POLICY_MIN_DIV; policy->max = maxfreq; - policy->cur = curfreq; policy->cpuinfo.min_freq = maxfreq / max_duration; policy->cpuinfo.max_freq = maxfreq; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c index 794123fcf3e3..bf8902a0866d 100644 --- a/drivers/cpufreq/highbank-cpufreq.c +++ b/drivers/cpufreq/highbank-cpufreq.c @@ -66,7 +66,8 @@ static int hb_cpufreq_driver_init(void) struct device_node *np; int ret; - if (!of_machine_is_compatible("calxeda,highbank")) + if ((!of_machine_is_compatible("calxeda,highbank")) && + (!of_machine_is_compatible("calxeda,ecx-2000"))) return -ENODEV; cpu_dev = get_cpu_device(0); diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 3e14f0317175..53c6ac637e10 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -141,7 +141,6 @@ processor_set_freq ( { int ret = 0; u32 value = 0; - struct cpufreq_freqs cpufreq_freqs; cpumask_t saved_mask; int retval; @@ -168,13 +167,6 @@ processor_set_freq ( pr_debug("Transitioning from P%d to P%d\n", data->acpi_data.state, state); - /* cpufreq frequency struct */ - cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; - cpufreq_freqs.new = data->freq_table[state].frequency; - - /* notify cpufreq */ - cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_PRECHANGE); - /* * First we write the target state's 'control' value to the * control_register. @@ -186,22 +178,11 @@ processor_set_freq ( ret = processor_set_pstate(value); if (ret) { - unsigned int tmp = cpufreq_freqs.new; - cpufreq_notify_transition(policy, &cpufreq_freqs, - CPUFREQ_POSTCHANGE); - cpufreq_freqs.new = cpufreq_freqs.old; - cpufreq_freqs.old = tmp; - cpufreq_notify_transition(policy, &cpufreq_freqs, - CPUFREQ_PRECHANGE); - cpufreq_notify_transition(policy, &cpufreq_freqs, - CPUFREQ_POSTCHANGE); printk(KERN_WARNING "Transition failed with error %d\n", ret); retval = -ENODEV; goto migrate_end; } - cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_POSTCHANGE); - data->acpi_data.state = state; retval = 0; @@ -227,42 +208,11 @@ acpi_cpufreq_get ( static int acpi_cpufreq_target ( struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - unsigned int next_state = 0; - unsigned int result = 0; - - pr_debug("acpi_cpufreq_setpolicy\n"); - - result = cpufreq_frequency_table_target(policy, - data->freq_table, target_freq, relation, &next_state); - if (result) - return (result); - - result = processor_set_freq(data, policy, next_state); - - return (result); -} - - -static int -acpi_cpufreq_verify ( - struct cpufreq_policy *policy) + unsigned int index) { - unsigned int result = 0; - struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - - pr_debug("acpi_cpufreq_verify\n"); - - result = cpufreq_frequency_table_verify(policy, - data->freq_table); - - return (result); + return processor_set_freq(acpi_io_data[policy->cpu], policy, index); } - static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -321,7 +271,6 @@ acpi_cpufreq_cpu_init ( data->acpi_data.states[i].transition_latency * 1000; } } - policy->cur = processor_get_freq(data, policy->cpu); /* table init */ for (i = 0; i <= data->acpi_data.state_count; i++) @@ -335,7 +284,7 @@ acpi_cpufreq_cpu_init ( } } - result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); + result = cpufreq_table_validate_and_show(policy, data->freq_table); if (result) { goto err_freqfree; } @@ -356,8 +305,6 @@ acpi_cpufreq_cpu_init ( (u32) data->acpi_data.states[i].status, (u32) data->acpi_data.states[i].control); - cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); - /* the first call to ->target() should result in us actually * writing something to the appropriate registers. */ data->resume = 1; @@ -396,20 +343,14 @@ acpi_cpufreq_cpu_exit ( } -static struct freq_attr* acpi_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - static struct cpufreq_driver acpi_cpufreq_driver = { - .verify = acpi_cpufreq_verify, - .target = acpi_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = acpi_cpufreq_target, .get = acpi_cpufreq_get, .init = acpi_cpufreq_cpu_init, .exit = acpi_cpufreq_cpu_exit, .name = "acpi-cpufreq", - .attr = acpi_cpufreq_attr, + .attr = cpufreq_generic_attr, }; diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index c3fd2a101ca0..4b3f18e5f36b 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -13,7 +13,7 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/opp.h> +#include <linux/pm_opp.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -35,73 +35,52 @@ static struct device *cpu_dev; static struct cpufreq_frequency_table *freq_table; static unsigned int transition_latency; -static int imx6q_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, freq_table); -} - static unsigned int imx6q_get_speed(unsigned int cpu) { return clk_get_rate(arm_clk) / 1000; } -static int imx6q_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) +static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) { - struct cpufreq_freqs freqs; - struct opp *opp; + struct dev_pm_opp *opp; unsigned long freq_hz, volt, volt_old; - unsigned int index; + unsigned int old_freq, new_freq; int ret; - ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, - relation, &index); - if (ret) { - dev_err(cpu_dev, "failed to match target frequency %d: %d\n", - target_freq, ret); - return ret; - } - - freqs.new = freq_table[index].frequency; - freq_hz = freqs.new * 1000; - freqs.old = clk_get_rate(arm_clk) / 1000; - - if (freqs.old == freqs.new) - return 0; + new_freq = freq_table[index].frequency; + freq_hz = new_freq * 1000; + old_freq = clk_get_rate(arm_clk) / 1000; rcu_read_lock(); - opp = opp_find_freq_ceil(cpu_dev, &freq_hz); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); return PTR_ERR(opp); } - volt = opp_get_voltage(opp); + volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", - freqs.old / 1000, volt_old / 1000, - freqs.new / 1000, volt / 1000); - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + old_freq / 1000, volt_old / 1000, + new_freq / 1000, volt / 1000); /* scaling up? scale voltage before frequency */ - if (freqs.new > freqs.old) { + if (new_freq > old_freq) { ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); - freqs.new = freqs.old; - goto post_notify; + return ret; } /* * Need to increase vddpu and vddsoc for safety * if we are about to run at 1.2 GHz. */ - if (freqs.new == FREQ_1P2_GHZ / 1000) { + if (new_freq == FREQ_1P2_GHZ / 1000) { regulator_set_voltage_tol(pu_reg, PU_SOC_VOLTAGE_HIGH, 0); regulator_set_voltage_tol(soc_reg, @@ -121,21 +100,20 @@ static int imx6q_set_target(struct cpufreq_policy *policy, clk_set_parent(step_clk, pll2_pfd2_396m_clk); clk_set_parent(pll1_sw_clk, step_clk); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { - clk_set_rate(pll1_sys_clk, freqs.new * 1000); + clk_set_rate(pll1_sys_clk, new_freq * 1000); clk_set_parent(pll1_sw_clk, pll1_sys_clk); } /* Ensure the arm clock divider is what we expect */ - ret = clk_set_rate(arm_clk, freqs.new * 1000); + ret = clk_set_rate(arm_clk, new_freq * 1000); if (ret) { dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); regulator_set_voltage_tol(arm_reg, volt_old, 0); - freqs.new = freqs.old; - goto post_notify; + return ret; } /* scaling down? scale voltage after frequency */ - if (freqs.new < freqs.old) { + if (new_freq < old_freq) { ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_warn(cpu_dev, @@ -143,7 +121,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, ret = 0; } - if (freqs.old == FREQ_1P2_GHZ / 1000) { + if (old_freq == FREQ_1P2_GHZ / 1000) { regulator_set_voltage_tol(pu_reg, PU_SOC_VOLTAGE_NORMAL, 0); regulator_set_voltage_tol(soc_reg, @@ -151,55 +129,28 @@ static int imx6q_set_target(struct cpufreq_policy *policy, } } -post_notify: - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - return ret; -} - -static int imx6q_cpufreq_init(struct cpufreq_policy *policy) -{ - int ret; - - ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (ret) { - dev_err(cpu_dev, "invalid frequency table: %d\n", ret); - return ret; - } - - policy->cpuinfo.transition_latency = transition_latency; - policy->cur = clk_get_rate(arm_clk) / 1000; - cpumask_setall(policy->cpus); - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - return 0; } -static int imx6q_cpufreq_exit(struct cpufreq_policy *policy) +static int imx6q_cpufreq_init(struct cpufreq_policy *policy) { - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_generic_init(policy, freq_table, transition_latency); } -static struct freq_attr *imx6q_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver imx6q_cpufreq_driver = { - .verify = imx6q_verify_speed, - .target = imx6q_set_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = imx6q_set_target, .get = imx6q_get_speed, .init = imx6q_cpufreq_init, - .exit = imx6q_cpufreq_exit, + .exit = cpufreq_generic_exit, .name = "imx6q-cpufreq", - .attr = imx6q_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int imx6q_cpufreq_probe(struct platform_device *pdev) { struct device_node *np; - struct opp *opp; + struct dev_pm_opp *opp; unsigned long min_volt, max_volt; int num, ret; @@ -237,14 +188,14 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) } /* We expect an OPP table supplied by platform */ - num = opp_get_opp_count(cpu_dev); + num = dev_pm_opp_get_opp_count(cpu_dev); if (num < 0) { ret = num; dev_err(cpu_dev, "no OPP table is found: %d\n", ret); goto put_node; } - ret = opp_init_cpufreq_table(cpu_dev, &freq_table); + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); if (ret) { dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); goto put_node; @@ -259,12 +210,12 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) * same order. */ rcu_read_lock(); - opp = opp_find_freq_exact(cpu_dev, + opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[0].frequency * 1000, true); - min_volt = opp_get_voltage(opp); - opp = opp_find_freq_exact(cpu_dev, + min_volt = dev_pm_opp_get_voltage(opp); + opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[--num].frequency * 1000, true); - max_volt = opp_get_voltage(opp); + max_volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); if (ret > 0) @@ -292,7 +243,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) return 0; free_freq_table: - opp_free_cpufreq_table(cpu_dev, &freq_table); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); put_node: of_node_put(np); return ret; @@ -301,7 +252,7 @@ put_node: static int imx6q_cpufreq_remove(struct platform_device *pdev) { cpufreq_unregister_driver(&imx6q_cpufreq_driver); - opp_free_cpufreq_table(cpu_dev, &freq_table); + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); return 0; } diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c index f7c99df0880b..7d8ab000d317 100644 --- a/drivers/cpufreq/integrator-cpufreq.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -15,18 +15,19 @@ #include <linux/smp.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_address.h> -#include <mach/hardware.h> -#include <mach/platform.h> #include <asm/mach-types.h> #include <asm/hardware/icst.h> -static struct cpufreq_driver integrator_driver; +static void __iomem *cm_base; +/* The cpufreq driver only use the OSC register */ +#define INTEGRATOR_HDR_OSC_OFFSET 0x08 +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 -#define CM_ID __io_address(INTEGRATOR_HDR_ID) -#define CM_OSC __io_address(INTEGRATOR_HDR_OSC) -#define CM_STAT __io_address(INTEGRATOR_HDR_STAT) -#define CM_LOCK __io_address(INTEGRATOR_HDR_LOCK) +static struct cpufreq_driver integrator_driver; static const struct icst_params lclk_params = { .ref = 24000000, @@ -59,9 +60,7 @@ static int integrator_verify_policy(struct cpufreq_policy *policy) { struct icst_vco vco; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); vco = icst_hz_to_vco(&cclk_params, policy->max * 1000); policy->max = icst_hz(&cclk_params, vco) / 1000; @@ -69,10 +68,7 @@ static int integrator_verify_policy(struct cpufreq_policy *policy) vco = icst_hz_to_vco(&cclk_params, policy->min * 1000); policy->min = icst_hz(&cclk_params, vco) / 1000; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - + cpufreq_verify_within_cpu_limits(policy); return 0; } @@ -100,7 +96,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, BUG_ON(cpu != smp_processor_id()); /* get current setting */ - cm_osc = __raw_readl(CM_OSC); + cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); if (machine_is_integrator()) { vco.s = (cm_osc >> 8) & 7; @@ -128,7 +124,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - cm_osc = __raw_readl(CM_OSC); + cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); if (machine_is_integrator()) { cm_osc &= 0xfffff800; @@ -138,9 +134,9 @@ static int integrator_set_target(struct cpufreq_policy *policy, } cm_osc |= vco.v; - __raw_writel(0xa05f, CM_LOCK); - __raw_writel(cm_osc, CM_OSC); - __raw_writel(0, CM_LOCK); + __raw_writel(0xa05f, cm_base + INTEGRATOR_HDR_LOCK_OFFSET); + __raw_writel(cm_osc, cm_base + INTEGRATOR_HDR_OSC_OFFSET); + __raw_writel(0, cm_base + INTEGRATOR_HDR_LOCK_OFFSET); /* * Restore the CPUs allowed mask. @@ -165,7 +161,7 @@ static unsigned int integrator_get(unsigned int cpu) BUG_ON(cpu != smp_processor_id()); /* detect memory etc. */ - cm_osc = __raw_readl(CM_OSC); + cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); if (machine_is_integrator()) { vco.s = (cm_osc >> 8) & 7; @@ -186,10 +182,9 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy) { /* set default policy and cpuinfo */ - policy->cpuinfo.max_freq = 160000; - policy->cpuinfo.min_freq = 12000; + policy->max = policy->cpuinfo.max_freq = 160000; + policy->min = policy->cpuinfo.min_freq = 12000; policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */ - policy->cur = policy->min = policy->max = integrator_get(policy->cpu); return 0; } @@ -202,19 +197,43 @@ static struct cpufreq_driver integrator_driver = { .name = "integrator", }; -static int __init integrator_cpu_init(void) +static int __init integrator_cpufreq_probe(struct platform_device *pdev) { + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + cm_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!cm_base) + return -ENODEV; + return cpufreq_register_driver(&integrator_driver); } -static void __exit integrator_cpu_exit(void) +static void __exit integrator_cpufreq_remove(struct platform_device *pdev) { cpufreq_unregister_driver(&integrator_driver); } +static const struct of_device_id integrator_cpufreq_match[] = { + { .compatible = "arm,core-module-integrator"}, + { }, +}; + +static struct platform_driver integrator_cpufreq_driver = { + .driver = { + .name = "integrator-cpufreq", + .owner = THIS_MODULE, + .of_match_table = integrator_cpufreq_match, + }, + .remove = __exit_p(integrator_cpufreq_remove), +}; + +module_platform_driver_probe(integrator_cpufreq_driver, + integrator_cpufreq_probe); + MODULE_AUTHOR ("Russell M. King"); MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs"); MODULE_LICENSE ("GPL"); - -module_init(integrator_cpu_init); -module_exit(integrator_cpu_exit); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index eb3fdc755000..d51f17ed691e 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -25,6 +25,7 @@ #include <linux/types.h> #include <linux/fs.h> #include <linux/debugfs.h> +#include <linux/acpi.h> #include <trace/events/power.h> #include <asm/div64.h> @@ -33,6 +34,8 @@ #define SAMPLE_COUNT 3 +#define BYT_RATIOS 0x66a + #define FRAC_BITS 8 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS) @@ -78,7 +81,6 @@ struct cpudata { struct timer_list timer; - struct pstate_adjust_policy *pstate_policy; struct pstate_data pstate; struct _pid pid; @@ -100,15 +102,21 @@ struct pstate_adjust_policy { int i_gain_pct; }; -static struct pstate_adjust_policy default_policy = { - .sample_rate_ms = 10, - .deadband = 0, - .setpoint = 97, - .p_gain_pct = 20, - .d_gain_pct = 0, - .i_gain_pct = 0, +struct pstate_funcs { + int (*get_max)(void); + int (*get_min)(void); + int (*get_turbo)(void); + void (*set)(int pstate); +}; + +struct cpu_defaults { + struct pstate_adjust_policy pid_policy; + struct pstate_funcs funcs; }; +static struct pstate_adjust_policy pid_params; +static struct pstate_funcs pstate_funcs; + struct perf_limits { int no_turbo; int max_perf_pct; @@ -185,14 +193,14 @@ static signed int pid_calc(struct _pid *pid, int32_t busy) static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu) { - pid_p_gain_set(&cpu->pid, cpu->pstate_policy->p_gain_pct); - pid_d_gain_set(&cpu->pid, cpu->pstate_policy->d_gain_pct); - pid_i_gain_set(&cpu->pid, cpu->pstate_policy->i_gain_pct); + pid_p_gain_set(&cpu->pid, pid_params.p_gain_pct); + pid_d_gain_set(&cpu->pid, pid_params.d_gain_pct); + pid_i_gain_set(&cpu->pid, pid_params.i_gain_pct); pid_reset(&cpu->pid, - cpu->pstate_policy->setpoint, + pid_params.setpoint, 100, - cpu->pstate_policy->deadband, + pid_params.deadband, 0); } @@ -226,12 +234,12 @@ struct pid_param { }; static struct pid_param pid_files[] = { - {"sample_rate_ms", &default_policy.sample_rate_ms}, - {"d_gain_pct", &default_policy.d_gain_pct}, - {"i_gain_pct", &default_policy.i_gain_pct}, - {"deadband", &default_policy.deadband}, - {"setpoint", &default_policy.setpoint}, - {"p_gain_pct", &default_policy.p_gain_pct}, + {"sample_rate_ms", &pid_params.sample_rate_ms}, + {"d_gain_pct", &pid_params.d_gain_pct}, + {"i_gain_pct", &pid_params.i_gain_pct}, + {"deadband", &pid_params.deadband}, + {"setpoint", &pid_params.setpoint}, + {"p_gain_pct", &pid_params.p_gain_pct}, {NULL, NULL} }; @@ -336,33 +344,92 @@ static void intel_pstate_sysfs_expose_params(void) } /************************** sysfs end ************************/ +static int byt_get_min_pstate(void) +{ + u64 value; + rdmsrl(BYT_RATIOS, value); + return value & 0xFF; +} + +static int byt_get_max_pstate(void) +{ + u64 value; + rdmsrl(BYT_RATIOS, value); + return (value >> 16) & 0xFF; +} -static int intel_pstate_min_pstate(void) +static int core_get_min_pstate(void) { u64 value; rdmsrl(MSR_PLATFORM_INFO, value); return (value >> 40) & 0xFF; } -static int intel_pstate_max_pstate(void) +static int core_get_max_pstate(void) { u64 value; rdmsrl(MSR_PLATFORM_INFO, value); return (value >> 8) & 0xFF; } -static int intel_pstate_turbo_pstate(void) +static int core_get_turbo_pstate(void) { u64 value; int nont, ret; rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value); - nont = intel_pstate_max_pstate(); + nont = core_get_max_pstate(); ret = ((value) & 255); if (ret <= nont) ret = nont; return ret; } +static void core_set_pstate(int pstate) +{ + u64 val; + + val = pstate << 8; + if (limits.no_turbo) + val |= (u64)1 << 32; + + wrmsrl(MSR_IA32_PERF_CTL, val); +} + +static struct cpu_defaults core_params = { + .pid_policy = { + .sample_rate_ms = 10, + .deadband = 0, + .setpoint = 97, + .p_gain_pct = 20, + .d_gain_pct = 0, + .i_gain_pct = 0, + }, + .funcs = { + .get_max = core_get_max_pstate, + .get_min = core_get_min_pstate, + .get_turbo = core_get_turbo_pstate, + .set = core_set_pstate, + }, +}; + +static struct cpu_defaults byt_params = { + .pid_policy = { + .sample_rate_ms = 10, + .deadband = 0, + .setpoint = 97, + .p_gain_pct = 14, + .d_gain_pct = 0, + .i_gain_pct = 4, + }, + .funcs = { + .get_max = byt_get_max_pstate, + .get_min = byt_get_min_pstate, + .get_turbo = byt_get_max_pstate, + .set = core_set_pstate, + }, +}; + + static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) { int max_perf = cpu->pstate.turbo_pstate; @@ -383,7 +450,6 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) { int max_perf, min_perf; - u64 val; intel_pstate_get_min_max(cpu, &min_perf, &max_perf); @@ -395,11 +461,8 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) trace_cpu_frequency(pstate * 100000, cpu->cpu); cpu->pstate.current_pstate = pstate; - val = pstate << 8; - if (limits.no_turbo) - val |= (u64)1 << 32; - wrmsrl(MSR_IA32_PERF_CTL, val); + pstate_funcs.set(pstate); } static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) @@ -421,9 +484,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) { sprintf(cpu->name, "Intel 2nd generation core"); - cpu->pstate.min_pstate = intel_pstate_min_pstate(); - cpu->pstate.max_pstate = intel_pstate_max_pstate(); - cpu->pstate.turbo_pstate = intel_pstate_turbo_pstate(); + cpu->pstate.min_pstate = pstate_funcs.get_min(); + cpu->pstate.max_pstate = pstate_funcs.get_max(); + cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); /* * goto max pstate so we don't slow up boot if we are built-in if we are @@ -465,7 +528,7 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) { int sample_time, delay; - sample_time = cpu->pstate_policy->sample_rate_ms; + sample_time = pid_params.sample_rate_ms; delay = msecs_to_jiffies(sample_time); mod_timer_pinned(&cpu->timer, jiffies + delay); } @@ -518,17 +581,19 @@ static void intel_pstate_timer_func(unsigned long __data) } #define ICPU(model, policy) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy } + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF,\ + (unsigned long)&policy } static const struct x86_cpu_id intel_pstate_cpu_ids[] = { - ICPU(0x2a, default_policy), - ICPU(0x2d, default_policy), - ICPU(0x3a, default_policy), - ICPU(0x3c, default_policy), - ICPU(0x3e, default_policy), - ICPU(0x3f, default_policy), - ICPU(0x45, default_policy), - ICPU(0x46, default_policy), + ICPU(0x2a, core_params), + ICPU(0x2d, core_params), + ICPU(0x37, byt_params), + ICPU(0x3a, core_params), + ICPU(0x3c, core_params), + ICPU(0x3e, core_params), + ICPU(0x3f, core_params), + ICPU(0x45, core_params), + ICPU(0x46, core_params), {} }; MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); @@ -550,10 +615,14 @@ static int intel_pstate_init_cpu(unsigned int cpunum) cpu = all_cpu_data[cpunum]; intel_pstate_get_cpu_pstates(cpu); + if (!cpu->pstate.current_pstate) { + all_cpu_data[cpunum] = NULL; + kfree(cpu); + return -ENODATA; + } cpu->cpu = cpunum; - cpu->pstate_policy = - (struct pstate_adjust_policy *)id->driver_data; + init_timer_deferrable(&cpu->timer); cpu->timer.function = intel_pstate_timer_func; cpu->timer.data = @@ -613,9 +682,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) static int intel_pstate_verify_policy(struct cpufreq_policy *policy) { - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && (policy->policy != CPUFREQ_POLICY_PERFORMANCE)) @@ -683,9 +750,9 @@ static int intel_pstate_msrs_not_valid(void) rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); - if (!intel_pstate_min_pstate() || - !intel_pstate_max_pstate() || - !intel_pstate_turbo_pstate()) + if (!pstate_funcs.get_max() || + !pstate_funcs.get_min() || + !pstate_funcs.get_turbo()) return -ENODEV; rdmsrl(MSR_IA32_APERF, tmp); @@ -698,10 +765,96 @@ static int intel_pstate_msrs_not_valid(void) return 0; } + +static void copy_pid_params(struct pstate_adjust_policy *policy) +{ + pid_params.sample_rate_ms = policy->sample_rate_ms; + pid_params.p_gain_pct = policy->p_gain_pct; + pid_params.i_gain_pct = policy->i_gain_pct; + pid_params.d_gain_pct = policy->d_gain_pct; + pid_params.deadband = policy->deadband; + pid_params.setpoint = policy->setpoint; +} + +static void copy_cpu_funcs(struct pstate_funcs *funcs) +{ + pstate_funcs.get_max = funcs->get_max; + pstate_funcs.get_min = funcs->get_min; + pstate_funcs.get_turbo = funcs->get_turbo; + pstate_funcs.set = funcs->set; +} + +#if IS_ENABLED(CONFIG_ACPI) +#include <acpi/processor.h> + +static bool intel_pstate_no_acpi_pss(void) +{ + int i; + + for_each_possible_cpu(i) { + acpi_status status; + union acpi_object *pss; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_processor *pr = per_cpu(processors, i); + + if (!pr) + continue; + + status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); + if (ACPI_FAILURE(status)) + continue; + + pss = buffer.pointer; + if (pss && pss->type == ACPI_TYPE_PACKAGE) { + kfree(pss); + return false; + } + + kfree(pss); + } + + return true; +} + +struct hw_vendor_info { + u16 valid; + char oem_id[ACPI_OEM_ID_SIZE]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; +}; + +/* Hardware vendor-specific info that has its own power management modes */ +static struct hw_vendor_info vendor_info[] = { + {1, "HP ", "ProLiant"}, + {0, "", ""}, +}; + +static bool intel_pstate_platform_pwr_mgmt_exists(void) +{ + struct acpi_table_header hdr; + struct hw_vendor_info *v_info; + + if (acpi_disabled + || ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr))) + return false; + + for (v_info = vendor_info; v_info->valid; v_info++) { + if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE) + && !strncmp(hdr.oem_table_id, v_info->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) + && intel_pstate_no_acpi_pss()) + return true; + } + + return false; +} +#else /* CONFIG_ACPI not enabled */ +static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; } +#endif /* CONFIG_ACPI */ + static int __init intel_pstate_init(void) { int cpu, rc = 0; const struct x86_cpu_id *id; + struct cpu_defaults *cpu_info; if (no_load) return -ENODEV; @@ -710,6 +863,18 @@ static int __init intel_pstate_init(void) if (!id) return -ENODEV; + /* + * The Intel pstate driver will be ignored if the platform + * firmware has its own power management modes. + */ + if (intel_pstate_platform_pwr_mgmt_exists()) + return -ENODEV; + + cpu_info = (struct cpu_defaults *)id->driver_data; + + copy_pid_params(&cpu_info->pid_policy); + copy_cpu_funcs(&cpu_info->funcs); + if (intel_pstate_msrs_not_valid()) return -ENODEV; diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index ba10658a9394..0767a4e29dfe 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -55,69 +55,37 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu) return kirkwood_freq_table[0].frequency; } -static void kirkwood_cpufreq_set_cpu_state(struct cpufreq_policy *policy, - unsigned int index) +static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, + unsigned int index) { - struct cpufreq_freqs freqs; unsigned int state = kirkwood_freq_table[index].driver_data; unsigned long reg; - freqs.old = kirkwood_cpufreq_get_cpu_frequency(0); - freqs.new = kirkwood_freq_table[index].frequency; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n", - kirkwood_freq_table[index].frequency); - dev_dbg(priv.dev, "old frequency was %i KHz\n", - kirkwood_cpufreq_get_cpu_frequency(0)); - - if (freqs.old != freqs.new) { - local_irq_disable(); - - /* Disable interrupts to the CPU */ - reg = readl_relaxed(priv.base); - reg |= CPU_SW_INT_BLK; - writel_relaxed(reg, priv.base); - - switch (state) { - case STATE_CPU_FREQ: - clk_disable(priv.powersave_clk); - break; - case STATE_DDR_FREQ: - clk_enable(priv.powersave_clk); - break; - } + local_irq_disable(); - /* Wait-for-Interrupt, while the hardware changes frequency */ - cpu_do_idle(); + /* Disable interrupts to the CPU */ + reg = readl_relaxed(priv.base); + reg |= CPU_SW_INT_BLK; + writel_relaxed(reg, priv.base); - /* Enable interrupts to the CPU */ - reg = readl_relaxed(priv.base); - reg &= ~CPU_SW_INT_BLK; - writel_relaxed(reg, priv.base); - - local_irq_enable(); + switch (state) { + case STATE_CPU_FREQ: + clk_disable(priv.powersave_clk); + break; + case STATE_DDR_FREQ: + clk_enable(priv.powersave_clk); + break; } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); -}; - -static int kirkwood_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, kirkwood_freq_table); -} -static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int index = 0; + /* Wait-for-Interrupt, while the hardware changes frequency */ + cpu_do_idle(); - if (cpufreq_frequency_table_target(policy, kirkwood_freq_table, - target_freq, relation, &index)) - return -EINVAL; + /* Enable interrupts to the CPU */ + reg = readl_relaxed(priv.base); + reg &= ~CPU_SW_INT_BLK; + writel_relaxed(reg, priv.base); - kirkwood_cpufreq_set_cpu_state(policy, index); + local_irq_enable(); return 0; } @@ -125,40 +93,17 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, /* Module init and exit code */ static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy) { - int result; - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 5000; /* 5uS */ - policy->cur = kirkwood_cpufreq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, kirkwood_freq_table); - if (result) - return result; - - cpufreq_frequency_table_get_attr(kirkwood_freq_table, policy->cpu); - - return 0; -} - -static int kirkwood_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_generic_init(policy, kirkwood_freq_table, 5000); } -static struct freq_attr *kirkwood_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver kirkwood_cpufreq_driver = { .get = kirkwood_cpufreq_get_cpu_frequency, - .verify = kirkwood_cpufreq_verify, - .target = kirkwood_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = kirkwood_cpufreq_target, .init = kirkwood_cpufreq_cpu_init, - .exit = kirkwood_cpufreq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "kirkwood-cpufreq", - .attr = kirkwood_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int kirkwood_cpufreq_probe(struct platform_device *pdev) diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 4ada1cccb052..45bafddfd8ea 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -625,28 +625,13 @@ static void longhaul_setup_voltagescaling(void) } -static int longhaul_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, longhaul_table); -} - - static int longhaul_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) + unsigned int table_index) { - unsigned int table_index = 0; unsigned int i; unsigned int dir = 0; u8 vid, current_vid; - if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, - relation, &table_index)) - return -EINVAL; - - /* Don't set same frequency again */ - if (longhaul_index == table_index) - return 0; - if (!can_scale_voltage) longhaul_setstate(policy, table_index); else { @@ -919,36 +904,18 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) longhaul_setup_voltagescaling(); policy->cpuinfo.transition_latency = 200000; /* nsec */ - policy->cur = calc_speed(longhaul_get_cpu_mult()); - - ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); - if (ret) - return ret; - - cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); - return 0; + return cpufreq_table_validate_and_show(policy, longhaul_table); } -static int longhaul_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static struct freq_attr *longhaul_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver longhaul_driver = { - .verify = longhaul_verify, - .target = longhaul_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = longhaul_target, .get = longhaul_get, .init = longhaul_cpu_init, - .exit = longhaul_cpu_exit, + .exit = cpufreq_generic_exit, .name = "longhaul", - .attr = longhaul_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id longhaul_id[] = { diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c index 5aa031612d53..074971b12635 100644 --- a/drivers/cpufreq/longrun.c +++ b/drivers/cpufreq/longrun.c @@ -129,9 +129,7 @@ static int longrun_verify_policy(struct cpufreq_policy *policy) return -EINVAL; policy->cpu = 0; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && (policy->policy != CPUFREQ_POLICY_PERFORMANCE)) diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index 7bc3c44d34e2..a43609218105 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -53,51 +53,24 @@ static unsigned int loongson2_cpufreq_get(unsigned int cpu) * Here we notify other drivers of the proposed change and the final change. */ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int index) { unsigned int cpu = policy->cpu; - unsigned int newstate = 0; cpumask_t cpus_allowed; - struct cpufreq_freqs freqs; unsigned int freq; cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); - if (cpufreq_frequency_table_target - (policy, &loongson2_clockmod_table[0], target_freq, relation, - &newstate)) - return -EINVAL; - freq = ((cpu_clock_freq / 1000) * - loongson2_clockmod_table[newstate].driver_data) / 8; - if (freq < policy->min || freq > policy->max) - return -EINVAL; - - pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000); - - freqs.old = loongson2_cpufreq_get(cpu); - freqs.new = freq; - freqs.flags = 0; - - if (freqs.new == freqs.old) - return 0; - - /* notifiers */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + loongson2_clockmod_table[index].driver_data) / 8; set_cpus_allowed_ptr(current, &cpus_allowed); /* setting the cpu frequency */ clk_set_rate(cpuclk, freq); - /* notifiers */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - pr_debug("cpufreq: set frequency %u kHz\n", freq); - return 0; } @@ -131,40 +104,24 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) return ret; } - policy->cur = loongson2_cpufreq_get(policy->cpu); - - cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0], - policy->cpu); - - return cpufreq_frequency_table_cpuinfo(policy, - &loongson2_clockmod_table[0]); -} - -static int loongson2_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - &loongson2_clockmod_table[0]); + return cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0); } static int loongson2_cpufreq_exit(struct cpufreq_policy *policy) { + cpufreq_frequency_table_put_attr(policy->cpu); clk_put(cpuclk); return 0; } -static struct freq_attr *loongson2_table_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver loongson2_cpufreq_driver = { .name = "loongson2", .init = loongson2_cpufreq_cpu_init, - .verify = loongson2_cpufreq_verify, - .target = loongson2_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = loongson2_cpufreq_target, .get = loongson2_cpufreq_get, .exit = loongson2_cpufreq_exit, - .attr = loongson2_table_attr, + .attr = cpufreq_generic_attr, }; static struct platform_device_id platform_device_ids[] = { diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c index 6168d77b296d..c4dfa42a75ac 100644 --- a/drivers/cpufreq/maple-cpufreq.c +++ b/drivers/cpufreq/maple-cpufreq.c @@ -64,18 +64,11 @@ static struct cpufreq_frequency_table maple_cpu_freqs[] = { {0, CPUFREQ_TABLE_END}, }; -static struct freq_attr *maple_cpu_freqs_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - /* Power mode data is an array of the 32 bits PCR values to use for * the various frequencies, retrieved from the device-tree */ static int maple_pmode_cur; -static DEFINE_MUTEX(maple_switch_mutex); - static const u32 *maple_pmode_data; static int maple_pmode_max; @@ -135,37 +128,10 @@ static int maple_scom_query_freq(void) * Common interface to the cpufreq core */ -static int maple_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, maple_cpu_freqs); -} - static int maple_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) + unsigned int index) { - unsigned int newstate = 0; - struct cpufreq_freqs freqs; - int rc; - - if (cpufreq_frequency_table_target(policy, maple_cpu_freqs, - target_freq, relation, &newstate)) - return -EINVAL; - - if (maple_pmode_cur == newstate) - return 0; - - mutex_lock(&maple_switch_mutex); - - freqs.old = maple_cpu_freqs[maple_pmode_cur].frequency; - freqs.new = maple_cpu_freqs[newstate].frequency; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - rc = maple_scom_switch_freq(newstate); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - mutex_unlock(&maple_switch_mutex); - - return rc; + return maple_scom_switch_freq(index); } static unsigned int maple_cpufreq_get_speed(unsigned int cpu) @@ -175,27 +141,17 @@ static unsigned int maple_cpufreq_get_speed(unsigned int cpu) static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy) { - policy->cpuinfo.transition_latency = 12000; - policy->cur = maple_cpu_freqs[maple_scom_query_freq()].frequency; - /* secondary CPUs are tied to the primary one by the - * cpufreq core if in the secondary policy we tell it that - * it actually must be one policy together with all others. */ - cpumask_setall(policy->cpus); - cpufreq_frequency_table_get_attr(maple_cpu_freqs, policy->cpu); - - return cpufreq_frequency_table_cpuinfo(policy, - maple_cpu_freqs); + return cpufreq_generic_init(policy, maple_cpu_freqs, 12000); } - static struct cpufreq_driver maple_cpufreq_driver = { .name = "maple", .flags = CPUFREQ_CONST_LOOPS, .init = maple_cpufreq_cpu_init, - .verify = maple_cpufreq_verify, - .target = maple_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = maple_cpufreq_target, .get = maple_cpufreq_get_speed, - .attr = maple_cpu_freqs_attr, + .attr = cpufreq_generic_attr, }; static int __init maple_cpufreq_init(void) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index f31fcfcad514..a0acd0bfba40 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -22,7 +22,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/opp.h> +#include <linux/pm_opp.h> #include <linux/cpu.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -40,13 +40,6 @@ static struct clk *mpu_clk; static struct device *mpu_dev; static struct regulator *mpu_reg; -static int omap_verify_speed(struct cpufreq_policy *policy) -{ - if (!freq_table) - return -EINVAL; - return cpufreq_frequency_table_verify(policy, freq_table); -} - static unsigned int omap_getspeed(unsigned int cpu) { unsigned long rate; @@ -58,42 +51,17 @@ static unsigned int omap_getspeed(unsigned int cpu) return rate; } -static int omap_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int omap_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int i; - int r, ret = 0; - struct cpufreq_freqs freqs; - struct opp *opp; + int r, ret; + struct dev_pm_opp *opp; unsigned long freq, volt = 0, volt_old = 0, tol = 0; + unsigned int old_freq, new_freq; - if (!freq_table) { - dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, - policy->cpu); - return -EINVAL; - } + old_freq = omap_getspeed(policy->cpu); + new_freq = freq_table[index].frequency; - ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, - relation, &i); - if (ret) { - dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n", - __func__, policy->cpu, target_freq, ret); - return ret; - } - freqs.new = freq_table[i].frequency; - if (!freqs.new) { - dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__, - policy->cpu, target_freq); - return -EINVAL; - } - - freqs.old = omap_getspeed(policy->cpu); - - if (freqs.old == freqs.new && policy->cur == freqs.new) - return ret; - - freq = freqs.new * 1000; + freq = new_freq * 1000; ret = clk_round_rate(mpu_clk, freq); if (IS_ERR_VALUE(ret)) { dev_warn(mpu_dev, @@ -105,143 +73,103 @@ static int omap_target(struct cpufreq_policy *policy, if (mpu_reg) { rcu_read_lock(); - opp = opp_find_freq_ceil(mpu_dev, &freq); + opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", - __func__, freqs.new); + __func__, new_freq); return -EINVAL; } - volt = opp_get_voltage(opp); + volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); tol = volt * OPP_TOLERANCE / 100; volt_old = regulator_get_voltage(mpu_reg); } dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", - freqs.old / 1000, volt_old ? volt_old / 1000 : -1, - freqs.new / 1000, volt ? volt / 1000 : -1); - - /* notifiers */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + old_freq / 1000, volt_old ? volt_old / 1000 : -1, + new_freq / 1000, volt ? volt / 1000 : -1); /* scaling up? scale voltage before frequency */ - if (mpu_reg && (freqs.new > freqs.old)) { + if (mpu_reg && (new_freq > old_freq)) { r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); if (r < 0) { dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", __func__); - freqs.new = freqs.old; - goto done; + return r; } } - ret = clk_set_rate(mpu_clk, freqs.new * 1000); + ret = clk_set_rate(mpu_clk, new_freq * 1000); /* scaling down? scale voltage after frequency */ - if (mpu_reg && (freqs.new < freqs.old)) { + if (mpu_reg && (new_freq < old_freq)) { r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); if (r < 0) { dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", __func__); - ret = clk_set_rate(mpu_clk, freqs.old * 1000); - freqs.new = freqs.old; - goto done; + clk_set_rate(mpu_clk, old_freq * 1000); + return r; } } - freqs.new = omap_getspeed(policy->cpu); - -done: - /* notifiers */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - return ret; } static inline void freq_table_free(void) { if (atomic_dec_and_test(&freq_table_users)) - opp_free_cpufreq_table(mpu_dev, &freq_table); + dev_pm_opp_free_cpufreq_table(mpu_dev, &freq_table); } static int omap_cpu_init(struct cpufreq_policy *policy) { - int result = 0; + int result; mpu_clk = clk_get(NULL, "cpufreq_ck"); if (IS_ERR(mpu_clk)) return PTR_ERR(mpu_clk); - if (policy->cpu >= NR_CPUS) { - result = -EINVAL; - goto fail_ck; - } - - policy->cur = omap_getspeed(policy->cpu); - - if (!freq_table) - result = opp_init_cpufreq_table(mpu_dev, &freq_table); - - if (result) { - dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n", + if (!freq_table) { + result = dev_pm_opp_init_cpufreq_table(mpu_dev, &freq_table); + if (result) { + dev_err(mpu_dev, + "%s: cpu%d: failed creating freq table[%d]\n", __func__, policy->cpu, result); - goto fail_ck; + goto fail; + } } atomic_inc_return(&freq_table_users); - result = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (result) - goto fail_table; - - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - - policy->cur = omap_getspeed(policy->cpu); - - /* - * On OMAP SMP configuartion, both processors share the voltage - * and clock. So both CPUs needs to be scaled together and hence - * needs software co-ordination. Use cpufreq affected_cpus - * interface to handle this scenario. Additional is_smp() check - * is to keep SMP_ON_UP build working. - */ - if (is_smp()) - cpumask_setall(policy->cpus); - /* FIXME: what's the actual transition time? */ - policy->cpuinfo.transition_latency = 300 * 1000; - - return 0; + result = cpufreq_generic_init(policy, freq_table, 300 * 1000); + if (!result) + return 0; -fail_table: freq_table_free(); -fail_ck: +fail: clk_put(mpu_clk); return result; } static int omap_cpu_exit(struct cpufreq_policy *policy) { + cpufreq_frequency_table_put_attr(policy->cpu); freq_table_free(); clk_put(mpu_clk); return 0; } -static struct freq_attr *omap_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver omap_driver = { .flags = CPUFREQ_STICKY, - .verify = omap_verify_speed, - .target = omap_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = omap_target, .get = omap_getspeed, .init = omap_cpu_init, .exit = omap_cpu_exit, .name = "omap", - .attr = omap_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int omap_cpufreq_probe(struct platform_device *pdev) diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index 2f0a2a65c37f..3d1cba9fd5f9 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -105,47 +105,21 @@ static struct cpufreq_frequency_table p4clockmod_table[] = { }; -static int cpufreq_p4_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int newstate = DC_RESV; - struct cpufreq_freqs freqs; int i; - if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], - target_freq, relation, &newstate)) - return -EINVAL; - - freqs.old = cpufreq_p4_get(policy->cpu); - freqs.new = stock_freq * p4clockmod_table[newstate].driver_data / 8; - - if (freqs.new == freqs.old) - return 0; - - /* notifiers */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* run on each logical CPU, * see section 13.15.3 of IA32 Intel Architecture Software * Developer's Manual, Volume 3 */ for_each_cpu(i, policy->cpus) - cpufreq_p4_setdc(i, p4clockmod_table[newstate].driver_data); - - /* notifiers */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data); return 0; } -static int cpufreq_p4_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]); -} - - static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) { if (c->x86 == 0x06) { @@ -230,25 +204,17 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) else p4clockmod_table[i].frequency = (stock_freq * i)/8; } - cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); /* cpuinfo and default policy values */ /* the transition latency is set to be 1 higher than the maximum * transition latency of the ondemand governor */ policy->cpuinfo.transition_latency = 10000001; - policy->cur = stock_freq; - return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]); + return cpufreq_table_validate_and_show(policy, &p4clockmod_table[0]); } -static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - static unsigned int cpufreq_p4_get(unsigned int cpu) { u32 l, h; @@ -267,19 +233,14 @@ static unsigned int cpufreq_p4_get(unsigned int cpu) return stock_freq; } -static struct freq_attr *p4clockmod_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver p4clockmod_driver = { - .verify = cpufreq_p4_verify, - .target = cpufreq_p4_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = cpufreq_p4_target, .init = cpufreq_p4_cpu_init, - .exit = cpufreq_p4_cpu_exit, + .exit = cpufreq_generic_exit, .get = cpufreq_p4_get, .name = "p4-clockmod", - .attr = p4clockmod_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id cpufreq_p4_id[] = { diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c index 534e43a60d1f..0426008380d8 100644 --- a/drivers/cpufreq/pasemi-cpufreq.c +++ b/drivers/cpufreq/pasemi-cpufreq.c @@ -28,6 +28,7 @@ #include <linux/cpufreq.h> #include <linux/timer.h> #include <linux/module.h> +#include <linux/of_address.h> #include <asm/hw_irq.h> #include <asm/io.h> @@ -51,8 +52,6 @@ static void __iomem *sdcpwr_mapbase; static void __iomem *sdcasr_mapbase; -static DEFINE_MUTEX(pas_switch_mutex); - /* Current astate, is used when waking up from power savings on * one core, in case the other core has switched states during * the idle time. @@ -69,11 +68,6 @@ static struct cpufreq_frequency_table pas_freqs[] = { {0, CPUFREQ_TABLE_END}, }; -static struct freq_attr *pas_cpu_freqs_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - /* * hardware specific functions */ @@ -209,22 +203,13 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("%d: %d\n", i, pas_freqs[i].frequency); } - policy->cpuinfo.transition_latency = get_gizmo_latency(); - cur_astate = get_cur_astate(policy->cpu); pr_debug("current astate is at %d\n",cur_astate); policy->cur = pas_freqs[cur_astate].frequency; - cpumask_copy(policy->cpus, cpu_online_mask); - ppc_proc_freq = policy->cur * 1000ul; - cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu); - - /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max - * are set correctly - */ - return cpufreq_frequency_table_cpuinfo(policy, pas_freqs); + return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency()); out_unmap_sdcpwr: iounmap(sdcpwr_mapbase); @@ -253,31 +238,11 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy) return 0; } -static int pas_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, pas_freqs); -} - static int pas_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int pas_astate_new) { - struct cpufreq_freqs freqs; - int pas_astate_new; int i; - cpufreq_frequency_table_target(policy, - pas_freqs, - target_freq, - relation, - &pas_astate_new); - - freqs.old = policy->cur; - freqs.new = pas_freqs[pas_astate_new].frequency; - - mutex_lock(&pas_switch_mutex); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", policy->cpu, pas_freqs[pas_astate_new].frequency, @@ -288,10 +253,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy, for_each_online_cpu(i) set_astate(i, pas_astate_new); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - mutex_unlock(&pas_switch_mutex); - - ppc_proc_freq = freqs.new * 1000ul; + ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul; return 0; } @@ -300,9 +262,9 @@ static struct cpufreq_driver pas_cpufreq_driver = { .flags = CPUFREQ_CONST_LOOPS, .init = pas_cpufreq_cpu_init, .exit = pas_cpufreq_cpu_exit, - .verify = pas_cpufreq_verify, - .target = pas_cpufreq_target, - .attr = pas_cpu_freqs_attr, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = pas_cpufreq_target, + .attr = cpufreq_generic_attr, }; /* diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index d81c4e5ea0ad..e2b4f40ff69a 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -111,8 +111,7 @@ static struct pcc_cpu __percpu *pcc_cpu_info; static int pcc_cpufreq_verify(struct cpufreq_policy *policy) { - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); return 0; } @@ -396,15 +395,14 @@ static int __init pcc_cpufreq_probe(void) struct pcc_memory_resource *mem_resource; struct pcc_register_resource *reg_resource; union acpi_object *out_obj, *member; - acpi_handle handle, osc_handle, pcch_handle; + acpi_handle handle, osc_handle; int ret = 0; status = acpi_get_handle(NULL, "\\_SB", &handle); if (ACPI_FAILURE(status)) return -ENODEV; - status = acpi_get_handle(handle, "PCCH", &pcch_handle); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(handle, "PCCH")) return -ENODEV; status = acpi_get_handle(handle, "_OSC", &osc_handle); @@ -560,13 +558,6 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) ioread32(&pcch_hdr->nominal) * 1000; policy->min = policy->cpuinfo.min_freq = ioread32(&pcch_hdr->minimum_frequency) * 1000; - policy->cur = pcc_get_freq(cpu); - - if (!policy->cur) { - pr_debug("init: Unable to get current CPU frequency\n"); - result = -EINVAL; - goto out; - } pr_debug("init: policy->max is %d, policy->min is %d\n", policy->max, policy->min); diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c index a096cd3fa23d..cf55d202f332 100644 --- a/drivers/cpufreq/pmac32-cpufreq.c +++ b/drivers/cpufreq/pmac32-cpufreq.c @@ -86,11 +86,6 @@ static struct cpufreq_frequency_table pmac_cpu_freqs[] = { {0, CPUFREQ_TABLE_END}, }; -static struct freq_attr* pmac_cpu_freqs_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static inline void local_delay(unsigned long ms) { if (no_schedule) @@ -336,21 +331,11 @@ static int pmu_set_cpu_speed(int low_speed) return 0; } -static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode, - int notify) +static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode) { - struct cpufreq_freqs freqs; unsigned long l3cr; static unsigned long prev_l3cr; - freqs.old = cur_freq; - freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; - - if (freqs.old == freqs.new) - return 0; - - if (notify) - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (speed_mode == CPUFREQ_LOW && cpu_has_feature(CPU_FTR_L3CR)) { l3cr = _get_L3CR(); @@ -366,8 +351,6 @@ static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode, if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) _set_L3CR(prev_l3cr); } - if (notify) - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; return 0; @@ -378,23 +361,12 @@ static unsigned int pmac_cpufreq_get_speed(unsigned int cpu) return cur_freq; } -static int pmac_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); -} - static int pmac_cpufreq_target( struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int index) { - unsigned int newstate = 0; int rc; - if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs, - target_freq, relation, &newstate)) - return -EINVAL; - - rc = do_set_cpu_speed(policy, newstate, 1); + rc = do_set_cpu_speed(policy, index); ppc_proc_freq = cur_freq * 1000ul; return rc; @@ -402,14 +374,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy, static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) { - if (policy->cpu != 0) - return -ENODEV; - - policy->cpuinfo.transition_latency = transition_latency; - policy->cur = cur_freq; - - cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu); - return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs); + return cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency); } static u32 read_gpio(struct device_node *np) @@ -443,7 +408,7 @@ static int pmac_cpufreq_suspend(struct cpufreq_policy *policy) no_schedule = 1; sleep_freq = cur_freq; if (cur_freq == low_freq && !is_pmu_based) - do_set_cpu_speed(policy, CPUFREQ_HIGH, 0); + do_set_cpu_speed(policy, CPUFREQ_HIGH); return 0; } @@ -460,7 +425,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy) * probably high speed due to our suspend() routine */ do_set_cpu_speed(policy, sleep_freq == low_freq ? - CPUFREQ_LOW : CPUFREQ_HIGH, 0); + CPUFREQ_LOW : CPUFREQ_HIGH); ppc_proc_freq = cur_freq * 1000ul; @@ -469,14 +434,14 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy) } static struct cpufreq_driver pmac_cpufreq_driver = { - .verify = pmac_cpufreq_verify, - .target = pmac_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = pmac_cpufreq_target, .get = pmac_cpufreq_get_speed, .init = pmac_cpufreq_cpu_init, .suspend = pmac_cpufreq_suspend, .resume = pmac_cpufreq_resume, .flags = CPUFREQ_PM_NO_WARN, - .attr = pmac_cpu_freqs_attr, + .attr = cpufreq_generic_attr, .name = "powermac", }; diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c index 3a51ad7e47c8..6a338f8c3860 100644 --- a/drivers/cpufreq/pmac64-cpufreq.c +++ b/drivers/cpufreq/pmac64-cpufreq.c @@ -70,11 +70,6 @@ static struct cpufreq_frequency_table g5_cpu_freqs[] = { {0, CPUFREQ_TABLE_END}, }; -static struct freq_attr* g5_cpu_freqs_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - /* Power mode data is an array of the 32 bits PCR values to use for * the various frequencies, retrieved from the device-tree */ @@ -84,8 +79,6 @@ static void (*g5_switch_volt)(int speed_mode); static int (*g5_switch_freq)(int speed_mode); static int (*g5_query_freq)(void); -static DEFINE_MUTEX(g5_switch_mutex); - static unsigned long transition_latency; #ifdef CONFIG_PMAC_SMU @@ -142,7 +135,7 @@ static void g5_vdnap_switch_volt(int speed_mode) pmf_call_one(pfunc_vdnap0_complete, &args); if (done) break; - msleep(1); + usleep_range(1000, 1000); } if (done == 0) printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n"); @@ -241,7 +234,7 @@ static void g5_pfunc_switch_volt(int speed_mode) if (pfunc_cpu1_volt_low) pmf_call_one(pfunc_cpu1_volt_low, NULL); } - msleep(10); /* should be faster , to fix */ + usleep_range(10000, 10000); /* should be faster , to fix */ } /* @@ -286,7 +279,7 @@ static int g5_pfunc_switch_freq(int speed_mode) pmf_call_one(pfunc_slewing_done, &args); if (done) break; - msleep(1); + usleep_range(500, 500); } if (done == 0) printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n"); @@ -317,37 +310,9 @@ static int g5_pfunc_query_freq(void) * Common interface to the cpufreq core */ -static int g5_cpufreq_verify(struct cpufreq_policy *policy) +static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { - return cpufreq_frequency_table_verify(policy, g5_cpu_freqs); -} - -static int g5_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) -{ - unsigned int newstate = 0; - struct cpufreq_freqs freqs; - int rc; - - if (cpufreq_frequency_table_target(policy, g5_cpu_freqs, - target_freq, relation, &newstate)) - return -EINVAL; - - if (g5_pmode_cur == newstate) - return 0; - - mutex_lock(&g5_switch_mutex); - - freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency; - freqs.new = g5_cpu_freqs[newstate].frequency; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - rc = g5_switch_freq(newstate); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - mutex_unlock(&g5_switch_mutex); - - return rc; + return g5_switch_freq(index); } static unsigned int g5_cpufreq_get_speed(unsigned int cpu) @@ -357,27 +322,17 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu) static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) { - policy->cpuinfo.transition_latency = transition_latency; - policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; - /* secondary CPUs are tied to the primary one by the - * cpufreq core if in the secondary policy we tell it that - * it actually must be one policy together with all others. */ - cpumask_copy(policy->cpus, cpu_online_mask); - cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu); - - return cpufreq_frequency_table_cpuinfo(policy, - g5_cpu_freqs); + return cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency); } - static struct cpufreq_driver g5_cpufreq_driver = { .name = "powermac", .flags = CPUFREQ_CONST_LOOPS, .init = g5_cpufreq_cpu_init, - .verify = g5_cpufreq_verify, - .target = g5_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = g5_cpufreq_target, .get = g5_cpufreq_get_speed, - .attr = g5_cpu_freqs_attr, + .attr = cpufreq_generic_attr, }; @@ -397,7 +352,8 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode) /* Check supported platforms */ if (of_machine_is_compatible("PowerMac8,1") || of_machine_is_compatible("PowerMac8,2") || - of_machine_is_compatible("PowerMac9,1")) + of_machine_is_compatible("PowerMac9,1") || + of_machine_is_compatible("PowerMac12,1")) use_volts_smu = 1; else if (of_machine_is_compatible("PowerMac11,2")) use_volts_vdnap = 1; @@ -647,8 +603,10 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) g5_cpu_freqs[0].frequency = max_freq; g5_cpu_freqs[1].frequency = min_freq; + /* Based on a measurement on Xserve G5, rounded up. */ + transition_latency = 10 * NSEC_PER_MSEC; + /* Set callbacks */ - transition_latency = CPUFREQ_ETERNAL; g5_switch_volt = g5_pfunc_switch_volt; g5_switch_freq = g5_pfunc_switch_freq; g5_query_freq = g5_pfunc_query_freq; diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index 85f1c8c25ddc..643e7952cad3 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -63,12 +63,12 @@ static int powernow_k6_get_cpu_multiplier(void) /** - * powernow_k6_set_state - set the PowerNow! multiplier + * powernow_k6_target - set the PowerNow! multiplier * @best_i: clock_ratio[best_i] is the target multiplier * * Tries to change the PowerNow! multiplier */ -static void powernow_k6_set_state(struct cpufreq_policy *policy, +static int powernow_k6_target(struct cpufreq_policy *policy, unsigned int best_i) { unsigned long outvalue = 0, invalue = 0; @@ -77,7 +77,7 @@ static void powernow_k6_set_state(struct cpufreq_policy *policy, if (clock_ratio[best_i].driver_data > max_multiplier) { printk(KERN_ERR PFX "invalid target frequency\n"); - return; + return -EINVAL; } freqs.old = busfreq * powernow_k6_get_cpu_multiplier(); @@ -100,44 +100,6 @@ static void powernow_k6_set_state(struct cpufreq_policy *policy, cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - return; -} - - -/** - * powernow_k6_verify - verifies a new CPUfreq policy - * @policy: new policy - * - * Policy must be within lowest and highest possible CPU Frequency, - * and at least one possible state must be within min and max. - */ -static int powernow_k6_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &clock_ratio[0]); -} - - -/** - * powernow_k6_setpolicy - sets a new CPUFreq policy - * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) - * - * sets a new CPUFreq policy - */ -static int powernow_k6_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, &clock_ratio[0], - target_freq, relation, &newstate)) - return -EINVAL; - - powernow_k6_set_state(policy, newstate); - return 0; } @@ -145,7 +107,6 @@ static int powernow_k6_target(struct cpufreq_policy *policy, static int powernow_k6_cpu_init(struct cpufreq_policy *policy) { unsigned int i, f; - int result; if (policy->cpu != 0) return -ENODEV; @@ -165,15 +126,8 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = 200000; - policy->cur = busfreq * max_multiplier; - - result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio); - if (result) - return result; - - cpufreq_frequency_table_get_attr(clock_ratio, policy->cpu); - return 0; + return cpufreq_table_validate_and_show(policy, clock_ratio); } @@ -182,7 +136,7 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy) unsigned int i; for (i = 0; i < 8; i++) { if (i == max_multiplier) - powernow_k6_set_state(policy, i); + powernow_k6_target(policy, i); } cpufreq_frequency_table_put_attr(policy->cpu); return 0; @@ -195,19 +149,14 @@ static unsigned int powernow_k6_get(unsigned int cpu) return ret; } -static struct freq_attr *powernow_k6_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver powernow_k6_driver = { - .verify = powernow_k6_verify, - .target = powernow_k6_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = powernow_k6_target, .init = powernow_k6_cpu_init, .exit = powernow_k6_cpu_exit, .get = powernow_k6_get, .name = "powernow-k6", - .attr = powernow_k6_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id powernow_k6_ids[] = { diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 14ce480be8ab..946708a1d745 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -248,7 +248,7 @@ static void change_VID(int vid) } -static void change_speed(struct cpufreq_policy *policy, unsigned int index) +static int powernow_target(struct cpufreq_policy *policy, unsigned int index) { u8 fid, vid; struct cpufreq_freqs freqs; @@ -291,6 +291,8 @@ static void change_speed(struct cpufreq_policy *policy, unsigned int index) local_irq_enable(); cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + + return 0; } @@ -533,27 +535,6 @@ static int powernow_decode_bios(int maxfid, int startvid) } -static int powernow_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate; - - if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, - relation, &newstate)) - return -EINVAL; - - change_speed(policy, newstate); - - return 0; -} - - -static int powernow_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, powernow_table); -} - /* * We use the fact that the bus frequency is somehow * a multiple of 100000/3 khz, then we compute sgtc according @@ -678,11 +659,7 @@ static int powernow_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); - policy->cur = powernow_get(0); - - cpufreq_frequency_table_get_attr(powernow_table, policy->cpu); - - return cpufreq_frequency_table_cpuinfo(policy, powernow_table); + return cpufreq_table_validate_and_show(policy, powernow_table); } static int powernow_cpu_exit(struct cpufreq_policy *policy) @@ -701,14 +678,9 @@ static int powernow_cpu_exit(struct cpufreq_policy *policy) return 0; } -static struct freq_attr *powernow_table_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver powernow_driver = { - .verify = powernow_verify, - .target = powernow_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = powernow_target, .get = powernow_get, #ifdef CONFIG_X86_POWERNOW_K7_ACPI .bios_limit = acpi_processor_get_bios_limit, @@ -716,7 +688,7 @@ static struct cpufreq_driver powernow_driver = { .init = powernow_cpu_init, .exit = powernow_cpu_exit, .name = "powernow-k7", - .attr = powernow_table_attr, + .attr = cpufreq_generic_attr, }; static int __init powernow_init(void) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 2344a9ed17f3..0023c7d40a51 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -977,20 +977,17 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, struct powernowk8_target_arg { struct cpufreq_policy *pol; - unsigned targfreq; - unsigned relation; + unsigned newstate; }; static long powernowk8_target_fn(void *arg) { struct powernowk8_target_arg *pta = arg; struct cpufreq_policy *pol = pta->pol; - unsigned targfreq = pta->targfreq; - unsigned relation = pta->relation; + unsigned newstate = pta->newstate; struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); u32 checkfid; u32 checkvid; - unsigned int newstate; int ret; if (!data) @@ -1004,8 +1001,9 @@ static long powernowk8_target_fn(void *arg) return -EIO; } - pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", - pol->cpu, targfreq, pol->min, pol->max, relation); + pr_debug("targ: cpu %d, %d kHz, min %d, max %d\n", + pol->cpu, data->powernow_table[newstate].frequency, pol->min, + pol->max); if (query_current_values_with_pending_wait(data)) return -EIO; @@ -1021,10 +1019,6 @@ static long powernowk8_target_fn(void *arg) checkvid, data->currvid); } - if (cpufreq_frequency_table_target(pol, data->powernow_table, - targfreq, relation, &newstate)) - return -EIO; - mutex_lock(&fidvid_mutex); powernow_k8_acpi_pst_values(data, newstate); @@ -1044,26 +1038,13 @@ static long powernowk8_target_fn(void *arg) } /* Driver entry point to switch to the target frequency */ -static int powernowk8_target(struct cpufreq_policy *pol, - unsigned targfreq, unsigned relation) +static int powernowk8_target(struct cpufreq_policy *pol, unsigned index) { - struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq, - .relation = relation }; + struct powernowk8_target_arg pta = { .pol = pol, .newstate = index }; return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); } -/* Driver entry point to verify the policy and range of frequencies */ -static int powernowk8_verify(struct cpufreq_policy *pol) -{ - struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); - - if (!data) - return -EINVAL; - - return cpufreq_frequency_table_verify(pol, data->powernow_table); -} - struct init_on_cpu { struct powernow_k8_data *data; int rc; @@ -1152,11 +1133,8 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu)); data->available_cores = pol->cpus; - pol->cur = find_khz_freq_from_fid(data->currfid); - pr_debug("policy current frequency %d kHz\n", pol->cur); - /* min/max the cpu is capable of */ - if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { + if (cpufreq_table_validate_and_show(pol, data->powernow_table)) { printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n"); powernow_k8_cpu_exit_acpi(data); kfree(data->powernow_table); @@ -1164,8 +1142,6 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) return -EINVAL; } - cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); - pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); @@ -1227,20 +1203,16 @@ out: return khz; } -static struct freq_attr *powernow_k8_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver cpufreq_amd64_driver = { - .verify = powernowk8_verify, - .target = powernowk8_target, + .flags = CPUFREQ_ASYNC_NOTIFICATION, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = powernowk8_target, .bios_limit = acpi_processor_get_bios_limit, .init = powernowk8_cpu_init, .exit = powernowk8_cpu_exit, .get = powernowk8_get, .name = "powernow-k8", - .attr = powernow_k8_attr, + .attr = cpufreq_generic_attr, }; static void __request_acpi_cpufreq(void) diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c index 60e81d524ea8..3f7be46d2b27 100644 --- a/drivers/cpufreq/ppc-corenet-cpufreq.c +++ b/drivers/cpufreq/ppc-corenet-cpufreq.c @@ -69,8 +69,6 @@ static const struct soc_data sdata[] = { static u32 min_cpufreq; static const u32 *fmask; -/* serialize frequency changes */ -static DEFINE_MUTEX(cpufreq_lock); static DEFINE_PER_CPU(struct cpu_data *, cpu_data); /* cpumask in a cluster */ @@ -202,7 +200,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) table[i].frequency = CPUFREQ_TABLE_END; /* set the min and max frequency properly */ - ret = cpufreq_frequency_table_cpuinfo(policy, table); + ret = cpufreq_table_validate_and_show(policy, table); if (ret) { pr_err("invalid frequency table: %d\n", ret); goto err_nomem1; @@ -217,9 +215,6 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) per_cpu(cpu_data, i) = data; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = corenet_cpufreq_get_speed(policy->cpu); - - cpufreq_frequency_table_get_attr(table, cpu); of_node_put(np); return 0; @@ -253,60 +248,25 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy) return 0; } -static int corenet_cpufreq_verify(struct cpufreq_policy *policy) -{ - struct cpufreq_frequency_table *table = - per_cpu(cpu_data, policy->cpu)->table; - - return cpufreq_frequency_table_verify(policy, table); -} - static int corenet_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) + unsigned int index) { - struct cpufreq_freqs freqs; - unsigned int new; struct clk *parent; - int ret; struct cpu_data *data = per_cpu(cpu_data, policy->cpu); - cpufreq_frequency_table_target(policy, data->table, - target_freq, relation, &new); - - if (policy->cur == data->table[new].frequency) - return 0; - - freqs.old = policy->cur; - freqs.new = data->table[new].frequency; - - mutex_lock(&cpufreq_lock); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - parent = of_clk_get(data->parent, data->table[new].driver_data); - ret = clk_set_parent(data->clk, parent); - if (ret) - freqs.new = freqs.old; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - mutex_unlock(&cpufreq_lock); - - return ret; + parent = of_clk_get(data->parent, data->table[index].driver_data); + return clk_set_parent(data->clk, parent); } -static struct freq_attr *corenet_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver ppc_corenet_cpufreq_driver = { .name = "ppc_cpufreq", .flags = CPUFREQ_CONST_LOOPS, .init = corenet_cpufreq_cpu_init, .exit = __exit_p(corenet_cpufreq_cpu_exit), - .verify = corenet_cpufreq_verify, - .target = corenet_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = corenet_cpufreq_target, .get = corenet_cpufreq_get_speed, - .attr = corenet_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static const struct of_device_id node_matches[] __initdata = { diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index 2e448f0bbdc5..e42ca9c31cea 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c @@ -30,9 +30,6 @@ #include "ppc_cbe_cpufreq.h" -static DEFINE_MUTEX(cbe_switch_mutex); - - /* the CBE supports an 8 step frequency scaling */ static struct cpufreq_frequency_table cbe_freqs[] = { {1, 0}, @@ -123,63 +120,28 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); #endif - cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); - /* this ensures that policy->cpuinfo_min * and policy->cpuinfo_max are set correctly */ - return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); -} - -static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static int cbe_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, cbe_freqs); + return cpufreq_table_validate_and_show(policy, cbe_freqs); } static int cbe_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int cbe_pmode_new) { - int rc; - struct cpufreq_freqs freqs; - unsigned int cbe_pmode_new; - - cpufreq_frequency_table_target(policy, - cbe_freqs, - target_freq, - relation, - &cbe_pmode_new); - - freqs.old = policy->cur; - freqs.new = cbe_freqs[cbe_pmode_new].frequency; - - mutex_lock(&cbe_switch_mutex); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - pr_debug("setting frequency for cpu %d to %d kHz, " \ "1/%d of max frequency\n", policy->cpu, cbe_freqs[cbe_pmode_new].frequency, cbe_freqs[cbe_pmode_new].driver_data); - rc = set_pmode(policy->cpu, cbe_pmode_new); - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - mutex_unlock(&cbe_switch_mutex); - - return rc; + return set_pmode(policy->cpu, cbe_pmode_new); } static struct cpufreq_driver cbe_cpufreq_driver = { - .verify = cbe_cpufreq_verify, - .target = cbe_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = cbe_cpufreq_target, .init = cbe_cpufreq_cpu_init, - .exit = cbe_cpufreq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "cbe-cpufreq", .flags = CPUFREQ_CONST_LOOPS, }; diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 8749eaf18793..0a0f4369636a 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -262,36 +262,15 @@ static u32 mdrefr_dri(unsigned int freq) return (interval - (cpu_is_pxa27x() ? 31 : 0)) / 32; } -/* find a valid frequency point */ -static int pxa_verify_policy(struct cpufreq_policy *policy) -{ - struct cpufreq_frequency_table *pxa_freqs_table; - pxa_freqs_t *pxa_freqs; - int ret; - - find_freq_tables(&pxa_freqs_table, &pxa_freqs); - ret = cpufreq_frequency_table_verify(policy, pxa_freqs_table); - - if (freq_debug) - pr_debug("Verified CPU policy: %dKhz min to %dKhz max\n", - policy->min, policy->max); - - return ret; -} - static unsigned int pxa_cpufreq_get(unsigned int cpu) { return get_clk_frequency_khz(0); } -static int pxa_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) { struct cpufreq_frequency_table *pxa_freqs_table; pxa_freqs_t *pxa_freq_settings; - struct cpufreq_freqs freqs; - unsigned int idx; unsigned long flags; unsigned int new_freq_cpu, new_freq_mem; unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; @@ -300,32 +279,19 @@ static int pxa_set_target(struct cpufreq_policy *policy, /* Get the current policy */ find_freq_tables(&pxa_freqs_table, &pxa_freq_settings); - /* Lookup the next frequency */ - if (cpufreq_frequency_table_target(policy, pxa_freqs_table, - target_freq, relation, &idx)) { - return -EINVAL; - } - new_freq_cpu = pxa_freq_settings[idx].khz; new_freq_mem = pxa_freq_settings[idx].membus; - freqs.old = policy->cur; - freqs.new = new_freq_cpu; if (freq_debug) pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", - freqs.new / 1000, (pxa_freq_settings[idx].div2) ? + new_freq_cpu / 1000, (pxa_freq_settings[idx].div2) ? (new_freq_mem / 2000) : (new_freq_mem / 1000)); - if (vcc_core && freqs.new > freqs.old) + if (vcc_core && new_freq_cpu > policy->cur) { ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); - if (ret) - return ret; - /* - * Tell everyone what we're about to do... - * you should add a notify client with any platform specific - * Vcc changing capability - */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + if (ret) + return ret; + } /* Calculate the next MDREFR. If we're slowing down the SDRAM clock * we need to preset the smaller DRI before the change. If we're @@ -376,13 +342,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, local_irq_restore(flags); /* - * Tell everyone what we've just done... - * you should add a notify client with any platform specific - * SDRAM refresh timer adjustments - */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - /* * Even if voltage setting fails, we don't report it, as the frequency * change succeeded. The voltage reduction is not a critical failure, * only power savings will suffer from this. @@ -391,7 +350,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, * bug is triggered (seems a deadlock). Should anybody find out where, * the "return 0" should become a "return ret". */ - if (vcc_core && freqs.new < freqs.old) + if (vcc_core && new_freq_cpu < policy->cur) ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); return 0; @@ -414,8 +373,6 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) /* set default policy and cpuinfo */ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ - policy->cur = get_clk_frequency_khz(0); /* current freq */ - policy->min = policy->max = policy->cur; /* Generate pxa25x the run cpufreq_frequency_table struct */ for (i = 0; i < NUM_PXA25x_RUN_FREQS; i++) { @@ -453,10 +410,12 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) find_freq_tables(&pxa255_freq_table, &pxa255_freqs); pr_info("PXA255 cpufreq using %s frequency table\n", pxa255_turbo_table ? "turbo" : "run"); - cpufreq_frequency_table_cpuinfo(policy, pxa255_freq_table); + + cpufreq_table_validate_and_show(policy, pxa255_freq_table); + } + else if (cpu_is_pxa27x()) { + cpufreq_table_validate_and_show(policy, pxa27x_freq_table); } - else if (cpu_is_pxa27x()) - cpufreq_frequency_table_cpuinfo(policy, pxa27x_freq_table); printk(KERN_INFO "PXA CPU frequency change support initialized\n"); @@ -464,9 +423,10 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver pxa_cpufreq_driver = { - .verify = pxa_verify_policy, - .target = pxa_set_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = pxa_set_target, .init = pxa_cpufreq_init, + .exit = cpufreq_generic_exit, .get = pxa_cpufreq_get, .name = "PXA2xx", }; diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index d26306fb00d2..93840048dd11 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -108,7 +108,7 @@ static int setup_freqs_table(struct cpufreq_policy *policy, pxa3xx_freqs_num = num; pxa3xx_freqs_table = table; - return cpufreq_frequency_table_cpuinfo(policy, table); + return cpufreq_table_validate_and_show(policy, table); } static void __update_core_freq(struct pxa3xx_freq_info *info) @@ -150,54 +150,26 @@ static void __update_bus_freq(struct pxa3xx_freq_info *info) cpu_relax(); } -static int pxa3xx_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, pxa3xx_freqs_table); -} - static unsigned int pxa3xx_cpufreq_get(unsigned int cpu) { return pxa3xx_get_clk_frequency_khz(0); } -static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index) { struct pxa3xx_freq_info *next; - struct cpufreq_freqs freqs; unsigned long flags; - int idx; if (policy->cpu != 0) return -EINVAL; - /* Lookup the next frequency */ - if (cpufreq_frequency_table_target(policy, pxa3xx_freqs_table, - target_freq, relation, &idx)) - return -EINVAL; - - next = &pxa3xx_freqs[idx]; - - freqs.old = policy->cur; - freqs.new = next->cpufreq_mhz * 1000; - - pr_debug("CPU frequency from %d MHz to %d MHz%s\n", - freqs.old / 1000, freqs.new / 1000, - (freqs.old == freqs.new) ? " (skipped)" : ""); - - if (freqs.old == target_freq) - return 0; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + next = &pxa3xx_freqs[index]; local_irq_save(flags); __update_core_freq(next); __update_bus_freq(next); local_irq_restore(flags); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - return 0; } @@ -206,11 +178,10 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) int ret = -EINVAL; /* set default policy and cpuinfo */ - policy->cpuinfo.min_freq = 104000; - policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000; + policy->min = policy->cpuinfo.min_freq = 104000; + policy->max = policy->cpuinfo.max_freq = + (cpu_is_pxa320()) ? 806000 : 624000; policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ - policy->max = pxa3xx_get_clk_frequency_khz(0); - policy->cur = policy->min = policy->max; if (cpu_is_pxa300() || cpu_is_pxa310()) ret = setup_freqs_table(policy, pxa300_freqs, @@ -230,9 +201,10 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver pxa3xx_cpufreq_driver = { - .verify = pxa3xx_cpufreq_verify, - .target = pxa3xx_cpufreq_set, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = pxa3xx_cpufreq_set, .init = pxa3xx_cpufreq_init, + .exit = cpufreq_generic_exit, .get = pxa3xx_cpufreq_get, .name = "pxa3xx-cpufreq", }; diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index 22dcb81ef9d0..8d904a00027b 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -87,16 +87,6 @@ static struct cpufreq_frequency_table s3c2450_freq_table[] = { { 0, CPUFREQ_TABLE_END }, }; -static int s3c2416_cpufreq_verify_speed(struct cpufreq_policy *policy) -{ - struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - - if (policy->cpu != 0) - return -EINVAL; - - return cpufreq_frequency_table_verify(policy, s3c_freq->freq_table); -} - static unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu) { struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; @@ -227,24 +217,15 @@ static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx) } static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int index) { struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; - struct cpufreq_freqs freqs; + unsigned int new_freq; int idx, ret, to_dvs = 0; - unsigned int i; mutex_lock(&cpufreq_lock); - pr_debug("cpufreq: to %dKHz, relation %d\n", target_freq, relation); - - ret = cpufreq_frequency_table_target(policy, s3c_freq->freq_table, - target_freq, relation, &i); - if (ret != 0) - goto out; - - idx = s3c_freq->freq_table[i].driver_data; + idx = s3c_freq->freq_table[index].driver_data; if (idx == SOURCE_HCLK) to_dvs = 1; @@ -256,24 +237,13 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, goto out; } - freqs.flags = 0; - freqs.old = s3c_freq->is_dvs ? FREQ_DVS - : clk_get_rate(s3c_freq->armclk) / 1000; - /* When leavin dvs mode, always switch the armdiv to the hclk rate * The S3C2416 has stability issues when switching directly to * higher frequencies. */ - freqs.new = (s3c_freq->is_dvs && !to_dvs) + new_freq = (s3c_freq->is_dvs && !to_dvs) ? clk_get_rate(s3c_freq->hclk) / 1000 - : s3c_freq->freq_table[i].frequency; - - pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new); - - if (!to_dvs && freqs.old == freqs.new) - goto out; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + : s3c_freq->freq_table[index].frequency; if (to_dvs) { pr_debug("cpufreq: enter dvs\n"); @@ -282,12 +252,10 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, pr_debug("cpufreq: leave dvs\n"); ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx); } else { - pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new); - ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new); + pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq); + ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq); } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - out: mutex_unlock(&cpufreq_lock); @@ -486,20 +454,14 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) freq++; } - policy->cur = clk_get_rate(s3c_freq->armclk) / 1000; - /* Datasheet says PLL stabalisation time must be at least 300us, * so but add some fudge. (reference in LOCKCON0 register description) */ - policy->cpuinfo.transition_latency = (500 * 1000) + - s3c_freq->regulator_latency; - - ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table); + ret = cpufreq_generic_init(policy, s3c_freq->freq_table, + (500 * 1000) + s3c_freq->regulator_latency); if (ret) goto err_freq_table; - cpufreq_frequency_table_get_attr(s3c_freq->freq_table, 0); - register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier); return 0; @@ -518,19 +480,14 @@ err_hclk: return ret; } -static struct freq_attr *s3c2416_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver s3c2416_cpufreq_driver = { .flags = 0, - .verify = s3c2416_cpufreq_verify_speed, - .target = s3c2416_cpufreq_set_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = s3c2416_cpufreq_set_target, .get = s3c2416_cpufreq_get_speed, .init = s3c2416_cpufreq_driver_init, .name = "s3c2416", - .attr = s3c2416_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int __init s3c2416_cpufreq_init(void) diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index b0f343fcb7ee..485088253358 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -373,23 +373,7 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) static int s3c_cpufreq_init(struct cpufreq_policy *policy) { - printk(KERN_INFO "%s: initialising policy %p\n", __func__, policy); - - if (policy->cpu != 0) - return -EINVAL; - - policy->cur = s3c_cpufreq_get(0); - policy->min = policy->cpuinfo.min_freq = 0; - policy->max = policy->cpuinfo.max_freq = cpu_cur.info->max.fclk / 1000; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - - /* feed the latency information from the cpu driver */ - policy->cpuinfo.transition_latency = cpu_cur.info->latency; - - if (ftab) - cpufreq_frequency_table_cpuinfo(policy, ftab); - - return 0; + return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); } static int __init s3c_cpufreq_initclks(void) @@ -416,14 +400,6 @@ static int __init s3c_cpufreq_initclks(void) return 0; } -static int s3c_cpufreq_verify(struct cpufreq_policy *policy) -{ - if (policy->cpu != 0) - return -EINVAL; - - return 0; -} - #ifdef CONFIG_PM static struct cpufreq_frequency_table suspend_pll; static unsigned int suspend_freq; @@ -473,7 +449,6 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy) static struct cpufreq_driver s3c24xx_driver = { .flags = CPUFREQ_STICKY, - .verify = s3c_cpufreq_verify, .target = s3c_cpufreq_target, .get = s3c_cpufreq_get, .init = s3c_cpufreq_init, diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 15631f92ab7d..67e302eeefec 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -54,14 +54,6 @@ static struct cpufreq_frequency_table s3c64xx_freq_table[] = { }; #endif -static int s3c64xx_cpufreq_verify_speed(struct cpufreq_policy *policy) -{ - if (policy->cpu != 0) - return -EINVAL; - - return cpufreq_frequency_table_verify(policy, s3c64xx_freq_table); -} - static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu) { if (cpu != 0) @@ -71,66 +63,48 @@ static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu) } static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) + unsigned int index) { - int ret; - unsigned int i; - struct cpufreq_freqs freqs; struct s3c64xx_dvfs *dvfs; + unsigned int old_freq, new_freq; + int ret; - ret = cpufreq_frequency_table_target(policy, s3c64xx_freq_table, - target_freq, relation, &i); - if (ret != 0) - return ret; - - freqs.old = clk_get_rate(armclk) / 1000; - freqs.new = s3c64xx_freq_table[i].frequency; - freqs.flags = 0; - dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[i].driver_data]; - - if (freqs.old == freqs.new) - return 0; - - pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new); - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + old_freq = clk_get_rate(armclk) / 1000; + new_freq = s3c64xx_freq_table[index].frequency; + dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data]; #ifdef CONFIG_REGULATOR - if (vddarm && freqs.new > freqs.old) { + if (vddarm && new_freq > old_freq) { ret = regulator_set_voltage(vddarm, dvfs->vddarm_min, dvfs->vddarm_max); if (ret != 0) { pr_err("Failed to set VDDARM for %dkHz: %d\n", - freqs.new, ret); - freqs.new = freqs.old; - goto post_notify; + new_freq, ret); + return ret; } } #endif - ret = clk_set_rate(armclk, freqs.new * 1000); + ret = clk_set_rate(armclk, new_freq * 1000); if (ret < 0) { pr_err("Failed to set rate %dkHz: %d\n", - freqs.new, ret); - freqs.new = freqs.old; + new_freq, ret); + return ret; } -post_notify: - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - if (ret) - goto err; - #ifdef CONFIG_REGULATOR - if (vddarm && freqs.new < freqs.old) { + if (vddarm && new_freq < old_freq) { ret = regulator_set_voltage(vddarm, dvfs->vddarm_min, dvfs->vddarm_max); if (ret != 0) { pr_err("Failed to set VDDARM for %dkHz: %d\n", - freqs.new, ret); - goto err_clk; + new_freq, ret); + if (clk_set_rate(armclk, old_freq * 1000) < 0) + pr_err("Failed to restore original clock rate\n"); + + return ret; } } #endif @@ -139,14 +113,6 @@ post_notify: clk_get_rate(armclk) / 1000); return 0; - -err_clk: - if (clk_set_rate(armclk, freqs.old * 1000) < 0) - pr_err("Failed to restore original clock rate\n"); -err: - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - return ret; } #ifdef CONFIG_REGULATOR @@ -243,15 +209,12 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) freq++; } - policy->cur = clk_get_rate(armclk) / 1000; - /* Datasheet says PLL stabalisation time (if we were to use * the PLLs, which we don't currently) is ~300us worst case, * but add some fudge. */ - policy->cpuinfo.transition_latency = (500 * 1000) + regulator_latency; - - ret = cpufreq_frequency_table_cpuinfo(policy, s3c64xx_freq_table); + ret = cpufreq_generic_init(policy, s3c64xx_freq_table, + (500 * 1000) + regulator_latency); if (ret != 0) { pr_err("Failed to configure frequency table: %d\n", ret); @@ -264,8 +227,8 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) static struct cpufreq_driver s3c64xx_cpufreq_driver = { .flags = 0, - .verify = s3c64xx_cpufreq_verify_speed, - .target = s3c64xx_cpufreq_set_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = s3c64xx_cpufreq_set_target, .get = s3c64xx_cpufreq_get_speed, .init = s3c64xx_cpufreq_driver_init, .name = "s3c", diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 5c7757073793..e3973dae28a7 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -26,7 +26,6 @@ static struct clk *cpu_clk; static struct clk *dmc0_clk; static struct clk *dmc1_clk; -static struct cpufreq_freqs freqs; static DEFINE_MUTEX(set_freq_lock); /* APLL M,P,S values for 1G/800Mhz */ @@ -36,16 +35,7 @@ static DEFINE_MUTEX(set_freq_lock); /* Use 800MHz when entering sleep mode */ #define SLEEP_FREQ (800 * 1000) -/* - * relation has an additional symantics other than the standard of cpufreq - * DISALBE_FURTHER_CPUFREQ: disable further access to target - * ENABLE_FURTUER_CPUFREQ: enable access to target - */ -enum cpufreq_access { - DISABLE_FURTHER_CPUFREQ = 0x10, - ENABLE_FURTHER_CPUFREQ = 0x20, -}; - +/* Tracks if cpu freqency can be updated anymore */ static bool no_cpufreq_access; /* @@ -174,14 +164,6 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) __raw_writel(tmp1, reg); } -static int s5pv210_verify_speed(struct cpufreq_policy *policy) -{ - if (policy->cpu) - return -EINVAL; - - return cpufreq_frequency_table_verify(policy, s5pv210_freq_table); -} - static unsigned int s5pv210_getspeed(unsigned int cpu) { if (cpu) @@ -190,22 +172,18 @@ static unsigned int s5pv210_getspeed(unsigned int cpu) return clk_get_rate(cpu_clk) / 1000; } -static int s5pv210_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) { unsigned long reg; - unsigned int index, priv_index; + unsigned int priv_index; unsigned int pll_changing = 0; unsigned int bus_speed_changing = 0; + unsigned int old_freq, new_freq; int arm_volt, int_volt; int ret = 0; mutex_lock(&set_freq_lock); - if (relation & ENABLE_FURTHER_CPUFREQ) - no_cpufreq_access = false; - if (no_cpufreq_access) { #ifdef CONFIG_PM_VERBOSE pr_err("%s:%d denied access to %s as it is disabled" @@ -215,27 +193,13 @@ static int s5pv210_target(struct cpufreq_policy *policy, goto exit; } - if (relation & DISABLE_FURTHER_CPUFREQ) - no_cpufreq_access = true; - - relation &= ~(ENABLE_FURTHER_CPUFREQ | DISABLE_FURTHER_CPUFREQ); - - freqs.old = s5pv210_getspeed(0); - - if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, - target_freq, relation, &index)) { - ret = -EINVAL; - goto exit; - } - - freqs.new = s5pv210_freq_table[index].frequency; - - if (freqs.new == freqs.old) - goto exit; + old_freq = s5pv210_getspeed(0); + new_freq = s5pv210_freq_table[index].frequency; /* Finding current running level index */ if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, - freqs.old, relation, &priv_index)) { + old_freq, CPUFREQ_RELATION_H, + &priv_index)) { ret = -EINVAL; goto exit; } @@ -243,7 +207,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, arm_volt = dvs_conf[index].arm_volt; int_volt = dvs_conf[index].int_volt; - if (freqs.new > freqs.old) { + if (new_freq > old_freq) { ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt_max); if (ret) @@ -255,8 +219,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, goto exit; } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* Check if there need to change PLL */ if ((index == L0) || (priv_index == L0)) pll_changing = 1; @@ -467,9 +429,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - - if (freqs.new < freqs.old) { + if (new_freq < old_freq) { regulator_set_voltage(int_regulator, int_volt, int_volt_max); @@ -551,13 +511,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000); s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk); - policy->cur = policy->min = policy->max = s5pv210_getspeed(0); - - cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu); - - policy->cpuinfo.transition_latency = 40000; - - return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); + return cpufreq_generic_init(policy, s5pv210_freq_table, 40000); out_dmc1: clk_put(dmc0_clk); @@ -573,16 +527,18 @@ static int s5pv210_cpufreq_notifier_event(struct notifier_block *this, switch (event) { case PM_SUSPEND_PREPARE: - ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, - DISABLE_FURTHER_CPUFREQ); + ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0); if (ret < 0) return NOTIFY_BAD; + /* Disable updation of cpu frequency */ + no_cpufreq_access = true; return NOTIFY_OK; case PM_POST_RESTORE: case PM_POST_SUSPEND: - cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, - ENABLE_FURTHER_CPUFREQ); + /* Enable updation of cpu frequency */ + no_cpufreq_access = false; + cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0); return NOTIFY_OK; } @@ -595,18 +551,18 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this, { int ret; - ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, - DISABLE_FURTHER_CPUFREQ); + ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0); if (ret < 0) return NOTIFY_BAD; + no_cpufreq_access = true; return NOTIFY_DONE; } static struct cpufreq_driver s5pv210_driver = { .flags = CPUFREQ_STICKY, - .verify = s5pv210_verify_speed, - .target = s5pv210_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = s5pv210_target, .get = s5pv210_getspeed, .init = s5pv210_cpu_init, .name = "s5pv210", diff --git a/drivers/cpufreq/sa1100-cpufreq.c b/drivers/cpufreq/sa1100-cpufreq.c index cff18e87ca58..623da742f8e7 100644 --- a/drivers/cpufreq/sa1100-cpufreq.c +++ b/drivers/cpufreq/sa1100-cpufreq.c @@ -177,60 +177,33 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed) } } -static int sa1100_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr) { unsigned int cur = sa11x0_getspeed(0); - unsigned int new_ppcr; - struct cpufreq_freqs freqs; - - new_ppcr = sa11x0_freq_to_ppcr(target_freq); - switch (relation) { - case CPUFREQ_RELATION_L: - if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max) - new_ppcr--; - break; - case CPUFREQ_RELATION_H: - if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) && - (sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min)) - new_ppcr--; - break; - } - - freqs.old = cur; - freqs.new = sa11x0_ppcr_to_freq(new_ppcr); + unsigned int new_freq; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + new_freq = sa11x0_freq_table[ppcr].frequency; - if (freqs.new > cur) - sa1100_update_dram_timings(cur, freqs.new); + if (new_freq > cur) + sa1100_update_dram_timings(cur, new_freq); - PPCR = new_ppcr; + PPCR = ppcr; - if (freqs.new < cur) - sa1100_update_dram_timings(cur, freqs.new); - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + if (new_freq < cur) + sa1100_update_dram_timings(cur, new_freq); return 0; } static int __init sa1100_cpu_init(struct cpufreq_policy *policy) { - if (policy->cpu != 0) - return -EINVAL; - policy->cur = policy->min = policy->max = sa11x0_getspeed(0); - policy->cpuinfo.min_freq = 59000; - policy->cpuinfo.max_freq = 287000; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - return 0; + return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL); } static struct cpufreq_driver sa1100_driver __refdata = { .flags = CPUFREQ_STICKY, - .verify = sa11x0_verify_speed, - .target = sa1100_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = sa1100_target, .get = sa11x0_getspeed, .init = sa1100_cpu_init, .name = "sa1100", diff --git a/drivers/cpufreq/sa1110-cpufreq.c b/drivers/cpufreq/sa1110-cpufreq.c index 39c90b6f4286..2c2b2e601d13 100644 --- a/drivers/cpufreq/sa1110-cpufreq.c +++ b/drivers/cpufreq/sa1110-cpufreq.c @@ -229,36 +229,14 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram) /* * Ok, set the CPU frequency. */ -static int sa1110_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) { struct sdram_params *sdram = &sdram_params; - struct cpufreq_freqs freqs; struct sdram_info sd; unsigned long flags; - unsigned int ppcr, unused; - - switch (relation) { - case CPUFREQ_RELATION_L: - ppcr = sa11x0_freq_to_ppcr(target_freq); - if (sa11x0_ppcr_to_freq(ppcr) > policy->max) - ppcr--; - break; - case CPUFREQ_RELATION_H: - ppcr = sa11x0_freq_to_ppcr(target_freq); - if (ppcr && (sa11x0_ppcr_to_freq(ppcr) > target_freq) && - (sa11x0_ppcr_to_freq(ppcr-1) >= policy->min)) - ppcr--; - break; - default: - return -EINVAL; - } - - freqs.old = sa11x0_getspeed(0); - freqs.new = sa11x0_ppcr_to_freq(ppcr); + unsigned int unused; - sdram_calculate_timing(&sd, freqs.new, sdram); + sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram); #if 0 /* @@ -277,8 +255,6 @@ static int sa1110_target(struct cpufreq_policy *policy, sd.mdcas[2] = 0xaaaaaaaa; #endif - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* * The clock could be going away for some time. Set the SDRAMs * to refresh rapidly (every 64 memory clock cycles). To get @@ -323,30 +299,22 @@ static int sa1110_target(struct cpufreq_policy *policy, /* * Now, return the SDRAM refresh back to normal. */ - sdram_update_refresh(freqs.new, sdram); - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram); return 0; } static int __init sa1110_cpu_init(struct cpufreq_policy *policy) { - if (policy->cpu != 0) - return -EINVAL; - policy->cur = policy->min = policy->max = sa11x0_getspeed(0); - policy->cpuinfo.min_freq = 59000; - policy->cpuinfo.max_freq = 287000; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - return 0; + return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL); } /* sa1110_driver needs __refdata because it must remain after init registers * it with cpufreq_register_driver() */ static struct cpufreq_driver sa1110_driver __refdata = { .flags = CPUFREQ_STICKY, - .verify = sa11x0_verify_speed, - .target = sa1110_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = sa1110_target, .get = sa11x0_getspeed, .init = sa1110_cpu_init, .name = "sa1110", diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c index d6f6c6f4efa7..6adb354e359c 100644 --- a/drivers/cpufreq/sc520_freq.c +++ b/drivers/cpufreq/sc520_freq.c @@ -53,21 +53,11 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) } } -static void sc520_freq_set_cpu_state(struct cpufreq_policy *policy, - unsigned int state) +static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) { - struct cpufreq_freqs freqs; u8 clockspeed_reg; - freqs.old = sc520_freq_get_cpu_frequency(0); - freqs.new = sc520_freq_table[state].frequency; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - pr_debug("attempting to set frequency to %i kHz\n", - sc520_freq_table[state].frequency); - local_irq_disable(); clockspeed_reg = *cpuctl & ~0x03; @@ -75,30 +65,9 @@ static void sc520_freq_set_cpu_state(struct cpufreq_policy *policy, local_irq_enable(); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); -}; - -static int sc520_freq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]); -} - -static int sc520_freq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, sc520_freq_table, - target_freq, relation, &newstate)) - return -EINVAL; - - sc520_freq_set_cpu_state(policy, newstate); - return 0; } - /* * Module init and exit code */ @@ -106,7 +75,6 @@ static int sc520_freq_target(struct cpufreq_policy *policy, static int sc520_freq_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = &cpu_data(0); - int result; /* capability check */ if (c->x86_vendor != X86_VENDOR_AMD || @@ -115,39 +83,19 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy) /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = 1000000; /* 1ms */ - policy->cur = sc520_freq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table); - if (result) - return result; - - cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu); - - return 0; -} - -static int sc520_freq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_table_validate_and_show(policy, sc520_freq_table); } -static struct freq_attr *sc520_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - static struct cpufreq_driver sc520_freq_driver = { .get = sc520_freq_get_cpu_frequency, - .verify = sc520_freq_verify, - .target = sc520_freq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = sc520_freq_target, .init = sc520_freq_cpu_init, - .exit = sc520_freq_cpu_exit, + .exit = cpufreq_generic_exit, .name = "sc520_freq", - .attr = sc520_freq_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id sc520_ids[] = { diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index ffc6d24b0cfb..387af12503a6 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -87,15 +87,12 @@ static int sh_cpufreq_verify(struct cpufreq_policy *policy) if (freq_table) return cpufreq_frequency_table_verify(policy, freq_table); - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); + cpufreq_verify_within_cpu_limits(policy); 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); - + cpufreq_verify_within_cpu_limits(policy); return 0; } @@ -114,15 +111,13 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) 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); + result = cpufreq_table_validate_and_show(policy, freq_table); + if (result) + return result; } else { dev_notice(dev, "no frequency table found, falling back " "to rate rounding.\n"); @@ -154,11 +149,6 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy) return 0; } -static struct freq_attr *sh_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver sh_cpufreq_driver = { .name = "sh", .get = sh_cpufreq_get, @@ -166,7 +156,7 @@ static struct cpufreq_driver sh_cpufreq_driver = { .verify = sh_cpufreq_verify, .init = sh_cpufreq_cpu_init, .exit = sh_cpufreq_cpu_exit, - .attr = sh_freq_attr, + .attr = cpufreq_generic_attr, }; static int __init sh_cpufreq_module_init(void) diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c index cf5bc2ca16fa..62aa23e219d4 100644 --- a/drivers/cpufreq/sparc-us2e-cpufreq.c +++ b/drivers/cpufreq/sparc-us2e-cpufreq.c @@ -245,14 +245,12 @@ static unsigned int us2e_freq_get(unsigned int cpu) return clock_tick / estar_to_divisor(estar); } -static void us2e_set_cpu_divider_index(struct cpufreq_policy *policy, - unsigned int index) +static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index) { unsigned int cpu = policy->cpu; unsigned long new_bits, new_freq; unsigned long clock_tick, divisor, old_divisor, estar; cpumask_t cpus_allowed; - struct cpufreq_freqs freqs; cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -266,41 +264,15 @@ static void us2e_set_cpu_divider_index(struct cpufreq_policy *policy, old_divisor = estar_to_divisor(estar); - freqs.old = clock_tick / old_divisor; - freqs.new = new_freq; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - if (old_divisor != divisor) us2e_transition(estar, new_bits, clock_tick * 1000, old_divisor, divisor); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - set_cpus_allowed_ptr(current, &cpus_allowed); -} - -static int us2e_freq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int new_index = 0; - - if (cpufreq_frequency_table_target(policy, - &us2e_freq_table[policy->cpu].table[0], - target_freq, relation, &new_index)) - return -EINVAL; - - us2e_set_cpu_divider_index(policy, new_index); return 0; } -static int us2e_freq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - &us2e_freq_table[policy->cpu].table[0]); -} - static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; @@ -324,13 +296,15 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; - return cpufreq_frequency_table_cpuinfo(policy, table); + return cpufreq_table_validate_and_show(policy, table); } static int us2e_freq_cpu_exit(struct cpufreq_policy *policy) { - if (cpufreq_us2e_driver) - us2e_set_cpu_divider_index(policy, 0); + if (cpufreq_us2e_driver) { + cpufreq_frequency_table_put_attr(policy->cpu); + us2e_freq_target(policy, 0); + } return 0; } @@ -361,8 +335,8 @@ static int __init us2e_freq_init(void) goto err_out; driver->init = us2e_freq_cpu_init; - driver->verify = us2e_freq_verify; - driver->target = us2e_freq_target; + driver->verify = cpufreq_generic_frequency_table_verify; + driver->target_index = us2e_freq_target; driver->get = us2e_freq_get; driver->exit = us2e_freq_cpu_exit; strcpy(driver->name, "UltraSPARC-IIe"); diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index ac76b489979d..724ffbd7105d 100644 --- a/drivers/cpufreq/sparc-us3-cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c @@ -93,13 +93,11 @@ static unsigned int us3_freq_get(unsigned int cpu) return ret; } -static void us3_set_cpu_divider_index(struct cpufreq_policy *policy, - unsigned int index) +static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index) { unsigned int cpu = policy->cpu; unsigned long new_bits, new_freq, reg; cpumask_t cpus_allowed; - struct cpufreq_freqs freqs; cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -125,43 +123,15 @@ static void us3_set_cpu_divider_index(struct cpufreq_policy *policy, reg = read_safari_cfg(); - freqs.old = get_current_freq(cpu, reg); - freqs.new = new_freq; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - reg &= ~SAFARI_CFG_DIV_MASK; reg |= new_bits; write_safari_cfg(reg); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - set_cpus_allowed_ptr(current, &cpus_allowed); -} - -static int us3_freq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int new_index = 0; - - if (cpufreq_frequency_table_target(policy, - &us3_freq_table[policy->cpu].table[0], - target_freq, - relation, - &new_index)) - return -EINVAL; - - us3_set_cpu_divider_index(policy, new_index); return 0; } -static int us3_freq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - &us3_freq_table[policy->cpu].table[0]); -} - static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; @@ -181,13 +151,15 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; - return cpufreq_frequency_table_cpuinfo(policy, table); + return cpufreq_table_validate_and_show(policy, table); } static int us3_freq_cpu_exit(struct cpufreq_policy *policy) { - if (cpufreq_us3_driver) - us3_set_cpu_divider_index(policy, 0); + if (cpufreq_us3_driver) { + cpufreq_frequency_table_put_attr(policy->cpu); + us3_freq_target(policy, 0); + } return 0; } @@ -222,8 +194,8 @@ static int __init us3_freq_init(void) goto err_out; driver->init = us3_freq_cpu_init; - driver->verify = us3_freq_verify; - driver->target = us3_freq_target; + driver->verify = cpufreq_generic_frequency_table_verify; + driver->target_index = us3_freq_target; driver->get = us3_freq_get; driver->exit = us3_freq_cpu_exit; strcpy(driver->name, "UltraSPARC-III"); diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index 3f418166ce02..d02ccd19c9c4 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -30,11 +30,6 @@ static struct { u32 cnt; } spear_cpufreq; -static int spear_cpufreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl); -} - static unsigned int spear_cpufreq_get(unsigned int cpu) { return clk_get_rate(spear_cpufreq.clk) / 1000; @@ -110,20 +105,14 @@ static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq) } static int spear_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) + unsigned int index) { - struct cpufreq_freqs freqs; long newfreq; struct clk *srcclk; - int index, ret, mult = 1; - - if (cpufreq_frequency_table_target(policy, spear_cpufreq.freq_tbl, - target_freq, relation, &index)) - return -EINVAL; - - freqs.old = spear_cpufreq_get(0); + int ret, mult = 1; newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; + if (of_machine_is_compatible("st,spear1340")) { /* * SPEAr1340 is special in the sense that due to the possibility @@ -154,65 +143,32 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, return newfreq; } - freqs.new = newfreq / 1000; - freqs.new /= mult; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - if (mult == 2) ret = spear1340_set_cpu_rate(srcclk, newfreq); else ret = clk_set_rate(spear_cpufreq.clk, newfreq); - /* Get current rate after clk_set_rate, in case of failure */ - if (ret) { + if (ret) pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); - freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000; - } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return ret; } static int spear_cpufreq_init(struct cpufreq_policy *policy) { - int ret; - - ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl); - if (ret) { - pr_err("cpufreq_frequency_table_cpuinfo() failed"); - return ret; - } - - cpufreq_frequency_table_get_attr(spear_cpufreq.freq_tbl, policy->cpu); - policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency; - policy->cur = spear_cpufreq_get(0); - - cpumask_setall(policy->cpus); - - return 0; -} - -static int spear_cpufreq_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_generic_init(policy, spear_cpufreq.freq_tbl, + spear_cpufreq.transition_latency); } -static struct freq_attr *spear_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver spear_cpufreq_driver = { .name = "cpufreq-spear", .flags = CPUFREQ_STICKY, - .verify = spear_cpufreq_verify, - .target = spear_cpufreq_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = spear_cpufreq_target, .get = spear_cpufreq_get, .init = spear_cpufreq_init, - .exit = spear_cpufreq_exit, - .attr = spear_cpufreq_attr, + .exit = cpufreq_generic_exit, + .attr = cpufreq_generic_attr, }; static int spear_cpufreq_driver_init(void) diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index f897d5105842..4e1daca5ce3b 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -343,9 +343,7 @@ static unsigned int get_cur_freq(unsigned int cpu) static int centrino_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); - unsigned freq; unsigned l, h; - int ret; int i; /* Only Intel makes Enhanced Speedstep-capable CPUs */ @@ -373,9 +371,8 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) return -ENODEV; } - if (centrino_cpu_init_table(policy)) { + if (centrino_cpu_init_table(policy)) return -ENODEV; - } /* Check to see if Enhanced SpeedStep is enabled, and try to enable it if not. */ @@ -395,22 +392,11 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) } } - freq = get_cur_freq(policy->cpu); policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ - policy->cur = freq; - - pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur); - ret = cpufreq_frequency_table_cpuinfo(policy, + return cpufreq_table_validate_and_show(policy, per_cpu(centrino_model, policy->cpu)->op_points); - if (ret) - return (ret); - - cpufreq_frequency_table_get_attr( - per_cpu(centrino_model, policy->cpu)->op_points, policy->cpu); - - return 0; } static int centrino_cpu_exit(struct cpufreq_policy *policy) @@ -428,36 +414,18 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy) } /** - * centrino_verify - verifies a new CPUFreq policy - * @policy: new policy - * - * Limit must be within this model's frequency range at least one - * border included. - */ -static int centrino_verify (struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - per_cpu(centrino_model, policy->cpu)->op_points); -} - -/** * centrino_setpolicy - set a new CPUFreq policy * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * @index: index of target frequency * * Sets a new CPUFreq policy. */ -static int centrino_target (struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int centrino_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int newstate = 0; unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; - struct cpufreq_freqs freqs; int retval = 0; - unsigned int j, first_cpu, tmp; + unsigned int j, first_cpu; + struct cpufreq_frequency_table *op_points; cpumask_var_t covered_cpus; if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) @@ -468,16 +436,8 @@ static int centrino_target (struct cpufreq_policy *policy, goto out; } - if (unlikely(cpufreq_frequency_table_target(policy, - per_cpu(centrino_model, cpu)->op_points, - target_freq, - relation, - &newstate))) { - retval = -EINVAL; - goto out; - } - first_cpu = 1; + op_points = &per_cpu(centrino_model, cpu)->op_points[index]; for_each_cpu(j, policy->cpus) { int good_cpu; @@ -501,7 +461,7 @@ static int centrino_target (struct cpufreq_policy *policy, break; } - msr = per_cpu(centrino_model, cpu)->op_points[newstate].driver_data; + msr = op_points->driver_data; if (first_cpu) { rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); @@ -512,15 +472,6 @@ static int centrino_target (struct cpufreq_policy *policy, goto out; } - freqs.old = extract_clock(oldmsr, cpu, 0); - freqs.new = extract_clock(msr, cpu, 0); - - pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", - target_freq, freqs.old, freqs.new, msr); - - cpufreq_notify_transition(policy, &freqs, - CPUFREQ_PRECHANGE); - first_cpu = 0; /* all but 16 LSB are reserved, treat them with care */ oldmsr &= ~0xffff; @@ -535,8 +486,6 @@ static int centrino_target (struct cpufreq_policy *policy, cpumask_set_cpu(j, covered_cpus); } - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - if (unlikely(retval)) { /* * We have failed halfway through the frequency change. @@ -547,12 +496,6 @@ static int centrino_target (struct cpufreq_policy *policy, for_each_cpu(j, covered_cpus) wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); - - tmp = freqs.new; - freqs.new = freqs.old; - freqs.old = tmp; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); } retval = 0; @@ -561,20 +504,15 @@ out: return retval; } -static struct freq_attr* centrino_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver centrino_driver = { .name = "centrino", /* should be speedstep-centrino, but there's a 16 char limit */ .init = centrino_cpu_init, .exit = centrino_cpu_exit, - .verify = centrino_verify, - .target = centrino_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = centrino_target, .get = get_cur_freq, - .attr = centrino_attr, + .attr = cpufreq_generic_attr, }; /* diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index 5355abb69afc..7639b2be2a90 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c @@ -251,56 +251,23 @@ static unsigned int speedstep_get(unsigned int cpu) /** * speedstep_target - set a new CPUFreq policy * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * @index: index of target frequency * * Sets a new CPUFreq policy. */ -static int speedstep_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int newstate = 0, policy_cpu; - struct cpufreq_freqs freqs; - - if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], - target_freq, relation, &newstate)) - return -EINVAL; + unsigned int policy_cpu; policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); - freqs.old = speedstep_get(policy_cpu); - freqs.new = speedstep_freqs[newstate].frequency; - - pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); - - /* no transition necessary */ - if (freqs.old == freqs.new) - return 0; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, + smp_call_function_single(policy_cpu, _speedstep_set_state, &index, true); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - return 0; } -/** - * speedstep_verify - verifies a new CPUFreq policy - * @policy: new policy - * - * Limit must be within speedstep_low_freq and speedstep_high_freq, with - * at least one border included. - */ -static int speedstep_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); -} - struct get_freqs { struct cpufreq_policy *policy; int ret; @@ -320,8 +287,7 @@ static void get_freqs_on_cpu(void *_get_freqs) static int speedstep_cpu_init(struct cpufreq_policy *policy) { - int result; - unsigned int policy_cpu, speed; + unsigned int policy_cpu; struct get_freqs gf; /* only run on CPU to be set, or on its sibling */ @@ -336,49 +302,18 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (gf.ret) return gf.ret; - /* get current speed setting */ - speed = speedstep_get(policy_cpu); - if (!speed) - return -EIO; - - pr_debug("currently at %s speed setting - %i MHz\n", - (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) - ? "low" : "high", - (speed / 1000)); - - /* cpuinfo and default policy values */ - policy->cur = speed; - - result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); - if (result) - return result; - - cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); - - return 0; + return cpufreq_table_validate_and_show(policy, speedstep_freqs); } -static int speedstep_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static struct freq_attr *speedstep_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - static struct cpufreq_driver speedstep_driver = { .name = "speedstep-ich", - .verify = speedstep_verify, - .target = speedstep_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = speedstep_target, .init = speedstep_cpu_init, - .exit = speedstep_cpu_exit, + .exit = cpufreq_generic_exit, .get = speedstep_get, - .attr = speedstep_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id ss_smi_ids[] = { diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index abfba4f731eb..0f5326d6f79f 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -235,52 +235,21 @@ static void speedstep_set_state(unsigned int state) /** * speedstep_target - set a new CPUFreq policy * @policy: new policy - * @target_freq: new freq - * @relation: + * @index: index of new freq * * Sets a new CPUFreq policy/freq. */ -static int speedstep_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) +static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int newstate = 0; - struct cpufreq_freqs freqs; - - if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], - target_freq, relation, &newstate)) - return -EINVAL; - - freqs.old = speedstep_freqs[speedstep_get_state()].frequency; - freqs.new = speedstep_freqs[newstate].frequency; - - if (freqs.old == freqs.new) - return 0; - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - speedstep_set_state(newstate); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + speedstep_set_state(index); return 0; } -/** - * speedstep_verify - verifies a new CPUFreq policy - * @policy: new policy - * - * Limit must be within speedstep_low_freq and speedstep_high_freq, with - * at least one border included. - */ -static int speedstep_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); -} - - static int speedstep_cpu_init(struct cpufreq_policy *policy) { int result; - unsigned int speed, state; unsigned int *low, *high; /* capability check */ @@ -316,32 +285,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) pr_debug("workaround worked.\n"); } - /* get current speed setting */ - state = speedstep_get_state(); - speed = speedstep_freqs[state].frequency; - - pr_debug("currently at %s speed setting - %i MHz\n", - (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) - ? "low" : "high", - (speed / 1000)); - - /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = speed; - - result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); - if (result) - return result; - - cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); - - return 0; -} - -static int speedstep_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; + return cpufreq_table_validate_and_show(policy, speedstep_freqs); } static unsigned int speedstep_get(unsigned int cpu) @@ -362,20 +307,15 @@ static int speedstep_resume(struct cpufreq_policy *policy) return result; } -static struct freq_attr *speedstep_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver speedstep_driver = { .name = "speedstep-smi", - .verify = speedstep_verify, - .target = speedstep_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = speedstep_target, .init = speedstep_cpu_init, - .exit = speedstep_cpu_exit, + .exit = cpufreq_generic_exit, .get = speedstep_get, .resume = speedstep_resume, - .attr = speedstep_attr, + .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id ss_smi_ids[] = { diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c index a7b876fdc1d8..b7309c37033d 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra-cpufreq.c @@ -51,11 +51,6 @@ static unsigned long target_cpu_speed[NUM_CPUS]; static DEFINE_MUTEX(tegra_cpu_lock); static bool is_suspended; -static int tegra_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, freq_table); -} - static unsigned int tegra_getspeed(unsigned int cpu) { unsigned long rate; @@ -107,12 +102,8 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, unsigned long rate) { int ret = 0; - struct cpufreq_freqs freqs; - freqs.old = tegra_getspeed(0); - freqs.new = rate; - - if (freqs.old == freqs.new) + if (tegra_getspeed(0) == rate) return ret; /* @@ -126,21 +117,10 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, else clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - -#ifdef CONFIG_CPU_FREQ_DEBUG - printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n", - freqs.old, freqs.new); -#endif - - ret = tegra_cpu_clk_set_rate(freqs.new * 1000); - if (ret) { - pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n", - freqs.new); - freqs.new = freqs.old; - } - - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + ret = tegra_cpu_clk_set_rate(rate * 1000); + if (ret) + pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n", + rate); return ret; } @@ -155,25 +135,17 @@ static unsigned long tegra_cpu_highest_speed(void) return rate; } -static int tegra_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int tegra_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int idx; unsigned int freq; int ret = 0; mutex_lock(&tegra_cpu_lock); - if (is_suspended) { - ret = -EBUSY; + if (is_suspended) goto out; - } - cpufreq_frequency_table_target(policy, freq_table, target_freq, - relation, &idx); - - freq = freq_table[idx].frequency; + freq = freq_table[index].frequency; target_cpu_speed[policy->cpu] = freq; @@ -209,21 +181,23 @@ static struct notifier_block tegra_cpu_pm_notifier = { static int tegra_cpu_init(struct cpufreq_policy *policy) { + int ret; + if (policy->cpu >= NUM_CPUS) return -EINVAL; clk_prepare_enable(emc_clk); clk_prepare_enable(cpu_clk); - cpufreq_frequency_table_cpuinfo(policy, freq_table); - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - policy->cur = tegra_getspeed(policy->cpu); - target_cpu_speed[policy->cpu] = policy->cur; + target_cpu_speed[policy->cpu] = tegra_getspeed(policy->cpu); /* FIXME: what's the actual transition time? */ - policy->cpuinfo.transition_latency = 300 * 1000; - - cpumask_copy(policy->cpus, cpu_possible_mask); + ret = cpufreq_generic_init(policy, freq_table, 300 * 1000); + if (ret) { + clk_disable_unprepare(cpu_clk); + clk_disable_unprepare(emc_clk); + return ret; + } if (policy->cpu == 0) register_pm_notifier(&tegra_cpu_pm_notifier); @@ -233,24 +207,20 @@ static int tegra_cpu_init(struct cpufreq_policy *policy) static int tegra_cpu_exit(struct cpufreq_policy *policy) { - cpufreq_frequency_table_cpuinfo(policy, freq_table); + cpufreq_frequency_table_put_attr(policy->cpu); + clk_disable_unprepare(cpu_clk); clk_disable_unprepare(emc_clk); return 0; } -static struct freq_attr *tegra_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - static struct cpufreq_driver tegra_cpufreq_driver = { - .verify = tegra_verify_speed, - .target = tegra_target, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = tegra_target, .get = tegra_getspeed, .init = tegra_cpu_init, .exit = tegra_cpu_exit, .name = "tegra", - .attr = tegra_cpufreq_attr, + .attr = cpufreq_generic_attr, }; static int __init tegra_cpufreq_init(void) diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index b225f04d8ae5..653ae2955b55 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -29,9 +29,7 @@ static int ucv2_verify_speed(struct cpufreq_policy *policy) if (policy->cpu) return -EINVAL; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - + cpufreq_verify_within_cpu_limits(policy); return 0; } @@ -68,7 +66,6 @@ static int __init ucv2_cpu_init(struct cpufreq_policy *policy) { if (policy->cpu != 0) return -EINVAL; - policy->cur = ucv2_getspeed(0); policy->min = policy->cpuinfo.min_freq = 250000; policy->max = policy->cpuinfo.max_freq = 1000000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c b/drivers/cpufreq/vexpress-spc-cpufreq.c new file mode 100644 index 000000000000..7f7c9c01b44e --- /dev/null +++ b/drivers/cpufreq/vexpress-spc-cpufreq.c @@ -0,0 +1,70 @@ +/* + * Versatile Express SPC CPUFreq Interface driver + * + * It provides necessary ops to arm_big_little cpufreq driver. + * + * Copyright (C) 2013 ARM Ltd. + * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com> + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/cpufreq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> +#include <linux/types.h> + +#include "arm_big_little.h" + +static int ve_spc_init_opp_table(struct device *cpu_dev) +{ + /* + * platform specific SPC code must initialise the opp table + * so just check if the OPP count is non-zero + */ + return dev_pm_opp_get_opp_count(cpu_dev) <= 0; +} + +static int ve_spc_get_transition_latency(struct device *cpu_dev) +{ + return 1000000; /* 1 ms */ +} + +static struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = { + .name = "vexpress-spc", + .get_transition_latency = ve_spc_get_transition_latency, + .init_opp_table = ve_spc_init_opp_table, +}; + +static int ve_spc_cpufreq_probe(struct platform_device *pdev) +{ + return bL_cpufreq_register(&ve_spc_cpufreq_ops); +} + +static int ve_spc_cpufreq_remove(struct platform_device *pdev) +{ + bL_cpufreq_unregister(&ve_spc_cpufreq_ops); + return 0; +} + +static struct platform_driver ve_spc_cpufreq_platdrv = { + .driver = { + .name = "vexpress-spc-cpufreq", + .owner = THIS_MODULE, + }, + .probe = ve_spc_cpufreq_probe, + .remove = ve_spc_cpufreq_remove, +}; +module_platform_driver(ve_spc_cpufreq_platdrv); + +MODULE_LICENSE("GPL"); |