summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/cpufreq
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/Kconfig11
-rw-r--r--drivers/cpufreq/Kconfig.arm19
-rw-r--r--drivers/cpufreq/Kconfig.powerpc6
-rw-r--r--drivers/cpufreq/Kconfig.x8615
-rw-r--r--drivers/cpufreq/Makefile6
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c52
-rw-r--r--drivers/cpufreq/arm_big_little.c453
-rw-r--r--drivers/cpufreq/arm_big_little.h5
-rw-r--r--drivers/cpufreq/arm_big_little_dt.c2
-rw-r--r--drivers/cpufreq/at32ap-cpufreq.c106
-rw-r--r--drivers/cpufreq/blackfin-cpufreq.c54
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c119
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c5
-rw-r--r--drivers/cpufreq/cpufreq.c322
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c10
-rw-r--r--drivers/cpufreq/cpufreq_governor.c4
-rw-r--r--drivers/cpufreq/cpufreq_governor.h5
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c1
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c11
-rw-r--r--drivers/cpufreq/cris-artpec3-cpufreq.c64
-rw-r--r--drivers/cpufreq/cris-etraxfs-cpufreq.c61
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c77
-rw-r--r--drivers/cpufreq/dbx500-cpufreq.c78
-rw-r--r--drivers/cpufreq/e_powersaver.c59
-rw-r--r--drivers/cpufreq/elanfreq.c88
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c87
-rw-r--r--drivers/cpufreq/exynos4210-cpufreq.c68
-rw-r--r--drivers/cpufreq/exynos4x12-cpufreq.c70
-rw-r--r--drivers/cpufreq/exynos5250-cpufreq.c1
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c67
-rw-r--r--drivers/cpufreq/freq_table.c59
-rw-r--r--drivers/cpufreq/gx-suspmod.c5
-rw-r--r--drivers/cpufreq/highbank-cpufreq.c3
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c71
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c117
-rw-r--r--drivers/cpufreq/integrator-cpufreq.c75
-rw-r--r--drivers/cpufreq/intel_pstate.c255
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c107
-rw-r--r--drivers/cpufreq/longhaul.c45
-rw-r--r--drivers/cpufreq/longrun.c4
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c57
-rw-r--r--drivers/cpufreq/maple-cpufreq.c56
-rw-r--r--drivers/cpufreq/omap-cpufreq.c144
-rw-r--r--drivers/cpufreq/p4-clockmod.c53
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c52
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c15
-rw-r--r--drivers/cpufreq/pmac32-cpufreq.c53
-rw-r--r--drivers/cpufreq/pmac64-cpufreq.c70
-rw-r--r--drivers/cpufreq/powernow-k6.c67
-rw-r--r--drivers/cpufreq/powernow-k7.c42
-rw-r--r--drivers/cpufreq/powernow-k8.c52
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c54
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c50
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c70
-rw-r--r--drivers/cpufreq/pxa3xx-cpufreq.c46
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c67
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c27
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c81
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c86
-rw-r--r--drivers/cpufreq/sa1100-cpufreq.c49
-rw-r--r--drivers/cpufreq/sa1110-cpufreq.c46
-rw-r--r--drivers/cpufreq/sc520_freq.c64
-rw-r--r--drivers/cpufreq/sh-cpufreq.c22
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c42
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c44
-rw-r--r--drivers/cpufreq/spear-cpufreq.c64
-rw-r--r--drivers/cpufreq/speedstep-centrino.c84
-rw-r--r--drivers/cpufreq/speedstep-ich.c85
-rw-r--r--drivers/cpufreq/speedstep-smi.c76
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c74
-rw-r--r--drivers/cpufreq/unicore2-cpufreq.c5
-rw-r--r--drivers/cpufreq/vexpress-spc-cpufreq.c70
72 files changed, 2966 insertions, 1568 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 38093e2..534fcb8 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -17,11 +17,15 @@ 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
@@ -139,6 +143,7 @@ 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.
@@ -182,6 +187,7 @@ 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)
@@ -217,6 +223,7 @@ 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
@@ -233,6 +240,7 @@ 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.
@@ -254,6 +262,7 @@ 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.
@@ -263,6 +272,7 @@ 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.
@@ -275,6 +285,7 @@ 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 ce52ed9..0fa204b 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -5,6 +5,7 @@
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.
@@ -17,6 +18,7 @@ config ARM_DT_BL_CPUFREQ
config ARM_EXYNOS_CPUFREQ
bool
+ select CPU_FREQ_TABLE
config ARM_EXYNOS4210_CPUFREQ
bool "SAMSUNG EXYNOS4210"
@@ -56,6 +58,7 @@ 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
@@ -82,6 +85,7 @@ 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.
@@ -97,6 +101,7 @@ 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.
@@ -105,6 +110,7 @@ config ARM_OMAP2PLUS_CPUFREQ
bool "TI OMAP2+"
depends on ARCH_OMAP2PLUS
default ARCH_OMAP2PLUS
+ select CPU_FREQ_TABLE
config ARM_S3C_CPUFREQ
bool
@@ -159,6 +165,7 @@ 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
@@ -189,6 +196,7 @@ 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.
@@ -198,6 +206,7 @@ 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
@@ -214,6 +223,7 @@ 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.
@@ -221,14 +231,7 @@ 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 ca0021a..25ca9db 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -1,6 +1,7 @@
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.
@@ -19,6 +20,7 @@ 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).
@@ -26,6 +28,7 @@ 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,
@@ -35,6 +38,7 @@ 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
@@ -43,6 +47,7 @@ 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.
@@ -50,6 +55,7 @@ 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 d369349..e2b6eab 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -31,6 +31,7 @@ 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
@@ -59,6 +60,7 @@ 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
@@ -74,6 +76,7 @@ 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.
@@ -85,6 +88,7 @@ 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
@@ -96,6 +100,7 @@ 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.
@@ -113,6 +118,7 @@ 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.
@@ -126,10 +132,11 @@ 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 (available on AMD
+ change decisions based on feedback from hardware (availble on AMD
Family 16h and above).
Hardware feedback tells software how "sensitive" to frequency changes
@@ -153,6 +160,7 @@ 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
@@ -182,6 +190,7 @@ 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
@@ -195,6 +204,7 @@ 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
@@ -207,6 +217,7 @@ 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
@@ -248,6 +259,7 @@ 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,
@@ -260,6 +272,7 @@ 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 7494565..ad5866c 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -1,5 +1,5 @@
# CPUfreq core
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
@@ -11,6 +11,9 @@ 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
##################################################################################
@@ -74,7 +77,6 @@ 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 caf41eb..506fd23 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -424,21 +424,34 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
}
static int acpi_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int index)
+ unsigned int target_freq, unsigned int relation)
{
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;
- next_perf_state = data->freq_table[index].driver_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;
if (perf->state == next_perf_state) {
if (unlikely(data->resume)) {
pr_debug("Called after resume, resetting to P%d\n",
@@ -479,17 +492,23 @@ 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, data->freq_table[index].frequency,
- data)) {
+ if (!check_freqs(cmd.mask, freqs.new, 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;
@@ -497,6 +516,15 @@ 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)
{
@@ -809,7 +837,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_table_validate_and_show(policy, data->freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
if (result)
goto err_freqfree;
@@ -818,16 +846,12 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
switch (perf->control_register.space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO:
- /*
- * 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.
- */
+ /* Current speed is unknown and not detectable by IO port */
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;
@@ -844,6 +868,8 @@ 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.
@@ -903,8 +929,8 @@ static struct freq_attr *acpi_cpufreq_attr[] = {
};
static struct cpufreq_driver acpi_cpufreq_driver = {
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = acpi_cpufreq_target,
+ .verify = acpi_cpufreq_verify,
+ .target = 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 5519933..3549f07 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -24,323 +24,110 @@
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
#include <linux/export.h>
-#include <linux/mutex.h>
#include <linux/of_platform.h>
-#include <linux/pm_opp.h>
+#include <linux/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 + 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 struct mutex cluster_lock[MAX_CLUSTERS];
-
-static inline int raw_cpu_to_cluster(int cpu)
-{
- return topology_physical_package_id(cpu);
-}
-
-static inline int cpu_to_cluster(int cpu)
-{
- return is_bL_switching_enabled() ?
- MAX_CLUSTERS : raw_cpu_to_cluster(cpu);
-}
-
-static unsigned int find_cluster_maxfreq(int cluster)
-{
- 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 struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
+static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
-static unsigned int clk_get_cpu_rate(unsigned int cpu)
+static unsigned int bL_cpufreq_get(unsigned int cpu)
{
- u32 cur_cluster = per_cpu(physical_cluster, cpu);
- u32 rate = clk_get_rate(clk[cur_cluster]) / 1000;
+ u32 cur_cluster = cpu_to_cluster(cpu);
- /* 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;
+ return clk_get_rate(clk[cur_cluster]) / 1000;
}
-static unsigned int bL_cpufreq_get_rate(unsigned int cpu)
+/* Validate policy frequency range */
+static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
{
- 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]);
-
- 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]);
- }
+ u32 cur_cluster = cpu_to_cluster(policy->cpu);
- return 0;
+ return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]);
}
/* Set clock frequency */
static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
- unsigned int index)
+ unsigned int target_freq, unsigned int relation)
{
- 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;
- }
- }
+ struct cpufreq_freqs freqs;
+ u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
+ int ret = 0;
- return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
-}
+ cur_cluster = cpu_to_cluster(policy->cpu);
-static inline u32 get_table_count(struct cpufreq_frequency_table *table)
-{
- int count;
+ freqs.old = bL_cpufreq_get(policy->cpu);
- for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; 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;
- return 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);
-/* 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;
-}
+ if (freqs.old == freqs.new)
+ return 0;
-/* 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;
-}
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
-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++;
- }
+ 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;
}
- table[k].driver_data = k;
- table[k].frequency = CPUFREQ_TABLE_END;
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- 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);
+ return ret;
}
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);
- 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);
+ 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);
}
-
- /* 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 = raw_cpu_to_cluster(cpu_dev->id);
+ u32 cluster = cpu_to_cluster(cpu_dev->id);
char name[14] = "cpu-cluster.";
int ret;
- if (freq_table[cluster])
+ if (atomic_inc_return(&cluster_usage[cluster]) != 1)
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 out;
+ goto atomic_dec;
}
- ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
+ ret = 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 out;
+ goto atomic_dec;
}
name[12] = cluster + '0';
- clk[cluster] = clk_get(cpu_dev, name);
+ clk[cluster] = clk_get_sys(name, NULL);
if (!IS_ERR(clk[cluster])) {
dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n",
__func__, clk[cluster], freq_table[cluster],
@@ -351,74 +138,15 @@ 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]);
- dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+ opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
-out:
+atomic_dec:
+ atomic_dec(&cluster_usage[cluster]);
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)
{
@@ -437,7 +165,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
if (ret)
return ret;
- ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]);
+ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster]);
if (ret) {
dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
policy->cpu, cur_cluster);
@@ -445,14 +173,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
return ret;
}
- 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;
- }
+ cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
if (arm_bL_ops->get_transition_latency)
policy->cpuinfo.transition_latency =
@@ -460,8 +181,9 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
else
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
- if (is_bL_switching_enabled())
- per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu);
+ policy->cur = bL_cpufreq_get(policy->cpu);
+
+ cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu);
return 0;
@@ -478,60 +200,33 @@ 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 |
- CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = bL_cpufreq_set_target,
- .get = bL_cpufreq_get_rate,
+ .flags = CPUFREQ_STICKY,
+ .verify = bL_cpufreq_verify_policy,
+ .target = bL_cpufreq_set_target,
+ .get = bL_cpufreq_get,
.init = bL_cpufreq_init,
.exit = bL_cpufreq_exit,
- .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,
+ .have_governor_per_policy = true,
+ .attr = bL_cpufreq_attr,
};
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
{
- int ret, i;
+ int ret;
if (arm_bL_ops) {
pr_debug("%s: Already registered: %s, exiting\n", __func__,
@@ -546,29 +241,16 @@ 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 {
- 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);
- }
+ pr_info("%s: Registered platform driver: %s\n", __func__,
+ ops->name);
}
- bL_switcher_put_enabled();
return ret;
}
EXPORT_SYMBOL_GPL(bL_cpufreq_register);
@@ -581,10 +263,7 @@ 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 70f18fc..79b2ce1 100644
--- a/drivers/cpufreq/arm_big_little.h
+++ b/drivers/cpufreq/arm_big_little.h
@@ -34,6 +34,11 @@ 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 8d9d591..480c0bd 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/pm_opp.h>
+#include <linux/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 856ad80..e0c38d9 100644
--- a/drivers/cpufreq/at32ap-cpufreq.c
+++ b/drivers/cpufreq/at32ap-cpufreq.c
@@ -19,10 +19,18 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/slab.h>
static struct clk *cpuclk;
-static struct cpufreq_frequency_table *freq_table;
+
+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 unsigned int at32_get_speed(unsigned int cpu)
{
@@ -35,94 +43,74 @@ 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 index)
+static int at32_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
- unsigned int old_freq, new_freq;
+ 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);
- old_freq = at32_get_speed(0);
- new_freq = freq_table[index].frequency;
+ freqs.old = at32_get_speed(0);
+ freqs.new = (freq + 500) / 1000;
+ freqs.flags = 0;
if (!ref_freq) {
- ref_freq = old_freq;
+ ref_freq = freqs.old;
loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
}
- if (old_freq < new_freq)
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ if (freqs.old < freqs.new)
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
- loops_per_jiffy_ref, ref_freq, new_freq);
- clk_set_rate(cpuclk, new_freq * 1000);
- if (new_freq < old_freq)
+ loops_per_jiffy_ref, ref_freq, freqs.new);
+ clk_set_rate(cpuclk, freq);
+ if (freqs.new < freqs.old)
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
- loops_per_jiffy_ref, ref_freq, new_freq);
+ loops_per_jiffy_ref, ref_freq, freqs.new);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
+ pr_debug("cpufreq: set frequency %lu Hz\n", freq);
return 0;
}
static int __init 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");
- retval = PTR_ERR(cpuclk);
- goto out_err;
+ return PTR_ERR(cpuclk);
}
- min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
- frequency = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+ policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+ policy->cpuinfo.max_freq = (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;
- /*
- * 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;
- }
-
- 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;
- }
+ printk("cpufreq: AT32AP CPU frequency driver\n");
- 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;
+ return 0;
}
static struct cpufreq_driver at32_driver = {
.name = "at32ap",
.init = at32_cpufreq_driver_init,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = at32_set_target,
+ .verify = at32_verify_speed,
+ .target = 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 e9e63fc..ef05978 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -127,28 +127,41 @@ unsigned long cpu_set_cclk(int cpu, unsigned long new)
}
#endif
-static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
+static int bfin_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
{
#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
- old_freq = bfin_getfreq_khz(0);
- new_freq = bfin_freq_table[index].frequency;
+ if (cpufreq_frequency_table_target(policy, bfin_freq_table, target_freq,
+ relation, &index))
+ return -EINVAL;
+ 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, new_freq * 1000);
+ ret = cpu_set_cclk(policy->cpu, freqs.new * 1000);
if (ret != 0) {
WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
return ret;
@@ -164,16 +177,25 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
#endif
if (!lpj_ref_freq) {
lpj_ref = loops_per_jiffy;
- lpj_ref_freq = old_freq;
+ lpj_ref_freq = freqs.old;
}
- if (new_freq != old_freq) {
+ if (freqs.new != freqs.old) {
loops_per_jiffy = cpufreq_scale(lpj_ref,
- lpj_ref_freq, new_freq);
+ lpj_ref_freq, freqs.new);
}
+ /* 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)
{
@@ -187,17 +209,23 @@ static int __bfin_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 50000; /* 50us assumed */
- return cpufreq_table_validate_and_show(policy, bfin_freq_table);
+ policy->cur = cclk;
+ cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu);
+ return cpufreq_frequency_table_cpuinfo(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 = cpufreq_generic_frequency_table_verify,
- .target_index = bfin_target,
+ .verify = bfin_verify_speed,
+ .target = bfin_target,
.get = bfin_getfreq_khz,
.init = __bfin_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "bfin cpufreq",
- .attr = cpufreq_generic_attr,
+ .attr = bfin_freq_attr,
};
static int __init bfin_cpu_init(void)
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index d4585ce..c522a95 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/pm_opp.h>
+#include <linux/opp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -30,51 +30,73 @@ 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 index)
+static int cpu0_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
{
- struct dev_pm_opp *opp;
+ struct cpufreq_freqs freqs;
+ struct 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;
- new_freq = freq_Hz / 1000;
- old_freq = clk_get_rate(cpu_clk) / 1000;
+ 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);
if (!IS_ERR(cpu_reg)) {
rcu_read_lock();
- opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
+ opp = 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);
- return PTR_ERR(opp);
+ freqs.new = freqs.old;
+ ret = PTR_ERR(opp);
+ goto post_notify;
}
- volt = dev_pm_opp_get_voltage(opp);
+ volt = 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",
- old_freq / 1000, volt_old ? volt_old / 1000 : -1,
- new_freq / 1000, volt ? volt / 1000 : -1);
+ freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+ freqs.new / 1000, volt ? volt / 1000 : -1);
/* scaling up? scale voltage before frequency */
- if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
+ if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) {
pr_err("failed to scale voltage up: %d\n", ret);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
@@ -83,35 +105,72 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
pr_err("failed to set clock rate: %d\n", ret);
if (!IS_ERR(cpu_reg))
regulator_set_voltage_tol(cpu_reg, volt_old, tol);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
/* scaling down? scale voltage after frequency */
- if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
+ if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) {
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, old_freq * 1000);
+ clk_set_rate(cpu_clk, freqs.old * 1000);
+ freqs.new = freqs.old;
}
}
+post_notify:
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
return ret;
}
static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, freq_table, transition_latency);
+ 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;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = cpu0_set_target,
+ .verify = cpu0_verify_speed,
+ .target = cpu0_set_target,
.get = cpu0_get_speed,
.init = cpu0_cpufreq_init,
- .exit = cpufreq_generic_exit,
+ .exit = cpu0_cpufreq_exit,
.name = "generic_cpu0",
- .attr = cpufreq_generic_attr,
+ .attr = cpu0_cpufreq_attr,
};
static int cpu0_cpufreq_probe(struct platform_device *pdev)
@@ -159,7 +218,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
goto out_put_node;
}
- ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
pr_err("failed to init cpufreq table: %d\n", ret);
goto out_put_node;
@@ -171,7 +230,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
transition_latency = CPUFREQ_ETERNAL;
if (!IS_ERR(cpu_reg)) {
- struct dev_pm_opp *opp;
+ struct opp *opp;
unsigned long min_uV, max_uV;
int i;
@@ -183,12 +242,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 = dev_pm_opp_find_freq_exact(cpu_dev,
+ opp = opp_find_freq_exact(cpu_dev,
freq_table[0].frequency * 1000, true);
- min_uV = dev_pm_opp_get_voltage(opp);
- opp = dev_pm_opp_find_freq_exact(cpu_dev,
+ min_uV = opp_get_voltage(opp);
+ opp = opp_find_freq_exact(cpu_dev,
freq_table[i-1].frequency * 1000, true);
- max_uV = dev_pm_opp_get_voltage(opp);
+ max_uV = opp_get_voltage(opp);
rcu_read_unlock();
ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
if (ret > 0)
@@ -205,7 +264,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
return 0;
out_free_table:
- dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ opp_free_cpufreq_table(cpu_dev, &freq_table);
out_put_node:
of_node_put(np);
return ret;
@@ -214,7 +273,7 @@ out_put_node:
static int cpu0_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&cpu0_cpufreq_driver);
- dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ 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 a05b876..b83d45f6 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -303,7 +303,9 @@ 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_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
return 0;
}
@@ -360,6 +362,7 @@ 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 02d534d..04548f7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -47,11 +47,49 @@ static LIST_HEAD(cpufreq_policy_list);
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
#endif
-static inline bool has_target(void)
-{
- return cpufreq_driver->target_index || cpufreq_driver->target;
+/*
+ * 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)); \
}
+unlock_policy_rwsem(read, cpu);
+unlock_policy_rwsem(write, cpu);
+
/*
* rwsem to guarantee that cpufreq driver module doesn't unload during critical
* sections
@@ -97,7 +135,7 @@ static DEFINE_MUTEX(cpufreq_governor_mutex);
bool have_governor_per_policy(void)
{
- return !!(cpufreq_driver->flags & CPUFREQ_HAVE_GOVERNOR_PER_POLICY);
+ return cpufreq_driver->have_governor_per_policy;
}
EXPORT_SYMBOL_GPL(have_governor_per_policy);
@@ -145,37 +183,6 @@ 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;
@@ -356,7 +363,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
*policy = CPUFREQ_POLICY_POWERSAVE;
err = 0;
}
- } else if (has_target()) {
+ } else if (cpufreq_driver->target) {
struct cpufreq_governor *t;
mutex_lock(&cpufreq_governor_mutex);
@@ -407,7 +414,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);
/**
@@ -428,7 +435,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; \
@@ -486,7 +493,11 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
&new_policy.governor))
return -EINVAL;
- ret = cpufreq_set_policy(policy, &new_policy);
+ /*
+ * Do not use cpufreq_set_policy here or the user_policy.max
+ * will be wrongly overridden
+ */
+ ret = __cpufreq_set_policy(policy, &new_policy);
policy->user_policy.policy = policy->policy;
policy->user_policy.governor = policy->governor;
@@ -514,7 +525,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
ssize_t i = 0;
struct cpufreq_governor *t;
- if (!has_target()) {
+ if (!cpufreq_driver->target) {
i += sprintf(buf, "performance powersave");
goto out;
}
@@ -642,21 +653,24 @@ 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;
+ ssize_t ret = -EINVAL;
if (!down_read_trylock(&cpufreq_rwsem))
- return -EINVAL;
+ goto exit;
- down_read(&policy->rwsem);
+ if (lock_policy_rwsem_read(policy->cpu) < 0)
+ goto up_read;
if (fattr->show)
ret = fattr->show(policy, buf);
else
ret = -EIO;
- up_read(&policy->rwsem);
- up_read(&cpufreq_rwsem);
+ unlock_policy_rwsem_read(policy->cpu);
+up_read:
+ up_read(&cpufreq_rwsem);
+exit:
return ret;
}
@@ -675,15 +689,17 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
if (!down_read_trylock(&cpufreq_rwsem))
goto unlock;
- down_write(&policy->rwsem);
+ if (lock_policy_rwsem_write(policy->cpu) < 0)
+ goto up_read;
if (fattr->store)
ret = fattr->store(policy, buf, count);
else
ret = -EIO;
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(policy->cpu);
+up_read:
up_read(&cpufreq_rwsem);
unlock:
put_online_cpus();
@@ -799,7 +815,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
if (ret)
goto err_out_kobj_put;
}
- if (has_target()) {
+ if (cpufreq_driver->target) {
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
if (ret)
goto err_out_kobj_put;
@@ -828,11 +844,11 @@ 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 */
+ /* assure that the starting sequence is run in __cpufreq_set_policy */
policy->governor = NULL;
/* set default policy */
- 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;
@@ -848,10 +864,10 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
unsigned int cpu, struct device *dev,
bool frozen)
{
- int ret = 0;
+ int ret = 0, has_target = !!cpufreq_driver->target;
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__);
@@ -859,7 +875,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
}
}
- down_write(&policy->rwsem);
+ lock_policy_rwsem_write(policy->cpu);
write_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -867,9 +883,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);
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(policy->cpu);
- 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__);
@@ -914,8 +930,6 @@ 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:
@@ -935,17 +949,26 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
{
- if (WARN_ON(cpu == policy->cpu))
+ if (cpu == policy->cpu)
return;
- down_write(&policy->rwsem);
+ /*
+ * 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));
policy->last_cpu = policy->cpu;
policy->cpu = cpu;
- up_write(&policy->rwsem);
+ up_write(&per_cpu(cpu_policy_rwsem, policy->last_cpu));
+#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);
}
@@ -1030,14 +1053,6 @@ 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);
@@ -1092,9 +1107,6 @@ 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:
cpufreq_policy_free(policy);
nomem_out:
@@ -1135,9 +1147,9 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
if (ret) {
pr_err("%s: Failed to move kobj: %d", __func__, ret);
- down_write(&policy->rwsem);
+ WARN_ON(lock_policy_rwsem_write(old_cpu));
cpumask_set_cpu(old_cpu, policy->cpus);
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(old_cpu);
ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
"cpufreq");
@@ -1174,7 +1186,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
return -EINVAL;
}
- if (has_target()) {
+ if (cpufreq_driver->target) {
ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
if (ret) {
pr_err("%s: Failed to stop governor\n", __func__);
@@ -1188,21 +1200,22 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
policy->governor->name, CPUFREQ_NAME_LEN);
#endif
- down_read(&policy->rwsem);
+ lock_policy_rwsem_read(cpu);
cpus = cpumask_weight(policy->cpus);
- up_read(&policy->rwsem);
+ unlock_policy_rwsem_read(cpu);
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);
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);
}
}
}
@@ -1230,16 +1243,16 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
return -EINVAL;
}
- down_write(&policy->rwsem);
+ WARN_ON(lock_policy_rwsem_write(cpu));
cpus = cpumask_weight(policy->cpus);
if (cpus > 1)
cpumask_clear_cpu(cpu, policy->cpus);
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(cpu);
/* If cpu is last user of policy, free policy */
if (cpus == 1) {
- if (has_target()) {
+ if (cpufreq_driver->target) {
ret = __cpufreq_governor(policy,
CPUFREQ_GOV_POLICY_EXIT);
if (ret) {
@@ -1250,10 +1263,10 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
}
if (!frozen) {
- down_read(&policy->rwsem);
+ lock_policy_rwsem_read(cpu);
kobj = &policy->kobj;
cmp = &policy->kobj_unregister;
- up_read(&policy->rwsem);
+ unlock_policy_rwsem_read(cpu);
kobject_put(kobj);
/*
@@ -1282,7 +1295,7 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
if (!frozen)
cpufreq_policy_free(policy);
} else {
- if (has_target()) {
+ if (cpufreq_driver->target) {
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
pr_err("%s: Failed to start governor\n",
@@ -1297,26 +1310,38 @@ 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 int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
+static inline int __cpufreq_remove_dev(struct device *dev,
+ struct subsys_interface *sif,
+ bool frozen)
{
- unsigned int cpu = dev->id;
int ret;
- if (cpu_is_offline(cpu))
- return 0;
-
- ret = __cpufreq_remove_dev_prepare(dev, sif, false);
+ ret = __cpufreq_remove_dev_prepare(dev, sif, frozen);
if (!ret)
- ret = __cpufreq_remove_dev_finish(dev, sif, false);
+ 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;
+
+ if (cpu_is_offline(cpu))
+ return 0;
+
+ retval = __cpufreq_remove_dev(dev, sif, false);
+ return retval;
+}
+
static void handle_update(struct work_struct *work)
{
struct cpufreq_policy *policy =
@@ -1433,22 +1458,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;
- down_read(&policy->rwsem);
+ if (unlikely(lock_policy_rwsem_read(cpu)))
+ goto out_policy;
ret_freq = __cpufreq_get(cpu);
- up_read(&policy->rwsem);
+ unlock_policy_rwsem_read(cpu);
+
+out_policy:
up_read(&cpufreq_rwsem);
return ret_freq;
@@ -1656,75 +1681,12 @@ 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);
@@ -1735,12 +1697,14 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
{
int ret = -EINVAL;
- down_write(&policy->rwsem);
+ if (unlikely(lock_policy_rwsem_write(policy->cpu)))
+ goto fail;
ret = __cpufreq_driver_target(policy, target_freq, relation);
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(policy->cpu);
+fail:
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
@@ -1907,10 +1871,10 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
EXPORT_SYMBOL(cpufreq_get_policy);
/*
- * policy : current policy.
- * new_policy: policy to be set.
+ * data : current policy.
+ * 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;
@@ -1970,10 +1934,10 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
/* end old governor */
if (policy->governor) {
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(new_policy->cpu);
__cpufreq_governor(policy,
CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
+ lock_policy_rwsem_write(new_policy->cpu);
}
/* start new governor */
@@ -1982,10 +1946,10 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
failed = 0;
} else {
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(new_policy->cpu);
__cpufreq_governor(policy,
CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
+ lock_policy_rwsem_write(new_policy->cpu);
}
}
@@ -2031,7 +1995,10 @@ int cpufreq_update_policy(unsigned int cpu)
goto no_policy;
}
- down_write(&policy->rwsem);
+ if (unlikely(lock_policy_rwsem_write(cpu))) {
+ ret = -EINVAL;
+ goto fail;
+ }
pr_debug("updating policy for CPU %u\n", cpu);
memcpy(&new_policy, policy, sizeof(*policy));
@@ -2050,16 +2017,17 @@ 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 && has_target())
+ if (policy->cur != new_policy.cur && cpufreq_driver->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);
- up_write(&policy->rwsem);
+ unlock_policy_rwsem_write(cpu);
+fail:
cpufreq_cpu_put(policy);
no_policy:
return ret;
@@ -2128,8 +2096,7 @@ 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_index ||
- driver_data->target))
+ ((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL;
pr_debug("trying to register driver %s\n", driver_data->name);
@@ -2216,9 +2183,14 @@ 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 25a70d0..f62d822 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -68,9 +68,6 @@ 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;
@@ -83,18 +80,13 @@ 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;
- 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;
+ dbs_info->requested_freq -= get_freq_target(cs_tuners, policy);
__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 e6be635..0806c31 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -328,6 +328,10 @@ 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 b5f2b86..88cd39f 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -191,10 +191,7 @@ 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
- * CPUFREQ_HAVE_GOVERNOR_PER_POLICY
- */
+ /* Common data for platforms that don't set 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 18d4091..32f26f6 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -168,6 +168,7 @@ 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 4dbf1db..0307809 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -38,7 +38,18 @@ 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 8655904..cb8276d 100644
--- a/drivers/cpufreq/cris-artpec3-cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -27,11 +27,18 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
return clk_ctrl.pll ? 200000 : 6000;
}
-static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
+static void cris_freq_set_cpu_state(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
@@ -44,22 +51,67 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
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)
{
- return cpufreq_generic_init(policy, cris_freq_table, 1000000);
+ 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;
}
+
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = cris_freq_target,
+ .verify = cris_freq_verify,
+ .target = cris_freq_target,
.init = cris_freq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = cris_freq_cpu_exit,
.name = "cris_freq",
- .attr = cpufreq_generic_attr,
+ .attr = cris_freq_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 26d940d..72328f7 100644
--- a/drivers/cpufreq/cris-etraxfs-cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -27,11 +27,18 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
return clk_ctrl.pll ? 200000 : 6000;
}
-static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
+static void cris_freq_set_cpu_state(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
@@ -44,22 +51,64 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
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)
{
- return cpufreq_generic_init(policy, cris_freq_table, 1000000);
+ 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;
+}
+
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = cris_freq_target,
+ .verify = cris_freq_verify,
+ .target = cris_freq_target,
.init = cris_freq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = cris_freq_cpu_exit,
.name = "cris_freq",
- .attr = cpufreq_generic_attr,
+ .attr = cris_freq_attr,
};
static int __init cris_freq_init(void)
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index 5e8a854..551dd65 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -50,7 +50,9 @@ static int davinci_verify_speed(struct cpufreq_policy *policy)
if (policy->cpu)
return -EINVAL;
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
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,
@@ -66,38 +68,58 @@ 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 idx)
+static int davinci_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
{
+ 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;
- old_freq = davinci_getspeed(0);
- new_freq = pdata->freq_table[idx].frequency;
+ 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);
/* if moving to higher frequency, up the voltage beforehand */
- if (pdata->set_voltage && new_freq > old_freq) {
+ if (pdata->set_voltage && freqs.new > freqs.old) {
ret = pdata->set_voltage(idx);
if (ret)
- return ret;
+ goto out;
}
ret = clk_set_rate(armclk, idx);
if (ret)
- return ret;
+ goto out;
if (cpufreq.asyncclk) {
ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
if (ret)
- return ret;
+ goto out;
}
/* if moving to lower freq, lower the voltage after lowering freq */
- if (pdata->set_voltage && new_freq < old_freq)
+ if (pdata->set_voltage && freqs.new < freqs.old)
pdata->set_voltage(idx);
- return 0;
+out:
+ if (ret)
+ freqs.new = freqs.old;
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
}
static int davinci_cpu_init(struct cpufreq_policy *policy)
@@ -116,24 +138,47 @@ 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.
*/
- return cpufreq_generic_init(policy, freq_table, 2000 * 1000);
+ policy->cpuinfo.transition_latency = 2000 * 1000;
+ return 0;
}
+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_index = davinci_target,
+ .target = davinci_target,
.get = davinci_getspeed,
.init = davinci_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = davinci_cpu_exit,
.name = "davinci",
- .attr = cpufreq_generic_attr,
+ .attr = davinci_cpufreq_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 0e67ab9..26321cd 100644
--- a/drivers/cpufreq/dbx500-cpufreq.c
+++ b/drivers/cpufreq/dbx500-cpufreq.c
@@ -19,11 +19,51 @@
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 index)
+ unsigned int target_freq,
+ unsigned int relation)
{
+ 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 */
- return clk_set_rate(armss_clk, freq_table[index].frequency * 1000);
+ 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;
}
static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
@@ -44,17 +84,43 @@ static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
static int dbx500_cpufreq_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, freq_table, 20 * 1000);
+ 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;
}
static struct cpufreq_driver dbx500_cpufreq_driver = {
.flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = dbx500_cpufreq_target,
+ .verify = dbx500_cpufreq_verify_speed,
+ .target = dbx500_cpufreq_target,
.get = dbx500_cpufreq_getspeed,
.init = dbx500_cpufreq_init,
.name = "DBX500",
- .attr = cpufreq_generic_attr,
+ .attr = dbx500_cpufreq_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 9012b8b..09f64cc 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -107,9 +107,15 @@ 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;
@@ -118,7 +124,8 @@ static int eps_set_state(struct eps_cpu_data *centaur,
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i++;
if (unlikely(i > 64)) {
- return -ENODEV;
+ err = -ENODEV;
+ goto postchange;
}
}
/* Set new multiplier and voltage */
@@ -130,10 +137,16 @@ static int eps_set_state(struct eps_cpu_data *centaur,
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i++;
if (unlikely(i > 64)) {
- return -ENODEV;
+ err = -ENODEV;
+ goto postchange;
}
} 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;
@@ -148,12 +161,19 @@ static int eps_set_state(struct eps_cpu_data *centaur,
current_multiplier);
}
#endif
- return 0;
+ if (err)
+ freqs.new = freqs.old;
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ return err;
}
-static int eps_target(struct cpufreq_policy *policy, unsigned int index)
+static int eps_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
struct eps_cpu_data *centaur;
+ unsigned int newstate = 0;
unsigned int cpu = policy->cpu;
unsigned int dest_state;
int ret;
@@ -162,14 +182,28 @@ static int eps_target(struct cpufreq_policy *policy, unsigned int index)
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[index].driver_data & 0xffff;
+ dest_state = centaur->freq_table[newstate].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;
@@ -367,13 +401,15 @@ 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_table_validate_and_show(policy, &centaur->freq_table[0]);
+ ret = cpufreq_frequency_table_cpuinfo(policy, &centaur->freq_table[0]);
if (ret) {
kfree(centaur);
return ret;
}
+ cpufreq_frequency_table_get_attr(&centaur->freq_table[0], policy->cpu);
return 0;
}
@@ -388,14 +424,19 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = eps_target,
+ .verify = eps_verify,
+ .target = eps_target,
.init = eps_cpu_init,
.exit = eps_cpu_exit,
.get = eps_get,
.name = "e_powersaver",
- .attr = cpufreq_generic_attr,
+ .attr = eps_attr,
};
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index de08acf..823a400 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -105,9 +105,32 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
}
-static int elanfreq_target(struct cpufreq_policy *policy,
- unsigned int state)
+/**
+ * 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)
{
+ 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)
@@ -138,8 +161,39 @@ static int elanfreq_target(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
*/
@@ -148,6 +202,7 @@ 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) ||
@@ -166,8 +221,21 @@ 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;
- return cpufreq_table_validate_and_show(policy, elanfreq_table);
+ 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;
}
@@ -193,14 +261,20 @@ __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 = cpufreq_generic_frequency_table_verify,
- .target_index = elanfreq_target,
+ .verify = elanfreq_verify,
+ .target = elanfreq_target,
.init = elanfreq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = elanfreq_cpu_exit,
.name = "elanfreq",
- .attr = cpufreq_generic_attr,
+ .attr = elanfreq_attr,
};
static const struct x86_cpu_id elan_id[] = {
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index f3c2287..0fac344 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -25,11 +25,18 @@
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;
@@ -58,18 +65,21 @@ 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;
- old_freq = policy->cur;
+ freqs.old = policy->cur;
+ freqs.new = target_freq;
+
+ if (freqs.new == freqs.old)
+ goto out;
/*
* 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 frequency table.
+ * policy and get the index from the raw freqeuncy table.
*/
- old_index = exynos_cpufreq_get_index(old_freq);
+ old_index = exynos_cpufreq_get_index(freqs.old);
if (old_index < 0) {
ret = old_index;
goto out;
@@ -94,14 +104,17 @@ 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 ((target_freq > old_freq) && !safe_arm_volt) {
+ if ((freqs.new > freqs.old) && !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);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
@@ -111,17 +124,24 @@ 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);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
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 ((target_freq < old_freq) ||
- ((target_freq > old_freq) && safe_arm_volt)) {
+ if ((freqs.new < freqs.old) ||
+ ((freqs.new > freqs.old) && safe_arm_volt)) {
/* down the voltage after frequency change */
- ret = regulator_set_voltage(arm_regulator, arm_volt,
+ regulator_set_voltage(arm_regulator, arm_volt,
arm_volt);
if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n",
@@ -131,14 +151,19 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
}
out:
+
cpufreq_cpu_put(policy);
return ret;
}
-static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
+static int exynos_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+ unsigned int index;
+ unsigned int new_freq;
int ret = 0;
mutex_lock(&cpufreq_lock);
@@ -146,7 +171,15 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
if (frequency_locked)
goto out;
- ret = exynos_cpufreq_scale(freq_table[index].frequency);
+ 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);
out:
mutex_unlock(&cpufreq_lock);
@@ -214,18 +247,38 @@ static struct notifier_block exynos_cpufreq_nb = {
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
+ 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;
}
+static struct freq_attr *exynos_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = exynos_target,
+ .verify = exynos_verify_speed,
+ .target = exynos_target,
.get = exynos_getspeed,
.init = exynos_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
- .attr = cpufreq_generic_attr,
+ .attr = exynos_cpufreq_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 dfd1643..add7fbe 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, freq = apll_freq_4210[index].freq;
+ unsigned int tmp;
- /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+ /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
clk_set_parent(moutcore, mout_mpll);
do {
@@ -92,9 +92,21 @@ static void exynos4210_set_apll(unsigned int index)
tmp &= 0x7;
} while (tmp != 0x2);
- clk_set_rate(mout_apll, freq * 1000);
+ /* 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);
- /* MUX_CORE_SEL = APLL */
+ /* 4. wait_lock_time */
+ do {
+ tmp = __raw_readl(EXYNOS4_APLL_CON0);
+ } while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
+
+ /* 5. MUX_CORE_SEL = APLL */
clk_set_parent(moutcore, mout_apll);
do {
@@ -103,15 +115,53 @@ 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) {
- exynos4210_set_clkdiv(new_index);
- exynos4210_set_apll(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);
+ }
} else if (old_index < new_index) {
- exynos4210_set_apll(new_index);
- exynos4210_set_clkdiv(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);
+ }
}
}
@@ -144,6 +194,7 @@ 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;
@@ -157,3 +208,4 @@ 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 efad5e6..08b7477 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, freq = apll_freq_4x12[index].freq;
+ unsigned int tmp, pdiv;
- /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+ /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
clk_set_parent(moutcore, mout_mpll);
do {
@@ -140,9 +140,24 @@ static void exynos4x12_set_apll(unsigned int index)
tmp &= 0x7;
} while (tmp != 0x2);
- clk_set_rate(mout_apll, freq * 1000);
+ /* 2. Set APLL Lock time */
+ pdiv = ((apll_freq_4x12[index].mps >> 8) & 0x3f);
- /* MUX_CORE_SEL = APLL */
+ __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 */
clk_set_parent(moutcore, mout_apll);
do {
@@ -152,15 +167,52 @@ 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) {
- exynos4x12_set_clkdiv(new_index);
- exynos4x12_set_apll(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);
+ }
} else if (old_index < new_index) {
- exynos4x12_set_apll(new_index);
- exynos4x12_set_clkdiv(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);
+ }
}
}
@@ -198,6 +250,7 @@ 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;
@@ -211,3 +264,4 @@ 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 8feda86..9fae466 100644
--- a/drivers/cpufreq/exynos5250-cpufreq.c
+++ b/drivers/cpufreq/exynos5250-cpufreq.c
@@ -236,3 +236,4 @@ 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 76bef8b..be5380e 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/pm_opp.h>
+#include <linux/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 dev_pm_opp *opp;
+ struct opp *opp;
rcu_read_lock();
for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
- opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
+ opp = 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 = dev_pm_opp_get_voltage(opp);
+ volt_id = 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,22 +209,38 @@ 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 index)
+static int exynos_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
- unsigned int tmp;
- int i;
+ unsigned int index, tmp;
+ int ret = 0, 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 */
@@ -235,8 +251,9 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
}
+out:
mutex_unlock(&cpufreq_lock);
- return 0;
+ return ret;
}
static void exynos_cpufreq_work(struct work_struct *work)
@@ -307,19 +324,30 @@ static void exynos_sort_descend_freq_table(void)
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, dvfs_info->freq_table,
- dvfs_info->latency);
+ 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;
}
static struct cpufreq_driver exynos_driver = {
- .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = exynos_target,
+ .flags = CPUFREQ_STICKY,
+ .verify = exynos_verify_speed,
+ .target = 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[] = {
@@ -371,14 +399,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
goto err_put_node;
}
- ret = dev_pm_opp_init_cpufreq_table(dvfs_info->dev,
- &dvfs_info->freq_table);
+ ret = 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 = dev_pm_opp_get_opp_count(dvfs_info->dev);
+ dvfs_info->freq_count = opp_get_opp_count(dvfs_info->dev);
exynos_sort_descend_freq_table();
if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency))
@@ -427,7 +454,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
return 0;
err_free_table:
- dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+ 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__);
@@ -437,7 +464,7 @@ err_put_node:
static int exynos_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&exynos_driver);
- dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+ 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 3458d27..f111454a 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -54,30 +54,31 @@ 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, freq, i = 0;
- bool found = false;
+ unsigned int next_larger = ~0;
+ unsigned int i;
+ unsigned int count = 0;
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
policy->min, policy->max, policy->cpu);
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
- for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) {
+ for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+ unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
- if ((freq >= policy->min) && (freq <= policy->max)) {
- found = true;
- break;
- }
-
- if ((next_larger > freq) && (freq > policy->max))
+ if ((freq >= policy->min) && (freq <= policy->max))
+ count++;
+ else if ((next_larger > freq) && (freq > policy->max))
next_larger = freq;
}
- if (!found) {
+ if (!count)
policy->max = next_larger;
- cpufreq_verify_within_cpu_limits(policy);
- }
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
policy->min, policy->max, policy->cpu);
@@ -86,20 +87,6 @@ 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,
@@ -213,12 +200,6 @@ 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!
@@ -238,18 +219,6 @@ 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 d83e826..70442c7 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;
+ unsigned int maxfreq, curfreq;
if (!policy || policy->cpu != 0)
return -ENODEV;
@@ -415,8 +415,10 @@ 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;
@@ -426,6 +428,7 @@ 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 bf8902a..794123f 100644
--- a/drivers/cpufreq/highbank-cpufreq.c
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -66,8 +66,7 @@ static int hb_cpufreq_driver_init(void)
struct device_node *np;
int ret;
- if ((!of_machine_is_compatible("calxeda,highbank")) &&
- (!of_machine_is_compatible("calxeda,ecx-2000")))
+ if (!of_machine_is_compatible("calxeda,highbank"))
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 53c6ac6..3e14f03 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -141,6 +141,7 @@ processor_set_freq (
{
int ret = 0;
u32 value = 0;
+ struct cpufreq_freqs cpufreq_freqs;
cpumask_t saved_mask;
int retval;
@@ -167,6 +168,13 @@ 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.
@@ -178,11 +186,22 @@ 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;
@@ -208,11 +227,42 @@ acpi_cpufreq_get (
static int
acpi_cpufreq_target (
struct cpufreq_policy *policy,
- unsigned int index)
+ 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)
{
- return processor_set_freq(acpi_io_data[policy->cpu], policy, 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);
}
+
static int
acpi_cpufreq_cpu_init (
struct cpufreq_policy *policy)
@@ -271,6 +321,7 @@ 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++)
@@ -284,7 +335,7 @@ acpi_cpufreq_cpu_init (
}
}
- result = cpufreq_table_validate_and_show(policy, data->freq_table);
+ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
if (result) {
goto err_freqfree;
}
@@ -305,6 +356,8 @@ 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;
@@ -343,14 +396,20 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = acpi_cpufreq_target,
+ .verify = acpi_cpufreq_verify,
+ .target = acpi_cpufreq_target,
.get = acpi_cpufreq_get,
.init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit,
.name = "acpi-cpufreq",
- .attr = cpufreq_generic_attr,
+ .attr = acpi_cpufreq_attr,
};
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index 4b3f18e..c3fd2a1 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/pm_opp.h>
+#include <linux/opp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -35,52 +35,73 @@ 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 index)
+static int imx6q_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
{
- struct dev_pm_opp *opp;
+ struct cpufreq_freqs freqs;
+ struct opp *opp;
unsigned long freq_hz, volt, volt_old;
- unsigned int old_freq, new_freq;
+ unsigned int index;
int ret;
- new_freq = freq_table[index].frequency;
- freq_hz = new_freq * 1000;
- old_freq = clk_get_rate(arm_clk) / 1000;
+ 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;
rcu_read_lock();
- opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
+ opp = 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 = dev_pm_opp_get_voltage(opp);
+ volt = 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",
- old_freq / 1000, volt_old / 1000,
- new_freq / 1000, volt / 1000);
+ freqs.old / 1000, volt_old / 1000,
+ freqs.new / 1000, volt / 1000);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* scaling up? scale voltage before frequency */
- if (new_freq > old_freq) {
+ if (freqs.new > freqs.old) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) {
dev_err(cpu_dev,
"failed to scale vddarm up: %d\n", ret);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
/*
* Need to increase vddpu and vddsoc for safety
* if we are about to run at 1.2 GHz.
*/
- if (new_freq == FREQ_1P2_GHZ / 1000) {
+ if (freqs.new == FREQ_1P2_GHZ / 1000) {
regulator_set_voltage_tol(pu_reg,
PU_SOC_VOLTAGE_HIGH, 0);
regulator_set_voltage_tol(soc_reg,
@@ -100,20 +121,21 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
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, new_freq * 1000);
+ clk_set_rate(pll1_sys_clk, freqs.new * 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, new_freq * 1000);
+ ret = clk_set_rate(arm_clk, freqs.new * 1000);
if (ret) {
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
regulator_set_voltage_tol(arm_reg, volt_old, 0);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
/* scaling down? scale voltage after frequency */
- if (new_freq < old_freq) {
+ if (freqs.new < freqs.old) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) {
dev_warn(cpu_dev,
@@ -121,7 +143,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
ret = 0;
}
- if (old_freq == FREQ_1P2_GHZ / 1000) {
+ if (freqs.old == FREQ_1P2_GHZ / 1000) {
regulator_set_voltage_tol(pu_reg,
PU_SOC_VOLTAGE_NORMAL, 0);
regulator_set_voltage_tol(soc_reg,
@@ -129,28 +151,55 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
}
}
- return 0;
+post_notify:
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
}
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, freq_table, transition_latency);
+ 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)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *imx6q_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver imx6q_cpufreq_driver = {
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = imx6q_set_target,
+ .verify = imx6q_verify_speed,
+ .target = imx6q_set_target,
.get = imx6q_get_speed,
.init = imx6q_cpufreq_init,
- .exit = cpufreq_generic_exit,
+ .exit = imx6q_cpufreq_exit,
.name = "imx6q-cpufreq",
- .attr = cpufreq_generic_attr,
+ .attr = imx6q_cpufreq_attr,
};
static int imx6q_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
- struct dev_pm_opp *opp;
+ struct opp *opp;
unsigned long min_volt, max_volt;
int num, ret;
@@ -188,14 +237,14 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
}
/* We expect an OPP table supplied by platform */
- num = dev_pm_opp_get_opp_count(cpu_dev);
+ num = 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 = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ ret = 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;
@@ -210,12 +259,12 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
* same order.
*/
rcu_read_lock();
- opp = dev_pm_opp_find_freq_exact(cpu_dev,
+ opp = opp_find_freq_exact(cpu_dev,
freq_table[0].frequency * 1000, true);
- min_volt = dev_pm_opp_get_voltage(opp);
- opp = dev_pm_opp_find_freq_exact(cpu_dev,
+ min_volt = opp_get_voltage(opp);
+ opp = opp_find_freq_exact(cpu_dev,
freq_table[--num].frequency * 1000, true);
- max_volt = dev_pm_opp_get_voltage(opp);
+ max_volt = opp_get_voltage(opp);
rcu_read_unlock();
ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
if (ret > 0)
@@ -243,7 +292,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
return 0;
free_freq_table:
- dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ opp_free_cpufreq_table(cpu_dev, &freq_table);
put_node:
of_node_put(np);
return ret;
@@ -252,7 +301,7 @@ put_node:
static int imx6q_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&imx6q_cpufreq_driver);
- dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ 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 7d8ab000d..f7c99df 100644
--- a/drivers/cpufreq/integrator-cpufreq.c
+++ b/drivers/cpufreq/integrator-cpufreq.c
@@ -15,20 +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 void __iomem *cm_base;
-/* The cpufreq driver only use the OSC register */
-#define INTEGRATOR_HDR_OSC_OFFSET 0x08
-#define INTEGRATOR_HDR_LOCK_OFFSET 0x14
-
static struct cpufreq_driver integrator_driver;
+#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 const struct icst_params lclk_params = {
.ref = 24000000,
.vco_max = ICST525_VCO_MAX_5V,
@@ -60,7 +59,9 @@ static int integrator_verify_policy(struct cpufreq_policy *policy)
{
struct icst_vco vco;
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
vco = icst_hz_to_vco(&cclk_params, policy->max * 1000);
policy->max = icst_hz(&cclk_params, vco) / 1000;
@@ -68,7 +69,10 @@ 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_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
return 0;
}
@@ -96,7 +100,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
BUG_ON(cpu != smp_processor_id());
/* get current setting */
- cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
+ cm_osc = __raw_readl(CM_OSC);
if (machine_is_integrator()) {
vco.s = (cm_osc >> 8) & 7;
@@ -124,7 +128,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
- cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
+ cm_osc = __raw_readl(CM_OSC);
if (machine_is_integrator()) {
cm_osc &= 0xfffff800;
@@ -134,9 +138,9 @@ static int integrator_set_target(struct cpufreq_policy *policy,
}
cm_osc |= vco.v;
- __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);
+ __raw_writel(0xa05f, CM_LOCK);
+ __raw_writel(cm_osc, CM_OSC);
+ __raw_writel(0, CM_LOCK);
/*
* Restore the CPUs allowed mask.
@@ -161,7 +165,7 @@ static unsigned int integrator_get(unsigned int cpu)
BUG_ON(cpu != smp_processor_id());
/* detect memory etc. */
- cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
+ cm_osc = __raw_readl(CM_OSC);
if (machine_is_integrator()) {
vco.s = (cm_osc >> 8) & 7;
@@ -182,9 +186,10 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
{
/* set default policy and cpuinfo */
- policy->max = policy->cpuinfo.max_freq = 160000;
- policy->min = policy->cpuinfo.min_freq = 12000;
+ policy->cpuinfo.max_freq = 160000;
+ 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;
}
@@ -197,43 +202,19 @@ static struct cpufreq_driver integrator_driver = {
.name = "integrator",
};
-static int __init integrator_cpufreq_probe(struct platform_device *pdev)
+static int __init integrator_cpu_init(void)
{
- 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_cpufreq_remove(struct platform_device *pdev)
+static void __exit integrator_cpu_exit(void)
{
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 5f1cbae..eb3fdc7 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -25,7 +25,6 @@
#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>
@@ -34,8 +33,6 @@
#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)
@@ -81,6 +78,7 @@ struct cpudata {
struct timer_list timer;
+ struct pstate_adjust_policy *pstate_policy;
struct pstate_data pstate;
struct _pid pid;
@@ -102,21 +100,15 @@ struct pstate_adjust_policy {
int i_gain_pct;
};
-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 default_policy = {
+ .sample_rate_ms = 10,
+ .deadband = 0,
+ .setpoint = 97,
+ .p_gain_pct = 20,
+ .d_gain_pct = 0,
+ .i_gain_pct = 0,
};
-static struct pstate_adjust_policy pid_params;
-static struct pstate_funcs pstate_funcs;
-
struct perf_limits {
int no_turbo;
int max_perf_pct;
@@ -193,14 +185,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, 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_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_reset(&cpu->pid,
- pid_params.setpoint,
+ cpu->pstate_policy->setpoint,
100,
- pid_params.deadband,
+ cpu->pstate_policy->deadband,
0);
}
@@ -234,12 +226,12 @@ struct pid_param {
};
static struct pid_param pid_files[] = {
- {"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},
+ {"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},
{NULL, NULL}
};
@@ -344,92 +336,33 @@ 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 core_get_min_pstate(void)
+static int intel_pstate_min_pstate(void)
{
u64 value;
rdmsrl(MSR_PLATFORM_INFO, value);
return (value >> 40) & 0xFF;
}
-static int core_get_max_pstate(void)
+static int intel_pstate_max_pstate(void)
{
u64 value;
rdmsrl(MSR_PLATFORM_INFO, value);
return (value >> 8) & 0xFF;
}
-static int core_get_turbo_pstate(void)
+static int intel_pstate_turbo_pstate(void)
{
u64 value;
int nont, ret;
rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
- nont = core_get_max_pstate();
+ nont = intel_pstate_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;
@@ -450,6 +383,7 @@ 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);
@@ -461,8 +395,11 @@ 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;
- pstate_funcs.set(pstate);
+ wrmsrl(MSR_IA32_PERF_CTL, val);
}
static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
@@ -484,9 +421,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
sprintf(cpu->name, "Intel 2nd generation core");
- cpu->pstate.min_pstate = pstate_funcs.get_min();
- cpu->pstate.max_pstate = pstate_funcs.get_max();
- cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
+ cpu->pstate.min_pstate = intel_pstate_min_pstate();
+ cpu->pstate.max_pstate = intel_pstate_max_pstate();
+ cpu->pstate.turbo_pstate = intel_pstate_turbo_pstate();
/*
* goto max pstate so we don't slow up boot if we are built-in if we are
@@ -528,7 +465,7 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
{
int sample_time, delay;
- sample_time = pid_params.sample_rate_ms;
+ sample_time = cpu->pstate_policy->sample_rate_ms;
delay = msecs_to_jiffies(sample_time);
mod_timer_pinned(&cpu->timer, jiffies + delay);
}
@@ -584,15 +521,14 @@ static void intel_pstate_timer_func(unsigned long __data)
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy }
static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
- 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),
+ 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),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
@@ -616,7 +552,8 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
intel_pstate_get_cpu_pstates(cpu);
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 =
@@ -676,7 +613,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
{
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
(policy->policy != CPUFREQ_POLICY_PERFORMANCE))
@@ -744,9 +683,9 @@ static int intel_pstate_msrs_not_valid(void)
rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf);
- if (!pstate_funcs.get_max() ||
- !pstate_funcs.get_min() ||
- !pstate_funcs.get_turbo())
+ if (!intel_pstate_min_pstate() ||
+ !intel_pstate_max_pstate() ||
+ !intel_pstate_turbo_pstate())
return -ENODEV;
rdmsrl(MSR_IA32_APERF, tmp);
@@ -759,96 +698,10 @@ 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;
@@ -857,18 +710,6 @@ 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 0767a4e..ba10658 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -55,37 +55,69 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
return kirkwood_freq_table[0].frequency;
}
-static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int index)
+static void kirkwood_cpufreq_set_cpu_state(struct cpufreq_policy *policy,
+ unsigned int index)
{
+ struct cpufreq_freqs freqs;
unsigned int state = kirkwood_freq_table[index].driver_data;
unsigned long reg;
- local_irq_disable();
+ 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;
+ }
- /* Disable interrupts to the CPU */
- reg = readl_relaxed(priv.base);
- reg |= CPU_SW_INT_BLK;
- writel_relaxed(reg, priv.base);
+ /* Wait-for-Interrupt, while the hardware changes frequency */
+ cpu_do_idle();
- switch (state) {
- case STATE_CPU_FREQ:
- clk_disable(priv.powersave_clk);
- break;
- case STATE_DDR_FREQ:
- clk_enable(priv.powersave_clk);
- break;
+ /* Enable interrupts to the CPU */
+ reg = readl_relaxed(priv.base);
+ reg &= ~CPU_SW_INT_BLK;
+ writel_relaxed(reg, priv.base);
+
+ local_irq_enable();
}
+ 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);
+}
- /* Wait-for-Interrupt, while the hardware changes frequency */
- cpu_do_idle();
+static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int index = 0;
- /* Enable interrupts to the CPU */
- reg = readl_relaxed(priv.base);
- reg &= ~CPU_SW_INT_BLK;
- writel_relaxed(reg, priv.base);
+ if (cpufreq_frequency_table_target(policy, kirkwood_freq_table,
+ target_freq, relation, &index))
+ return -EINVAL;
- local_irq_enable();
+ kirkwood_cpufreq_set_cpu_state(policy, index);
return 0;
}
@@ -93,17 +125,40 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
/* Module init and exit code */
static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
+ 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;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = kirkwood_cpufreq_target,
+ .verify = kirkwood_cpufreq_verify,
+ .target = kirkwood_cpufreq_target,
.init = kirkwood_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = kirkwood_cpufreq_cpu_exit,
.name = "kirkwood-cpufreq",
- .attr = cpufreq_generic_attr,
+ .attr = kirkwood_cpufreq_attr,
};
static int kirkwood_cpufreq_probe(struct platform_device *pdev)
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 45bafdd..4ada1cc 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -625,13 +625,28 @@ 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 table_index)
+ unsigned int target_freq, unsigned int relation)
{
+ 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 {
@@ -904,18 +919,36 @@ 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 cpufreq_table_validate_and_show(policy, longhaul_table);
+ return 0;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = longhaul_target,
+ .verify = longhaul_verify,
+ .target = longhaul_target,
.get = longhaul_get,
.init = longhaul_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = longhaul_cpu_exit,
.name = "longhaul",
- .attr = cpufreq_generic_attr,
+ .attr = longhaul_attr,
};
static const struct x86_cpu_id longhaul_id[] = {
diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c
index 074971b..5aa0316 100644
--- a/drivers/cpufreq/longrun.c
+++ b/drivers/cpufreq/longrun.c
@@ -129,7 +129,9 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
return -EINVAL;
policy->cpu = 0;
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
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 a436092..7bc3c44 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -53,24 +53,51 @@ 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 index)
+ unsigned int target_freq,
+ unsigned int relation)
{
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[index].driver_data) / 8;
+ 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);
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;
}
@@ -104,24 +131,40 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
return ret;
}
- return cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
+ 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]);
}
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 = cpufreq_generic_frequency_table_verify,
- .target_index = loongson2_cpufreq_target,
+ .verify = loongson2_cpufreq_verify,
+ .target = loongson2_cpufreq_target,
.get = loongson2_cpufreq_get,
.exit = loongson2_cpufreq_exit,
- .attr = cpufreq_generic_attr,
+ .attr = loongson2_table_attr,
};
static struct platform_device_id platform_device_ids[] = {
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index c4dfa42..6168d77 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -64,11 +64,18 @@ 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;
@@ -128,10 +135,37 @@ 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 index)
+ unsigned int target_freq, unsigned int relation)
{
- return maple_scom_switch_freq(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;
}
static unsigned int maple_cpufreq_get_speed(unsigned int cpu)
@@ -141,17 +175,27 @@ static unsigned int maple_cpufreq_get_speed(unsigned int cpu)
static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
+ 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);
}
+
static struct cpufreq_driver maple_cpufreq_driver = {
.name = "maple",
.flags = CPUFREQ_CONST_LOOPS,
.init = maple_cpufreq_cpu_init,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = maple_cpufreq_target,
+ .verify = maple_cpufreq_verify,
+ .target = maple_cpufreq_target,
.get = maple_cpufreq_get_speed,
- .attr = cpufreq_generic_attr,
+ .attr = maple_cpu_freqs_attr,
};
static int __init maple_cpufreq_init(void)
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index a0acd0b..f31fcfc 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/pm_opp.h>
+#include <linux/opp.h>
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -40,6 +40,13 @@ 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;
@@ -51,17 +58,42 @@ static unsigned int omap_getspeed(unsigned int cpu)
return rate;
}
-static int omap_target(struct cpufreq_policy *policy, unsigned int index)
+static int omap_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
- int r, ret;
- struct dev_pm_opp *opp;
+ unsigned int i;
+ int r, ret = 0;
+ struct cpufreq_freqs freqs;
+ struct opp *opp;
unsigned long freq, volt = 0, volt_old = 0, tol = 0;
- unsigned int old_freq, new_freq;
- old_freq = omap_getspeed(policy->cpu);
- new_freq = freq_table[index].frequency;
+ if (!freq_table) {
+ dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
+ policy->cpu);
+ return -EINVAL;
+ }
- freq = new_freq * 1000;
+ 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;
ret = clk_round_rate(mpu_clk, freq);
if (IS_ERR_VALUE(ret)) {
dev_warn(mpu_dev,
@@ -73,103 +105,143 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
if (mpu_reg) {
rcu_read_lock();
- opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
+ opp = 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__, new_freq);
+ __func__, freqs.new);
return -EINVAL;
}
- volt = dev_pm_opp_get_voltage(opp);
+ volt = 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",
- old_freq / 1000, volt_old ? volt_old / 1000 : -1,
- new_freq / 1000, volt ? volt / 1000 : -1);
+ freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+ freqs.new / 1000, volt ? volt / 1000 : -1);
+
+ /* notifiers */
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* scaling up? scale voltage before frequency */
- if (mpu_reg && (new_freq > old_freq)) {
+ if (mpu_reg && (freqs.new > freqs.old)) {
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__);
- return r;
+ freqs.new = freqs.old;
+ goto done;
}
}
- ret = clk_set_rate(mpu_clk, new_freq * 1000);
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
/* scaling down? scale voltage after frequency */
- if (mpu_reg && (new_freq < old_freq)) {
+ if (mpu_reg && (freqs.new < freqs.old)) {
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__);
- clk_set_rate(mpu_clk, old_freq * 1000);
- return r;
+ ret = clk_set_rate(mpu_clk, freqs.old * 1000);
+ freqs.new = freqs.old;
+ goto done;
}
}
+ 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))
- dev_pm_opp_free_cpufreq_table(mpu_dev, &freq_table);
+ opp_free_cpufreq_table(mpu_dev, &freq_table);
}
static int omap_cpu_init(struct cpufreq_policy *policy)
{
- int result;
+ int result = 0;
mpu_clk = clk_get(NULL, "cpufreq_ck");
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
- 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",
+ 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",
__func__, policy->cpu, result);
- goto fail;
- }
+ goto fail_ck;
}
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? */
- result = cpufreq_generic_init(policy, freq_table, 300 * 1000);
- if (!result)
- return 0;
+ policy->cpuinfo.transition_latency = 300 * 1000;
+ return 0;
+
+fail_table:
freq_table_free();
-fail:
+fail_ck:
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 = cpufreq_generic_frequency_table_verify,
- .target_index = omap_target,
+ .verify = omap_verify_speed,
+ .target = omap_target,
.get = omap_getspeed,
.init = omap_cpu_init,
.exit = omap_cpu_exit,
.name = "omap",
- .attr = cpufreq_generic_attr,
+ .attr = omap_cpufreq_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 3d1cba9..2f0a2a6 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -105,21 +105,47 @@ static struct cpufreq_frequency_table p4clockmod_table[] = {
};
-static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index)
+static int cpufreq_p4_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
+ 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[index].driver_data);
+ cpufreq_p4_setdc(i, p4clockmod_table[newstate].driver_data);
+
+ /* notifiers */
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
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) {
@@ -204,17 +230,25 @@ 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_table_validate_and_show(policy, &p4clockmod_table[0]);
+ return cpufreq_frequency_table_cpuinfo(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;
@@ -233,14 +267,19 @@ 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_generic_frequency_table_verify,
- .target_index = cpufreq_p4_target,
+ .verify = cpufreq_p4_verify,
+ .target = cpufreq_p4_target,
.init = cpufreq_p4_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = cpufreq_p4_cpu_exit,
.get = cpufreq_p4_get,
.name = "p4-clockmod",
- .attr = cpufreq_generic_attr,
+ .attr = p4clockmod_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 0426008..534e43a 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -28,7 +28,6 @@
#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>
@@ -52,6 +51,8 @@
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.
@@ -68,6 +69,11 @@ 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
*/
@@ -203,13 +209,22 @@ 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;
- return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
+ 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);
out_unmap_sdcpwr:
iounmap(sdcpwr_mapbase);
@@ -238,11 +253,31 @@ 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 pas_astate_new)
+ unsigned int target_freq,
+ unsigned int relation)
{
+ 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,
@@ -253,7 +288,10 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
for_each_online_cpu(i)
set_astate(i, pas_astate_new);
- ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul;
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&pas_switch_mutex);
+
+ ppc_proc_freq = freqs.new * 1000ul;
return 0;
}
@@ -262,9 +300,9 @@ static struct cpufreq_driver pas_cpufreq_driver = {
.flags = CPUFREQ_CONST_LOOPS,
.init = pas_cpufreq_cpu_init,
.exit = pas_cpufreq_cpu_exit,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = pas_cpufreq_target,
- .attr = cpufreq_generic_attr,
+ .verify = pas_cpufreq_verify,
+ .target = pas_cpufreq_target,
+ .attr = pas_cpu_freqs_attr,
};
/*
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index e2b4f40..d81c4e5 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -111,7 +111,8 @@ static struct pcc_cpu __percpu *pcc_cpu_info;
static int pcc_cpufreq_verify(struct cpufreq_policy *policy)
{
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
return 0;
}
@@ -395,14 +396,15 @@ 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;
+ acpi_handle handle, osc_handle, pcch_handle;
int ret = 0;
status = acpi_get_handle(NULL, "\\_SB", &handle);
if (ACPI_FAILURE(status))
return -ENODEV;
- if (!acpi_has_method(handle, "PCCH"))
+ status = acpi_get_handle(handle, "PCCH", &pcch_handle);
+ if (ACPI_FAILURE(status))
return -ENODEV;
status = acpi_get_handle(handle, "_OSC", &osc_handle);
@@ -558,6 +560,13 @@ 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 cf55d20..a096cd3 100644
--- a/drivers/cpufreq/pmac32-cpufreq.c
+++ b/drivers/cpufreq/pmac32-cpufreq.c
@@ -86,6 +86,11 @@ 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)
@@ -331,11 +336,21 @@ static int pmu_set_cpu_speed(int low_speed)
return 0;
}
-static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode)
+static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode,
+ int notify)
{
+ 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();
@@ -351,6 +366,8 @@ 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;
@@ -361,12 +378,23 @@ 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 index)
+ unsigned int target_freq,
+ unsigned int relation)
{
+ unsigned int newstate = 0;
int rc;
- rc = do_set_cpu_speed(policy, index);
+ if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
+ target_freq, relation, &newstate))
+ return -EINVAL;
+
+ rc = do_set_cpu_speed(policy, newstate, 1);
ppc_proc_freq = cur_freq * 1000ul;
return rc;
@@ -374,7 +402,14 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
+ 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);
}
static u32 read_gpio(struct device_node *np)
@@ -408,7 +443,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);
+ do_set_cpu_speed(policy, CPUFREQ_HIGH, 0);
return 0;
}
@@ -425,7 +460,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);
+ CPUFREQ_LOW : CPUFREQ_HIGH, 0);
ppc_proc_freq = cur_freq * 1000ul;
@@ -434,14 +469,14 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
}
static struct cpufreq_driver pmac_cpufreq_driver = {
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = pmac_cpufreq_target,
+ .verify = pmac_cpufreq_verify,
+ .target = 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 = cpufreq_generic_attr,
+ .attr = pmac_cpu_freqs_attr,
.name = "powermac",
};
diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c
index 6a338f8..3a51ad7 100644
--- a/drivers/cpufreq/pmac64-cpufreq.c
+++ b/drivers/cpufreq/pmac64-cpufreq.c
@@ -70,6 +70,11 @@ 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
*/
@@ -79,6 +84,8 @@ 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
@@ -135,7 +142,7 @@ static void g5_vdnap_switch_volt(int speed_mode)
pmf_call_one(pfunc_vdnap0_complete, &args);
if (done)
break;
- usleep_range(1000, 1000);
+ msleep(1);
}
if (done == 0)
printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
@@ -234,7 +241,7 @@ static void g5_pfunc_switch_volt(int speed_mode)
if (pfunc_cpu1_volt_low)
pmf_call_one(pfunc_cpu1_volt_low, NULL);
}
- usleep_range(10000, 10000); /* should be faster , to fix */
+ msleep(10); /* should be faster , to fix */
}
/*
@@ -279,7 +286,7 @@ static int g5_pfunc_switch_freq(int speed_mode)
pmf_call_one(pfunc_slewing_done, &args);
if (done)
break;
- usleep_range(500, 500);
+ msleep(1);
}
if (done == 0)
printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
@@ -310,9 +317,37 @@ static int g5_pfunc_query_freq(void)
* Common interface to the cpufreq core
*/
-static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
+static int g5_cpufreq_verify(struct cpufreq_policy *policy)
{
- return g5_switch_freq(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;
}
static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
@@ -322,17 +357,27 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
+ 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);
}
+
static struct cpufreq_driver g5_cpufreq_driver = {
.name = "powermac",
.flags = CPUFREQ_CONST_LOOPS,
.init = g5_cpufreq_cpu_init,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = g5_cpufreq_target,
+ .verify = g5_cpufreq_verify,
+ .target = g5_cpufreq_target,
.get = g5_cpufreq_get_speed,
- .attr = cpufreq_generic_attr,
+ .attr = g5_cpu_freqs_attr,
};
@@ -352,8 +397,7 @@ 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("PowerMac12,1"))
+ of_machine_is_compatible("PowerMac9,1"))
use_volts_smu = 1;
else if (of_machine_is_compatible("PowerMac11,2"))
use_volts_vdnap = 1;
@@ -603,10 +647,8 @@ 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 643e795..85f1c8c 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_target - set the PowerNow! multiplier
+ * powernow_k6_set_state - set the PowerNow! multiplier
* @best_i: clock_ratio[best_i] is the target multiplier
*
* Tries to change the PowerNow! multiplier
*/
-static int powernow_k6_target(struct cpufreq_policy *policy,
+static void powernow_k6_set_state(struct cpufreq_policy *policy,
unsigned int best_i)
{
unsigned long outvalue = 0, invalue = 0;
@@ -77,7 +77,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
if (clock_ratio[best_i].driver_data > max_multiplier) {
printk(KERN_ERR PFX "invalid target frequency\n");
- return -EINVAL;
+ return;
}
freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
@@ -100,6 +100,44 @@ static int powernow_k6_target(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;
}
@@ -107,6 +145,7 @@ 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;
@@ -126,8 +165,15 @@ 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 cpufreq_table_validate_and_show(policy, clock_ratio);
+ return 0;
}
@@ -136,7 +182,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_target(policy, i);
+ powernow_k6_set_state(policy, i);
}
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
@@ -149,14 +195,19 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = powernow_k6_target,
+ .verify = powernow_k6_verify,
+ .target = powernow_k6_target,
.init = powernow_k6_cpu_init,
.exit = powernow_k6_cpu_exit,
.get = powernow_k6_get,
.name = "powernow-k6",
- .attr = cpufreq_generic_attr,
+ .attr = powernow_k6_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 946708a..14ce480 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -248,7 +248,7 @@ static void change_VID(int vid)
}
-static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
+static void change_speed(struct cpufreq_policy *policy, unsigned int index)
{
u8 fid, vid;
struct cpufreq_freqs freqs;
@@ -291,8 +291,6 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
local_irq_enable();
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
-
- return 0;
}
@@ -535,6 +533,27 @@ 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
@@ -659,7 +678,11 @@ static int powernow_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency =
cpufreq_scale(2000000UL, fsb, latency);
- return cpufreq_table_validate_and_show(policy, powernow_table);
+ policy->cur = powernow_get(0);
+
+ cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
+
+ return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
}
static int powernow_cpu_exit(struct cpufreq_policy *policy)
@@ -678,9 +701,14 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = powernow_target,
+ .verify = powernow_verify,
+ .target = powernow_target,
.get = powernow_get,
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
.bios_limit = acpi_processor_get_bios_limit,
@@ -688,7 +716,7 @@ static struct cpufreq_driver powernow_driver = {
.init = powernow_cpu_init,
.exit = powernow_cpu_exit,
.name = "powernow-k7",
- .attr = cpufreq_generic_attr,
+ .attr = powernow_table_attr,
};
static int __init powernow_init(void)
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 0023c7d..2344a9e 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -977,17 +977,20 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
struct powernowk8_target_arg {
struct cpufreq_policy *pol;
- unsigned newstate;
+ unsigned targfreq;
+ unsigned relation;
};
static long powernowk8_target_fn(void *arg)
{
struct powernowk8_target_arg *pta = arg;
struct cpufreq_policy *pol = pta->pol;
- unsigned newstate = pta->newstate;
+ unsigned targfreq = pta->targfreq;
+ unsigned relation = pta->relation;
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
u32 checkfid;
u32 checkvid;
+ unsigned int newstate;
int ret;
if (!data)
@@ -1001,9 +1004,8 @@ static long powernowk8_target_fn(void *arg)
return -EIO;
}
- pr_debug("targ: cpu %d, %d kHz, min %d, max %d\n",
- pol->cpu, data->powernow_table[newstate].frequency, pol->min,
- pol->max);
+ pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
+ pol->cpu, targfreq, pol->min, pol->max, relation);
if (query_current_values_with_pending_wait(data))
return -EIO;
@@ -1019,6 +1021,10 @@ 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);
@@ -1038,13 +1044,26 @@ 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 index)
+static int powernowk8_target(struct cpufreq_policy *pol,
+ unsigned targfreq, unsigned relation)
{
- struct powernowk8_target_arg pta = { .pol = pol, .newstate = index };
+ struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq,
+ .relation = relation };
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;
@@ -1133,8 +1152,11 @@ 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_table_validate_and_show(pol, data->powernow_table)) {
+ if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n");
powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table);
@@ -1142,6 +1164,8 @@ 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);
@@ -1203,16 +1227,20 @@ out:
return khz;
}
+static struct freq_attr *powernow_k8_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver cpufreq_amd64_driver = {
- .flags = CPUFREQ_ASYNC_NOTIFICATION,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = powernowk8_target,
+ .verify = powernowk8_verify,
+ .target = powernowk8_target,
.bios_limit = acpi_processor_get_bios_limit,
.init = powernowk8_cpu_init,
.exit = powernowk8_cpu_exit,
.get = powernowk8_get,
.name = "powernow-k8",
- .attr = cpufreq_generic_attr,
+ .attr = powernow_k8_attr,
};
static void __request_acpi_cpufreq(void)
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 3f7be46..60e81d5 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -69,6 +69,8 @@ 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 */
@@ -200,7 +202,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_table_validate_and_show(policy, table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, table);
if (ret) {
pr_err("invalid frequency table: %d\n", ret);
goto err_nomem1;
@@ -215,6 +217,9 @@ 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;
@@ -248,25 +253,60 @@ 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 index)
+ unsigned int target_freq, unsigned int relation)
{
+ struct cpufreq_freqs freqs;
+ unsigned int new;
struct clk *parent;
+ int ret;
struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
- parent = of_clk_get(data->parent, data->table[index].driver_data);
- return clk_set_parent(data->clk, parent);
+ 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;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = corenet_cpufreq_target,
+ .verify = corenet_cpufreq_verify,
+ .target = corenet_cpufreq_target,
.get = corenet_cpufreq_get_speed,
- .attr = cpufreq_generic_attr,
+ .attr = corenet_cpufreq_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 e42ca9c..2e448f0 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -30,6 +30,9 @@
#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},
@@ -120,28 +123,63 @@ 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_table_validate_and_show(policy, cbe_freqs);
+ 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);
}
static int cbe_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int cbe_pmode_new)
+ unsigned int target_freq,
+ unsigned int relation)
{
+ 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);
- return set_pmode(policy->cpu, cbe_pmode_new);
+ rc = set_pmode(policy->cpu, cbe_pmode_new);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&cbe_switch_mutex);
+
+ return rc;
}
static struct cpufreq_driver cbe_cpufreq_driver = {
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = cbe_cpufreq_target,
+ .verify = cbe_cpufreq_verify,
+ .target = cbe_cpufreq_target,
.init = cbe_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = cbe_cpufreq_cpu_exit,
.name = "cbe-cpufreq",
.flags = CPUFREQ_CONST_LOOPS,
};
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index 0a0f436..8749eaf 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -262,15 +262,36 @@ 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 idx)
+static int pxa_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
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;
@@ -279,19 +300,32 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
/* 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",
- new_freq_cpu / 1000, (pxa_freq_settings[idx].div2) ?
+ freqs.new / 1000, (pxa_freq_settings[idx].div2) ?
(new_freq_mem / 2000) : (new_freq_mem / 1000));
- if (vcc_core && new_freq_cpu > policy->cur) {
+ if (vcc_core && freqs.new > freqs.old)
ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
- if (ret)
- return ret;
- }
+ 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);
/* 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
@@ -342,6 +376,13 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
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.
@@ -350,7 +391,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
* bug is triggered (seems a deadlock). Should anybody find out where,
* the "return 0" should become a "return ret".
*/
- if (vcc_core && new_freq_cpu < policy->cur)
+ if (vcc_core && freqs.new < freqs.old)
ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
return 0;
@@ -373,6 +414,8 @@ 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++) {
@@ -410,12 +453,10 @@ 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_table_validate_and_show(policy, pxa255_freq_table);
- }
- else if (cpu_is_pxa27x()) {
- cpufreq_table_validate_and_show(policy, pxa27x_freq_table);
+ cpufreq_frequency_table_cpuinfo(policy, pxa255_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");
@@ -423,10 +464,9 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver pxa_cpufreq_driver = {
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = pxa_set_target,
+ .verify = pxa_verify_policy,
+ .target = 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 9384004..d26306f 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_table_validate_and_show(policy, table);
+ return cpufreq_frequency_table_cpuinfo(policy, table);
}
static void __update_core_freq(struct pxa3xx_freq_info *info)
@@ -150,26 +150,54 @@ 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 index)
+static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
struct pxa3xx_freq_info *next;
+ struct cpufreq_freqs freqs;
unsigned long flags;
+ int idx;
if (policy->cpu != 0)
return -EINVAL;
- next = &pxa3xx_freqs[index];
+ /* 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);
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;
}
@@ -178,10 +206,11 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
int ret = -EINVAL;
/* set default policy and cpuinfo */
- policy->min = policy->cpuinfo.min_freq = 104000;
- policy->max = policy->cpuinfo.max_freq =
- (cpu_is_pxa320()) ? 806000 : 624000;
+ policy->cpuinfo.min_freq = 104000;
+ 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,
@@ -201,10 +230,9 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver pxa3xx_cpufreq_driver = {
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = pxa3xx_cpufreq_set,
+ .verify = pxa3xx_cpufreq_verify,
+ .target = 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 8d904a0..22dcb81 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -87,6 +87,16 @@ 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;
@@ -217,15 +227,24 @@ 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 index)
+ unsigned int target_freq,
+ unsigned int relation)
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
- unsigned int new_freq;
+ struct cpufreq_freqs freqs;
int idx, ret, to_dvs = 0;
+ unsigned int i;
mutex_lock(&cpufreq_lock);
- idx = s3c_freq->freq_table[index].driver_data;
+ 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;
if (idx == SOURCE_HCLK)
to_dvs = 1;
@@ -237,13 +256,24 @@ 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.
*/
- new_freq = (s3c_freq->is_dvs && !to_dvs)
+ freqs.new = (s3c_freq->is_dvs && !to_dvs)
? clk_get_rate(s3c_freq->hclk) / 1000
- : s3c_freq->freq_table[index].frequency;
+ : 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);
if (to_dvs) {
pr_debug("cpufreq: enter dvs\n");
@@ -252,10 +282,12 @@ 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", new_freq);
- ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq);
+ pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new);
+ ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new);
}
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
out:
mutex_unlock(&cpufreq_lock);
@@ -454,14 +486,20 @@ 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)
*/
- ret = cpufreq_generic_init(policy, s3c_freq->freq_table,
- (500 * 1000) + s3c_freq->regulator_latency);
+ policy->cpuinfo.transition_latency = (500 * 1000) +
+ s3c_freq->regulator_latency;
+
+ ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table);
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;
@@ -480,14 +518,19 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = s3c2416_cpufreq_set_target,
+ .verify = s3c2416_cpufreq_verify_speed,
+ .target = s3c2416_cpufreq_set_target,
.get = s3c2416_cpufreq_get_speed,
.init = s3c2416_cpufreq_driver_init,
.name = "s3c2416",
- .attr = cpufreq_generic_attr,
+ .attr = s3c2416_cpufreq_attr,
};
static int __init s3c2416_cpufreq_init(void)
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 4850882..b0f343f 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -373,7 +373,23 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name)
static int s3c_cpufreq_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency);
+ 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;
}
static int __init s3c_cpufreq_initclks(void)
@@ -400,6 +416,14 @@ 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;
@@ -449,6 +473,7 @@ 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 67e302e..15631f9 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -54,6 +54,14 @@ 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)
@@ -63,48 +71,66 @@ static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu)
}
static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
- unsigned int index)
+ unsigned int target_freq,
+ unsigned int relation)
{
- struct s3c64xx_dvfs *dvfs;
- unsigned int old_freq, new_freq;
int ret;
+ unsigned int i;
+ struct cpufreq_freqs freqs;
+ struct s3c64xx_dvfs *dvfs;
+
+ 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];
- old_freq = clk_get_rate(armclk) / 1000;
- new_freq = s3c64xx_freq_table[index].frequency;
- dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].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);
#ifdef CONFIG_REGULATOR
- if (vddarm && new_freq > old_freq) {
+ if (vddarm && freqs.new > freqs.old) {
ret = regulator_set_voltage(vddarm,
dvfs->vddarm_min,
dvfs->vddarm_max);
if (ret != 0) {
pr_err("Failed to set VDDARM for %dkHz: %d\n",
- new_freq, ret);
- return ret;
+ freqs.new, ret);
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
#endif
- ret = clk_set_rate(armclk, new_freq * 1000);
+ ret = clk_set_rate(armclk, freqs.new * 1000);
if (ret < 0) {
pr_err("Failed to set rate %dkHz: %d\n",
- new_freq, ret);
- return ret;
+ freqs.new, ret);
+ freqs.new = freqs.old;
}
+post_notify:
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ if (ret)
+ goto err;
+
#ifdef CONFIG_REGULATOR
- if (vddarm && new_freq < old_freq) {
+ if (vddarm && freqs.new < freqs.old) {
ret = regulator_set_voltage(vddarm,
dvfs->vddarm_min,
dvfs->vddarm_max);
if (ret != 0) {
pr_err("Failed to set VDDARM for %dkHz: %d\n",
- new_freq, ret);
- if (clk_set_rate(armclk, old_freq * 1000) < 0)
- pr_err("Failed to restore original clock rate\n");
-
- return ret;
+ freqs.new, ret);
+ goto err_clk;
}
}
#endif
@@ -113,6 +139,14 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
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
@@ -209,12 +243,15 @@ 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.
*/
- ret = cpufreq_generic_init(policy, s3c64xx_freq_table,
- (500 * 1000) + regulator_latency);
+ policy->cpuinfo.transition_latency = (500 * 1000) + regulator_latency;
+
+ ret = cpufreq_frequency_table_cpuinfo(policy, s3c64xx_freq_table);
if (ret != 0) {
pr_err("Failed to configure frequency table: %d\n",
ret);
@@ -227,8 +264,8 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
static struct cpufreq_driver s3c64xx_cpufreq_driver = {
.flags = 0,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = s3c64xx_cpufreq_set_target,
+ .verify = s3c64xx_cpufreq_verify_speed,
+ .target = 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 e3973da..5c77570 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -26,6 +26,7 @@
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 */
@@ -35,7 +36,16 @@ static DEFINE_MUTEX(set_freq_lock);
/* Use 800MHz when entering sleep mode */
#define SLEEP_FREQ (800 * 1000)
-/* Tracks if cpu freqency can be updated anymore */
+/*
+ * 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,
+};
+
static bool no_cpufreq_access;
/*
@@ -164,6 +174,14 @@ 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)
@@ -172,18 +190,22 @@ 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 index)
+static int s5pv210_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
unsigned long reg;
- unsigned int priv_index;
+ unsigned int index, 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"
@@ -193,13 +215,27 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
goto exit;
}
- old_freq = s5pv210_getspeed(0);
- new_freq = s5pv210_freq_table[index].frequency;
+ 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;
/* Finding current running level index */
if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
- old_freq, CPUFREQ_RELATION_H,
- &priv_index)) {
+ freqs.old, relation, &priv_index)) {
ret = -EINVAL;
goto exit;
}
@@ -207,7 +243,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
arm_volt = dvs_conf[index].arm_volt;
int_volt = dvs_conf[index].int_volt;
- if (new_freq > old_freq) {
+ if (freqs.new > freqs.old) {
ret = regulator_set_voltage(arm_regulator,
arm_volt, arm_volt_max);
if (ret)
@@ -219,6 +255,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
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;
@@ -429,7 +467,9 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
}
}
- if (new_freq < old_freq) {
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
+ if (freqs.new < freqs.old) {
regulator_set_voltage(int_regulator,
int_volt, int_volt_max);
@@ -511,7 +551,13 @@ 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);
- return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
+ 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);
out_dmc1:
clk_put(dmc0_clk);
@@ -527,18 +573,16 @@ 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, 0);
+ ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+ DISABLE_FURTHER_CPUFREQ);
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:
- /* Enable updation of cpu frequency */
- no_cpufreq_access = false;
- cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
+ cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+ ENABLE_FURTHER_CPUFREQ);
return NOTIFY_OK;
}
@@ -551,18 +595,18 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
{
int ret;
- ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
+ ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+ DISABLE_FURTHER_CPUFREQ);
if (ret < 0)
return NOTIFY_BAD;
- no_cpufreq_access = true;
return NOTIFY_DONE;
}
static struct cpufreq_driver s5pv210_driver = {
.flags = CPUFREQ_STICKY,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = s5pv210_target,
+ .verify = s5pv210_verify_speed,
+ .target = 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 623da74..cff18e8 100644
--- a/drivers/cpufreq/sa1100-cpufreq.c
+++ b/drivers/cpufreq/sa1100-cpufreq.c
@@ -177,33 +177,60 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
}
}
-static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr)
+static int sa1100_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
unsigned int cur = sa11x0_getspeed(0);
- unsigned int new_freq;
+ 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);
- new_freq = sa11x0_freq_table[ppcr].frequency;
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
- if (new_freq > cur)
- sa1100_update_dram_timings(cur, new_freq);
+ if (freqs.new > cur)
+ sa1100_update_dram_timings(cur, freqs.new);
- PPCR = ppcr;
+ PPCR = new_ppcr;
- if (new_freq < cur)
- sa1100_update_dram_timings(cur, new_freq);
+ if (freqs.new < cur)
+ sa1100_update_dram_timings(cur, freqs.new);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL);
+ 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;
}
static struct cpufreq_driver sa1100_driver __refdata = {
.flags = CPUFREQ_STICKY,
- .verify = cpufreq_generic_frequency_table_verify,
- .target_index = sa1100_target,
+ .verify = sa11x0_verify_speed,
+ .target = 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 2c2b2e6..39c90b6 100644
--- a/drivers/cpufreq/sa1110-cpufreq.c
+++ b/drivers/cpufreq/sa1110-cpufreq.c
@@ -229,14 +229,36 @@ 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 ppcr)
+static int sa1110_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
struct sdram_params *sdram = &sdram_params;
+ struct cpufreq_freqs freqs;
struct sdram_info sd;
unsigned long flags;
- unsigned int unused;
+ 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);
- sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram);
+ sdram_calculate_timing(&sd, freqs.new, sdram);
#if 0
/*
@@ -255,6 +277,8 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
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
@@ -299,22 +323,30 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
/*
* Now, return the SDRAM refresh back to normal.
*/
- sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram);
+ sdram_update_refresh(freqs.new, sdram);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, sa11x0_freq_table, CPUFREQ_ETERNAL);
+ 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;
}
/* 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 = cpufreq_generic_frequency_table_verify,
- .target_index = sa1110_target,
+ .verify = sa11x0_verify_speed,
+ .target = 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 6adb354..d6f6c6f 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -53,11 +53,21 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
}
}
-static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
+static void sc520_freq_set_cpu_state(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;
@@ -65,9 +75,30 @@ static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
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
*/
@@ -75,6 +106,7 @@ static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
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 ||
@@ -83,19 +115,39 @@ 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;
+}
- return cpufreq_table_validate_and_show(policy, sc520_freq_table);
+
+static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = sc520_freq_target,
+ .verify = sc520_freq_verify,
+ .target = sc520_freq_target,
.init = sc520_freq_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = sc520_freq_cpu_exit,
.name = "sc520_freq",
- .attr = cpufreq_generic_attr,
+ .attr = sc520_freq_attr,
};
static const struct x86_cpu_id sc520_ids[] = {
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 387af12..ffc6d24 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -87,12 +87,15 @@ static int sh_cpufreq_verify(struct cpufreq_policy *policy)
if (freq_table)
return cpufreq_frequency_table_verify(policy, freq_table);
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000;
policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
return 0;
}
@@ -111,13 +114,15 @@ 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_table_validate_and_show(policy, freq_table);
- if (result)
- return result;
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+ cpufreq_frequency_table_get_attr(freq_table, cpu);
} else {
dev_notice(dev, "no frequency table found, falling back "
"to rate rounding.\n");
@@ -149,6 +154,11 @@ 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,
@@ -156,7 +166,7 @@ static struct cpufreq_driver sh_cpufreq_driver = {
.verify = sh_cpufreq_verify,
.init = sh_cpufreq_cpu_init,
.exit = sh_cpufreq_cpu_exit,
- .attr = cpufreq_generic_attr,
+ .attr = sh_freq_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 62aa23e..cf5bc2c 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -245,12 +245,14 @@ static unsigned int us2e_freq_get(unsigned int cpu)
return clock_tick / estar_to_divisor(estar);
}
-static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
+static void us2e_set_cpu_divider_index(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));
@@ -264,15 +266,41 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
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;
@@ -296,15 +324,13 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
- return cpufreq_table_validate_and_show(policy, table);
+ return cpufreq_frequency_table_cpuinfo(policy, table);
}
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us2e_driver) {
- cpufreq_frequency_table_put_attr(policy->cpu);
- us2e_freq_target(policy, 0);
- }
+ if (cpufreq_us2e_driver)
+ us2e_set_cpu_divider_index(policy, 0);
return 0;
}
@@ -335,8 +361,8 @@ static int __init us2e_freq_init(void)
goto err_out;
driver->init = us2e_freq_cpu_init;
- driver->verify = cpufreq_generic_frequency_table_verify;
- driver->target_index = us2e_freq_target;
+ driver->verify = us2e_freq_verify;
+ driver->target = 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 724ffbd..ac76b48 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -93,11 +93,13 @@ static unsigned int us3_freq_get(unsigned int cpu)
return ret;
}
-static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
+static void us3_set_cpu_divider_index(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));
@@ -123,15 +125,43 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
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;
@@ -151,15 +181,13 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
- return cpufreq_table_validate_and_show(policy, table);
+ return cpufreq_frequency_table_cpuinfo(policy, table);
}
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us3_driver) {
- cpufreq_frequency_table_put_attr(policy->cpu);
- us3_freq_target(policy, 0);
- }
+ if (cpufreq_us3_driver)
+ us3_set_cpu_divider_index(policy, 0);
return 0;
}
@@ -194,8 +222,8 @@ static int __init us3_freq_init(void)
goto err_out;
driver->init = us3_freq_cpu_init;
- driver->verify = cpufreq_generic_frequency_table_verify;
- driver->target_index = us3_freq_target;
+ driver->verify = us3_freq_verify;
+ driver->target = 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 d02ccd1..3f41816 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -30,6 +30,11 @@ 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;
@@ -105,14 +110,20 @@ static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq)
}
static int spear_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int index)
+ unsigned int target_freq, unsigned int relation)
{
+ struct cpufreq_freqs freqs;
long newfreq;
struct clk *srcclk;
- int ret, mult = 1;
+ int index, ret, mult = 1;
- newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000;
+ if (cpufreq_frequency_table_target(policy, spear_cpufreq.freq_tbl,
+ target_freq, relation, &index))
+ return -EINVAL;
+
+ freqs.old = spear_cpufreq_get(0);
+ 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
@@ -143,32 +154,65 @@ 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);
- if (ret)
+ /* Get current rate after clk_set_rate, in case of failure */
+ 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)
{
- return cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
- spear_cpufreq.transition_latency);
+ 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;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = spear_cpufreq_target,
+ .verify = spear_cpufreq_verify,
+ .target = spear_cpufreq_target,
.get = spear_cpufreq_get,
.init = spear_cpufreq_init,
- .exit = cpufreq_generic_exit,
- .attr = cpufreq_generic_attr,
+ .exit = spear_cpufreq_exit,
+ .attr = spear_cpufreq_attr,
};
static int spear_cpufreq_driver_init(void)
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 4e1daca..f897d51 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -343,7 +343,9 @@ 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 */
@@ -371,8 +373,9 @@ 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. */
@@ -392,11 +395,22 @@ 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);
- return cpufreq_table_validate_and_show(policy,
+ ret = cpufreq_frequency_table_cpuinfo(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)
@@ -414,18 +428,36 @@ 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
- * @index: index of target frequency
+ * @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 centrino_target(struct cpufreq_policy *policy, unsigned int index)
+static int centrino_target (struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
+ 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;
- struct cpufreq_frequency_table *op_points;
+ unsigned int j, first_cpu, tmp;
cpumask_var_t covered_cpus;
if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL)))
@@ -436,8 +468,16 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
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;
@@ -461,7 +501,7 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
break;
}
- msr = op_points->driver_data;
+ msr = per_cpu(centrino_model, cpu)->op_points[newstate].driver_data;
if (first_cpu) {
rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h);
@@ -472,6 +512,15 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
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;
@@ -486,6 +535,8 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
cpumask_set_cpu(j, covered_cpus);
}
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
if (unlikely(retval)) {
/*
* We have failed halfway through the frequency change.
@@ -496,6 +547,12 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
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;
@@ -504,15 +561,20 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = centrino_target,
+ .verify = centrino_verify,
+ .target = centrino_target,
.get = get_cur_freq,
- .attr = cpufreq_generic_attr,
+ .attr = centrino_attr,
};
/*
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index 7639b2b..5355abb 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -251,23 +251,56 @@ static unsigned int speedstep_get(unsigned int cpu)
/**
* speedstep_target - set a new CPUFreq policy
* @policy: new policy
- * @index: index of target frequency
+ * @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 speedstep_target(struct cpufreq_policy *policy, unsigned int index)
+static int speedstep_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
- unsigned int policy_cpu;
+ 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;
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;
- smp_call_function_single(policy_cpu, _speedstep_set_state, &index,
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+ smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate,
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;
@@ -287,7 +320,8 @@ static void get_freqs_on_cpu(void *_get_freqs)
static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
- unsigned int policy_cpu;
+ int result;
+ unsigned int policy_cpu, speed;
struct get_freqs gf;
/* only run on CPU to be set, or on its sibling */
@@ -302,18 +336,49 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
if (gf.ret)
return gf.ret;
- return cpufreq_table_validate_and_show(policy, speedstep_freqs);
+ /* 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;
}
+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 = cpufreq_generic_frequency_table_verify,
- .target_index = speedstep_target,
+ .verify = speedstep_verify,
+ .target = speedstep_target,
.init = speedstep_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = speedstep_cpu_exit,
.get = speedstep_get,
- .attr = cpufreq_generic_attr,
+ .attr = speedstep_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 0f5326d..abfba4f 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -235,21 +235,52 @@ static void speedstep_set_state(unsigned int state)
/**
* speedstep_target - set a new CPUFreq policy
* @policy: new policy
- * @index: index of new freq
+ * @target_freq: new freq
+ * @relation:
*
* Sets a new CPUFreq policy/freq.
*/
-static int speedstep_target(struct cpufreq_policy *policy, unsigned int index)
+static int speedstep_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
{
- speedstep_set_state(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);
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 */
@@ -285,8 +316,32 @@ 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;
- return cpufreq_table_validate_and_show(policy, speedstep_freqs);
+ 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;
}
static unsigned int speedstep_get(unsigned int cpu)
@@ -307,15 +362,20 @@ 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 = cpufreq_generic_frequency_table_verify,
- .target_index = speedstep_target,
+ .verify = speedstep_verify,
+ .target = speedstep_target,
.init = speedstep_cpu_init,
- .exit = cpufreq_generic_exit,
+ .exit = speedstep_cpu_exit,
.get = speedstep_get,
.resume = speedstep_resume,
- .attr = cpufreq_generic_attr,
+ .attr = speedstep_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 b7309c3..a7b876f 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -51,6 +51,11 @@ 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;
@@ -102,8 +107,12 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
unsigned long rate)
{
int ret = 0;
+ struct cpufreq_freqs freqs;
- if (tegra_getspeed(0) == rate)
+ freqs.old = tegra_getspeed(0);
+ freqs.new = rate;
+
+ if (freqs.old == freqs.new)
return ret;
/*
@@ -117,10 +126,21 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
else
clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
- ret = tegra_cpu_clk_set_rate(rate * 1000);
- if (ret)
- pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n",
- rate);
+ 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);
return ret;
}
@@ -135,17 +155,25 @@ static unsigned long tegra_cpu_highest_speed(void)
return rate;
}
-static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
+static int tegra_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
+ unsigned int idx;
unsigned int freq;
int ret = 0;
mutex_lock(&tegra_cpu_lock);
- if (is_suspended)
+ if (is_suspended) {
+ ret = -EBUSY;
goto out;
+ }
- freq = freq_table[index].frequency;
+ cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &idx);
+
+ freq = freq_table[idx].frequency;
target_cpu_speed[policy->cpu] = freq;
@@ -181,23 +209,21 @@ 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);
- target_cpu_speed[policy->cpu] = tegra_getspeed(policy->cpu);
+ 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;
/* FIXME: what's the actual transition time? */
- ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
- if (ret) {
- clk_disable_unprepare(cpu_clk);
- clk_disable_unprepare(emc_clk);
- return ret;
- }
+ policy->cpuinfo.transition_latency = 300 * 1000;
+
+ cpumask_copy(policy->cpus, cpu_possible_mask);
if (policy->cpu == 0)
register_pm_notifier(&tegra_cpu_pm_notifier);
@@ -207,20 +233,24 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
static int tegra_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
- clk_disable_unprepare(cpu_clk);
+ cpufreq_frequency_table_cpuinfo(policy, freq_table);
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 = cpufreq_generic_frequency_table_verify,
- .target_index = tegra_target,
+ .verify = tegra_verify_speed,
+ .target = tegra_target,
.get = tegra_getspeed,
.init = tegra_cpu_init,
.exit = tegra_cpu_exit,
.name = "tegra",
- .attr = cpufreq_generic_attr,
+ .attr = tegra_cpufreq_attr,
};
static int __init tegra_cpufreq_init(void)
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c
index 653ae29..b225f04 100644
--- a/drivers/cpufreq/unicore2-cpufreq.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -29,7 +29,9 @@ static int ucv2_verify_speed(struct cpufreq_policy *policy)
if (policy->cpu)
return -EINVAL;
- cpufreq_verify_within_cpu_limits(policy);
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
+
return 0;
}
@@ -66,6 +68,7 @@ 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
deleted file mode 100644
index 7f7c9c0..0000000
--- a/drivers/cpufreq/vexpress-spc-cpufreq.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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");