mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-10-31 18:09:19 +00:00
Merge branch 'pm-cpufreq'
* pm-cpufreq: (57 commits) cpufreq: MAINTAINERS: Add co-maintainer cpufreq: pxa2xx: initialize variables ARM: S5pv210: compiling issue, ARM_S5PV210_CPUFREQ needs CONFIG_CPU_FREQ_TABLE=y cpufreq: cpu0: Put cpu parent node after using it cpufreq: ARM big LITTLE: Adapt to latest cpufreq updates cpufreq: ARM big LITTLE: put DT nodes after using them cpufreq: Don't call __cpufreq_governor() for drivers without target() cpufreq: exynos5440: Protect OPP search calls with RCU lock cpufreq: dbx500: Round to closest available freq cpufreq: Call __cpufreq_governor() with correct policy->cpus mask cpufreq / intel_pstate: Optimize intel_pstate_set_policy cpufreq: OMAP: instantiate omap-cpufreq as a platform_driver arm: exynos: Enable OPP library support for exynos5440 cpufreq: exynos: Remove error return even if no soc is found cpufreq: exynos: Add cpufreq driver for exynos5440 cpufreq: AMD "frequency sensitivity feedback" powersave bias for ondemand governor cpufreq: ondemand: allow custom powersave_bias_target handler to be registered cpufreq: convert cpufreq_driver to using RCU cpufreq: powerpc/platforms/cell: move cpufreq driver to drivers/cpufreq cpufreq: sparc: move cpufreq driver to drivers/cpufreq ... Conflicts: MAINTAINERS (with commita8e39c3
from pm-cpuidle) drivers/cpufreq/cpufreq_governor.h (with commitbeb0ff3
)
This commit is contained in:
commit
885f925eef
122 changed files with 2769 additions and 1239 deletions
|
@ -108,8 +108,9 @@ policy->governor must contain the "default policy" for
|
|||
cpufreq_driver.target is called with
|
||||
these values.
|
||||
|
||||
For setting some of these values, the frequency table helpers might be
|
||||
helpful. See the section 2 for more information on them.
|
||||
For setting some of these values (cpuinfo.min[max]_freq, policy->min[max]), the
|
||||
frequency table helpers might be helpful. See the section 2 for more information
|
||||
on them.
|
||||
|
||||
SMP systems normally have same clock source for a group of cpus. For these the
|
||||
.init() would be called only once for the first online cpu. Here the .init()
|
||||
|
@ -184,10 +185,10 @@ the reference implementation in drivers/cpufreq/longrun.c
|
|||
As most cpufreq processors only allow for being set to a few specific
|
||||
frequencies, a "frequency table" with some functions might assist in
|
||||
some work of the processor driver. Such a "frequency table" consists
|
||||
of an array of struct cpufreq_freq_table entries, with any value in
|
||||
of an array of struct cpufreq_frequency_table entries, with any value in
|
||||
"index" you want to use, and the corresponding frequency in
|
||||
"frequency". At the end of the table, you need to add a
|
||||
cpufreq_freq_table entry with frequency set to CPUFREQ_TABLE_END. And
|
||||
cpufreq_frequency_table entry with frequency set to CPUFREQ_TABLE_END. And
|
||||
if you want to skip one entry in the table, set the frequency to
|
||||
CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending
|
||||
order.
|
||||
|
|
|
@ -167,6 +167,27 @@ of load evaluation and helping the CPU stay at its top speed when truly
|
|||
busy, rather than shifting back and forth in speed. This tunable has no
|
||||
effect on behavior at lower speeds/lower CPU loads.
|
||||
|
||||
powersave_bias: this parameter takes a value between 0 to 1000. It
|
||||
defines the percentage (times 10) value of the target frequency that
|
||||
will be shaved off of the target. For example, when set to 100 -- 10%,
|
||||
when ondemand governor would have targeted 1000 MHz, it will target
|
||||
1000 MHz - (10% of 1000 MHz) = 900 MHz instead. This is set to 0
|
||||
(disabled) by default.
|
||||
When AMD frequency sensitivity powersave bias driver --
|
||||
drivers/cpufreq/amd_freq_sensitivity.c is loaded, this parameter
|
||||
defines the workload frequency sensitivity threshold in which a lower
|
||||
frequency is chosen instead of ondemand governor's original target.
|
||||
The frequency sensitivity is a hardware reported (on AMD Family 16h
|
||||
Processors and above) value between 0 to 100% that tells software how
|
||||
the performance of the workload running on a CPU will change when
|
||||
frequency changes. A workload with sensitivity of 0% (memory/IO-bound)
|
||||
will not perform any better on higher core frequency, whereas a
|
||||
workload with sensitivity of 100% (CPU-bound) will perform better
|
||||
higher the frequency. When the driver is loaded, this is set to 400
|
||||
by default -- for CPUs running workloads with sensitivity value below
|
||||
40%, a lower frequency is chosen. Unloading the driver or writing 0
|
||||
will disable this feature.
|
||||
|
||||
|
||||
2.5 Conservative
|
||||
----------------
|
||||
|
@ -191,6 +212,12 @@ governor but for the opposite direction. For example when set to its
|
|||
default value of '20' it means that if the CPU usage needs to be below
|
||||
20% between samples to have the frequency decreased.
|
||||
|
||||
sampling_down_factor: similar functionality as in "ondemand" governor.
|
||||
But in "conservative", it controls the rate at which the kernel makes
|
||||
a decision on when to decrease the frequency while running in any
|
||||
speed. Load for frequency increase is still evaluated every
|
||||
sampling rate.
|
||||
|
||||
3. The Governor Interface in the CPUfreq Core
|
||||
=============================================
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
Generic ARM big LITTLE cpufreq driver's DT glue
|
||||
-----------------------------------------------
|
||||
|
||||
This is DT specific glue layer for generic cpufreq driver for big LITTLE
|
||||
systems.
|
||||
|
||||
Both required and optional properties listed below must be defined
|
||||
under node /cpus/cpu@x. Where x is the first cpu inside a cluster.
|
||||
|
||||
FIXME: Cpus should boot in the order specified in DT and all cpus for a cluster
|
||||
must be present contiguously. Generic DT driver will check only node 'x' for
|
||||
cpu:x.
|
||||
|
||||
Required properties:
|
||||
- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
|
||||
for details
|
||||
|
||||
Optional properties:
|
||||
- clock-latency: Specify the possible maximum transition latency for clock,
|
||||
in unit of nanoseconds.
|
||||
|
||||
Examples:
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@0 {
|
||||
compatible = "arm,cortex-a15";
|
||||
reg = <0>;
|
||||
next-level-cache = <&L2>;
|
||||
operating-points = <
|
||||
/* kHz uV */
|
||||
792000 1100000
|
||||
396000 950000
|
||||
198000 850000
|
||||
>;
|
||||
clock-latency = <61036>; /* two CLK32 periods */
|
||||
};
|
||||
|
||||
cpu@1 {
|
||||
compatible = "arm,cortex-a15";
|
||||
reg = <1>;
|
||||
next-level-cache = <&L2>;
|
||||
};
|
||||
|
||||
cpu@100 {
|
||||
compatible = "arm,cortex-a7";
|
||||
reg = <100>;
|
||||
next-level-cache = <&L2>;
|
||||
operating-points = <
|
||||
/* kHz uV */
|
||||
792000 950000
|
||||
396000 750000
|
||||
198000 450000
|
||||
>;
|
||||
clock-latency = <61036>; /* two CLK32 periods */
|
||||
};
|
||||
|
||||
cpu@101 {
|
||||
compatible = "arm,cortex-a7";
|
||||
reg = <101>;
|
||||
next-level-cache = <&L2>;
|
||||
};
|
||||
};
|
|
@ -32,7 +32,7 @@ cpus {
|
|||
396000 950000
|
||||
198000 850000
|
||||
>;
|
||||
transition-latency = <61036>; /* two CLK32 periods */
|
||||
clock-latency = <61036>; /* two CLK32 periods */
|
||||
};
|
||||
|
||||
cpu@1 {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
Exynos5440 cpufreq driver
|
||||
-------------------
|
||||
|
||||
Exynos5440 SoC cpufreq driver for CPU frequency scaling.
|
||||
|
||||
Required properties:
|
||||
- interrupts: Interrupt to know the completion of cpu frequency change.
|
||||
- operating-points: Table of frequencies and voltage CPU could be transitioned into,
|
||||
in the decreasing order. Frequency should be in KHz units and voltage
|
||||
should be in microvolts.
|
||||
|
||||
Optional properties:
|
||||
- clock-latency: Clock monitor latency in microsecond.
|
||||
|
||||
All the required listed above must be defined under node cpufreq.
|
||||
|
||||
Example:
|
||||
--------
|
||||
cpufreq@160000 {
|
||||
compatible = "samsung,exynos5440-cpufreq";
|
||||
reg = <0x160000 0x1000>;
|
||||
interrupts = <0 57 0>;
|
||||
operating-points = <
|
||||
1000000 975000
|
||||
800000 925000>;
|
||||
clock-latency = <100000>;
|
||||
};
|
13
MAINTAINERS
13
MAINTAINERS
|
@ -2200,12 +2200,25 @@ F: drivers/net/ethernet/ti/cpmac.c
|
|||
|
||||
CPU FREQUENCY DRIVERS
|
||||
M: Rafael J. Wysocki <rjw@sisk.pl>
|
||||
M: Viresh Kumar <viresh.kumar@linaro.org>
|
||||
L: cpufreq@vger.kernel.org
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
|
||||
F: drivers/cpufreq/
|
||||
F: include/linux/cpufreq.h
|
||||
|
||||
CPU FREQUENCY DRIVERS - ARM BIG LITTLE
|
||||
M: Viresh Kumar <viresh.kumar@linaro.org>
|
||||
M: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
|
||||
L: cpufreq@vger.kernel.org
|
||||
L: linux-pm@vger.kernel.org
|
||||
W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
|
||||
S: Maintained
|
||||
F: drivers/cpufreq/arm_big_little.h
|
||||
F: drivers/cpufreq/arm_big_little.c
|
||||
F: drivers/cpufreq/arm_big_little_dt.c
|
||||
|
||||
CPUIDLE DRIVERS
|
||||
M: Rafael J. Wysocki <rjw@sisk.pl>
|
||||
M: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
|
|
|
@ -2160,7 +2160,6 @@ endmenu
|
|||
menu "CPU Power Management"
|
||||
|
||||
if ARCH_HAS_CPUFREQ
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
config CPU_FREQ_IMX
|
||||
|
@ -2170,30 +2169,6 @@ config CPU_FREQ_IMX
|
|||
help
|
||||
This enables the CPUfreq driver for i.MX CPUs.
|
||||
|
||||
config CPU_FREQ_SA1100
|
||||
bool
|
||||
|
||||
config CPU_FREQ_SA1110
|
||||
bool
|
||||
|
||||
config CPU_FREQ_INTEGRATOR
|
||||
tristate "CPUfreq driver for ARM Integrator CPUs"
|
||||
depends on ARCH_INTEGRATOR && CPU_FREQ
|
||||
default y
|
||||
help
|
||||
This enables the CPUfreq driver for ARM Integrator CPUs.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say Y.
|
||||
|
||||
config CPU_FREQ_PXA
|
||||
bool
|
||||
depends on CPU_FREQ && ARCH_PXA && PXA25x
|
||||
default y
|
||||
select CPU_FREQ_DEFAULT_GOV_USERSPACE
|
||||
select CPU_FREQ_TABLE
|
||||
|
||||
config CPU_FREQ_S3C
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -37,7 +37,6 @@ obj-$(CONFIG_MACH_MITYOMAPL138) += board-mityomapl138.o
|
|||
obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o
|
||||
|
||||
# Power Management
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_SUSPEND) += pm.o sleep.o
|
||||
obj-$(CONFIG_HAVE_CLK) += pm_domain.o
|
||||
|
|
|
@ -72,10 +72,12 @@ config SOC_EXYNOS5440
|
|||
bool "SAMSUNG EXYNOS5440"
|
||||
default y
|
||||
depends on ARCH_EXYNOS5
|
||||
select ARCH_HAS_OPP
|
||||
select ARM_ARCH_TIMER
|
||||
select AUTO_ZRELADDR
|
||||
select PINCTRL
|
||||
select PINCTRL_EXYNOS5440
|
||||
select PM_OPP
|
||||
help
|
||||
Enable EXYNOS5440 SoC support
|
||||
|
||||
|
|
|
@ -87,13 +87,12 @@ static int mxc_set_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = clk_get_rate(cpu_clk) / 1000;
|
||||
freqs.new = freq_Hz / 1000;
|
||||
freqs.cpu = 0;
|
||||
freqs.flags = 0;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
ret = set_cpu_freq(freq_Hz);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -145,14 +144,11 @@ static int mxc_cpufreq_init(struct cpufreq_policy *policy)
|
|||
imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
policy->cur = clk_get_rate(cpu_clk) / 1000;
|
||||
policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min;
|
||||
policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max;
|
||||
|
||||
/* Manual states, that PLL stabilizes in two CLK32 periods */
|
||||
policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ;
|
||||
|
||||
ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table);
|
||||
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "%s: failed to register i.MXC CPUfreq with error code %d\n",
|
||||
__func__, ret);
|
||||
|
|
|
@ -9,5 +9,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
|
|||
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
|
||||
|
||||
obj-$(CONFIG_PCI) += pci_v3.o pci.o
|
||||
obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o
|
||||
obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o
|
||||
|
|
|
@ -265,6 +265,12 @@ static void __init omap4_init_voltages(void)
|
|||
omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", "iva");
|
||||
}
|
||||
|
||||
static inline void omap_init_cpufreq(void)
|
||||
{
|
||||
struct platform_device_info devinfo = { .name = "omap-cpufreq", };
|
||||
platform_device_register_full(&devinfo);
|
||||
}
|
||||
|
||||
static int __init omap2_common_pm_init(void)
|
||||
{
|
||||
if (!of_have_populated_dt())
|
||||
|
@ -294,6 +300,9 @@ int __init omap2_common_pm_late_init(void)
|
|||
|
||||
/* Smartreflex device init */
|
||||
omap_devinit_smartreflex();
|
||||
|
||||
/* cpufreq dummy device instantiation */
|
||||
omap_init_cpufreq();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
|
|
|
@ -7,12 +7,6 @@ obj-y += clock.o devices.o generic.o irq.o \
|
|||
time.o reset.o
|
||||
obj-$(CONFIG_PM) += pm.o sleep.o standby.o
|
||||
|
||||
ifeq ($(CONFIG_CPU_FREQ),y)
|
||||
obj-$(CONFIG_PXA25x) += cpufreq-pxa2xx.o
|
||||
obj-$(CONFIG_PXA27x) += cpufreq-pxa2xx.o
|
||||
obj-$(CONFIG_PXA3xx) += cpufreq-pxa3xx.o
|
||||
endif
|
||||
|
||||
# Generic drivers that other drivers may depend upon
|
||||
|
||||
# SoC-specific code
|
||||
|
|
1
arch/arm/mach-pxa/include/mach/generic.h
Normal file
1
arch/arm/mach-pxa/include/mach/generic.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../../generic.h"
|
|
@ -204,7 +204,6 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
|
|||
freqs.old = cpu_cur.freq;
|
||||
freqs.new = cpu_new.freq;
|
||||
|
||||
freqs.freqs.cpu = 0;
|
||||
freqs.freqs.old = cpu_cur.freq.armclk / 1000;
|
||||
freqs.freqs.new = cpu_new.freq.armclk / 1000;
|
||||
|
||||
|
@ -218,9 +217,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
|
|||
s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
|
||||
|
||||
/* start the frequency change */
|
||||
|
||||
if (policy)
|
||||
cpufreq_notify_transition(&freqs.freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* If hclk is staying the same, then we do not need to
|
||||
* re-write the IO or the refresh timings whilst we are changing
|
||||
|
@ -264,8 +261,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
|
|||
local_irq_restore(flags);
|
||||
|
||||
/* notify everyone we've done this */
|
||||
if (policy)
|
||||
cpufreq_notify_transition(&freqs.freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
s3c_freq_dbg("%s: finished\n", __func__);
|
||||
return 0;
|
||||
|
|
|
@ -4,7 +4,7 @@ menu "SA11x0 Implementations"
|
|||
|
||||
config SA1100_ASSABET
|
||||
bool "Assabet"
|
||||
select CPU_FREQ_SA1110
|
||||
select ARM_SA1110_CPUFREQ
|
||||
help
|
||||
Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
|
||||
Microprocessor Development Board (also known as the Assabet).
|
||||
|
@ -20,7 +20,7 @@ config ASSABET_NEPONSET
|
|||
|
||||
config SA1100_CERF
|
||||
bool "CerfBoard"
|
||||
select CPU_FREQ_SA1110
|
||||
select ARM_SA1110_CPUFREQ
|
||||
help
|
||||
The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
|
||||
More information is available at:
|
||||
|
@ -47,7 +47,7 @@ endchoice
|
|||
|
||||
config SA1100_COLLIE
|
||||
bool "Sharp Zaurus SL5500"
|
||||
# FIXME: select CPU_FREQ_SA11x0
|
||||
# FIXME: select ARM_SA11x0_CPUFREQ
|
||||
select SHARP_LOCOMO
|
||||
select SHARP_PARAM
|
||||
select SHARP_SCOOP
|
||||
|
@ -56,7 +56,7 @@ config SA1100_COLLIE
|
|||
|
||||
config SA1100_H3100
|
||||
bool "Compaq iPAQ H3100"
|
||||
select CPU_FREQ_SA1110
|
||||
select ARM_SA1110_CPUFREQ
|
||||
select HTC_EGPIO
|
||||
help
|
||||
Say Y here if you intend to run this kernel on the Compaq iPAQ
|
||||
|
@ -67,7 +67,7 @@ config SA1100_H3100
|
|||
|
||||
config SA1100_H3600
|
||||
bool "Compaq iPAQ H3600/H3700"
|
||||
select CPU_FREQ_SA1110
|
||||
select ARM_SA1110_CPUFREQ
|
||||
select HTC_EGPIO
|
||||
help
|
||||
Say Y here if you intend to run this kernel on the Compaq iPAQ
|
||||
|
@ -78,7 +78,7 @@ config SA1100_H3600
|
|||
|
||||
config SA1100_BADGE4
|
||||
bool "HP Labs BadgePAD 4"
|
||||
select CPU_FREQ_SA1100
|
||||
select ARM_SA1100_CPUFREQ
|
||||
select SA1111
|
||||
help
|
||||
Say Y here if you want to build a kernel for the HP Laboratories
|
||||
|
@ -86,7 +86,7 @@ config SA1100_BADGE4
|
|||
|
||||
config SA1100_JORNADA720
|
||||
bool "HP Jornada 720"
|
||||
# FIXME: select CPU_FREQ_SA11x0
|
||||
# FIXME: select ARM_SA11x0_CPUFREQ
|
||||
select SA1111
|
||||
help
|
||||
Say Y here if you want to build a kernel for the HP Jornada 720
|
||||
|
@ -105,14 +105,14 @@ config SA1100_JORNADA720_SSP
|
|||
|
||||
config SA1100_HACKKIT
|
||||
bool "HackKit Core CPU Board"
|
||||
select CPU_FREQ_SA1100
|
||||
select ARM_SA1100_CPUFREQ
|
||||
help
|
||||
Say Y here to support the HackKit Core CPU Board
|
||||
<http://hackkit.eletztrick.de>;
|
||||
|
||||
config SA1100_LART
|
||||
bool "LART"
|
||||
select CPU_FREQ_SA1100
|
||||
select ARM_SA1100_CPUFREQ
|
||||
help
|
||||
Say Y here if you are using the Linux Advanced Radio Terminal
|
||||
(also known as the LART). See <http://www.lartmaker.nl/> for
|
||||
|
@ -120,7 +120,7 @@ config SA1100_LART
|
|||
|
||||
config SA1100_NANOENGINE
|
||||
bool "nanoEngine"
|
||||
select CPU_FREQ_SA1110
|
||||
select ARM_SA1110_CPUFREQ
|
||||
select PCI
|
||||
select PCI_NANOENGINE
|
||||
help
|
||||
|
@ -130,7 +130,7 @@ config SA1100_NANOENGINE
|
|||
|
||||
config SA1100_PLEB
|
||||
bool "PLEB"
|
||||
select CPU_FREQ_SA1100
|
||||
select ARM_SA1100_CPUFREQ
|
||||
help
|
||||
Say Y here if you are using version 1 of the Portable Linux
|
||||
Embedded Board (also known as PLEB).
|
||||
|
@ -139,7 +139,7 @@ config SA1100_PLEB
|
|||
|
||||
config SA1100_SHANNON
|
||||
bool "Shannon"
|
||||
select CPU_FREQ_SA1100
|
||||
select ARM_SA1100_CPUFREQ
|
||||
help
|
||||
The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
|
||||
limited edition webphone produced by Philips. The Shannon is a SA1100
|
||||
|
@ -148,7 +148,7 @@ config SA1100_SHANNON
|
|||
|
||||
config SA1100_SIMPAD
|
||||
bool "Simpad"
|
||||
select CPU_FREQ_SA1110
|
||||
select ARM_SA1110_CPUFREQ
|
||||
help
|
||||
The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
|
||||
are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
|
||||
|
|
|
@ -8,9 +8,6 @@ obj-m :=
|
|||
obj-n :=
|
||||
obj- :=
|
||||
|
||||
obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o
|
||||
obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o
|
||||
|
||||
# Specific board support
|
||||
obj-$(CONFIG_SA1100_ASSABET) += assabet.o
|
||||
obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o
|
||||
|
|
1
arch/arm/mach-sa1100/include/mach/generic.h
Normal file
1
arch/arm/mach-sa1100/include/mach/generic.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../../generic.h"
|
|
@ -24,7 +24,6 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
|
|||
endif
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
|
||||
obj-$(CONFIG_TEGRA_PCI) += pcie.o
|
||||
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
|
||||
|
|
|
@ -250,20 +250,7 @@ config ARCH_SUSPEND_POSSIBLE
|
|||
def_bool y
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
config CPU_FREQ_AT32AP
|
||||
bool "CPU frequency driver for AT32AP"
|
||||
depends on CPU_FREQ && PLATFORM_AT32AP
|
||||
default n
|
||||
help
|
||||
This enables the CPU frequency driver for AT32AP processors.
|
||||
|
||||
For details, take a look in <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -28,7 +28,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -27,7 +27,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -23,7 +23,7 @@ CONFIG_CPU_FREQ=y
|
|||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -29,7 +29,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -28,7 +28,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -25,7 +25,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
@ -27,7 +27,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
|
|
|
@ -31,7 +31,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
|
|
|
@ -24,7 +24,7 @@ CONFIG_CPU_FREQ=y
|
|||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_AT32AP=y
|
||||
CONFIG_AVR32_AT32AP_CPUFREQ=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
obj-y += pdc.o clock.o intc.o extint.o pio.o hsmc.o
|
||||
obj-y += hmatrix.o
|
||||
obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o
|
||||
obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
|
||||
obj-$(CONFIG_PM) += pm.o
|
||||
|
||||
ifeq ($(CONFIG_PM_DEBUG),y)
|
||||
|
|
|
@ -10,7 +10,6 @@ obj-$(CONFIG_PM) += pm.o
|
|||
ifneq ($(CONFIG_BF60x),y)
|
||||
obj-$(CONFIG_PM) += dpmc_modes.o
|
||||
endif
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#
|
||||
|
||||
obj-y := dma.o pinmux.o io.o arbiter.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
|
||||
clean:
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#
|
||||
|
||||
obj-y := dma.o pinmux.o io.o arbiter.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
|
||||
clean:
|
||||
|
||||
|
|
|
@ -591,9 +591,9 @@ source "kernel/power/Kconfig"
|
|||
source "drivers/acpi/Kconfig"
|
||||
|
||||
if PM
|
||||
|
||||
source "arch/ia64/kernel/cpufreq/Kconfig"
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
endmenu
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -23,7 +23,6 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o
|
|||
obj-$(CONFIG_NUMA) += numa.o
|
||||
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
|
||||
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
#
|
||||
# CPU Frequency scaling
|
||||
#
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
if CPU_FREQ
|
||||
|
||||
comment "CPUFreq processor drivers"
|
||||
|
||||
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
|
||||
Processor Performance States.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endif # CPU_FREQ
|
||||
|
||||
endmenu
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
|
||||
|
|
@ -2538,7 +2538,14 @@ source "kernel/power/Kconfig"
|
|||
|
||||
endmenu
|
||||
|
||||
source "arch/mips/kernel/cpufreq/Kconfig"
|
||||
config MIPS_EXTERNAL_TIMER
|
||||
bool
|
||||
|
||||
if CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
|
||||
menu "CPU Power Management"
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
endmenu
|
||||
endif
|
||||
|
||||
source "net/Kconfig"
|
||||
|
||||
|
|
|
@ -92,8 +92,6 @@ CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/n
|
|||
|
||||
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
|
||||
|
||||
obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
|
||||
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
|
||||
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# CPU Frequency scaling
|
||||
#
|
||||
|
||||
config MIPS_EXTERNAL_TIMER
|
||||
bool
|
||||
|
||||
config MIPS_CPUFREQ
|
||||
bool
|
||||
default y
|
||||
depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
|
||||
|
||||
if MIPS_CPUFREQ
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
if CPU_FREQ
|
||||
|
||||
comment "CPUFreq processor drivers"
|
||||
|
||||
config LOONGSON2_CPUFREQ
|
||||
tristate "Loongson2 CPUFreq Driver"
|
||||
select CPU_FREQ_TABLE
|
||||
depends on MIPS_CPUFREQ
|
||||
help
|
||||
This option adds a CPUFreq driver for loongson processors which
|
||||
support software configurable cpu frequency.
|
||||
|
||||
Loongson2F and it's successors support this feature.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endif # CPU_FREQ
|
||||
|
||||
endmenu
|
||||
|
||||
endif # MIPS_CPUFREQ
|
|
@ -1,5 +0,0 @@
|
|||
#
|
||||
# Makefile for the Linux/MIPS cpufreq.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
|
|
@ -113,34 +113,10 @@ config CBE_THERM
|
|||
default m
|
||||
depends on CBE_RAS && SPU_BASE
|
||||
|
||||
config CBE_CPUFREQ
|
||||
tristate "CBE frequency scaling"
|
||||
depends on CBE_RAS && CPU_FREQ
|
||||
default m
|
||||
help
|
||||
This adds the cpufreq driver for Cell BE processors.
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
If you don't have such processor, say N
|
||||
|
||||
config CBE_CPUFREQ_PMI_ENABLE
|
||||
bool "CBE frequency scaling using PMI interface"
|
||||
depends on CBE_CPUFREQ
|
||||
default n
|
||||
help
|
||||
Select this, if you want to use the PMI interface
|
||||
to switch frequencies. Using PMI, the
|
||||
processor will not only be able to run at lower speed,
|
||||
but also at lower core voltage.
|
||||
|
||||
config CBE_CPUFREQ_PMI
|
||||
tristate
|
||||
depends on CBE_CPUFREQ_PMI_ENABLE
|
||||
default CBE_CPUFREQ
|
||||
|
||||
config PPC_PMI
|
||||
tristate
|
||||
default y
|
||||
depends on CBE_CPUFREQ_PMI || PPC_IBM_CELL_POWERBUTTON
|
||||
depends on CPU_FREQ_CBE_PMI || PPC_IBM_CELL_POWERBUTTON
|
||||
help
|
||||
PMI (Platform Management Interrupt) is a way to
|
||||
communicate with the BMC (Baseboard Management Controller).
|
||||
|
|
|
@ -5,9 +5,6 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += iommu.o setup.o spider-pic.o \
|
|||
obj-$(CONFIG_CBE_RAS) += ras.o
|
||||
|
||||
obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
|
||||
obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o
|
||||
obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o
|
||||
cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o
|
||||
obj-$(CONFIG_CBE_CPUFREQ_SPU_GOVERNOR) += cpufreq_spudemand.o
|
||||
|
||||
obj-$(CONFIG_PPC_IBM_CELL_POWERBUTTON) += cbe_powerbutton.o
|
||||
|
|
|
@ -273,10 +273,9 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = pas_freqs[pas_astate_new].frequency;
|
||||
freqs.cpu = policy->cpu;
|
||||
|
||||
mutex_lock(&pas_switch_mutex);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
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,
|
||||
|
@ -288,7 +287,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
|
|||
for_each_online_cpu(i)
|
||||
set_astate(i, pas_astate_new);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
mutex_unlock(&pas_switch_mutex);
|
||||
|
||||
ppc_proc_freq = freqs.new * 1000ul;
|
||||
|
|
|
@ -335,7 +335,8 @@ static int pmu_set_cpu_speed(int low_speed)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_cpu_speed(int speed_mode, int notify)
|
||||
static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode,
|
||||
int notify)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long l3cr;
|
||||
|
@ -343,13 +344,12 @@ static int do_set_cpu_speed(int speed_mode, int notify)
|
|||
|
||||
freqs.old = cur_freq;
|
||||
freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
|
||||
freqs.cpu = smp_processor_id();
|
||||
|
||||
if (freqs.old == freqs.new)
|
||||
return 0;
|
||||
|
||||
if (notify)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
if (speed_mode == CPUFREQ_LOW &&
|
||||
cpu_has_feature(CPU_FTR_L3CR)) {
|
||||
l3cr = _get_L3CR();
|
||||
|
@ -366,7 +366,7 @@ static int do_set_cpu_speed(int speed_mode, int notify)
|
|||
_set_L3CR(prev_l3cr);
|
||||
}
|
||||
if (notify)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
|
||||
|
||||
return 0;
|
||||
|
@ -393,7 +393,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
|
|||
target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
rc = do_set_cpu_speed(newstate, 1);
|
||||
rc = do_set_cpu_speed(policy, newstate, 1);
|
||||
|
||||
ppc_proc_freq = cur_freq * 1000ul;
|
||||
return rc;
|
||||
|
@ -442,7 +442,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(CPUFREQ_HIGH, 0);
|
||||
do_set_cpu_speed(policy, CPUFREQ_HIGH, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -458,7 +458,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
|
|||
* is that we force a switch to whatever it was, which is
|
||||
* probably high speed due to our suspend() routine
|
||||
*/
|
||||
do_set_cpu_speed(sleep_freq == low_freq ?
|
||||
do_set_cpu_speed(policy, sleep_freq == low_freq ?
|
||||
CPUFREQ_LOW : CPUFREQ_HIGH, 0);
|
||||
|
||||
ppc_proc_freq = cur_freq * 1000ul;
|
||||
|
|
|
@ -339,11 +339,10 @@ static int g5_cpufreq_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
|
||||
freqs.new = g5_cpu_freqs[newstate].frequency;
|
||||
freqs.cpu = 0;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
rc = g5_switch_freq(newstate);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
mutex_unlock(&g5_switch_mutex);
|
||||
|
||||
|
|
|
@ -624,25 +624,7 @@ config SH_CLK_CPG_LEGACY
|
|||
endmenu
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
config SH_CPU_FREQ
|
||||
tristate "SuperH CPU Frequency driver"
|
||||
depends on CPU_FREQ
|
||||
select CPU_FREQ_TABLE
|
||||
help
|
||||
This adds the cpufreq driver for SuperH. Any CPU that supports
|
||||
clock rate rounding through the clock framework can use this
|
||||
driver. While it will make the kernel slightly larger, this is
|
||||
harmless for CPUs that don't support rate rounding. The driver
|
||||
will also generate a notice in the boot log before disabling
|
||||
itself if the CPU in question is not capable of rate rounding.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endmenu
|
||||
|
||||
source "arch/sh/drivers/Kconfig"
|
||||
|
|
|
@ -31,7 +31,6 @@ obj-$(CONFIG_VSYSCALL) += vsyscall/
|
|||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
|
||||
obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
|
|
|
@ -254,29 +254,6 @@ config HOTPLUG_CPU
|
|||
|
||||
if SPARC64
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
config US3_FREQ
|
||||
tristate "UltraSPARC-III CPU Frequency driver"
|
||||
depends on CPU_FREQ
|
||||
select CPU_FREQ_TABLE
|
||||
help
|
||||
This adds the CPUFreq driver for UltraSPARC-III processors.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config US2E_FREQ
|
||||
tristate "UltraSPARC-IIe CPU Frequency driver"
|
||||
depends on CPU_FREQ
|
||||
select CPU_FREQ_TABLE
|
||||
help
|
||||
This adds the CPUFreq driver for UltraSPARC-IIe processors.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endif
|
||||
|
||||
config US3_MC
|
||||
|
|
|
@ -102,9 +102,6 @@ obj-$(CONFIG_PCI_MSI) += pci_msi.o
|
|||
|
||||
obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
|
||||
|
||||
# sparc64 cpufreq
|
||||
obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
|
||||
obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
|
||||
obj-$(CONFIG_US3_MC) += chmc.o
|
||||
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
|
|
|
@ -9,7 +9,6 @@ obj-y += setup.o signal.o sys.o stacktrace.o traps.o
|
|||
obj-$(CONFIG_MODULES) += ksyms.o module.o
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
|
||||
obj-$(CONFIG_CPU_FREQ) += cpu-ucv2.o
|
||||
obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
|
||||
|
||||
# obj-y for architecture PKUnity v3
|
||||
|
|
|
@ -182,6 +182,7 @@
|
|||
#define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */
|
||||
#define X86_FEATURE_DTHERM (7*32+ 7) /* Digital Thermal Sensor */
|
||||
#define X86_FEATURE_HW_PSTATE (7*32+ 8) /* AMD HW-PState */
|
||||
#define X86_FEATURE_PROC_FEEDBACK (7*32+ 9) /* AMD ProcFeedbackInterface */
|
||||
|
||||
/* Virtualization flags: Linux defined, word 8 */
|
||||
#define X86_FEATURE_TPR_SHADOW (8*32+ 0) /* Intel TPR Shadow */
|
||||
|
|
|
@ -39,8 +39,9 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
|
|||
{ X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
|
||||
{ X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
|
||||
{ X86_FEATURE_XSAVEOPT, CR_EAX, 0, 0x0000000d, 1 },
|
||||
{ X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
|
||||
{ X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 },
|
||||
{ X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
|
||||
{ X86_FEATURE_PROC_FEEDBACK, CR_EDX,11, 0x80000007, 0 },
|
||||
{ X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a, 0 },
|
||||
{ X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a, 0 },
|
||||
{ X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a, 0 },
|
||||
|
|
|
@ -205,10 +205,99 @@ depends on ARM
|
|||
source "drivers/cpufreq/Kconfig.arm"
|
||||
endmenu
|
||||
|
||||
menu "AVR32 CPU frequency scaling drivers"
|
||||
depends on AVR32
|
||||
|
||||
config AVR32_AT32AP_CPUFREQ
|
||||
bool "CPU frequency driver for AT32AP"
|
||||
depends on PLATFORM_AT32AP
|
||||
default n
|
||||
help
|
||||
This enables the CPU frequency driver for AT32AP processors.
|
||||
If in doubt, say N.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "CPUFreq processor drivers"
|
||||
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
|
||||
Processor Performance States.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "MIPS CPUFreq processor drivers"
|
||||
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.
|
||||
|
||||
Loongson2F and it's successors support this feature.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "PowerPC CPU frequency scaling drivers"
|
||||
depends on PPC32 || PPC64
|
||||
source "drivers/cpufreq/Kconfig.powerpc"
|
||||
endmenu
|
||||
|
||||
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.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config SPARC_US2E_CPUFREQ
|
||||
tristate "UltraSPARC-IIe CPU Frequency driver"
|
||||
select CPU_FREQ_TABLE
|
||||
help
|
||||
This adds the CPUFreq driver for UltraSPARC-IIe processors.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
endmenu
|
||||
|
||||
menu "SH CPU Frequency scaling"
|
||||
depends on SUPERH
|
||||
config SH_CPU_FREQ
|
||||
tristate "SuperH CPU Frequency driver"
|
||||
select CPU_FREQ_TABLE
|
||||
help
|
||||
This adds the cpufreq driver for SuperH. Any CPU that supports
|
||||
clock rate rounding through the clock framework can use this
|
||||
driver. While it will make the kernel slightly larger, this is
|
||||
harmless for CPUs that don't support rate rounding. The driver
|
||||
will also generate a notice in the boot log before disabling
|
||||
itself if the CPU in question is not capable of rate rounding.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If unsure, say N.
|
||||
endmenu
|
||||
|
||||
endif
|
||||
endmenu
|
||||
|
|
|
@ -2,6 +2,93 @@
|
|||
# ARM CPU Frequency scaling drivers
|
||||
#
|
||||
|
||||
config ARM_BIG_LITTLE_CPUFREQ
|
||||
tristate
|
||||
depends on ARM_CPU_TOPOLOGY
|
||||
|
||||
config ARM_DT_BL_CPUFREQ
|
||||
tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
|
||||
select ARM_BIG_LITTLE_CPUFREQ
|
||||
depends on OF && HAVE_CLK
|
||||
help
|
||||
This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
|
||||
This gets frequency tables from DT.
|
||||
|
||||
config ARM_EXYNOS_CPUFREQ
|
||||
bool "SAMSUNG EXYNOS SoCs"
|
||||
depends on ARCH_EXYNOS
|
||||
default y
|
||||
help
|
||||
This adds the CPUFreq driver common part for Samsung
|
||||
EXYNOS SoCs.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_EXYNOS4210_CPUFREQ
|
||||
def_bool CPU_EXYNOS4210
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS4210
|
||||
SoC (S5PV310 or S5PC210).
|
||||
|
||||
config ARM_EXYNOS4X12_CPUFREQ
|
||||
def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS4X12
|
||||
SoC (EXYNOS4212 or EXYNOS4412).
|
||||
|
||||
config ARM_EXYNOS5250_CPUFREQ
|
||||
def_bool SOC_EXYNOS5250
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS5250
|
||||
SoC.
|
||||
|
||||
config ARM_EXYNOS5440_CPUFREQ
|
||||
def_bool SOC_EXYNOS5440
|
||||
depends on HAVE_CLK && PM_OPP && OF
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS5440
|
||||
SoC. The nature of exynos5440 clock controller is
|
||||
different than previous exynos controllers so not using
|
||||
the common exynos framework.
|
||||
|
||||
config ARM_HIGHBANK_CPUFREQ
|
||||
tristate "Calxeda Highbank-based"
|
||||
depends on ARCH_HIGHBANK
|
||||
select CPU_FREQ_TABLE
|
||||
select GENERIC_CPUFREQ_CPU0
|
||||
select PM_OPP
|
||||
select REGULATOR
|
||||
|
||||
default m
|
||||
help
|
||||
This adds the CPUFreq driver for Calxeda Highbank SoC
|
||||
based boards.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_IMX6Q_CPUFREQ
|
||||
tristate "Freescale i.MX6Q cpufreq support"
|
||||
depends on SOC_IMX6Q
|
||||
depends on REGULATOR_ANATOP
|
||||
help
|
||||
This adds cpufreq driver support for Freescale i.MX6Q SOC.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_INTEGRATOR
|
||||
tristate "CPUfreq driver for ARM Integrator CPUs"
|
||||
depends on ARCH_INTEGRATOR
|
||||
default y
|
||||
help
|
||||
This enables the CPUfreq driver for ARM Integrator CPUs.
|
||||
If in doubt, say Y.
|
||||
|
||||
config ARM_KIRKWOOD_CPUFREQ
|
||||
def_bool ARCH_KIRKWOOD && OF
|
||||
help
|
||||
This adds the CPUFreq driver for Marvell Kirkwood
|
||||
SoCs.
|
||||
|
||||
config ARM_OMAP2PLUS_CPUFREQ
|
||||
bool "TI OMAP2+"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
|
@ -42,6 +129,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
|
||||
|
@ -49,48 +137,11 @@ config ARM_S5PV210_CPUFREQ
|
|||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_EXYNOS_CPUFREQ
|
||||
bool "SAMSUNG EXYNOS SoCs"
|
||||
depends on ARCH_EXYNOS
|
||||
default y
|
||||
help
|
||||
This adds the CPUFreq driver common part for Samsung
|
||||
EXYNOS SoCs.
|
||||
config ARM_SA1100_CPUFREQ
|
||||
bool
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_EXYNOS4210_CPUFREQ
|
||||
def_bool CPU_EXYNOS4210
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS4210
|
||||
SoC (S5PV310 or S5PC210).
|
||||
|
||||
config ARM_EXYNOS4X12_CPUFREQ
|
||||
def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS4X12
|
||||
SoC (EXYNOS4212 or EXYNOS4412).
|
||||
|
||||
config ARM_EXYNOS5250_CPUFREQ
|
||||
def_bool SOC_EXYNOS5250
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS5250
|
||||
SoC.
|
||||
|
||||
config ARM_KIRKWOOD_CPUFREQ
|
||||
def_bool ARCH_KIRKWOOD && OF
|
||||
help
|
||||
This adds the CPUFreq driver for Marvell Kirkwood
|
||||
SoCs.
|
||||
|
||||
config ARM_IMX6Q_CPUFREQ
|
||||
tristate "Freescale i.MX6Q cpufreq support"
|
||||
depends on SOC_IMX6Q
|
||||
depends on REGULATOR_ANATOP
|
||||
help
|
||||
This adds cpufreq driver support for Freescale i.MX6Q SOC.
|
||||
|
||||
If in doubt, say N.
|
||||
config ARM_SA1110_CPUFREQ
|
||||
bool
|
||||
|
||||
config ARM_SPEAR_CPUFREQ
|
||||
bool "SPEAr CPUFreq support"
|
||||
|
@ -98,18 +149,3 @@ config ARM_SPEAR_CPUFREQ
|
|||
default y
|
||||
help
|
||||
This adds the CPUFreq driver support for SPEAr SOCs.
|
||||
|
||||
config ARM_HIGHBANK_CPUFREQ
|
||||
tristate "Calxeda Highbank-based"
|
||||
depends on ARCH_HIGHBANK
|
||||
select CPU_FREQ_TABLE
|
||||
select GENERIC_CPUFREQ_CPU0
|
||||
select PM_OPP
|
||||
select REGULATOR
|
||||
|
||||
default m
|
||||
help
|
||||
This adds the CPUFreq driver for Calxeda Highbank SoC
|
||||
based boards.
|
||||
|
||||
If in doubt, say N.
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
config CPU_FREQ_CBE
|
||||
tristate "CBE frequency scaling"
|
||||
depends on CBE_RAS && PPC_CELL
|
||||
default m
|
||||
help
|
||||
This adds the cpufreq driver for Cell BE processors.
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
If you don't have such processor, say N
|
||||
|
||||
config CPU_FREQ_CBE_PMI
|
||||
bool "CBE frequency scaling using PMI interface"
|
||||
depends on CPU_FREQ_CBE
|
||||
default n
|
||||
help
|
||||
Select this, if you want to use the PMI interface to switch
|
||||
frequencies. Using PMI, the processor will not only be able to run at
|
||||
lower speed, but also at lower core voltage.
|
||||
|
||||
config CPU_FREQ_MAPLE
|
||||
bool "Support for Maple 970FX Evaluation Board"
|
||||
depends on PPC_MAPLE
|
||||
|
|
|
@ -129,6 +129,23 @@ config X86_POWERNOW_K8
|
|||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
config X86_AMD_FREQ_SENSITIVITY
|
||||
tristate "AMD frequency sensitivity feedback powersave bias"
|
||||
depends on CPU_FREQ_GOV_ONDEMAND && X86_ACPI_CPUFREQ && CPU_SUP_AMD
|
||||
help
|
||||
This adds AMD-specific powersave bias function to the ondemand
|
||||
governor, which allows it to make more power-conscious frequency
|
||||
change decisions based on feedback from hardware (availble on AMD
|
||||
Family 16h and above).
|
||||
|
||||
Hardware feedback tells software how "sensitive" to frequency changes
|
||||
the CPUs' workloads are. CPU-bound workloads will be more sensitive
|
||||
-- they will perform better as frequency increases. Memory/IO-bound
|
||||
workloads will be less sensitive -- they will not necessarily perform
|
||||
better as frequency increases.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config X86_GX_SUSPMOD
|
||||
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
|
||||
depends on X86_32 && PCI
|
||||
|
|
|
@ -41,23 +41,54 @@ obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
|
|||
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
|
||||
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
|
||||
obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o
|
||||
obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o
|
||||
|
||||
##################################################################################
|
||||
# ARM SoC drivers
|
||||
obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
|
||||
# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
|
||||
# LITTLE drivers, so that it is probed last.
|
||||
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
|
||||
|
||||
obj-$(CONFIG_ARCH_DAVINCI_DA850) += davinci-cpufreq.o
|
||||
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
|
||||
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
|
||||
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
|
||||
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
|
||||
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
|
||||
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
|
||||
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
|
||||
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
|
||||
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
|
||||
obj-$(CONFIG_PXA25x) += pxa2xx-cpufreq.o
|
||||
obj-$(CONFIG_PXA27x) += pxa2xx-cpufreq.o
|
||||
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
|
||||
obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
|
||||
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_ARCH_TEGRA) += tegra-cpufreq.o
|
||||
|
||||
##################################################################################
|
||||
# PowerPC platform drivers
|
||||
obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o
|
||||
ppc-cbe-cpufreq-y += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
|
||||
obj-$(CONFIG_CPU_FREQ_CBE_PMI) += ppc_cbe_cpufreq_pmi.o
|
||||
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
|
||||
|
||||
##################################################################################
|
||||
# Other platform drivers
|
||||
obj-$(CONFIG_AVR32_AT32AP_CPUFREQ) += at32ap-cpufreq.o
|
||||
obj-$(CONFIG_BLACKFIN) += blackfin-cpufreq.o
|
||||
obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o
|
||||
obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o
|
||||
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o
|
||||
obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
|
||||
obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o
|
||||
obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o
|
||||
obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o
|
||||
obj-$(CONFIG_UNICORE32) += unicore2-cpufreq.o
|
||||
|
|
|
@ -423,7 +423,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
|
|||
struct drv_cmd cmd;
|
||||
unsigned int next_state = 0; /* Index into freq_table */
|
||||
unsigned int next_perf_state = 0; /* Index into perf table */
|
||||
unsigned int i;
|
||||
int result = 0;
|
||||
|
||||
pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
|
||||
|
@ -486,10 +485,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = perf->states[perf->state].core_frequency * 1000;
|
||||
freqs.new = data->freq_table[next_state].frequency;
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
drv_write(&cmd);
|
||||
|
||||
|
@ -502,10 +498,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
|
|||
}
|
||||
}
|
||||
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
perf->state = next_perf_state;
|
||||
|
||||
out:
|
||||
|
|
148
drivers/cpufreq/amd_freq_sensitivity.c
Normal file
148
drivers/cpufreq/amd_freq_sensitivity.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* amd_freq_sensitivity.c: AMD frequency sensitivity feedback powersave bias
|
||||
* for the ondemand governor.
|
||||
*
|
||||
* Copyright (C) 2013 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Author: Jacob Shin <jacob.shin@amd.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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/percpu-defs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#include "cpufreq_governor.h"
|
||||
|
||||
#define MSR_AMD64_FREQ_SENSITIVITY_ACTUAL 0xc0010080
|
||||
#define MSR_AMD64_FREQ_SENSITIVITY_REFERENCE 0xc0010081
|
||||
#define CLASS_CODE_SHIFT 56
|
||||
#define POWERSAVE_BIAS_MAX 1000
|
||||
#define POWERSAVE_BIAS_DEF 400
|
||||
|
||||
struct cpu_data_t {
|
||||
u64 actual;
|
||||
u64 reference;
|
||||
unsigned int freq_prev;
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct cpu_data_t, cpu_data);
|
||||
|
||||
static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
|
||||
unsigned int freq_next,
|
||||
unsigned int relation)
|
||||
{
|
||||
int sensitivity;
|
||||
long d_actual, d_reference;
|
||||
struct msr actual, reference;
|
||||
struct cpu_data_t *data = &per_cpu(cpu_data, policy->cpu);
|
||||
struct dbs_data *od_data = policy->governor_data;
|
||||
struct od_dbs_tuners *od_tuners = od_data->tuners;
|
||||
struct od_cpu_dbs_info_s *od_info =
|
||||
od_data->cdata->get_cpu_dbs_info_s(policy->cpu);
|
||||
|
||||
if (!od_info->freq_table)
|
||||
return freq_next;
|
||||
|
||||
rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_ACTUAL,
|
||||
&actual.l, &actual.h);
|
||||
rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_REFERENCE,
|
||||
&reference.l, &reference.h);
|
||||
actual.h &= 0x00ffffff;
|
||||
reference.h &= 0x00ffffff;
|
||||
|
||||
/* counter wrapped around, so stay on current frequency */
|
||||
if (actual.q < data->actual || reference.q < data->reference) {
|
||||
freq_next = policy->cur;
|
||||
goto out;
|
||||
}
|
||||
|
||||
d_actual = actual.q - data->actual;
|
||||
d_reference = reference.q - data->reference;
|
||||
|
||||
/* divide by 0, so stay on current frequency as well */
|
||||
if (d_reference == 0) {
|
||||
freq_next = policy->cur;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sensitivity = POWERSAVE_BIAS_MAX -
|
||||
(POWERSAVE_BIAS_MAX * (d_reference - d_actual) / d_reference);
|
||||
|
||||
clamp(sensitivity, 0, POWERSAVE_BIAS_MAX);
|
||||
|
||||
/* this workload is not CPU bound, so choose a lower freq */
|
||||
if (sensitivity < od_tuners->powersave_bias) {
|
||||
if (data->freq_prev == policy->cur)
|
||||
freq_next = policy->cur;
|
||||
|
||||
if (freq_next > policy->cur)
|
||||
freq_next = policy->cur;
|
||||
else if (freq_next < policy->cur)
|
||||
freq_next = policy->min;
|
||||
else {
|
||||
unsigned int index;
|
||||
|
||||
cpufreq_frequency_table_target(policy,
|
||||
od_info->freq_table, policy->cur - 1,
|
||||
CPUFREQ_RELATION_H, &index);
|
||||
freq_next = od_info->freq_table[index].frequency;
|
||||
}
|
||||
|
||||
data->freq_prev = freq_next;
|
||||
} else
|
||||
data->freq_prev = 0;
|
||||
|
||||
out:
|
||||
data->actual = actual.q;
|
||||
data->reference = reference.q;
|
||||
return freq_next;
|
||||
}
|
||||
|
||||
static int __init amd_freq_sensitivity_init(void)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
|
||||
return -ENODEV;
|
||||
|
||||
if (!static_cpu_has(X86_FEATURE_PROC_FEEDBACK))
|
||||
return -ENODEV;
|
||||
|
||||
if (rdmsrl_safe(MSR_AMD64_FREQ_SENSITIVITY_ACTUAL, &val))
|
||||
return -ENODEV;
|
||||
|
||||
if (!(val >> CLASS_CODE_SHIFT))
|
||||
return -ENODEV;
|
||||
|
||||
od_register_powersave_bias_handler(amd_powersave_bias_target,
|
||||
POWERSAVE_BIAS_DEF);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(amd_freq_sensitivity_init);
|
||||
|
||||
static void __exit amd_freq_sensitivity_exit(void)
|
||||
{
|
||||
od_unregister_powersave_bias_handler();
|
||||
}
|
||||
module_exit(amd_freq_sensitivity_exit);
|
||||
|
||||
static const struct x86_cpu_id amd_freq_sensitivity_ids[] = {
|
||||
X86_FEATURE_MATCH(X86_FEATURE_PROC_FEEDBACK),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, amd_freq_sensitivity_ids);
|
||||
|
||||
MODULE_AUTHOR("Jacob Shin <jacob.shin@amd.com>");
|
||||
MODULE_DESCRIPTION("AMD frequency sensitivity feedback powersave bias for "
|
||||
"the ondemand governor.");
|
||||
MODULE_LICENSE("GPL");
|
278
drivers/cpufreq/arm_big_little.c
Normal file
278
drivers/cpufreq/arm_big_little.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* ARM big.LITTLE Platforms CPUFreq support
|
||||
*
|
||||
* Copyright (C) 2013 ARM Ltd.
|
||||
* Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
|
||||
*
|
||||
* Copyright (C) 2013 Linaro.
|
||||
* Viresh Kumar <viresh.kumar@linaro.org>
|
||||
*
|
||||
* 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/clk.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "arm_big_little.h"
|
||||
|
||||
/* Currently we support only two clusters */
|
||||
#define MAX_CLUSTERS 2
|
||||
|
||||
static struct cpufreq_arm_bL_ops *arm_bL_ops;
|
||||
static struct clk *clk[MAX_CLUSTERS];
|
||||
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
|
||||
static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
|
||||
|
||||
static int cpu_to_cluster(int cpu)
|
||||
{
|
||||
return topology_physical_package_id(cpu);
|
||||
}
|
||||
|
||||
static unsigned int bL_cpufreq_get(unsigned int cpu)
|
||||
{
|
||||
u32 cur_cluster = cpu_to_cluster(cpu);
|
||||
|
||||
return clk_get_rate(clk[cur_cluster]) / 1000;
|
||||
}
|
||||
|
||||
/* Validate policy frequency range */
|
||||
static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
u32 cur_cluster = cpu_to_cluster(policy->cpu);
|
||||
|
||||
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 target_freq, unsigned int relation)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
|
||||
int ret = 0;
|
||||
|
||||
cur_cluster = cpu_to_cluster(policy->cpu);
|
||||
|
||||
freqs.old = bL_cpufreq_get(policy->cpu);
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
|
||||
if (freqs.old == freqs.new)
|
||||
return 0;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
|
||||
if (ret) {
|
||||
pr_err("clk_set_rate failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
policy->cur = freqs.new;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
|
||||
{
|
||||
u32 cluster = cpu_to_cluster(cpu_dev->id);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
|
||||
{
|
||||
u32 cluster = cpu_to_cluster(cpu_dev->id);
|
||||
char name[14] = "cpu-cluster.";
|
||||
int ret;
|
||||
|
||||
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 atomic_dec;
|
||||
}
|
||||
|
||||
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 atomic_dec;
|
||||
}
|
||||
|
||||
name[12] = cluster + '0';
|
||||
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],
|
||||
cluster);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
|
||||
__func__, cpu_dev->id, cluster);
|
||||
ret = PTR_ERR(clk[cluster]);
|
||||
opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
|
||||
|
||||
atomic_dec:
|
||||
atomic_dec(&cluster_usage[cluster]);
|
||||
dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
|
||||
cluster);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Per-CPU initialization */
|
||||
static int bL_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
u32 cur_cluster = cpu_to_cluster(policy->cpu);
|
||||
struct device *cpu_dev;
|
||||
int ret;
|
||||
|
||||
cpu_dev = get_cpu_device(policy->cpu);
|
||||
if (!cpu_dev) {
|
||||
pr_err("%s: failed to get cpu%d device\n", __func__,
|
||||
policy->cpu);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = get_cluster_clk_and_freq_table(cpu_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
put_cluster_clk_and_freq_table(cpu_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
|
||||
|
||||
if (arm_bL_ops->get_transition_latency)
|
||||
policy->cpuinfo.transition_latency =
|
||||
arm_bL_ops->get_transition_latency(cpu_dev);
|
||||
else
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
|
||||
policy->cur = bL_cpufreq_get(policy->cpu);
|
||||
|
||||
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
|
||||
|
||||
dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bL_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct device *cpu_dev;
|
||||
|
||||
cpu_dev = get_cpu_device(policy->cpu);
|
||||
if (!cpu_dev) {
|
||||
pr_err("%s: failed to get cpu%d device\n", __func__,
|
||||
policy->cpu);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
put_cluster_clk_and_freq_table(cpu_dev);
|
||||
dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Export freq_table to sysfs */
|
||||
static struct freq_attr *bL_cpufreq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct cpufreq_driver bL_cpufreq_driver = {
|
||||
.name = "arm-big-little",
|
||||
.flags = CPUFREQ_STICKY,
|
||||
.verify = bL_cpufreq_verify_policy,
|
||||
.target = bL_cpufreq_set_target,
|
||||
.get = bL_cpufreq_get,
|
||||
.init = bL_cpufreq_init,
|
||||
.exit = bL_cpufreq_exit,
|
||||
.have_governor_per_policy = true,
|
||||
.attr = bL_cpufreq_attr,
|
||||
};
|
||||
|
||||
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (arm_bL_ops) {
|
||||
pr_debug("%s: Already registered: %s, exiting\n", __func__,
|
||||
arm_bL_ops->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!ops || !strlen(ops->name) || !ops->init_opp_table) {
|
||||
pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
arm_bL_ops = ops;
|
||||
|
||||
ret = cpufreq_register_driver(&bL_cpufreq_driver);
|
||||
if (ret) {
|
||||
pr_info("%s: Failed registering platform driver: %s, err: %d\n",
|
||||
__func__, ops->name, ret);
|
||||
arm_bL_ops = NULL;
|
||||
} else {
|
||||
pr_info("%s: Registered platform driver: %s\n", __func__,
|
||||
ops->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bL_cpufreq_register);
|
||||
|
||||
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
|
||||
{
|
||||
if (arm_bL_ops != ops) {
|
||||
pr_err("%s: Registered with: %s, can't unregister, exiting\n",
|
||||
__func__, arm_bL_ops->name);
|
||||
return;
|
||||
}
|
||||
|
||||
cpufreq_unregister_driver(&bL_cpufreq_driver);
|
||||
pr_info("%s: Un-registered platform driver: %s\n", __func__,
|
||||
arm_bL_ops->name);
|
||||
arm_bL_ops = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
|
40
drivers/cpufreq/arm_big_little.h
Normal file
40
drivers/cpufreq/arm_big_little.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ARM big.LITTLE platform's CPUFreq header file
|
||||
*
|
||||
* Copyright (C) 2013 ARM Ltd.
|
||||
* Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
|
||||
*
|
||||
* Copyright (C) 2013 Linaro.
|
||||
* Viresh Kumar <viresh.kumar@linaro.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef CPUFREQ_ARM_BIG_LITTLE_H
|
||||
#define CPUFREQ_ARM_BIG_LITTLE_H
|
||||
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct cpufreq_arm_bL_ops {
|
||||
char name[CPUFREQ_NAME_LEN];
|
||||
int (*get_transition_latency)(struct device *cpu_dev);
|
||||
|
||||
/*
|
||||
* This must set opp table for cpu_dev in a similar way as done by
|
||||
* of_init_opp_table().
|
||||
*/
|
||||
int (*init_opp_table)(struct device *cpu_dev);
|
||||
};
|
||||
|
||||
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
|
||||
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
|
||||
|
||||
#endif /* CPUFREQ_ARM_BIG_LITTLE_H */
|
107
drivers/cpufreq/arm_big_little_dt.c
Normal file
107
drivers/cpufreq/arm_big_little_dt.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Generic big.LITTLE CPUFreq Interface driver
|
||||
*
|
||||
* It provides necessary ops to arm_big_little cpufreq driver and gets
|
||||
* Frequency information from Device Tree. Freq table in DT must be in KHz.
|
||||
*
|
||||
* Copyright (C) 2013 Linaro.
|
||||
* Viresh Kumar <viresh.kumar@linaro.org>
|
||||
*
|
||||
* 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/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include "arm_big_little.h"
|
||||
|
||||
static int dt_init_opp_table(struct device *cpu_dev)
|
||||
{
|
||||
struct device_node *np, *parent;
|
||||
int count = 0, ret;
|
||||
|
||||
parent = of_find_node_by_path("/cpus");
|
||||
if (!parent) {
|
||||
pr_err("failed to find OF /cpus\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for_each_child_of_node(parent, np) {
|
||||
if (count++ != cpu_dev->id)
|
||||
continue;
|
||||
if (!of_get_property(np, "operating-points", NULL)) {
|
||||
ret = -ENODATA;
|
||||
} else {
|
||||
cpu_dev->of_node = np;
|
||||
ret = of_init_opp_table(cpu_dev);
|
||||
}
|
||||
of_node_put(np);
|
||||
of_node_put(parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int dt_get_transition_latency(struct device *cpu_dev)
|
||||
{
|
||||
struct device_node *np, *parent;
|
||||
u32 transition_latency = CPUFREQ_ETERNAL;
|
||||
int count = 0;
|
||||
|
||||
parent = of_find_node_by_path("/cpus");
|
||||
if (!parent) {
|
||||
pr_err("failed to find OF /cpus\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for_each_child_of_node(parent, np) {
|
||||
if (count++ != cpu_dev->id)
|
||||
continue;
|
||||
|
||||
of_property_read_u32(np, "clock-latency", &transition_latency);
|
||||
of_node_put(np);
|
||||
of_node_put(parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct cpufreq_arm_bL_ops dt_bL_ops = {
|
||||
.name = "dt-bl",
|
||||
.get_transition_latency = dt_get_transition_latency,
|
||||
.init_opp_table = dt_init_opp_table,
|
||||
};
|
||||
|
||||
static int generic_bL_init(void)
|
||||
{
|
||||
return bL_cpufreq_register(&dt_bL_ops);
|
||||
}
|
||||
module_init(generic_bL_init);
|
||||
|
||||
static void generic_bL_exit(void)
|
||||
{
|
||||
return bL_cpufreq_unregister(&dt_bL_ops);
|
||||
}
|
||||
module_exit(generic_bL_exit);
|
||||
|
||||
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
|
||||
MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -61,7 +61,6 @@ static int at32_set_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = at32_get_speed(0);
|
||||
freqs.new = (freq + 500) / 1000;
|
||||
freqs.cpu = 0;
|
||||
freqs.flags = 0;
|
||||
|
||||
if (!ref_freq) {
|
||||
|
@ -69,7 +68,7 @@ static int at32_set_target(struct cpufreq_policy *policy,
|
|||
loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
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, freqs.new);
|
||||
|
@ -77,7 +76,7 @@ static int at32_set_target(struct cpufreq_policy *policy,
|
|||
if (freqs.new < freqs.old)
|
||||
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
|
||||
loops_per_jiffy_ref, ref_freq, freqs.new);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
pr_debug("cpufreq: set frequency %lu Hz\n", freq);
|
||||
|
|
@ -127,13 +127,13 @@ unsigned long cpu_set_cclk(int cpu, unsigned long new)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int bfin_target(struct cpufreq_policy *poli,
|
||||
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, cpu;
|
||||
unsigned int index;
|
||||
unsigned long cclk_hz;
|
||||
struct cpufreq_freqs freqs;
|
||||
static unsigned long lpj_ref;
|
||||
|
@ -144,59 +144,48 @@ static int bfin_target(struct cpufreq_policy *poli,
|
|||
cycles_t cycles;
|
||||
#endif
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
||||
if (cpufreq_frequency_table_target(policy, bfin_freq_table, target_freq,
|
||||
relation, &index))
|
||||
return -EINVAL;
|
||||
|
||||
if (!policy)
|
||||
continue;
|
||||
cclk_hz = bfin_freq_table[index].frequency;
|
||||
|
||||
if (cpufreq_frequency_table_target(policy, bfin_freq_table,
|
||||
target_freq, relation, &index))
|
||||
return -EINVAL;
|
||||
freqs.old = bfin_getfreq_khz(0);
|
||||
freqs.new = cclk_hz;
|
||||
|
||||
cclk_hz = bfin_freq_table[index].frequency;
|
||||
pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
|
||||
cclk_hz, target_freq, freqs.old);
|
||||
|
||||
freqs.old = bfin_getfreq_khz(0);
|
||||
freqs.new = cclk_hz;
|
||||
freqs.cpu = cpu;
|
||||
|
||||
pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
|
||||
cclk_hz, target_freq, freqs.old);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
if (cpu == CPUFREQ_CPU) {
|
||||
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);
|
||||
plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
|
||||
bfin_write_PLL_DIV(plldiv);
|
||||
#else
|
||||
ret = cpu_set_cclk(cpu, freqs.new * 1000);
|
||||
if (ret != 0) {
|
||||
WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
on_each_cpu(bfin_adjust_core_timer, &index, 1);
|
||||
#if defined(CONFIG_CYCLES_CLOCKSOURCE)
|
||||
cycles = get_cycles();
|
||||
SSYNC();
|
||||
cycles += 10; /* ~10 cycles we lose after get_cycles() */
|
||||
__bfin_cycles_off +=
|
||||
(cycles << __bfin_cycles_mod) - (cycles << index);
|
||||
__bfin_cycles_mod = index;
|
||||
#endif
|
||||
if (!lpj_ref_freq) {
|
||||
lpj_ref = loops_per_jiffy;
|
||||
lpj_ref_freq = freqs.old;
|
||||
}
|
||||
if (freqs.new != freqs.old) {
|
||||
loops_per_jiffy = cpufreq_scale(lpj_ref,
|
||||
lpj_ref_freq, freqs.new);
|
||||
}
|
||||
}
|
||||
/* TODO: just test case for cycles clock source, remove later */
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
ret = cpu_set_cclk(policy->cpu, freqs.new * 1000);
|
||||
if (ret != 0) {
|
||||
WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
on_each_cpu(bfin_adjust_core_timer, &index, 1);
|
||||
#if defined(CONFIG_CYCLES_CLOCKSOURCE)
|
||||
cycles = get_cycles();
|
||||
SSYNC();
|
||||
cycles += 10; /* ~10 cycles we lose after get_cycles() */
|
||||
__bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
|
||||
__bfin_cycles_mod = index;
|
||||
#endif
|
||||
if (!lpj_ref_freq) {
|
||||
lpj_ref = loops_per_jiffy;
|
||||
lpj_ref_freq = freqs.old;
|
||||
}
|
||||
if (freqs.new != freqs.old) {
|
||||
loops_per_jiffy = cpufreq_scale(lpj_ref,
|
||||
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;
|
|
@ -44,8 +44,9 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
|
|||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
struct opp *opp;
|
||||
unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
|
||||
unsigned int index, cpu;
|
||||
unsigned long volt = 0, volt_old = 0, tol = 0;
|
||||
long freq_Hz;
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
||||
ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
|
||||
|
@ -65,10 +66,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
|
|||
if (freqs.old == freqs.new)
|
||||
return 0;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
freqs.cpu = cpu;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
if (cpu_reg) {
|
||||
rcu_read_lock();
|
||||
|
@ -76,7 +74,9 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
|
|||
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 = opp_get_voltage(opp);
|
||||
rcu_read_unlock();
|
||||
|
@ -94,7 +94,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
|
|||
if (ret) {
|
||||
pr_err("failed to scale voltage up: %d\n", ret);
|
||||
freqs.new = freqs.old;
|
||||
return ret;
|
||||
goto post_notify;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
|
|||
pr_err("failed to set clock rate: %d\n", ret);
|
||||
if (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 */
|
||||
|
@ -113,25 +114,19 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
|
|||
pr_err("failed to scale voltage down: %d\n", ret);
|
||||
clk_set_rate(cpu_clk, freqs.old * 1000);
|
||||
freqs.new = freqs.old;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
freqs.cpu = cpu;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
post_notify:
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
if (ret) {
|
||||
pr_err("invalid frequency table: %d\n", ret);
|
||||
|
@ -262,6 +257,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
of_node_put(np);
|
||||
of_node_put(parent);
|
||||
return 0;
|
||||
|
||||
out_free_table:
|
||||
|
|
|
@ -263,7 +263,6 @@ static int nforce2_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = nforce2_get(policy->cpu);
|
||||
freqs.new = target_fsb * fid * 100;
|
||||
freqs.cpu = 0; /* Only one CPU on nForce2 platforms */
|
||||
|
||||
if (freqs.old == freqs.new)
|
||||
return 0;
|
||||
|
@ -271,7 +270,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
|
|||
pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
|
||||
freqs.old, freqs.new);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* Disable IRQs */
|
||||
/* local_irq_save(flags); */
|
||||
|
@ -286,7 +285,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
|
|||
/* Enable IRQs */
|
||||
/* local_irq_restore(flags); */
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -360,12 +359,10 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
|
|||
min_fsb = NFORCE2_MIN_FSB;
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
policy->cpuinfo.min_freq = min_fsb * fid * 100;
|
||||
policy->cpuinfo.max_freq = max_fsb * fid * 100;
|
||||
policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
|
||||
policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
policy->cur = nforce2_get(policy->cpu);
|
||||
policy->min = policy->cpuinfo.min_freq;
|
||||
policy->max = policy->cpuinfo.max_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -39,13 +39,13 @@
|
|||
* level driver of CPUFreq support, and its spinlock. This lock
|
||||
* also protects the cpufreq_cpu_data array.
|
||||
*/
|
||||
static struct cpufreq_driver *cpufreq_driver;
|
||||
static struct cpufreq_driver __rcu *cpufreq_driver;
|
||||
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/* This one keeps track of the previously set governor of a removed CPU */
|
||||
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
|
||||
#endif
|
||||
static DEFINE_SPINLOCK(cpufreq_driver_lock);
|
||||
static DEFINE_RWLOCK(cpufreq_driver_lock);
|
||||
|
||||
/*
|
||||
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
|
||||
|
@ -128,23 +128,36 @@ void disable_cpufreq(void)
|
|||
static LIST_HEAD(cpufreq_governor_list);
|
||||
static DEFINE_MUTEX(cpufreq_governor_mutex);
|
||||
|
||||
bool have_governor_per_policy(void)
|
||||
{
|
||||
bool have_governor_per_policy;
|
||||
rcu_read_lock();
|
||||
have_governor_per_policy =
|
||||
rcu_dereference(cpufreq_driver)->have_governor_per_policy;
|
||||
rcu_read_unlock();
|
||||
return have_governor_per_policy;
|
||||
}
|
||||
|
||||
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
|
||||
{
|
||||
struct cpufreq_policy *data;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned long flags;
|
||||
|
||||
if (cpu >= nr_cpu_ids)
|
||||
goto err_out;
|
||||
|
||||
/* get the cpufreq driver */
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
|
||||
if (!cpufreq_driver)
|
||||
if (!driver)
|
||||
goto err_out_unlock;
|
||||
|
||||
if (!try_module_get(cpufreq_driver->owner))
|
||||
if (!try_module_get(driver->owner))
|
||||
goto err_out_unlock;
|
||||
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
|
||||
/* get the CPU */
|
||||
data = per_cpu(cpufreq_cpu_data, cpu);
|
||||
|
@ -155,13 +168,15 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
|
|||
if (!sysfs && !kobject_get(&data->kobj))
|
||||
goto err_out_put_module;
|
||||
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
rcu_read_unlock();
|
||||
return data;
|
||||
|
||||
err_out_put_module:
|
||||
module_put(cpufreq_driver->owner);
|
||||
module_put(driver->owner);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
err_out_unlock:
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
rcu_read_unlock();
|
||||
err_out:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -184,7 +199,9 @@ static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
|
|||
{
|
||||
if (!sysfs)
|
||||
kobject_put(&data->kobj);
|
||||
module_put(cpufreq_driver->owner);
|
||||
rcu_read_lock();
|
||||
module_put(rcu_dereference(cpufreq_driver)->owner);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void cpufreq_cpu_put(struct cpufreq_policy *data)
|
||||
|
@ -244,32 +261,20 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
|
||||
* on frequency transition.
|
||||
*
|
||||
* This function calls the transition notifiers and the "adjust_jiffies"
|
||||
* function. It is called twice on all CPU frequency changes that have
|
||||
* external effects.
|
||||
*/
|
||||
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
|
||||
void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs, unsigned int state)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(irqs_disabled());
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return;
|
||||
|
||||
freqs->flags = cpufreq_driver->flags;
|
||||
rcu_read_lock();
|
||||
freqs->flags = rcu_dereference(cpufreq_driver)->flags;
|
||||
rcu_read_unlock();
|
||||
pr_debug("notification %u of frequency transition to %u kHz\n",
|
||||
state, freqs->new);
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
switch (state) {
|
||||
|
||||
case CPUFREQ_PRECHANGE:
|
||||
|
@ -277,7 +282,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
|
|||
* which is not equal to what the cpufreq core thinks is
|
||||
* "old frequency".
|
||||
*/
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if (!(freqs->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if ((policy) && (policy->cpu == freqs->cpu) &&
|
||||
(policy->cur) && (policy->cur != freqs->old)) {
|
||||
pr_debug("Warning: CPU frequency is"
|
||||
|
@ -303,6 +308,20 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
|
|||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
|
||||
* on frequency transition.
|
||||
*
|
||||
* This function calls the transition notifiers and the "adjust_jiffies"
|
||||
* function. It is called twice on all CPU frequency changes that have
|
||||
* external effects.
|
||||
*/
|
||||
void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs, unsigned int state)
|
||||
{
|
||||
for_each_cpu(freqs->cpu, policy->cpus)
|
||||
__cpufreq_notify_transition(policy, freqs, state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
|
||||
|
||||
|
||||
|
@ -329,11 +348,21 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|||
struct cpufreq_governor **governor)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct cpufreq_driver *driver;
|
||||
bool has_setpolicy;
|
||||
bool has_target;
|
||||
|
||||
if (!cpufreq_driver)
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (!driver) {
|
||||
rcu_read_unlock();
|
||||
goto out;
|
||||
}
|
||||
has_setpolicy = driver->setpolicy ? true : false;
|
||||
has_target = driver->target ? true : false;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (cpufreq_driver->setpolicy) {
|
||||
if (has_setpolicy) {
|
||||
if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
|
||||
*policy = CPUFREQ_POLICY_PERFORMANCE;
|
||||
err = 0;
|
||||
|
@ -342,7 +371,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|||
*policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
err = 0;
|
||||
}
|
||||
} else if (cpufreq_driver->target) {
|
||||
} else if (has_target) {
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
mutex_lock(&cpufreq_governor_mutex);
|
||||
|
@ -493,7 +522,12 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
|
|||
*/
|
||||
static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name);
|
||||
ssize_t size;
|
||||
rcu_read_lock();
|
||||
size = scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n",
|
||||
rcu_dereference(cpufreq_driver)->name);
|
||||
rcu_read_unlock();
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -505,10 +539,13 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
|
|||
ssize_t i = 0;
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
if (!cpufreq_driver->target) {
|
||||
rcu_read_lock();
|
||||
if (!rcu_dereference(cpufreq_driver)->target) {
|
||||
rcu_read_unlock();
|
||||
i += sprintf(buf, "performance powersave");
|
||||
goto out;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
|
||||
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
|
||||
|
@ -586,9 +623,15 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
|
|||
static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
unsigned int limit;
|
||||
int (*bios_limit)(int cpu, unsigned int *limit);
|
||||
int ret;
|
||||
if (cpufreq_driver->bios_limit) {
|
||||
ret = cpufreq_driver->bios_limit(policy->cpu, &limit);
|
||||
|
||||
rcu_read_lock();
|
||||
bios_limit = rcu_dereference(cpufreq_driver)->bios_limit;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (bios_limit) {
|
||||
ret = bios_limit(policy->cpu, &limit);
|
||||
if (!ret)
|
||||
return sprintf(buf, "%u\n", limit);
|
||||
}
|
||||
|
@ -731,6 +774,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
|
|||
{
|
||||
struct cpufreq_policy new_policy;
|
||||
struct freq_attr **drv_attr;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
unsigned int j;
|
||||
|
@ -742,35 +786,38 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
|
|||
return ret;
|
||||
|
||||
/* set up files for this cpu device */
|
||||
drv_attr = cpufreq_driver->attr;
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
drv_attr = driver->attr;
|
||||
while ((drv_attr) && (*drv_attr)) {
|
||||
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
|
||||
if (ret)
|
||||
goto err_out_kobj_put;
|
||||
goto err_out_unlock;
|
||||
drv_attr++;
|
||||
}
|
||||
if (cpufreq_driver->get) {
|
||||
if (driver->get) {
|
||||
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
|
||||
if (ret)
|
||||
goto err_out_kobj_put;
|
||||
goto err_out_unlock;
|
||||
}
|
||||
if (cpufreq_driver->target) {
|
||||
if (driver->target) {
|
||||
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
|
||||
if (ret)
|
||||
goto err_out_kobj_put;
|
||||
goto err_out_unlock;
|
||||
}
|
||||
if (cpufreq_driver->bios_limit) {
|
||||
if (driver->bios_limit) {
|
||||
ret = sysfs_create_file(&policy->kobj, &bios_limit.attr);
|
||||
if (ret)
|
||||
goto err_out_kobj_put;
|
||||
goto err_out_unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
for_each_cpu(j, policy->cpus) {
|
||||
per_cpu(cpufreq_cpu_data, j) = policy;
|
||||
per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
|
||||
}
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
ret = cpufreq_add_dev_symlink(cpu, policy);
|
||||
if (ret)
|
||||
|
@ -786,12 +833,20 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
|
|||
policy->user_policy.governor = policy->governor;
|
||||
|
||||
if (ret) {
|
||||
int (*exit)(struct cpufreq_policy *policy);
|
||||
|
||||
pr_debug("setting policy failed\n");
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(policy);
|
||||
rcu_read_lock();
|
||||
exit = rcu_dereference(cpufreq_driver)->exit;
|
||||
rcu_read_unlock();
|
||||
if (exit)
|
||||
exit(policy);
|
||||
|
||||
}
|
||||
return ret;
|
||||
|
||||
err_out_unlock:
|
||||
rcu_read_unlock();
|
||||
err_out_kobj_put:
|
||||
kobject_put(&policy->kobj);
|
||||
wait_for_completion(&policy->kobj_unregister);
|
||||
|
@ -803,27 +858,34 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
|
|||
struct device *dev)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
int ret = 0;
|
||||
int ret = 0, has_target = 0;
|
||||
unsigned long flags;
|
||||
|
||||
policy = cpufreq_cpu_get(sibling);
|
||||
WARN_ON(!policy);
|
||||
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
||||
rcu_read_lock();
|
||||
has_target = !!rcu_dereference(cpufreq_driver)->target;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (has_target)
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
||||
|
||||
lock_policy_rwsem_write(sibling);
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
|
||||
cpumask_set_cpu(cpu, policy->cpus);
|
||||
per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
|
||||
per_cpu(cpufreq_cpu_data, cpu) = policy;
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
unlock_policy_rwsem_write(sibling);
|
||||
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_START);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
if (has_target) {
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_START);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
}
|
||||
|
||||
ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
|
||||
if (ret) {
|
||||
|
@ -849,6 +911,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
unsigned int j, cpu = dev->id;
|
||||
int ret = -ENOMEM;
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_driver *driver;
|
||||
int (*init)(struct cpufreq_policy *policy);
|
||||
unsigned long flags;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
struct cpufreq_governor *gov;
|
||||
|
@ -871,22 +935,27 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/* Check if this cpu was hot-unplugged earlier and has siblings */
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
for_each_online_cpu(sibling) {
|
||||
struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
|
||||
if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
return cpufreq_add_policy_cpu(cpu, sibling, dev);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!try_module_get(cpufreq_driver->owner)) {
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (!try_module_get(driver->owner)) {
|
||||
rcu_read_unlock();
|
||||
ret = -EINVAL;
|
||||
goto module_out;
|
||||
}
|
||||
init = driver->init;
|
||||
rcu_read_unlock();
|
||||
|
||||
policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
|
||||
if (!policy)
|
||||
|
@ -911,7 +980,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
/* call driver. From then on the cpufreq must be able
|
||||
* to accept all calls to ->verify and ->setpolicy for this CPU
|
||||
*/
|
||||
ret = cpufreq_driver->init(policy);
|
||||
ret = init(policy);
|
||||
if (ret) {
|
||||
pr_debug("initialization failed\n");
|
||||
goto err_set_policy_cpu;
|
||||
|
@ -946,16 +1015,18 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
goto err_out_unregister;
|
||||
|
||||
kobject_uevent(&policy->kobj, KOBJ_ADD);
|
||||
module_put(cpufreq_driver->owner);
|
||||
rcu_read_lock();
|
||||
module_put(rcu_dereference(cpufreq_driver)->owner);
|
||||
rcu_read_unlock();
|
||||
pr_debug("initialization complete\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_unregister:
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
for_each_cpu(j, policy->cpus)
|
||||
per_cpu(cpufreq_cpu_data, j) = NULL;
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
kobject_put(&policy->kobj);
|
||||
wait_for_completion(&policy->kobj_unregister);
|
||||
|
@ -968,7 +1039,9 @@ err_free_cpumask:
|
|||
err_free_policy:
|
||||
kfree(policy);
|
||||
nomem_out:
|
||||
module_put(cpufreq_driver->owner);
|
||||
rcu_read_lock();
|
||||
module_put(rcu_dereference(cpufreq_driver)->owner);
|
||||
rcu_read_unlock();
|
||||
module_out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1002,36 +1075,46 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
|
|||
unsigned int cpu = dev->id, ret, cpus;
|
||||
unsigned long flags;
|
||||
struct cpufreq_policy *data;
|
||||
struct cpufreq_driver *driver;
|
||||
struct kobject *kobj;
|
||||
struct completion *cmp;
|
||||
struct device *cpu_dev;
|
||||
bool has_target;
|
||||
int (*exit)(struct cpufreq_policy *policy);
|
||||
|
||||
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
|
||||
data = per_cpu(cpufreq_cpu_data, cpu);
|
||||
per_cpu(cpufreq_cpu_data, cpu) = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
if (!data) {
|
||||
pr_debug("%s: No cpu_data found\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cpufreq_driver->target)
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
has_target = driver->target ? true : false;
|
||||
exit = driver->exit;
|
||||
if (has_target)
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (!cpufreq_driver->setpolicy)
|
||||
if (!driver->setpolicy)
|
||||
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
|
||||
data->governor->name, CPUFREQ_NAME_LEN);
|
||||
#endif
|
||||
rcu_read_unlock();
|
||||
|
||||
WARN_ON(lock_policy_rwsem_write(cpu));
|
||||
cpus = cpumask_weight(data->cpus);
|
||||
cpumask_clear_cpu(cpu, data->cpus);
|
||||
|
||||
if (cpus > 1)
|
||||
cpumask_clear_cpu(cpu, data->cpus);
|
||||
unlock_policy_rwsem_write(cpu);
|
||||
|
||||
if (cpu != data->cpu) {
|
||||
|
@ -1047,9 +1130,9 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
|
|||
WARN_ON(lock_policy_rwsem_write(cpu));
|
||||
cpumask_set_cpu(cpu, data->cpus);
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
per_cpu(cpufreq_cpu_data, cpu) = data;
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
unlock_policy_rwsem_write(cpu);
|
||||
|
||||
|
@ -1070,6 +1153,9 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
|
|||
|
||||
/* If cpu is last user of policy, free policy */
|
||||
if (cpus == 1) {
|
||||
if (has_target)
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
|
||||
|
||||
lock_policy_rwsem_read(cpu);
|
||||
kobj = &data->kobj;
|
||||
cmp = &data->kobj_unregister;
|
||||
|
@ -1084,13 +1170,13 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
|
|||
wait_for_completion(cmp);
|
||||
pr_debug("wait complete\n");
|
||||
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(data);
|
||||
if (exit)
|
||||
exit(data);
|
||||
|
||||
free_cpumask_var(data->related_cpus);
|
||||
free_cpumask_var(data->cpus);
|
||||
kfree(data);
|
||||
} else if (cpufreq_driver->target) {
|
||||
} else if (has_target) {
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_START);
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
|
||||
}
|
||||
|
@ -1134,16 +1220,23 @@ static void handle_update(struct work_struct *work)
|
|||
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
|
||||
unsigned int new_freq)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
|
||||
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
|
||||
|
||||
freqs.cpu = cpu;
|
||||
freqs.old = old_freq;
|
||||
freqs.new = new_freq;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1157,10 +1250,18 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
|
|||
unsigned int cpufreq_quick_get(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned int (*get)(unsigned int cpu);
|
||||
unsigned int ret_freq = 0;
|
||||
|
||||
if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)
|
||||
return cpufreq_driver->get(cpu);
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (driver && driver->setpolicy && driver->get) {
|
||||
get = driver->get;
|
||||
rcu_read_unlock();
|
||||
return get(cpu);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (policy) {
|
||||
|
@ -1196,15 +1297,26 @@ EXPORT_SYMBOL(cpufreq_quick_get_max);
|
|||
static unsigned int __cpufreq_get(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned int (*get)(unsigned int cpu);
|
||||
unsigned int ret_freq = 0;
|
||||
u8 flags;
|
||||
|
||||
if (!cpufreq_driver->get)
|
||||
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (!driver->get) {
|
||||
rcu_read_unlock();
|
||||
return ret_freq;
|
||||
}
|
||||
flags = driver->flags;
|
||||
get = driver->get;
|
||||
rcu_read_unlock();
|
||||
|
||||
ret_freq = cpufreq_driver->get(cpu);
|
||||
ret_freq = get(cpu);
|
||||
|
||||
if (ret_freq && policy->cur &&
|
||||
!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
!(flags & CPUFREQ_CONST_LOOPS)) {
|
||||
/* verify no discrepancy between actual and
|
||||
saved value exists */
|
||||
if (unlikely(ret_freq != policy->cur)) {
|
||||
|
@ -1260,6 +1372,7 @@ static struct subsys_interface cpufreq_interface = {
|
|||
*/
|
||||
static int cpufreq_bp_suspend(void)
|
||||
{
|
||||
int (*suspend)(struct cpufreq_policy *policy);
|
||||
int ret = 0;
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
|
@ -1272,8 +1385,11 @@ static int cpufreq_bp_suspend(void)
|
|||
if (!cpu_policy)
|
||||
return 0;
|
||||
|
||||
if (cpufreq_driver->suspend) {
|
||||
ret = cpufreq_driver->suspend(cpu_policy);
|
||||
rcu_read_lock();
|
||||
suspend = rcu_dereference(cpufreq_driver)->suspend;
|
||||
rcu_read_unlock();
|
||||
if (suspend) {
|
||||
ret = suspend(cpu_policy);
|
||||
if (ret)
|
||||
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
|
||||
"step on CPU %u\n", cpu_policy->cpu);
|
||||
|
@ -1299,6 +1415,7 @@ static int cpufreq_bp_suspend(void)
|
|||
static void cpufreq_bp_resume(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int (*resume)(struct cpufreq_policy *policy);
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
struct cpufreq_policy *cpu_policy;
|
||||
|
@ -1310,8 +1427,12 @@ static void cpufreq_bp_resume(void)
|
|||
if (!cpu_policy)
|
||||
return;
|
||||
|
||||
if (cpufreq_driver->resume) {
|
||||
ret = cpufreq_driver->resume(cpu_policy);
|
||||
rcu_read_lock();
|
||||
resume = rcu_dereference(cpufreq_driver)->resume;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (resume) {
|
||||
ret = resume(cpu_policy);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "cpufreq: resume failed in ->resume "
|
||||
"step on CPU %u\n", cpu_policy->cpu);
|
||||
|
@ -1338,10 +1459,14 @@ static struct syscore_ops cpufreq_syscore_ops = {
|
|||
*/
|
||||
const char *cpufreq_get_current_driver(void)
|
||||
{
|
||||
if (cpufreq_driver)
|
||||
return cpufreq_driver->name;
|
||||
|
||||
return NULL;
|
||||
struct cpufreq_driver *driver;
|
||||
const char *name = NULL;
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
if (driver)
|
||||
name = driver->name;
|
||||
rcu_read_unlock();
|
||||
return name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_get_current_driver);
|
||||
|
||||
|
@ -1435,6 +1560,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|||
{
|
||||
int retval = -EINVAL;
|
||||
unsigned int old_target_freq = target_freq;
|
||||
int (*target)(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation);
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return -ENODEV;
|
||||
|
@ -1451,8 +1579,11 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|||
if (target_freq == policy->cur)
|
||||
return 0;
|
||||
|
||||
if (cpufreq_driver->target)
|
||||
retval = cpufreq_driver->target(policy, target_freq, relation);
|
||||
rcu_read_lock();
|
||||
target = rcu_dereference(cpufreq_driver)->target;
|
||||
rcu_read_unlock();
|
||||
if (target)
|
||||
retval = target(policy, target_freq, relation);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -1485,18 +1616,24 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_target);
|
|||
int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int (*getavg)(struct cpufreq_policy *policy,
|
||||
unsigned int cpu);
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return ret;
|
||||
|
||||
if (!cpufreq_driver->getavg)
|
||||
rcu_read_lock();
|
||||
getavg = rcu_dereference(cpufreq_driver)->getavg;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!getavg)
|
||||
return 0;
|
||||
|
||||
policy = cpufreq_cpu_get(policy->cpu);
|
||||
if (!policy)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cpufreq_driver->getavg(policy, cpu);
|
||||
ret = getavg(policy, cpu);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
return ret;
|
||||
|
@ -1544,10 +1681,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
|||
policy->cpu, event);
|
||||
ret = policy->governor->governor(policy, event);
|
||||
|
||||
if (event == CPUFREQ_GOV_START)
|
||||
policy->governor->initialized++;
|
||||
else if (event == CPUFREQ_GOV_STOP)
|
||||
policy->governor->initialized--;
|
||||
if (!ret) {
|
||||
if (event == CPUFREQ_GOV_POLICY_INIT)
|
||||
policy->governor->initialized++;
|
||||
else if (event == CPUFREQ_GOV_POLICY_EXIT)
|
||||
policy->governor->initialized--;
|
||||
}
|
||||
|
||||
/* we keep one module reference alive for
|
||||
each CPU governed by this CPU */
|
||||
|
@ -1651,7 +1790,10 @@ EXPORT_SYMBOL(cpufreq_get_policy);
|
|||
static int __cpufreq_set_policy(struct cpufreq_policy *data,
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = 0, failed = 1;
|
||||
struct cpufreq_driver *driver;
|
||||
int (*verify)(struct cpufreq_policy *policy);
|
||||
int (*setpolicy)(struct cpufreq_policy *policy);
|
||||
|
||||
pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
|
||||
policy->min, policy->max);
|
||||
|
@ -1665,7 +1807,13 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
|
|||
}
|
||||
|
||||
/* verify the cpu speed can be set within this limit */
|
||||
ret = cpufreq_driver->verify(policy);
|
||||
rcu_read_lock();
|
||||
driver = rcu_dereference(cpufreq_driver);
|
||||
verify = driver->verify;
|
||||
setpolicy = driver->setpolicy;
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = verify(policy);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
|
@ -1679,7 +1827,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
|
|||
|
||||
/* verify the cpu speed can be set within this limit,
|
||||
which might be different to the first one */
|
||||
ret = cpufreq_driver->verify(policy);
|
||||
ret = verify(policy);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
|
@ -1693,10 +1841,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
|
|||
pr_debug("new min and max freqs are %u - %u kHz\n",
|
||||
data->min, data->max);
|
||||
|
||||
if (cpufreq_driver->setpolicy) {
|
||||
if (setpolicy) {
|
||||
data->policy = policy->policy;
|
||||
pr_debug("setting range\n");
|
||||
ret = cpufreq_driver->setpolicy(policy);
|
||||
ret = setpolicy(policy);
|
||||
} else {
|
||||
if (policy->governor != data->governor) {
|
||||
/* save old, working values */
|
||||
|
@ -1705,17 +1853,30 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
|
|||
pr_debug("governor switch\n");
|
||||
|
||||
/* end old governor */
|
||||
if (data->governor)
|
||||
if (data->governor) {
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
|
||||
__cpufreq_governor(data,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
}
|
||||
|
||||
/* start new governor */
|
||||
data->governor = policy->governor;
|
||||
if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
|
||||
if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
|
||||
if (!__cpufreq_governor(data, CPUFREQ_GOV_START))
|
||||
failed = 0;
|
||||
else
|
||||
__cpufreq_governor(data,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
/* new governor failed, so re-start old one */
|
||||
pr_debug("starting governor %s failed\n",
|
||||
data->governor->name);
|
||||
if (old_gov) {
|
||||
data->governor = old_gov;
|
||||
__cpufreq_governor(data,
|
||||
CPUFREQ_GOV_POLICY_INIT);
|
||||
__cpufreq_governor(data,
|
||||
CPUFREQ_GOV_START);
|
||||
}
|
||||
|
@ -1743,6 +1904,11 @@ int cpufreq_update_policy(unsigned int cpu)
|
|||
{
|
||||
struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
|
||||
struct cpufreq_policy policy;
|
||||
struct cpufreq_driver *driver;
|
||||
unsigned int (*get)(unsigned int cpu);
|
||||
int (*target)(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation);
|
||||
int ret;
|
||||
|
||||
if (!data) {
|
||||
|
@ -1764,13 +1930,18 @@ int cpufreq_update_policy(unsigned int cpu)
|
|||
|
||||
/* BIOS might change freq behind our back
|
||||
-> ask driver for current freq and notify governors about a change */
|
||||
if (cpufreq_driver->get) {
|
||||
policy.cur = cpufreq_driver->get(cpu);
|
||||
rcu_read_lock();
|
||||
driver = rcu_access_pointer(cpufreq_driver);
|
||||
get = driver->get;
|
||||
target = driver->target;
|
||||
rcu_read_unlock();
|
||||
if (get) {
|
||||
policy.cur = get(cpu);
|
||||
if (!data->cur) {
|
||||
pr_debug("Driver did not initialize current freq");
|
||||
data->cur = policy.cur;
|
||||
} else {
|
||||
if (data->cur != policy.cur && cpufreq_driver->target)
|
||||
if (data->cur != policy.cur && target)
|
||||
cpufreq_out_of_sync(cpu, data->cur,
|
||||
policy.cur);
|
||||
}
|
||||
|
@ -1848,19 +2019,20 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
if (driver_data->setpolicy)
|
||||
driver_data->flags |= CPUFREQ_CONST_LOOPS;
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
if (cpufreq_driver) {
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
if (rcu_access_pointer(cpufreq_driver)) {
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
cpufreq_driver = driver_data;
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
rcu_assign_pointer(cpufreq_driver, driver_data);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
synchronize_rcu();
|
||||
|
||||
ret = subsys_interface_register(&cpufreq_interface);
|
||||
if (ret)
|
||||
goto err_null_driver;
|
||||
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
|
||||
if (!(driver_data->flags & CPUFREQ_STICKY)) {
|
||||
int i;
|
||||
ret = -ENODEV;
|
||||
|
||||
|
@ -1886,9 +2058,10 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
err_if_unreg:
|
||||
subsys_interface_unregister(&cpufreq_interface);
|
||||
err_null_driver:
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
cpufreq_driver = NULL;
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
rcu_assign_pointer(cpufreq_driver, NULL);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
synchronize_rcu();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
|
||||
|
@ -1905,18 +2078,25 @@ EXPORT_SYMBOL_GPL(cpufreq_register_driver);
|
|||
int cpufreq_unregister_driver(struct cpufreq_driver *driver)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct cpufreq_driver *old_driver;
|
||||
|
||||
if (!cpufreq_driver || (driver != cpufreq_driver))
|
||||
rcu_read_lock();
|
||||
old_driver = rcu_access_pointer(cpufreq_driver);
|
||||
if (!old_driver || (driver != old_driver)) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
pr_debug("unregistering driver %s\n", driver->name);
|
||||
|
||||
subsys_interface_unregister(&cpufreq_interface);
|
||||
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
|
||||
|
||||
spin_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
cpufreq_driver = NULL;
|
||||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
rcu_assign_pointer(cpufreq_driver, NULL);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
synchronize_rcu();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/percpu-defs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
@ -28,25 +29,29 @@
|
|||
/* Conservative governor macros */
|
||||
#define DEF_FREQUENCY_UP_THRESHOLD (80)
|
||||
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
|
||||
#define DEF_FREQUENCY_STEP (5)
|
||||
#define DEF_SAMPLING_DOWN_FACTOR (1)
|
||||
#define MAX_SAMPLING_DOWN_FACTOR (10)
|
||||
|
||||
static struct dbs_data cs_dbs_data;
|
||||
static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);
|
||||
|
||||
static struct cs_dbs_tuners cs_tuners = {
|
||||
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
|
||||
.down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
|
||||
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
|
||||
.ignore_nice = 0,
|
||||
.freq_step = 5,
|
||||
};
|
||||
static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int freq_target = (cs_tuners->freq_step * policy->max) / 100;
|
||||
|
||||
/* max freq cannot be less than 100. But who knows... */
|
||||
if (unlikely(freq_target == 0))
|
||||
freq_target = DEF_FREQUENCY_STEP;
|
||||
|
||||
return freq_target;
|
||||
}
|
||||
|
||||
/*
|
||||
* Every sampling_rate, we check, if current idle time is less than 20%
|
||||
* (default), then we try to increase frequency Every sampling_rate *
|
||||
* sampling_down_factor, we check, if current idle time is more than 80%, then
|
||||
* we try to decrease frequency
|
||||
* (default), then we try to increase frequency. Every sampling_rate *
|
||||
* sampling_down_factor, we check, if current idle time is more than 80%
|
||||
* (default), then we try to decrease frequency
|
||||
*
|
||||
* Any frequency increase takes it to the maximum frequency. Frequency reduction
|
||||
* happens at minimum steps of 5% (default) of maximum frequency
|
||||
|
@ -55,30 +60,25 @@ static void cs_check_cpu(int cpu, unsigned int load)
|
|||
{
|
||||
struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
|
||||
struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
|
||||
unsigned int freq_target;
|
||||
struct dbs_data *dbs_data = policy->governor_data;
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
|
||||
/*
|
||||
* break out if we 'cannot' reduce the speed as the user might
|
||||
* want freq_step to be zero
|
||||
*/
|
||||
if (cs_tuners.freq_step == 0)
|
||||
if (cs_tuners->freq_step == 0)
|
||||
return;
|
||||
|
||||
/* Check for frequency increase */
|
||||
if (load > cs_tuners.up_threshold) {
|
||||
if (load > cs_tuners->up_threshold) {
|
||||
dbs_info->down_skip = 0;
|
||||
|
||||
/* if we are already at full speed then break out early */
|
||||
if (dbs_info->requested_freq == policy->max)
|
||||
return;
|
||||
|
||||
freq_target = (cs_tuners.freq_step * policy->max) / 100;
|
||||
|
||||
/* max freq cannot be less than 100. But who knows.... */
|
||||
if (unlikely(freq_target == 0))
|
||||
freq_target = 5;
|
||||
|
||||
dbs_info->requested_freq += freq_target;
|
||||
dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
|
||||
if (dbs_info->requested_freq > policy->max)
|
||||
dbs_info->requested_freq = policy->max;
|
||||
|
||||
|
@ -87,45 +87,48 @@ static void cs_check_cpu(int cpu, unsigned int load)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The optimal frequency is the frequency that is the lowest that can
|
||||
* support the current CPU usage without triggering the up policy. To be
|
||||
* safe, we focus 10 points under the threshold.
|
||||
*/
|
||||
if (load < (cs_tuners.down_threshold - 10)) {
|
||||
freq_target = (cs_tuners.freq_step * policy->max) / 100;
|
||||
|
||||
dbs_info->requested_freq -= freq_target;
|
||||
if (dbs_info->requested_freq < policy->min)
|
||||
dbs_info->requested_freq = policy->min;
|
||||
/* if sampling_down_factor is active break out early */
|
||||
if (++dbs_info->down_skip < cs_tuners->sampling_down_factor)
|
||||
return;
|
||||
dbs_info->down_skip = 0;
|
||||
|
||||
/* Check for frequency decrease */
|
||||
if (load < cs_tuners->down_threshold) {
|
||||
/*
|
||||
* if we cannot reduce the frequency anymore, break out early
|
||||
*/
|
||||
if (policy->cur == policy->min)
|
||||
return;
|
||||
|
||||
dbs_info->requested_freq -= get_freq_target(cs_tuners, policy);
|
||||
if (dbs_info->requested_freq < policy->min)
|
||||
dbs_info->requested_freq = policy->min;
|
||||
|
||||
__cpufreq_driver_target(policy, dbs_info->requested_freq,
|
||||
CPUFREQ_RELATION_H);
|
||||
CPUFREQ_RELATION_L);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cs_dbs_timer(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct cs_cpu_dbs_info_s *dbs_info = container_of(work,
|
||||
struct cs_cpu_dbs_info_s, cdbs.work.work);
|
||||
unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
|
||||
struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info,
|
||||
cpu);
|
||||
int delay = delay_for_sampling_rate(cs_tuners.sampling_rate);
|
||||
struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
int delay = delay_for_sampling_rate(cs_tuners->sampling_rate);
|
||||
bool modify_all = true;
|
||||
|
||||
mutex_lock(&core_dbs_info->cdbs.timer_mutex);
|
||||
if (need_load_eval(&core_dbs_info->cdbs, cs_tuners.sampling_rate))
|
||||
dbs_check_cpu(&cs_dbs_data, cpu);
|
||||
if (!need_load_eval(&core_dbs_info->cdbs, cs_tuners->sampling_rate))
|
||||
modify_all = false;
|
||||
else
|
||||
dbs_check_cpu(dbs_data, cpu);
|
||||
|
||||
schedule_delayed_work_on(smp_processor_id(), dw, delay);
|
||||
gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);
|
||||
mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
|
||||
}
|
||||
|
||||
|
@ -154,16 +157,12 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
|||
}
|
||||
|
||||
/************************** sysfs interface ************************/
|
||||
static ssize_t show_sampling_rate_min(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", cs_dbs_data.min_sampling_rate);
|
||||
}
|
||||
static struct common_dbs_data cs_dbs_cdata;
|
||||
|
||||
static ssize_t store_sampling_down_factor(struct kobject *a,
|
||||
struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
@ -171,13 +170,14 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
|
|||
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
|
||||
return -EINVAL;
|
||||
|
||||
cs_tuners.sampling_down_factor = input;
|
||||
cs_tuners->sampling_down_factor = input;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
@ -185,43 +185,46 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
|
|||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
cs_tuners.sampling_rate = max(input, cs_dbs_data.min_sampling_rate);
|
||||
cs_tuners->sampling_rate = max(input, dbs_data->min_sampling_rate);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
if (ret != 1 || input > 100 || input <= cs_tuners.down_threshold)
|
||||
if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
|
||||
return -EINVAL;
|
||||
|
||||
cs_tuners.up_threshold = input;
|
||||
cs_tuners->up_threshold = input;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_down_threshold(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
/* cannot be lower than 11 otherwise freq will not fall */
|
||||
if (ret != 1 || input < 11 || input > 100 ||
|
||||
input >= cs_tuners.up_threshold)
|
||||
input >= cs_tuners->up_threshold)
|
||||
return -EINVAL;
|
||||
|
||||
cs_tuners.down_threshold = input;
|
||||
cs_tuners->down_threshold = input;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int input, j;
|
||||
int ret;
|
||||
|
||||
|
@ -232,27 +235,28 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
|
|||
if (input > 1)
|
||||
input = 1;
|
||||
|
||||
if (input == cs_tuners.ignore_nice) /* nothing to do */
|
||||
if (input == cs_tuners->ignore_nice) /* nothing to do */
|
||||
return count;
|
||||
|
||||
cs_tuners.ignore_nice = input;
|
||||
cs_tuners->ignore_nice = input;
|
||||
|
||||
/* we need to re-evaluate prev_cpu_idle */
|
||||
for_each_online_cpu(j) {
|
||||
struct cs_cpu_dbs_info_s *dbs_info;
|
||||
dbs_info = &per_cpu(cs_cpu_dbs_info, j);
|
||||
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
|
||||
&dbs_info->cdbs.prev_cpu_wall);
|
||||
if (cs_tuners.ignore_nice)
|
||||
&dbs_info->cdbs.prev_cpu_wall, 0);
|
||||
if (cs_tuners->ignore_nice)
|
||||
dbs_info->cdbs.prev_cpu_nice =
|
||||
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
@ -267,43 +271,88 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
|
|||
* no need to test here if freq_step is zero as the user might actually
|
||||
* want this, they would be crazy though :)
|
||||
*/
|
||||
cs_tuners.freq_step = input;
|
||||
cs_tuners->freq_step = input;
|
||||
return count;
|
||||
}
|
||||
|
||||
show_one(cs, sampling_rate, sampling_rate);
|
||||
show_one(cs, sampling_down_factor, sampling_down_factor);
|
||||
show_one(cs, up_threshold, up_threshold);
|
||||
show_one(cs, down_threshold, down_threshold);
|
||||
show_one(cs, ignore_nice_load, ignore_nice);
|
||||
show_one(cs, freq_step, freq_step);
|
||||
show_store_one(cs, sampling_rate);
|
||||
show_store_one(cs, sampling_down_factor);
|
||||
show_store_one(cs, up_threshold);
|
||||
show_store_one(cs, down_threshold);
|
||||
show_store_one(cs, ignore_nice);
|
||||
show_store_one(cs, freq_step);
|
||||
declare_show_sampling_rate_min(cs);
|
||||
|
||||
define_one_global_rw(sampling_rate);
|
||||
define_one_global_rw(sampling_down_factor);
|
||||
define_one_global_rw(up_threshold);
|
||||
define_one_global_rw(down_threshold);
|
||||
define_one_global_rw(ignore_nice_load);
|
||||
define_one_global_rw(freq_step);
|
||||
define_one_global_ro(sampling_rate_min);
|
||||
gov_sys_pol_attr_rw(sampling_rate);
|
||||
gov_sys_pol_attr_rw(sampling_down_factor);
|
||||
gov_sys_pol_attr_rw(up_threshold);
|
||||
gov_sys_pol_attr_rw(down_threshold);
|
||||
gov_sys_pol_attr_rw(ignore_nice);
|
||||
gov_sys_pol_attr_rw(freq_step);
|
||||
gov_sys_pol_attr_ro(sampling_rate_min);
|
||||
|
||||
static struct attribute *dbs_attributes[] = {
|
||||
&sampling_rate_min.attr,
|
||||
&sampling_rate.attr,
|
||||
&sampling_down_factor.attr,
|
||||
&up_threshold.attr,
|
||||
&down_threshold.attr,
|
||||
&ignore_nice_load.attr,
|
||||
&freq_step.attr,
|
||||
static struct attribute *dbs_attributes_gov_sys[] = {
|
||||
&sampling_rate_min_gov_sys.attr,
|
||||
&sampling_rate_gov_sys.attr,
|
||||
&sampling_down_factor_gov_sys.attr,
|
||||
&up_threshold_gov_sys.attr,
|
||||
&down_threshold_gov_sys.attr,
|
||||
&ignore_nice_gov_sys.attr,
|
||||
&freq_step_gov_sys.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group cs_attr_group = {
|
||||
.attrs = dbs_attributes,
|
||||
static struct attribute_group cs_attr_group_gov_sys = {
|
||||
.attrs = dbs_attributes_gov_sys,
|
||||
.name = "conservative",
|
||||
};
|
||||
|
||||
static struct attribute *dbs_attributes_gov_pol[] = {
|
||||
&sampling_rate_min_gov_pol.attr,
|
||||
&sampling_rate_gov_pol.attr,
|
||||
&sampling_down_factor_gov_pol.attr,
|
||||
&up_threshold_gov_pol.attr,
|
||||
&down_threshold_gov_pol.attr,
|
||||
&ignore_nice_gov_pol.attr,
|
||||
&freq_step_gov_pol.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group cs_attr_group_gov_pol = {
|
||||
.attrs = dbs_attributes_gov_pol,
|
||||
.name = "conservative",
|
||||
};
|
||||
|
||||
/************************** sysfs end ************************/
|
||||
|
||||
static int cs_init(struct dbs_data *dbs_data)
|
||||
{
|
||||
struct cs_dbs_tuners *tuners;
|
||||
|
||||
tuners = kzalloc(sizeof(struct cs_dbs_tuners), GFP_KERNEL);
|
||||
if (!tuners) {
|
||||
pr_err("%s: kzalloc failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
|
||||
tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
|
||||
tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
|
||||
tuners->ignore_nice = 0;
|
||||
tuners->freq_step = DEF_FREQUENCY_STEP;
|
||||
|
||||
dbs_data->tuners = tuners;
|
||||
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
|
||||
jiffies_to_usecs(10);
|
||||
mutex_init(&dbs_data->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs_exit(struct dbs_data *dbs_data)
|
||||
{
|
||||
kfree(dbs_data->tuners);
|
||||
}
|
||||
|
||||
define_get_cpu_dbs_routines(cs_cpu_dbs_info);
|
||||
|
||||
static struct notifier_block cs_cpufreq_notifier_block = {
|
||||
|
@ -314,21 +363,23 @@ static struct cs_ops cs_ops = {
|
|||
.notifier_block = &cs_cpufreq_notifier_block,
|
||||
};
|
||||
|
||||
static struct dbs_data cs_dbs_data = {
|
||||
static struct common_dbs_data cs_dbs_cdata = {
|
||||
.governor = GOV_CONSERVATIVE,
|
||||
.attr_group = &cs_attr_group,
|
||||
.tuners = &cs_tuners,
|
||||
.attr_group_gov_sys = &cs_attr_group_gov_sys,
|
||||
.attr_group_gov_pol = &cs_attr_group_gov_pol,
|
||||
.get_cpu_cdbs = get_cpu_cdbs,
|
||||
.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
|
||||
.gov_dbs_timer = cs_dbs_timer,
|
||||
.gov_check_cpu = cs_check_cpu,
|
||||
.gov_ops = &cs_ops,
|
||||
.init = cs_init,
|
||||
.exit = cs_exit,
|
||||
};
|
||||
|
||||
static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
unsigned int event)
|
||||
{
|
||||
return cpufreq_governor_dbs(&cs_dbs_data, policy, event);
|
||||
return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
|
||||
|
@ -343,7 +394,6 @@ struct cpufreq_governor cpufreq_gov_conservative = {
|
|||
|
||||
static int __init cpufreq_gov_dbs_init(void)
|
||||
{
|
||||
mutex_init(&cs_dbs_data.mutex);
|
||||
return cpufreq_register_governor(&cpufreq_gov_conservative);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,12 +22,29 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "cpufreq_governor.h"
|
||||
|
||||
static struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (have_governor_per_policy())
|
||||
return &policy->kobj;
|
||||
else
|
||||
return cpufreq_global_kobject;
|
||||
}
|
||||
|
||||
static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
|
||||
{
|
||||
if (have_governor_per_policy())
|
||||
return dbs_data->cdata->attr_group_gov_pol;
|
||||
else
|
||||
return dbs_data->cdata->attr_group_gov_sys;
|
||||
}
|
||||
|
||||
static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
|
||||
{
|
||||
u64 idle_time;
|
||||
|
@ -50,13 +67,13 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
|
|||
return cputime_to_usecs(idle_time);
|
||||
}
|
||||
|
||||
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall)
|
||||
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
|
||||
{
|
||||
u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
|
||||
u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
|
||||
|
||||
if (idle_time == -1ULL)
|
||||
return get_cpu_idle_time_jiffy(cpu, wall);
|
||||
else
|
||||
else if (!io_busy)
|
||||
idle_time += get_cpu_iowait_time_us(cpu, wall);
|
||||
|
||||
return idle_time;
|
||||
|
@ -65,7 +82,7 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time);
|
|||
|
||||
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
|
||||
{
|
||||
struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
|
||||
struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
struct cpufreq_policy *policy;
|
||||
|
@ -73,7 +90,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
|
|||
unsigned int ignore_nice;
|
||||
unsigned int j;
|
||||
|
||||
if (dbs_data->governor == GOV_ONDEMAND)
|
||||
if (dbs_data->cdata->governor == GOV_ONDEMAND)
|
||||
ignore_nice = od_tuners->ignore_nice;
|
||||
else
|
||||
ignore_nice = cs_tuners->ignore_nice;
|
||||
|
@ -83,13 +100,22 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
|
|||
/* Get Absolute Load (in terms of freq for ondemand gov) */
|
||||
for_each_cpu(j, policy->cpus) {
|
||||
struct cpu_dbs_common_info *j_cdbs;
|
||||
u64 cur_wall_time, cur_idle_time, cur_iowait_time;
|
||||
unsigned int idle_time, wall_time, iowait_time;
|
||||
u64 cur_wall_time, cur_idle_time;
|
||||
unsigned int idle_time, wall_time;
|
||||
unsigned int load;
|
||||
int io_busy = 0;
|
||||
|
||||
j_cdbs = dbs_data->get_cpu_cdbs(j);
|
||||
j_cdbs = dbs_data->cdata->get_cpu_cdbs(j);
|
||||
|
||||
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
|
||||
/*
|
||||
* For the purpose of ondemand, waiting for disk IO is
|
||||
* an indication that you're performance critical, and
|
||||
* not that the system is actually idle. So do not add
|
||||
* the iowait time to the cpu idle time.
|
||||
*/
|
||||
if (dbs_data->cdata->governor == GOV_ONDEMAND)
|
||||
io_busy = od_tuners->io_is_busy;
|
||||
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time, io_busy);
|
||||
|
||||
wall_time = (unsigned int)
|
||||
(cur_wall_time - j_cdbs->prev_cpu_wall);
|
||||
|
@ -117,35 +143,12 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
|
|||
idle_time += jiffies_to_usecs(cur_nice_jiffies);
|
||||
}
|
||||
|
||||
if (dbs_data->governor == GOV_ONDEMAND) {
|
||||
struct od_cpu_dbs_info_s *od_j_dbs_info =
|
||||
dbs_data->get_cpu_dbs_info_s(cpu);
|
||||
|
||||
cur_iowait_time = get_cpu_iowait_time_us(j,
|
||||
&cur_wall_time);
|
||||
if (cur_iowait_time == -1ULL)
|
||||
cur_iowait_time = 0;
|
||||
|
||||
iowait_time = (unsigned int) (cur_iowait_time -
|
||||
od_j_dbs_info->prev_cpu_iowait);
|
||||
od_j_dbs_info->prev_cpu_iowait = cur_iowait_time;
|
||||
|
||||
/*
|
||||
* For the purpose of ondemand, waiting for disk IO is
|
||||
* an indication that you're performance critical, and
|
||||
* not that the system is actually idle. So subtract the
|
||||
* iowait time from the cpu idle time.
|
||||
*/
|
||||
if (od_tuners->io_is_busy && idle_time >= iowait_time)
|
||||
idle_time -= iowait_time;
|
||||
}
|
||||
|
||||
if (unlikely(!wall_time || wall_time < idle_time))
|
||||
continue;
|
||||
|
||||
load = 100 * (wall_time - idle_time) / wall_time;
|
||||
|
||||
if (dbs_data->governor == GOV_ONDEMAND) {
|
||||
if (dbs_data->cdata->governor == GOV_ONDEMAND) {
|
||||
int freq_avg = __cpufreq_driver_getavg(policy, j);
|
||||
if (freq_avg <= 0)
|
||||
freq_avg = policy->cur;
|
||||
|
@ -157,24 +160,42 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
|
|||
max_load = load;
|
||||
}
|
||||
|
||||
dbs_data->gov_check_cpu(cpu, max_load);
|
||||
dbs_data->cdata->gov_check_cpu(cpu, max_load);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dbs_check_cpu);
|
||||
|
||||
static inline void dbs_timer_init(struct dbs_data *dbs_data, int cpu,
|
||||
unsigned int sampling_rate)
|
||||
static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data,
|
||||
unsigned int delay)
|
||||
{
|
||||
int delay = delay_for_sampling_rate(sampling_rate);
|
||||
struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
|
||||
struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
|
||||
|
||||
schedule_delayed_work_on(cpu, &cdbs->work, delay);
|
||||
mod_delayed_work_on(cpu, system_wq, &cdbs->work, delay);
|
||||
}
|
||||
|
||||
static inline void dbs_timer_exit(struct dbs_data *dbs_data, int cpu)
|
||||
void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
|
||||
unsigned int delay, bool all_cpus)
|
||||
{
|
||||
struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
|
||||
int i;
|
||||
|
||||
cancel_delayed_work_sync(&cdbs->work);
|
||||
if (!all_cpus) {
|
||||
__gov_queue_work(smp_processor_id(), dbs_data, delay);
|
||||
} else {
|
||||
for_each_cpu(i, policy->cpus)
|
||||
__gov_queue_work(i, dbs_data, delay);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gov_queue_work);
|
||||
|
||||
static inline void gov_cancel_work(struct dbs_data *dbs_data,
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpu_dbs_common_info *cdbs;
|
||||
int i;
|
||||
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
cdbs = dbs_data->cdata->get_cpu_cdbs(i);
|
||||
cancel_delayed_work_sync(&cdbs->work);
|
||||
}
|
||||
}
|
||||
|
||||
/* Will return if we need to evaluate cpu load again or not */
|
||||
|
@ -196,31 +217,130 @@ bool need_load_eval(struct cpu_dbs_common_info *cdbs,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(need_load_eval);
|
||||
|
||||
int cpufreq_governor_dbs(struct dbs_data *dbs_data,
|
||||
struct cpufreq_policy *policy, unsigned int event)
|
||||
static void set_sampling_rate(struct dbs_data *dbs_data,
|
||||
unsigned int sampling_rate)
|
||||
{
|
||||
if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
cs_tuners->sampling_rate = sampling_rate;
|
||||
} else {
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
od_tuners->sampling_rate = sampling_rate;
|
||||
}
|
||||
}
|
||||
|
||||
int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
struct common_dbs_data *cdata, unsigned int event)
|
||||
{
|
||||
struct dbs_data *dbs_data;
|
||||
struct od_cpu_dbs_info_s *od_dbs_info = NULL;
|
||||
struct cs_cpu_dbs_info_s *cs_dbs_info = NULL;
|
||||
struct cs_ops *cs_ops = NULL;
|
||||
struct od_ops *od_ops = NULL;
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
struct od_dbs_tuners *od_tuners = NULL;
|
||||
struct cs_dbs_tuners *cs_tuners = NULL;
|
||||
struct cpu_dbs_common_info *cpu_cdbs;
|
||||
unsigned int *sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
|
||||
unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
|
||||
int io_busy = 0;
|
||||
int rc;
|
||||
|
||||
cpu_cdbs = dbs_data->get_cpu_cdbs(cpu);
|
||||
if (have_governor_per_policy())
|
||||
dbs_data = policy->governor_data;
|
||||
else
|
||||
dbs_data = cdata->gdbs_data;
|
||||
|
||||
if (dbs_data->governor == GOV_CONSERVATIVE) {
|
||||
cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
|
||||
sampling_rate = &cs_tuners->sampling_rate;
|
||||
WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT));
|
||||
|
||||
switch (event) {
|
||||
case CPUFREQ_GOV_POLICY_INIT:
|
||||
if (have_governor_per_policy()) {
|
||||
WARN_ON(dbs_data);
|
||||
} else if (dbs_data) {
|
||||
policy->governor_data = dbs_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL);
|
||||
if (!dbs_data) {
|
||||
pr_err("%s: POLICY_INIT: kzalloc failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dbs_data->cdata = cdata;
|
||||
rc = cdata->init(dbs_data);
|
||||
if (rc) {
|
||||
pr_err("%s: POLICY_INIT: init() failed\n", __func__);
|
||||
kfree(dbs_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sysfs_create_group(get_governor_parent_kobj(policy),
|
||||
get_sysfs_attr(dbs_data));
|
||||
if (rc) {
|
||||
cdata->exit(dbs_data);
|
||||
kfree(dbs_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
policy->governor_data = dbs_data;
|
||||
|
||||
/* policy latency is in nS. Convert it to uS first */
|
||||
latency = policy->cpuinfo.transition_latency / 1000;
|
||||
if (latency == 0)
|
||||
latency = 1;
|
||||
|
||||
/* Bring kernel and HW constraints together */
|
||||
dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
|
||||
MIN_LATENCY_MULTIPLIER * latency);
|
||||
set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
|
||||
latency * LATENCY_MULTIPLIER));
|
||||
|
||||
if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
|
||||
struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
|
||||
|
||||
cpufreq_register_notifier(cs_ops->notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
if (!have_governor_per_policy())
|
||||
cdata->gdbs_data = dbs_data;
|
||||
|
||||
return 0;
|
||||
case CPUFREQ_GOV_POLICY_EXIT:
|
||||
if ((policy->governor->initialized == 1) ||
|
||||
have_governor_per_policy()) {
|
||||
sysfs_remove_group(get_governor_parent_kobj(policy),
|
||||
get_sysfs_attr(dbs_data));
|
||||
|
||||
if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
|
||||
struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
|
||||
|
||||
cpufreq_unregister_notifier(cs_ops->notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
cdata->exit(dbs_data);
|
||||
kfree(dbs_data);
|
||||
cdata->gdbs_data = NULL;
|
||||
}
|
||||
|
||||
policy->governor_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpu_cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
|
||||
|
||||
if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
|
||||
cs_tuners = dbs_data->tuners;
|
||||
cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
|
||||
sampling_rate = cs_tuners->sampling_rate;
|
||||
ignore_nice = cs_tuners->ignore_nice;
|
||||
cs_ops = dbs_data->gov_ops;
|
||||
} else {
|
||||
od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
|
||||
sampling_rate = &od_tuners->sampling_rate;
|
||||
od_tuners = dbs_data->tuners;
|
||||
od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
|
||||
sampling_rate = od_tuners->sampling_rate;
|
||||
ignore_nice = od_tuners->ignore_nice;
|
||||
od_ops = dbs_data->gov_ops;
|
||||
od_ops = dbs_data->cdata->gov_ops;
|
||||
io_busy = od_tuners->io_is_busy;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
|
@ -232,96 +352,53 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,
|
|||
|
||||
for_each_cpu(j, policy->cpus) {
|
||||
struct cpu_dbs_common_info *j_cdbs =
|
||||
dbs_data->get_cpu_cdbs(j);
|
||||
dbs_data->cdata->get_cpu_cdbs(j);
|
||||
|
||||
j_cdbs->cpu = j;
|
||||
j_cdbs->cur_policy = policy;
|
||||
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
|
||||
&j_cdbs->prev_cpu_wall);
|
||||
&j_cdbs->prev_cpu_wall, io_busy);
|
||||
if (ignore_nice)
|
||||
j_cdbs->prev_cpu_nice =
|
||||
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
|
||||
|
||||
mutex_init(&j_cdbs->timer_mutex);
|
||||
INIT_DEFERRABLE_WORK(&j_cdbs->work,
|
||||
dbs_data->gov_dbs_timer);
|
||||
}
|
||||
|
||||
if (!policy->governor->initialized) {
|
||||
rc = sysfs_create_group(cpufreq_global_kobject,
|
||||
dbs_data->attr_group);
|
||||
if (rc) {
|
||||
mutex_unlock(&dbs_data->mutex);
|
||||
return rc;
|
||||
}
|
||||
dbs_data->cdata->gov_dbs_timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* conservative does not implement micro like ondemand
|
||||
* governor, thus we are bound to jiffes/HZ
|
||||
*/
|
||||
if (dbs_data->governor == GOV_CONSERVATIVE) {
|
||||
if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
|
||||
cs_dbs_info->down_skip = 0;
|
||||
cs_dbs_info->enable = 1;
|
||||
cs_dbs_info->requested_freq = policy->cur;
|
||||
|
||||
if (!policy->governor->initialized) {
|
||||
cpufreq_register_notifier(cs_ops->notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
|
||||
dbs_data->min_sampling_rate =
|
||||
MIN_SAMPLING_RATE_RATIO *
|
||||
jiffies_to_usecs(10);
|
||||
}
|
||||
} else {
|
||||
od_dbs_info->rate_mult = 1;
|
||||
od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
|
||||
od_ops->powersave_bias_init_cpu(cpu);
|
||||
|
||||
if (!policy->governor->initialized)
|
||||
od_tuners->io_is_busy = od_ops->io_busy();
|
||||
}
|
||||
|
||||
if (policy->governor->initialized)
|
||||
goto unlock;
|
||||
|
||||
/* policy latency is in nS. Convert it to uS first */
|
||||
latency = policy->cpuinfo.transition_latency / 1000;
|
||||
if (latency == 0)
|
||||
latency = 1;
|
||||
|
||||
/* Bring kernel and HW constraints together */
|
||||
dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
|
||||
MIN_LATENCY_MULTIPLIER * latency);
|
||||
*sampling_rate = max(dbs_data->min_sampling_rate, latency *
|
||||
LATENCY_MULTIPLIER);
|
||||
unlock:
|
||||
mutex_unlock(&dbs_data->mutex);
|
||||
|
||||
/* Initiate timer time stamp */
|
||||
cpu_cdbs->time_stamp = ktime_get();
|
||||
|
||||
for_each_cpu(j, policy->cpus)
|
||||
dbs_timer_init(dbs_data, j, *sampling_rate);
|
||||
gov_queue_work(dbs_data, policy,
|
||||
delay_for_sampling_rate(sampling_rate), true);
|
||||
break;
|
||||
|
||||
case CPUFREQ_GOV_STOP:
|
||||
if (dbs_data->governor == GOV_CONSERVATIVE)
|
||||
if (dbs_data->cdata->governor == GOV_CONSERVATIVE)
|
||||
cs_dbs_info->enable = 0;
|
||||
|
||||
for_each_cpu(j, policy->cpus)
|
||||
dbs_timer_exit(dbs_data, j);
|
||||
gov_cancel_work(dbs_data, policy);
|
||||
|
||||
mutex_lock(&dbs_data->mutex);
|
||||
mutex_destroy(&cpu_cdbs->timer_mutex);
|
||||
|
||||
if (policy->governor->initialized == 1) {
|
||||
sysfs_remove_group(cpufreq_global_kobject,
|
||||
dbs_data->attr_group);
|
||||
if (dbs_data->governor == GOV_CONSERVATIVE)
|
||||
cpufreq_unregister_notifier(cs_ops->notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
mutex_unlock(&dbs_data->mutex);
|
||||
|
||||
break;
|
||||
|
|
|
@ -34,20 +34,81 @@
|
|||
*/
|
||||
#define MIN_SAMPLING_RATE_RATIO (2)
|
||||
#define LATENCY_MULTIPLIER (1000)
|
||||
#define MIN_LATENCY_MULTIPLIER (100)
|
||||
#define MIN_LATENCY_MULTIPLIER (20)
|
||||
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
|
||||
|
||||
/* Ondemand Sampling types */
|
||||
enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
|
||||
|
||||
/* Macro creating sysfs show routines */
|
||||
#define show_one(_gov, file_name, object) \
|
||||
static ssize_t show_##file_name \
|
||||
/*
|
||||
* Macro for creating governors sysfs routines
|
||||
*
|
||||
* - gov_sys: One governor instance per whole system
|
||||
* - gov_pol: One governor instance per policy
|
||||
*/
|
||||
|
||||
/* Create attributes */
|
||||
#define gov_sys_attr_ro(_name) \
|
||||
static struct global_attr _name##_gov_sys = \
|
||||
__ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
|
||||
|
||||
#define gov_sys_attr_rw(_name) \
|
||||
static struct global_attr _name##_gov_sys = \
|
||||
__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
|
||||
|
||||
#define gov_pol_attr_ro(_name) \
|
||||
static struct freq_attr _name##_gov_pol = \
|
||||
__ATTR(_name, 0444, show_##_name##_gov_pol, NULL)
|
||||
|
||||
#define gov_pol_attr_rw(_name) \
|
||||
static struct freq_attr _name##_gov_pol = \
|
||||
__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
|
||||
|
||||
#define gov_sys_pol_attr_rw(_name) \
|
||||
gov_sys_attr_rw(_name); \
|
||||
gov_pol_attr_rw(_name)
|
||||
|
||||
#define gov_sys_pol_attr_ro(_name) \
|
||||
gov_sys_attr_ro(_name); \
|
||||
gov_pol_attr_ro(_name)
|
||||
|
||||
/* Create show/store routines */
|
||||
#define show_one(_gov, file_name) \
|
||||
static ssize_t show_##file_name##_gov_sys \
|
||||
(struct kobject *kobj, struct attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%u\n", _gov##_tuners.object); \
|
||||
struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
|
||||
return sprintf(buf, "%u\n", tuners->file_name); \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_##file_name##_gov_pol \
|
||||
(struct cpufreq_policy *policy, char *buf) \
|
||||
{ \
|
||||
struct dbs_data *dbs_data = policy->governor_data; \
|
||||
struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
|
||||
return sprintf(buf, "%u\n", tuners->file_name); \
|
||||
}
|
||||
|
||||
#define store_one(_gov, file_name) \
|
||||
static ssize_t store_##file_name##_gov_sys \
|
||||
(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
|
||||
return store_##file_name(dbs_data, buf, count); \
|
||||
} \
|
||||
\
|
||||
static ssize_t store_##file_name##_gov_pol \
|
||||
(struct cpufreq_policy *policy, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct dbs_data *dbs_data = policy->governor_data; \
|
||||
return store_##file_name(dbs_data, buf, count); \
|
||||
}
|
||||
|
||||
#define show_store_one(_gov, file_name) \
|
||||
show_one(_gov, file_name); \
|
||||
store_one(_gov, file_name)
|
||||
|
||||
/* create helper routines */
|
||||
#define define_get_cpu_dbs_routines(_dbs_info) \
|
||||
static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \
|
||||
{ \
|
||||
|
@ -87,7 +148,6 @@ struct cpu_dbs_common_info {
|
|||
|
||||
struct od_cpu_dbs_info_s {
|
||||
struct cpu_dbs_common_info cdbs;
|
||||
u64 prev_cpu_iowait;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
unsigned int freq_lo;
|
||||
unsigned int freq_lo_jiffies;
|
||||
|
@ -103,7 +163,7 @@ struct cs_cpu_dbs_info_s {
|
|||
unsigned int enable:1;
|
||||
};
|
||||
|
||||
/* Governers sysfs tunables */
|
||||
/* Per policy Governers sysfs tunables */
|
||||
struct od_dbs_tuners {
|
||||
unsigned int ignore_nice;
|
||||
unsigned int sampling_rate;
|
||||
|
@ -123,31 +183,42 @@ struct cs_dbs_tuners {
|
|||
unsigned int freq_step;
|
||||
};
|
||||
|
||||
/* Per Governer data */
|
||||
struct dbs_data {
|
||||
/* Common Governer data across policies */
|
||||
struct dbs_data;
|
||||
struct common_dbs_data {
|
||||
/* Common across governors */
|
||||
#define GOV_ONDEMAND 0
|
||||
#define GOV_CONSERVATIVE 1
|
||||
int governor;
|
||||
unsigned int min_sampling_rate;
|
||||
struct attribute_group *attr_group;
|
||||
void *tuners;
|
||||
struct attribute_group *attr_group_gov_sys; /* one governor - system */
|
||||
struct attribute_group *attr_group_gov_pol; /* one governor - policy */
|
||||
|
||||
/* dbs_mutex protects dbs_enable in governor start/stop */
|
||||
struct mutex mutex;
|
||||
/* 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);
|
||||
void *(*get_cpu_dbs_info_s)(int cpu);
|
||||
void (*gov_dbs_timer)(struct work_struct *work);
|
||||
void (*gov_check_cpu)(int cpu, unsigned int load);
|
||||
int (*init)(struct dbs_data *dbs_data);
|
||||
void (*exit)(struct dbs_data *dbs_data);
|
||||
|
||||
/* Governor specific ops, see below */
|
||||
void *gov_ops;
|
||||
};
|
||||
|
||||
/* Governer Per policy data */
|
||||
struct dbs_data {
|
||||
struct common_dbs_data *cdata;
|
||||
unsigned int min_sampling_rate;
|
||||
void *tuners;
|
||||
|
||||
/* dbs_mutex protects dbs_enable in governor start/stop */
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
/* Governor specific ops, will be passed to dbs_data->gov_ops */
|
||||
struct od_ops {
|
||||
int (*io_busy)(void);
|
||||
void (*powersave_bias_init_cpu)(int cpu);
|
||||
unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
|
||||
unsigned int freq_next, unsigned int relation);
|
||||
|
@ -169,10 +240,31 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
|
|||
return delay;
|
||||
}
|
||||
|
||||
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
|
||||
#define declare_show_sampling_rate_min(_gov) \
|
||||
static ssize_t show_sampling_rate_min_gov_sys \
|
||||
(struct kobject *kobj, struct attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
|
||||
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_sampling_rate_min_gov_pol \
|
||||
(struct cpufreq_policy *policy, char *buf) \
|
||||
{ \
|
||||
struct dbs_data *dbs_data = policy->governor_data; \
|
||||
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
|
||||
}
|
||||
|
||||
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
|
||||
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
|
||||
bool need_load_eval(struct cpu_dbs_common_info *cdbs,
|
||||
unsigned int sampling_rate);
|
||||
int cpufreq_governor_dbs(struct dbs_data *dbs_data,
|
||||
struct cpufreq_policy *policy, unsigned int event);
|
||||
int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
struct common_dbs_data *cdata, unsigned int event);
|
||||
void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
|
||||
unsigned int delay, bool all_cpus);
|
||||
void od_register_powersave_bias_handler(unsigned int (*f)
|
||||
(struct cpufreq_policy *, unsigned int, unsigned int),
|
||||
unsigned int powersave_bias);
|
||||
void od_unregister_powersave_bias_handler(void);
|
||||
#endif /* _CPUFREQ_GOVERNOR_H */
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/percpu-defs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include "cpufreq_governor.h"
|
||||
|
||||
|
@ -37,22 +39,14 @@
|
|||
#define MIN_FREQUENCY_UP_THRESHOLD (11)
|
||||
#define MAX_FREQUENCY_UP_THRESHOLD (100)
|
||||
|
||||
static struct dbs_data od_dbs_data;
|
||||
static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);
|
||||
|
||||
static struct od_ops od_ops;
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
|
||||
static struct cpufreq_governor cpufreq_gov_ondemand;
|
||||
#endif
|
||||
|
||||
static struct od_dbs_tuners od_tuners = {
|
||||
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
|
||||
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
|
||||
.adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
|
||||
DEF_FREQUENCY_DOWN_DIFFERENTIAL,
|
||||
.ignore_nice = 0,
|
||||
.powersave_bias = 0,
|
||||
};
|
||||
|
||||
static void ondemand_powersave_bias_init_cpu(int cpu)
|
||||
{
|
||||
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
|
||||
|
@ -89,7 +83,7 @@ static int should_io_be_busy(void)
|
|||
* Returns the freq_hi to be used right now and will set freq_hi_jiffies,
|
||||
* freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
|
||||
*/
|
||||
static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
|
||||
static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
|
||||
unsigned int freq_next, unsigned int relation)
|
||||
{
|
||||
unsigned int freq_req, freq_reduc, freq_avg;
|
||||
|
@ -98,6 +92,8 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
|
|||
unsigned int jiffies_total, jiffies_hi, jiffies_lo;
|
||||
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
|
||||
policy->cpu);
|
||||
struct dbs_data *dbs_data = policy->governor_data;
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
|
||||
if (!dbs_info->freq_table) {
|
||||
dbs_info->freq_lo = 0;
|
||||
|
@ -108,7 +104,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
|
|||
cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
|
||||
relation, &index);
|
||||
freq_req = dbs_info->freq_table[index].frequency;
|
||||
freq_reduc = freq_req * od_tuners.powersave_bias / 1000;
|
||||
freq_reduc = freq_req * od_tuners->powersave_bias / 1000;
|
||||
freq_avg = freq_req - freq_reduc;
|
||||
|
||||
/* Find freq bounds for freq_avg in freq_table */
|
||||
|
@ -127,7 +123,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
|
|||
dbs_info->freq_lo_jiffies = 0;
|
||||
return freq_lo;
|
||||
}
|
||||
jiffies_total = usecs_to_jiffies(od_tuners.sampling_rate);
|
||||
jiffies_total = usecs_to_jiffies(od_tuners->sampling_rate);
|
||||
jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
|
||||
jiffies_hi += ((freq_hi - freq_lo) / 2);
|
||||
jiffies_hi /= (freq_hi - freq_lo);
|
||||
|
@ -148,12 +144,16 @@ static void ondemand_powersave_bias_init(void)
|
|||
|
||||
static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
|
||||
{
|
||||
if (od_tuners.powersave_bias)
|
||||
freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H);
|
||||
struct dbs_data *dbs_data = p->governor_data;
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
|
||||
if (od_tuners->powersave_bias)
|
||||
freq = od_ops.powersave_bias_target(p, freq,
|
||||
CPUFREQ_RELATION_H);
|
||||
else if (p->cur == p->max)
|
||||
return;
|
||||
|
||||
__cpufreq_driver_target(p, freq, od_tuners.powersave_bias ?
|
||||
__cpufreq_driver_target(p, freq, od_tuners->powersave_bias ?
|
||||
CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
|
||||
}
|
||||
|
||||
|
@ -170,15 +170,17 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
|
|||
{
|
||||
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
|
||||
struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
|
||||
struct dbs_data *dbs_data = policy->governor_data;
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
|
||||
dbs_info->freq_lo = 0;
|
||||
|
||||
/* Check for frequency increase */
|
||||
if (load_freq > od_tuners.up_threshold * policy->cur) {
|
||||
if (load_freq > od_tuners->up_threshold * policy->cur) {
|
||||
/* If switching to max speed, apply sampling_down_factor */
|
||||
if (policy->cur < policy->max)
|
||||
dbs_info->rate_mult =
|
||||
od_tuners.sampling_down_factor;
|
||||
od_tuners->sampling_down_factor;
|
||||
dbs_freq_increase(policy, policy->max);
|
||||
return;
|
||||
}
|
||||
|
@ -193,9 +195,10 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
|
|||
* support the current CPU usage without triggering the up policy. To be
|
||||
* safe, we focus 10 points under the threshold.
|
||||
*/
|
||||
if (load_freq < od_tuners.adj_up_threshold * policy->cur) {
|
||||
if (load_freq < od_tuners->adj_up_threshold
|
||||
* policy->cur) {
|
||||
unsigned int freq_next;
|
||||
freq_next = load_freq / od_tuners.adj_up_threshold;
|
||||
freq_next = load_freq / od_tuners->adj_up_threshold;
|
||||
|
||||
/* No longer fully busy, reset rate_mult */
|
||||
dbs_info->rate_mult = 1;
|
||||
|
@ -203,65 +206,62 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
|
|||
if (freq_next < policy->min)
|
||||
freq_next = policy->min;
|
||||
|
||||
if (!od_tuners.powersave_bias) {
|
||||
if (!od_tuners->powersave_bias) {
|
||||
__cpufreq_driver_target(policy, freq_next,
|
||||
CPUFREQ_RELATION_L);
|
||||
} else {
|
||||
int freq = powersave_bias_target(policy, freq_next,
|
||||
CPUFREQ_RELATION_L);
|
||||
__cpufreq_driver_target(policy, freq,
|
||||
CPUFREQ_RELATION_L);
|
||||
return;
|
||||
}
|
||||
|
||||
freq_next = od_ops.powersave_bias_target(policy, freq_next,
|
||||
CPUFREQ_RELATION_L);
|
||||
__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
|
||||
}
|
||||
}
|
||||
|
||||
static void od_dbs_timer(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct od_cpu_dbs_info_s *dbs_info =
|
||||
container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work);
|
||||
unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
|
||||
struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info,
|
||||
cpu);
|
||||
int delay, sample_type = core_dbs_info->sample_type;
|
||||
bool eval_load;
|
||||
struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
int delay = 0, sample_type = core_dbs_info->sample_type;
|
||||
bool modify_all = true;
|
||||
|
||||
mutex_lock(&core_dbs_info->cdbs.timer_mutex);
|
||||
eval_load = need_load_eval(&core_dbs_info->cdbs,
|
||||
od_tuners.sampling_rate);
|
||||
if (!need_load_eval(&core_dbs_info->cdbs, od_tuners->sampling_rate)) {
|
||||
modify_all = false;
|
||||
goto max_delay;
|
||||
}
|
||||
|
||||
/* Common NORMAL_SAMPLE setup */
|
||||
core_dbs_info->sample_type = OD_NORMAL_SAMPLE;
|
||||
if (sample_type == OD_SUB_SAMPLE) {
|
||||
delay = core_dbs_info->freq_lo_jiffies;
|
||||
if (eval_load)
|
||||
__cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
|
||||
core_dbs_info->freq_lo,
|
||||
CPUFREQ_RELATION_H);
|
||||
__cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
|
||||
core_dbs_info->freq_lo, CPUFREQ_RELATION_H);
|
||||
} else {
|
||||
if (eval_load)
|
||||
dbs_check_cpu(&od_dbs_data, cpu);
|
||||
dbs_check_cpu(dbs_data, cpu);
|
||||
if (core_dbs_info->freq_lo) {
|
||||
/* Setup timer for SUB_SAMPLE */
|
||||
core_dbs_info->sample_type = OD_SUB_SAMPLE;
|
||||
delay = core_dbs_info->freq_hi_jiffies;
|
||||
} else {
|
||||
delay = delay_for_sampling_rate(od_tuners.sampling_rate
|
||||
* core_dbs_info->rate_mult);
|
||||
}
|
||||
}
|
||||
|
||||
schedule_delayed_work_on(smp_processor_id(), dw, delay);
|
||||
max_delay:
|
||||
if (!delay)
|
||||
delay = delay_for_sampling_rate(od_tuners->sampling_rate
|
||||
* core_dbs_info->rate_mult);
|
||||
|
||||
gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);
|
||||
mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
|
||||
}
|
||||
|
||||
/************************** sysfs interface ************************/
|
||||
|
||||
static ssize_t show_sampling_rate_min(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", od_dbs_data.min_sampling_rate);
|
||||
}
|
||||
static struct common_dbs_data od_dbs_cdata;
|
||||
|
||||
/**
|
||||
* update_sampling_rate - update sampling rate effective immediately if needed.
|
||||
|
@ -276,12 +276,14 @@ static ssize_t show_sampling_rate_min(struct kobject *kobj,
|
|||
* reducing the sampling rate, we need to make the new value effective
|
||||
* immediately.
|
||||
*/
|
||||
static void update_sampling_rate(unsigned int new_rate)
|
||||
static void update_sampling_rate(struct dbs_data *dbs_data,
|
||||
unsigned int new_rate)
|
||||
{
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
int cpu;
|
||||
|
||||
od_tuners.sampling_rate = new_rate = max(new_rate,
|
||||
od_dbs_data.min_sampling_rate);
|
||||
od_tuners->sampling_rate = new_rate = max(new_rate,
|
||||
dbs_data->min_sampling_rate);
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
struct cpufreq_policy *policy;
|
||||
|
@ -314,42 +316,54 @@ static void update_sampling_rate(unsigned int new_rate)
|
|||
cancel_delayed_work_sync(&dbs_info->cdbs.work);
|
||||
mutex_lock(&dbs_info->cdbs.timer_mutex);
|
||||
|
||||
schedule_delayed_work_on(cpu, &dbs_info->cdbs.work,
|
||||
usecs_to_jiffies(new_rate));
|
||||
gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy,
|
||||
usecs_to_jiffies(new_rate), true);
|
||||
|
||||
}
|
||||
mutex_unlock(&dbs_info->cdbs.timer_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
update_sampling_rate(input);
|
||||
|
||||
update_sampling_rate(dbs_data, input);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
unsigned int j;
|
||||
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
od_tuners.io_is_busy = !!input;
|
||||
od_tuners->io_is_busy = !!input;
|
||||
|
||||
/* we need to re-evaluate prev_cpu_idle */
|
||||
for_each_online_cpu(j) {
|
||||
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
|
||||
j);
|
||||
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
|
||||
&dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
@ -359,23 +373,24 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
|
|||
return -EINVAL;
|
||||
}
|
||||
/* Calculate the new adj_up_threshold */
|
||||
od_tuners.adj_up_threshold += input;
|
||||
od_tuners.adj_up_threshold -= od_tuners.up_threshold;
|
||||
od_tuners->adj_up_threshold += input;
|
||||
od_tuners->adj_up_threshold -= od_tuners->up_threshold;
|
||||
|
||||
od_tuners.up_threshold = input;
|
||||
od_tuners->up_threshold = input;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_sampling_down_factor(struct kobject *a,
|
||||
struct attribute *b, const char *buf, size_t count)
|
||||
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
unsigned int input, j;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
|
||||
return -EINVAL;
|
||||
od_tuners.sampling_down_factor = input;
|
||||
od_tuners->sampling_down_factor = input;
|
||||
|
||||
/* Reset down sampling multiplier in case it was active */
|
||||
for_each_online_cpu(j) {
|
||||
|
@ -386,9 +401,10 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
|
||||
|
@ -401,18 +417,18 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
|
|||
if (input > 1)
|
||||
input = 1;
|
||||
|
||||
if (input == od_tuners.ignore_nice) { /* nothing to do */
|
||||
if (input == od_tuners->ignore_nice) { /* nothing to do */
|
||||
return count;
|
||||
}
|
||||
od_tuners.ignore_nice = input;
|
||||
od_tuners->ignore_nice = input;
|
||||
|
||||
/* we need to re-evaluate prev_cpu_idle */
|
||||
for_each_online_cpu(j) {
|
||||
struct od_cpu_dbs_info_s *dbs_info;
|
||||
dbs_info = &per_cpu(od_cpu_dbs_info, j);
|
||||
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
|
||||
&dbs_info->cdbs.prev_cpu_wall);
|
||||
if (od_tuners.ignore_nice)
|
||||
&dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
|
||||
if (od_tuners->ignore_nice)
|
||||
dbs_info->cdbs.prev_cpu_nice =
|
||||
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
|
||||
|
||||
|
@ -420,9 +436,10 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
@ -433,68 +450,179 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
|
|||
if (input > 1000)
|
||||
input = 1000;
|
||||
|
||||
od_tuners.powersave_bias = input;
|
||||
od_tuners->powersave_bias = input;
|
||||
ondemand_powersave_bias_init();
|
||||
return count;
|
||||
}
|
||||
|
||||
show_one(od, sampling_rate, sampling_rate);
|
||||
show_one(od, io_is_busy, io_is_busy);
|
||||
show_one(od, up_threshold, up_threshold);
|
||||
show_one(od, sampling_down_factor, sampling_down_factor);
|
||||
show_one(od, ignore_nice_load, ignore_nice);
|
||||
show_one(od, powersave_bias, powersave_bias);
|
||||
show_store_one(od, sampling_rate);
|
||||
show_store_one(od, io_is_busy);
|
||||
show_store_one(od, up_threshold);
|
||||
show_store_one(od, sampling_down_factor);
|
||||
show_store_one(od, ignore_nice);
|
||||
show_store_one(od, powersave_bias);
|
||||
declare_show_sampling_rate_min(od);
|
||||
|
||||
define_one_global_rw(sampling_rate);
|
||||
define_one_global_rw(io_is_busy);
|
||||
define_one_global_rw(up_threshold);
|
||||
define_one_global_rw(sampling_down_factor);
|
||||
define_one_global_rw(ignore_nice_load);
|
||||
define_one_global_rw(powersave_bias);
|
||||
define_one_global_ro(sampling_rate_min);
|
||||
gov_sys_pol_attr_rw(sampling_rate);
|
||||
gov_sys_pol_attr_rw(io_is_busy);
|
||||
gov_sys_pol_attr_rw(up_threshold);
|
||||
gov_sys_pol_attr_rw(sampling_down_factor);
|
||||
gov_sys_pol_attr_rw(ignore_nice);
|
||||
gov_sys_pol_attr_rw(powersave_bias);
|
||||
gov_sys_pol_attr_ro(sampling_rate_min);
|
||||
|
||||
static struct attribute *dbs_attributes[] = {
|
||||
&sampling_rate_min.attr,
|
||||
&sampling_rate.attr,
|
||||
&up_threshold.attr,
|
||||
&sampling_down_factor.attr,
|
||||
&ignore_nice_load.attr,
|
||||
&powersave_bias.attr,
|
||||
&io_is_busy.attr,
|
||||
static struct attribute *dbs_attributes_gov_sys[] = {
|
||||
&sampling_rate_min_gov_sys.attr,
|
||||
&sampling_rate_gov_sys.attr,
|
||||
&up_threshold_gov_sys.attr,
|
||||
&sampling_down_factor_gov_sys.attr,
|
||||
&ignore_nice_gov_sys.attr,
|
||||
&powersave_bias_gov_sys.attr,
|
||||
&io_is_busy_gov_sys.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group od_attr_group = {
|
||||
.attrs = dbs_attributes,
|
||||
static struct attribute_group od_attr_group_gov_sys = {
|
||||
.attrs = dbs_attributes_gov_sys,
|
||||
.name = "ondemand",
|
||||
};
|
||||
|
||||
static struct attribute *dbs_attributes_gov_pol[] = {
|
||||
&sampling_rate_min_gov_pol.attr,
|
||||
&sampling_rate_gov_pol.attr,
|
||||
&up_threshold_gov_pol.attr,
|
||||
&sampling_down_factor_gov_pol.attr,
|
||||
&ignore_nice_gov_pol.attr,
|
||||
&powersave_bias_gov_pol.attr,
|
||||
&io_is_busy_gov_pol.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group od_attr_group_gov_pol = {
|
||||
.attrs = dbs_attributes_gov_pol,
|
||||
.name = "ondemand",
|
||||
};
|
||||
|
||||
/************************** sysfs end ************************/
|
||||
|
||||
static int od_init(struct dbs_data *dbs_data)
|
||||
{
|
||||
struct od_dbs_tuners *tuners;
|
||||
u64 idle_time;
|
||||
int cpu;
|
||||
|
||||
tuners = kzalloc(sizeof(struct od_dbs_tuners), GFP_KERNEL);
|
||||
if (!tuners) {
|
||||
pr_err("%s: kzalloc failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cpu = get_cpu();
|
||||
idle_time = get_cpu_idle_time_us(cpu, NULL);
|
||||
put_cpu();
|
||||
if (idle_time != -1ULL) {
|
||||
/* Idle micro accounting is supported. Use finer thresholds */
|
||||
tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
|
||||
tuners->adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
|
||||
MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
|
||||
/*
|
||||
* In nohz/micro accounting case we set the minimum frequency
|
||||
* not depending on HZ, but fixed (very low). The deferred
|
||||
* timer might skip some samples if idle/sleeping as needed.
|
||||
*/
|
||||
dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
|
||||
} else {
|
||||
tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
|
||||
tuners->adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
|
||||
DEF_FREQUENCY_DOWN_DIFFERENTIAL;
|
||||
|
||||
/* For correct statistics, we need 10 ticks for each measure */
|
||||
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
|
||||
jiffies_to_usecs(10);
|
||||
}
|
||||
|
||||
tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
|
||||
tuners->ignore_nice = 0;
|
||||
tuners->powersave_bias = 0;
|
||||
tuners->io_is_busy = should_io_be_busy();
|
||||
|
||||
dbs_data->tuners = tuners;
|
||||
pr_info("%s: tuners %p\n", __func__, tuners);
|
||||
mutex_init(&dbs_data->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void od_exit(struct dbs_data *dbs_data)
|
||||
{
|
||||
kfree(dbs_data->tuners);
|
||||
}
|
||||
|
||||
define_get_cpu_dbs_routines(od_cpu_dbs_info);
|
||||
|
||||
static struct od_ops od_ops = {
|
||||
.io_busy = should_io_be_busy,
|
||||
.powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu,
|
||||
.powersave_bias_target = powersave_bias_target,
|
||||
.powersave_bias_target = generic_powersave_bias_target,
|
||||
.freq_increase = dbs_freq_increase,
|
||||
};
|
||||
|
||||
static struct dbs_data od_dbs_data = {
|
||||
static struct common_dbs_data od_dbs_cdata = {
|
||||
.governor = GOV_ONDEMAND,
|
||||
.attr_group = &od_attr_group,
|
||||
.tuners = &od_tuners,
|
||||
.attr_group_gov_sys = &od_attr_group_gov_sys,
|
||||
.attr_group_gov_pol = &od_attr_group_gov_pol,
|
||||
.get_cpu_cdbs = get_cpu_cdbs,
|
||||
.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
|
||||
.gov_dbs_timer = od_dbs_timer,
|
||||
.gov_check_cpu = od_check_cpu,
|
||||
.gov_ops = &od_ops,
|
||||
.init = od_init,
|
||||
.exit = od_exit,
|
||||
};
|
||||
|
||||
static void od_set_powersave_bias(unsigned int powersave_bias)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct dbs_data *dbs_data;
|
||||
struct od_dbs_tuners *od_tuners;
|
||||
unsigned int cpu;
|
||||
cpumask_t done;
|
||||
|
||||
cpumask_clear(&done);
|
||||
|
||||
get_online_cpus();
|
||||
for_each_online_cpu(cpu) {
|
||||
if (cpumask_test_cpu(cpu, &done))
|
||||
continue;
|
||||
|
||||
policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.cur_policy;
|
||||
dbs_data = policy->governor_data;
|
||||
od_tuners = dbs_data->tuners;
|
||||
od_tuners->powersave_bias = powersave_bias;
|
||||
|
||||
cpumask_or(&done, &done, policy->cpus);
|
||||
}
|
||||
put_online_cpus();
|
||||
}
|
||||
|
||||
void od_register_powersave_bias_handler(unsigned int (*f)
|
||||
(struct cpufreq_policy *, unsigned int, unsigned int),
|
||||
unsigned int powersave_bias)
|
||||
{
|
||||
od_ops.powersave_bias_target = f;
|
||||
od_set_powersave_bias(powersave_bias);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(od_register_powersave_bias_handler);
|
||||
|
||||
void od_unregister_powersave_bias_handler(void)
|
||||
{
|
||||
od_ops.powersave_bias_target = generic_powersave_bias_target;
|
||||
od_set_powersave_bias(0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler);
|
||||
|
||||
static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
unsigned int event)
|
||||
{
|
||||
return cpufreq_governor_dbs(&od_dbs_data, policy, event);
|
||||
return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
|
||||
|
@ -509,29 +637,6 @@ struct cpufreq_governor cpufreq_gov_ondemand = {
|
|||
|
||||
static int __init cpufreq_gov_dbs_init(void)
|
||||
{
|
||||
u64 idle_time;
|
||||
int cpu = get_cpu();
|
||||
|
||||
mutex_init(&od_dbs_data.mutex);
|
||||
idle_time = get_cpu_idle_time_us(cpu, NULL);
|
||||
put_cpu();
|
||||
if (idle_time != -1ULL) {
|
||||
/* Idle micro accounting is supported. Use finer thresholds */
|
||||
od_tuners.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
|
||||
od_tuners.adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
|
||||
MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
|
||||
/*
|
||||
* In nohz/micro accounting case we set the minimum frequency
|
||||
* not depending on HZ, but fixed (very low). The deferred
|
||||
* timer might skip some samples if idle/sleeping as needed.
|
||||
*/
|
||||
od_dbs_data.min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
|
||||
} else {
|
||||
/* For correct statistics, we need 10 ticks for each measure */
|
||||
od_dbs_data.min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
|
||||
jiffies_to_usecs(10);
|
||||
}
|
||||
|
||||
return cpufreq_register_governor(&cpufreq_gov_ondemand);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,23 +27,17 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
|
|||
return clk_ctrl.pll ? 200000 : 6000;
|
||||
}
|
||||
|
||||
static void cris_freq_set_cpu_state(unsigned int state)
|
||||
static void cris_freq_set_cpu_state(struct cpufreq_policy *policy,
|
||||
unsigned int state)
|
||||
{
|
||||
int i = 0;
|
||||
struct cpufreq_freqs freqs;
|
||||
reg_clkgen_rw_clk_ctrl clk_ctrl;
|
||||
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
for_each_present_cpu(i)
|
||||
#endif
|
||||
{
|
||||
freqs.old = cris_freq_get_cpu_frequency(i);
|
||||
freqs.new = cris_freq_table[state].frequency;
|
||||
freqs.cpu = i;
|
||||
}
|
||||
freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
|
||||
freqs.new = cris_freq_table[state].frequency;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
|
@ -57,7 +51,7 @@ static void cris_freq_set_cpu_state(unsigned int state)
|
|||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
};
|
||||
|
||||
static int cris_freq_verify(struct cpufreq_policy *policy)
|
||||
|
@ -75,7 +69,7 @@ static int cris_freq_target(struct cpufreq_policy *policy,
|
|||
target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
cris_freq_set_cpu_state(newstate);
|
||||
cris_freq_set_cpu_state(policy, newstate);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -27,20 +27,17 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
|
|||
return clk_ctrl.pll ? 200000 : 6000;
|
||||
}
|
||||
|
||||
static void cris_freq_set_cpu_state(unsigned int state)
|
||||
static void cris_freq_set_cpu_state(struct cpufreq_policy *policy,
|
||||
unsigned int state)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_freqs freqs;
|
||||
reg_config_rw_clk_ctrl clk_ctrl;
|
||||
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
freqs.old = cris_freq_get_cpu_frequency(i);
|
||||
freqs.new = cris_freq_table[state].frequency;
|
||||
freqs.cpu = i;
|
||||
}
|
||||
freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
|
||||
freqs.new = cris_freq_table[state].frequency;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
|
@ -54,7 +51,7 @@ static void cris_freq_set_cpu_state(unsigned int state)
|
|||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
};
|
||||
|
||||
static int cris_freq_verify(struct cpufreq_policy *policy)
|
||||
|
@ -71,7 +68,7 @@ static int cris_freq_target(struct cpufreq_policy *policy,
|
|||
(policy, cris_freq_table, target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
cris_freq_set_cpu_state(newstate);
|
||||
cris_freq_set_cpu_state(policy, newstate);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -30,8 +30,6 @@
|
|||
#include <mach/cpufreq.h>
|
||||
#include <mach/common.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
struct davinci_cpufreq {
|
||||
struct device *dev;
|
||||
struct clk *armclk;
|
||||
|
@ -79,18 +77,8 @@ static int davinci_target(struct cpufreq_policy *policy,
|
|||
struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
|
||||
struct clk *armclk = cpufreq.armclk;
|
||||
|
||||
/*
|
||||
* Ensure desired rate is within allowed range. Some govenors
|
||||
* (ondemand) will just pass target_freq=0 to get the minimum.
|
||||
*/
|
||||
if (target_freq < policy->cpuinfo.min_freq)
|
||||
target_freq = policy->cpuinfo.min_freq;
|
||||
if (target_freq > policy->cpuinfo.max_freq)
|
||||
target_freq = policy->cpuinfo.max_freq;
|
||||
|
||||
freqs.old = davinci_getspeed(0);
|
||||
freqs.new = clk_round_rate(armclk, target_freq * 1000) / 1000;
|
||||
freqs.cpu = 0;
|
||||
|
||||
if (freqs.old == freqs.new)
|
||||
return ret;
|
||||
|
@ -102,7 +90,7 @@ static int davinci_target(struct cpufreq_policy *policy,
|
|||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* if moving to higher frequency, up the voltage beforehand */
|
||||
if (pdata->set_voltage && freqs.new > freqs.old) {
|
||||
|
@ -126,7 +114,7 @@ static int davinci_target(struct cpufreq_policy *policy,
|
|||
pdata->set_voltage(idx);
|
||||
|
||||
out:
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -147,21 +135,16 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
|
|||
return result;
|
||||
}
|
||||
|
||||
policy->cur = policy->min = policy->max = davinci_getspeed(0);
|
||||
policy->cur = davinci_getspeed(0);
|
||||
|
||||
if (freq_table) {
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
if (!result)
|
||||
cpufreq_frequency_table_get_attr(freq_table,
|
||||
policy->cpu);
|
||||
} else {
|
||||
policy->cpuinfo.min_freq = policy->min;
|
||||
policy->cpuinfo.max_freq = policy->max;
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
if (result) {
|
||||
pr_err("%s: cpufreq_frequency_table_cpuinfo() failed",
|
||||
__func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
policy->min = policy->cpuinfo.min_freq;
|
||||
policy->max = policy->cpuinfo.max_freq;
|
||||
policy->cur = davinci_getspeed(0);
|
||||
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
|
||||
|
||||
/*
|
||||
* Time measurement across the target() function yields ~1500-1800us
|
|
@ -37,12 +37,6 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
|
|||
unsigned int idx;
|
||||
int ret;
|
||||
|
||||
/* scale the target frequency to one of the extremes supported */
|
||||
if (target_freq < policy->cpuinfo.min_freq)
|
||||
target_freq = policy->cpuinfo.min_freq;
|
||||
if (target_freq > policy->cpuinfo.max_freq)
|
||||
target_freq = policy->cpuinfo.max_freq;
|
||||
|
||||
/* Lookup the next frequency */
|
||||
if (cpufreq_frequency_table_target(policy, freq_table, target_freq,
|
||||
relation, &idx))
|
||||
|
@ -55,8 +49,7 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
|
|||
return 0;
|
||||
|
||||
/* pre-change notification */
|
||||
for_each_cpu(freqs.cpu, policy->cpus)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* update armss clk frequency */
|
||||
ret = clk_set_rate(armss_clk, freqs.new * 1000);
|
||||
|
@ -68,8 +61,7 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
|
|||
}
|
||||
|
||||
/* post change notification */
|
||||
for_each_cpu(freqs.cpu, policy->cpus)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -79,15 +71,15 @@ static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
|
|||
int i = 0;
|
||||
unsigned long freq = clk_get_rate(armss_clk) / 1000;
|
||||
|
||||
while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
|
||||
if (freq <= freq_table[i].frequency)
|
||||
/* The value is rounded to closest frequency in the defined table. */
|
||||
while (freq_table[i + 1].frequency != CPUFREQ_TABLE_END) {
|
||||
if (freq < freq_table[i].frequency +
|
||||
(freq_table[i + 1].frequency - freq_table[i].frequency) / 2)
|
||||
return freq_table[i].frequency;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* We could not find a corresponding frequency. */
|
||||
pr_err("dbx500-cpufreq: Failed to find cpufreq speed\n");
|
||||
return 0;
|
||||
return freq_table[i].frequency;
|
||||
}
|
||||
|
||||
static int __cpuinit dbx500_cpufreq_init(struct cpufreq_policy *policy)
|
||||
|
|
|
@ -104,7 +104,7 @@ static unsigned int eps_get(unsigned int cpu)
|
|||
}
|
||||
|
||||
static int eps_set_state(struct eps_cpu_data *centaur,
|
||||
unsigned int cpu,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 dest_state)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
|
@ -112,10 +112,9 @@ static int eps_set_state(struct eps_cpu_data *centaur,
|
|||
int err = 0;
|
||||
int i;
|
||||
|
||||
freqs.old = eps_get(cpu);
|
||||
freqs.old = eps_get(policy->cpu);
|
||||
freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff);
|
||||
freqs.cpu = cpu;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* Wait while CPU is busy */
|
||||
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
|
||||
|
@ -162,7 +161,7 @@ postchange:
|
|||
current_multiplier);
|
||||
}
|
||||
#endif
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -190,7 +189,7 @@ static int eps_target(struct cpufreq_policy *policy,
|
|||
|
||||
/* Make frequency transition */
|
||||
dest_state = centaur->freq_table[newstate].index & 0xffff;
|
||||
ret = eps_set_state(centaur, cpu, dest_state);
|
||||
ret = eps_set_state(centaur, policy, dest_state);
|
||||
if (ret)
|
||||
printk(KERN_ERR "eps: Timeout!\n");
|
||||
return ret;
|
||||
|
|
|
@ -117,15 +117,15 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
|
|||
* There is no return value.
|
||||
*/
|
||||
|
||||
static void elanfreq_set_cpu_state(unsigned int state)
|
||||
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;
|
||||
freqs.cpu = 0; /* elanfreq.c is UP only driver */
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",
|
||||
elan_multiplier[state].clock);
|
||||
|
@ -161,7 +161,7 @@ static void elanfreq_set_cpu_state(unsigned int state)
|
|||
udelay(10000);
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
};
|
||||
|
||||
|
||||
|
@ -188,7 +188,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
|
|||
target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
elanfreq_set_cpu_state(newstate);
|
||||
elanfreq_set_cpu_state(policy, newstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,6 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
|||
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = target_freq;
|
||||
freqs.cpu = policy->cpu;
|
||||
|
||||
if (freqs.new == freqs.old)
|
||||
goto out;
|
||||
|
@ -105,8 +104,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
|||
}
|
||||
arm_volt = volt_table[index];
|
||||
|
||||
for_each_cpu(freqs.cpu, policy->cpus)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* When the new frequency is higher than current frequency */
|
||||
if ((freqs.new > freqs.old) && !safe_arm_volt) {
|
||||
|
@ -131,8 +129,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
|||
|
||||
exynos_info->set_freq(old_index, index);
|
||||
|
||||
for_each_cpu(freqs.cpu, policy->cpus)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
/* When the new frequency is lower than current frequency */
|
||||
if ((freqs.new < freqs.old) ||
|
||||
|
@ -297,7 +294,7 @@ static int __init exynos_cpufreq_init(void)
|
|||
else if (soc_is_exynos5250())
|
||||
ret = exynos5250_cpufreq_init(exynos_info);
|
||||
else
|
||||
pr_err("%s: CPU type not found\n", __func__);
|
||||
return 0;
|
||||
|
||||
if (ret)
|
||||
goto err_vdd_arm;
|
||||
|
|
481
drivers/cpufreq/exynos5440-cpufreq.c
Normal file
481
drivers/cpufreq/exynos5440-cpufreq.c
Normal file
|
@ -0,0 +1,481 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Amit Daniel Kachhap <amit.daniel@samsung.com>
|
||||
*
|
||||
* EXYNOS5440 - CPU frequency scaling support
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/opp.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Register definitions */
|
||||
#define XMU_DVFS_CTRL 0x0060
|
||||
#define XMU_PMU_P0_7 0x0064
|
||||
#define XMU_C0_3_PSTATE 0x0090
|
||||
#define XMU_P_LIMIT 0x00a0
|
||||
#define XMU_P_STATUS 0x00a4
|
||||
#define XMU_PMUEVTEN 0x00d0
|
||||
#define XMU_PMUIRQEN 0x00d4
|
||||
#define XMU_PMUIRQ 0x00d8
|
||||
|
||||
/* PMU mask and shift definations */
|
||||
#define P_VALUE_MASK 0x7
|
||||
|
||||
#define XMU_DVFS_CTRL_EN_SHIFT 0
|
||||
|
||||
#define P0_7_CPUCLKDEV_SHIFT 21
|
||||
#define P0_7_CPUCLKDEV_MASK 0x7
|
||||
#define P0_7_ATBCLKDEV_SHIFT 18
|
||||
#define P0_7_ATBCLKDEV_MASK 0x7
|
||||
#define P0_7_CSCLKDEV_SHIFT 15
|
||||
#define P0_7_CSCLKDEV_MASK 0x7
|
||||
#define P0_7_CPUEMA_SHIFT 28
|
||||
#define P0_7_CPUEMA_MASK 0xf
|
||||
#define P0_7_L2EMA_SHIFT 24
|
||||
#define P0_7_L2EMA_MASK 0xf
|
||||
#define P0_7_VDD_SHIFT 8
|
||||
#define P0_7_VDD_MASK 0x7f
|
||||
#define P0_7_FREQ_SHIFT 0
|
||||
#define P0_7_FREQ_MASK 0xff
|
||||
|
||||
#define C0_3_PSTATE_VALID_SHIFT 8
|
||||
#define C0_3_PSTATE_CURR_SHIFT 4
|
||||
#define C0_3_PSTATE_NEW_SHIFT 0
|
||||
|
||||
#define PSTATE_CHANGED_EVTEN_SHIFT 0
|
||||
|
||||
#define PSTATE_CHANGED_IRQEN_SHIFT 0
|
||||
|
||||
#define PSTATE_CHANGED_SHIFT 0
|
||||
|
||||
/* some constant values for clock divider calculation */
|
||||
#define CPU_DIV_FREQ_MAX 500
|
||||
#define CPU_DBG_FREQ_MAX 375
|
||||
#define CPU_ATB_FREQ_MAX 500
|
||||
|
||||
#define PMIC_LOW_VOLT 0x30
|
||||
#define PMIC_HIGH_VOLT 0x28
|
||||
|
||||
#define CPUEMA_HIGH 0x2
|
||||
#define CPUEMA_MID 0x4
|
||||
#define CPUEMA_LOW 0x7
|
||||
|
||||
#define L2EMA_HIGH 0x1
|
||||
#define L2EMA_MID 0x3
|
||||
#define L2EMA_LOW 0x4
|
||||
|
||||
#define DIV_TAB_MAX 2
|
||||
/* frequency unit is 20MHZ */
|
||||
#define FREQ_UNIT 20
|
||||
#define MAX_VOLTAGE 1550000 /* In microvolt */
|
||||
#define VOLTAGE_STEP 12500 /* In microvolt */
|
||||
|
||||
#define CPUFREQ_NAME "exynos5440_dvfs"
|
||||
#define DEF_TRANS_LATENCY 100000
|
||||
|
||||
enum cpufreq_level_index {
|
||||
L0, L1, L2, L3, L4,
|
||||
L5, L6, L7, L8, L9,
|
||||
};
|
||||
#define CPUFREQ_LEVEL_END (L7 + 1)
|
||||
|
||||
struct exynos_dvfs_data {
|
||||
void __iomem *base;
|
||||
struct resource *mem;
|
||||
int irq;
|
||||
struct clk *cpu_clk;
|
||||
unsigned int cur_frequency;
|
||||
unsigned int latency;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
unsigned int freq_count;
|
||||
struct device *dev;
|
||||
bool dvfs_enabled;
|
||||
struct work_struct irq_work;
|
||||
};
|
||||
|
||||
static struct exynos_dvfs_data *dvfs_info;
|
||||
static DEFINE_MUTEX(cpufreq_lock);
|
||||
static struct cpufreq_freqs freqs;
|
||||
|
||||
static int init_div_table(void)
|
||||
{
|
||||
struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
|
||||
unsigned int tmp, clk_div, ema_div, freq, volt_id;
|
||||
int i = 0;
|
||||
struct opp *opp;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
|
||||
opp = opp_find_freq_exact(dvfs_info->dev,
|
||||
freq_tbl[i].frequency * 1000, true);
|
||||
if (IS_ERR(opp)) {
|
||||
rcu_read_unlock();
|
||||
dev_err(dvfs_info->dev,
|
||||
"failed to find valid OPP for %u KHZ\n",
|
||||
freq_tbl[i].frequency);
|
||||
return PTR_ERR(opp);
|
||||
}
|
||||
|
||||
freq = freq_tbl[i].frequency / 1000; /* In MHZ */
|
||||
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
|
||||
<< P0_7_CPUCLKDEV_SHIFT;
|
||||
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
|
||||
<< P0_7_ATBCLKDEV_SHIFT;
|
||||
clk_div |= ((freq / CPU_DBG_FREQ_MAX) & P0_7_CSCLKDEV_MASK)
|
||||
<< P0_7_CSCLKDEV_SHIFT;
|
||||
|
||||
/* Calculate EMA */
|
||||
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) |
|
||||
(L2EMA_HIGH << P0_7_L2EMA_SHIFT);
|
||||
} else if (volt_id > PMIC_LOW_VOLT) {
|
||||
ema_div = (CPUEMA_LOW << P0_7_CPUEMA_SHIFT) |
|
||||
(L2EMA_LOW << P0_7_L2EMA_SHIFT);
|
||||
} else {
|
||||
ema_div = (CPUEMA_MID << P0_7_CPUEMA_SHIFT) |
|
||||
(L2EMA_MID << P0_7_L2EMA_SHIFT);
|
||||
}
|
||||
|
||||
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
|
||||
| ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
|
||||
|
||||
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_enable_dvfs(void)
|
||||
{
|
||||
unsigned int tmp, i, cpu;
|
||||
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
|
||||
/* Disable DVFS */
|
||||
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
|
||||
|
||||
/* Enable PSTATE Change Event */
|
||||
tmp = __raw_readl(dvfs_info->base + XMU_PMUEVTEN);
|
||||
tmp |= (1 << PSTATE_CHANGED_EVTEN_SHIFT);
|
||||
__raw_writel(tmp, dvfs_info->base + XMU_PMUEVTEN);
|
||||
|
||||
/* Enable PSTATE Change IRQ */
|
||||
tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQEN);
|
||||
tmp |= (1 << PSTATE_CHANGED_IRQEN_SHIFT);
|
||||
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
|
||||
|
||||
/* Set initial performance index */
|
||||
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
|
||||
if (freq_table[i].frequency == dvfs_info->cur_frequency)
|
||||
break;
|
||||
|
||||
if (freq_table[i].frequency == CPUFREQ_TABLE_END) {
|
||||
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
|
||||
/* Assign the highest frequency */
|
||||
i = 0;
|
||||
dvfs_info->cur_frequency = freq_table[i].frequency;
|
||||
}
|
||||
|
||||
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
|
||||
dvfs_info->cur_frequency);
|
||||
|
||||
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
|
||||
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
|
||||
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
|
||||
tmp |= (i << C0_3_PSTATE_NEW_SHIFT);
|
||||
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
|
||||
}
|
||||
|
||||
/* Enable DVFS */
|
||||
__raw_writel(1 << XMU_DVFS_CTRL_EN_SHIFT,
|
||||
dvfs_info->base + XMU_DVFS_CTRL);
|
||||
}
|
||||
|
||||
static int exynos_verify_speed(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_frequency_table_verify(policy,
|
||||
dvfs_info->freq_table);
|
||||
}
|
||||
|
||||
static unsigned int exynos_getspeed(unsigned int cpu)
|
||||
{
|
||||
return dvfs_info->cur_frequency;
|
||||
}
|
||||
|
||||
static int exynos_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
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;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* Set the target frequency in all C0_3_PSTATE register */
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
|
||||
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
|
||||
tmp |= (index << C0_3_PSTATE_NEW_SHIFT);
|
||||
|
||||
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&cpufreq_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exynos_cpufreq_work(struct work_struct *work)
|
||||
{
|
||||
unsigned int cur_pstate, index;
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
|
||||
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
|
||||
|
||||
/* Ensure we can access cpufreq structures */
|
||||
if (unlikely(dvfs_info->dvfs_enabled == false))
|
||||
goto skip_work;
|
||||
|
||||
mutex_lock(&cpufreq_lock);
|
||||
freqs.old = dvfs_info->cur_frequency;
|
||||
|
||||
cur_pstate = __raw_readl(dvfs_info->base + XMU_P_STATUS);
|
||||
if (cur_pstate >> C0_3_PSTATE_VALID_SHIFT & 0x1)
|
||||
index = (cur_pstate >> C0_3_PSTATE_CURR_SHIFT) & P_VALUE_MASK;
|
||||
else
|
||||
index = (cur_pstate >> C0_3_PSTATE_NEW_SHIFT) & P_VALUE_MASK;
|
||||
|
||||
if (likely(index < dvfs_info->freq_count)) {
|
||||
freqs.new = freq_table[index].frequency;
|
||||
dvfs_info->cur_frequency = freqs.new;
|
||||
} else {
|
||||
dev_crit(dvfs_info->dev, "New frequency out of range\n");
|
||||
freqs.new = dvfs_info->cur_frequency;
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
mutex_unlock(&cpufreq_lock);
|
||||
skip_work:
|
||||
enable_irq(dvfs_info->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t exynos_cpufreq_irq(int irq, void *id)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQ);
|
||||
if (tmp >> PSTATE_CHANGED_SHIFT & 0x1) {
|
||||
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQ);
|
||||
disable_irq_nosync(irq);
|
||||
schedule_work(&dvfs_info->irq_work);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void exynos_sort_descend_freq_table(void)
|
||||
{
|
||||
struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
|
||||
int i = 0, index;
|
||||
unsigned int tmp_freq;
|
||||
/*
|
||||
* Exynos5440 clock controller state logic expects the cpufreq table to
|
||||
* be in descending order. But the OPP library constructs the table in
|
||||
* ascending order. So to make the table descending we just need to
|
||||
* swap the i element with the N - i element.
|
||||
*/
|
||||
for (i = 0; i < dvfs_info->freq_count / 2; i++) {
|
||||
index = dvfs_info->freq_count - i - 1;
|
||||
tmp_freq = freq_tbl[i].frequency;
|
||||
freq_tbl[i].frequency = freq_tbl[index].frequency;
|
||||
freq_tbl[index].frequency = tmp_freq;
|
||||
}
|
||||
}
|
||||
|
||||
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cpufreq_frequency_table_cpuinfo(policy, dvfs_info->freq_table);
|
||||
if (ret) {
|
||||
dev_err(dvfs_info->dev, "Invalid frequency table: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
policy->cur = dvfs_info->cur_frequency;
|
||||
policy->cpuinfo.transition_latency = dvfs_info->latency;
|
||||
cpumask_setall(policy->cpus);
|
||||
|
||||
cpufreq_frequency_table_get_attr(dvfs_info->freq_table, policy->cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver exynos_driver = {
|
||||
.flags = CPUFREQ_STICKY,
|
||||
.verify = exynos_verify_speed,
|
||||
.target = exynos_target,
|
||||
.get = exynos_getspeed,
|
||||
.init = exynos_cpufreq_cpu_init,
|
||||
.name = CPUFREQ_NAME,
|
||||
};
|
||||
|
||||
static const struct of_device_id exynos_cpufreq_match[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5440-cpufreq",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_cpufreq_match);
|
||||
|
||||
static int exynos_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
|
||||
np = pdev->dev.of_node;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
dvfs_info = devm_kzalloc(&pdev->dev, sizeof(*dvfs_info), GFP_KERNEL);
|
||||
if (!dvfs_info) {
|
||||
ret = -ENOMEM;
|
||||
goto err_put_node;
|
||||
}
|
||||
|
||||
dvfs_info->dev = &pdev->dev;
|
||||
|
||||
ret = of_address_to_resource(np, 0, &res);
|
||||
if (ret)
|
||||
goto err_put_node;
|
||||
|
||||
dvfs_info->base = devm_ioremap_resource(dvfs_info->dev, &res);
|
||||
if (IS_ERR(dvfs_info->base)) {
|
||||
ret = PTR_ERR(dvfs_info->base);
|
||||
goto err_put_node;
|
||||
}
|
||||
|
||||
dvfs_info->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!dvfs_info->irq) {
|
||||
dev_err(dvfs_info->dev, "No cpufreq irq found\n");
|
||||
ret = -ENODEV;
|
||||
goto err_put_node;
|
||||
}
|
||||
|
||||
ret = of_init_opp_table(dvfs_info->dev);
|
||||
if (ret) {
|
||||
dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret);
|
||||
goto err_put_node;
|
||||
}
|
||||
|
||||
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 = opp_get_opp_count(dvfs_info->dev);
|
||||
exynos_sort_descend_freq_table();
|
||||
|
||||
if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency))
|
||||
dvfs_info->latency = DEF_TRANS_LATENCY;
|
||||
|
||||
dvfs_info->cpu_clk = devm_clk_get(dvfs_info->dev, "armclk");
|
||||
if (IS_ERR(dvfs_info->cpu_clk)) {
|
||||
dev_err(dvfs_info->dev, "Failed to get cpu clock\n");
|
||||
ret = PTR_ERR(dvfs_info->cpu_clk);
|
||||
goto err_free_table;
|
||||
}
|
||||
|
||||
dvfs_info->cur_frequency = clk_get_rate(dvfs_info->cpu_clk);
|
||||
if (!dvfs_info->cur_frequency) {
|
||||
dev_err(dvfs_info->dev, "Failed to get clock rate\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_table;
|
||||
}
|
||||
dvfs_info->cur_frequency /= 1000;
|
||||
|
||||
INIT_WORK(&dvfs_info->irq_work, exynos_cpufreq_work);
|
||||
ret = devm_request_irq(dvfs_info->dev, dvfs_info->irq,
|
||||
exynos_cpufreq_irq, IRQF_TRIGGER_NONE,
|
||||
CPUFREQ_NAME, dvfs_info);
|
||||
if (ret) {
|
||||
dev_err(dvfs_info->dev, "Failed to register IRQ\n");
|
||||
goto err_free_table;
|
||||
}
|
||||
|
||||
ret = init_div_table();
|
||||
if (ret) {
|
||||
dev_err(dvfs_info->dev, "Failed to initialise div table\n");
|
||||
goto err_free_table;
|
||||
}
|
||||
|
||||
exynos_enable_dvfs();
|
||||
ret = cpufreq_register_driver(&exynos_driver);
|
||||
if (ret) {
|
||||
dev_err(dvfs_info->dev,
|
||||
"%s: failed to register cpufreq driver\n", __func__);
|
||||
goto err_free_table;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
dvfs_info->dvfs_enabled = true;
|
||||
return 0;
|
||||
|
||||
err_free_table:
|
||||
opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
|
||||
err_put_node:
|
||||
of_node_put(np);
|
||||
dev_err(dvfs_info->dev, "%s: failed initialization\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_cpufreq_remove(struct platform_device *pdev)
|
||||
{
|
||||
cpufreq_unregister_driver(&exynos_driver);
|
||||
opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver exynos_cpufreq_platdrv = {
|
||||
.driver = {
|
||||
.name = "exynos5440-cpufreq",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = exynos_cpufreq_match,
|
||||
},
|
||||
.probe = exynos_cpufreq_probe,
|
||||
.remove = exynos_cpufreq_remove,
|
||||
};
|
||||
module_platform_driver(exynos_cpufreq_platdrv);
|
||||
|
||||
MODULE_AUTHOR("Amit Daniel Kachhap <amit.daniel@samsung.com>");
|
||||
MODULE_DESCRIPTION("Exynos5440 cpufreq driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -251,14 +251,13 @@ static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration,
|
|||
* set cpu speed in khz.
|
||||
**/
|
||||
|
||||
static void gx_set_cpuspeed(unsigned int khz)
|
||||
static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
|
||||
{
|
||||
u8 suscfg, pmer1;
|
||||
unsigned int new_khz;
|
||||
unsigned long flags;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
freqs.cpu = 0;
|
||||
freqs.old = gx_get_cpuspeed(0);
|
||||
|
||||
new_khz = gx_validate_speed(khz, &gx_params->on_duration,
|
||||
|
@ -266,11 +265,9 @@ static void gx_set_cpuspeed(unsigned int khz)
|
|||
|
||||
freqs.new = new_khz;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
local_irq_save(flags);
|
||||
|
||||
|
||||
|
||||
if (new_khz != stock_freq) {
|
||||
/* if new khz == 100% of CPU speed, it is special case */
|
||||
switch (gx_params->cs55x0->device) {
|
||||
|
@ -317,7 +314,7 @@ static void gx_set_cpuspeed(unsigned int khz)
|
|||
|
||||
gx_params->pci_suscfg = suscfg;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
|
||||
gx_params->on_duration * 32, gx_params->off_duration * 32);
|
||||
|
@ -397,7 +394,7 @@ static int cpufreq_gx_target(struct cpufreq_policy *policy,
|
|||
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
|
||||
}
|
||||
|
||||
gx_set_cpuspeed(tmp_freq);
|
||||
gx_set_cpuspeed(policy, tmp_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/*
|
||||
* arch/ia64/kernel/cpufreq/acpi-cpufreq.c
|
||||
* This file provides the ACPI based P-state support. This
|
||||
* module works with generic cpufreq infrastructure. Most of
|
||||
* the code is based on i386 version
|
||||
|
@ -137,7 +136,7 @@ migrate_end:
|
|||
static int
|
||||
processor_set_freq (
|
||||
struct cpufreq_acpi_io *data,
|
||||
unsigned int cpu,
|
||||
struct cpufreq_policy *policy,
|
||||
int state)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -149,8 +148,8 @@ processor_set_freq (
|
|||
pr_debug("processor_set_freq\n");
|
||||
|
||||
saved_mask = current->cpus_allowed;
|
||||
set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
||||
if (smp_processor_id() != cpu) {
|
||||
set_cpus_allowed_ptr(current, cpumask_of(policy->cpu));
|
||||
if (smp_processor_id() != policy->cpu) {
|
||||
retval = -EAGAIN;
|
||||
goto migrate_end;
|
||||
}
|
||||
|
@ -170,12 +169,11 @@ processor_set_freq (
|
|||
data->acpi_data.state, state);
|
||||
|
||||
/* cpufreq frequency struct */
|
||||
cpufreq_freqs.cpu = cpu;
|
||||
cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
|
||||
cpufreq_freqs.new = data->freq_table[state].frequency;
|
||||
|
||||
/* notify cpufreq */
|
||||
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/*
|
||||
* First we write the target state's 'control' value to the
|
||||
|
@ -189,17 +187,20 @@ processor_set_freq (
|
|||
ret = processor_set_pstate(value);
|
||||
if (ret) {
|
||||
unsigned int tmp = cpufreq_freqs.new;
|
||||
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &cpufreq_freqs,
|
||||
CPUFREQ_POSTCHANGE);
|
||||
cpufreq_freqs.new = cpufreq_freqs.old;
|
||||
cpufreq_freqs.old = tmp;
|
||||
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
|
||||
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(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
data->acpi_data.state = state;
|
||||
|
||||
|
@ -240,7 +241,7 @@ acpi_cpufreq_target (
|
|||
if (result)
|
||||
return (result);
|
||||
|
||||
result = processor_set_freq(data, policy->cpu, next_state);
|
||||
result = processor_set_freq(data, policy, next_state);
|
||||
|
||||
return (result);
|
||||
}
|
|
@ -50,7 +50,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
|
|||
struct cpufreq_freqs freqs;
|
||||
struct opp *opp;
|
||||
unsigned long freq_hz, volt, volt_old;
|
||||
unsigned int index, cpu;
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
||||
ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
|
||||
|
@ -68,10 +68,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
|
|||
if (freqs.old == freqs.new)
|
||||
return 0;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
freqs.cpu = cpu;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
rcu_read_lock();
|
||||
opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
|
||||
|
@ -166,10 +163,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
|
|||
}
|
||||
}
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
freqs.cpu = cpu;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* linux/arch/arm/mach-integrator/cpu.c
|
||||
*
|
||||
* Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -123,14 +121,12 @@ static int integrator_set_target(struct cpufreq_policy *policy,
|
|||
vco = icst_hz_to_vco(&cclk_params, target_freq * 1000);
|
||||
freqs.new = icst_hz(&cclk_params, vco) / 1000;
|
||||
|
||||
freqs.cpu = policy->cpu;
|
||||
|
||||
if (freqs.old == freqs.new) {
|
||||
set_cpus_allowed(current, cpus_allowed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
cm_osc = __raw_readl(CM_OSC);
|
||||
|
||||
|
@ -151,7 +147,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
|
|||
*/
|
||||
set_cpus_allowed(current, cpus_allowed);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* cpufreq_snb.c: Native P state management for Intel processors
|
||||
* intel_pstate.c: Native P state management for Intel processors
|
||||
*
|
||||
* (C) Copyright 2012 Intel Corporation
|
||||
* Author: Dirk Brandewie <dirk.j.brandewie@intel.com>
|
||||
|
@ -657,30 +657,27 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
|
|||
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpudata *cpu;
|
||||
int min, max;
|
||||
|
||||
cpu = all_cpu_data[policy->cpu];
|
||||
|
||||
if (!policy->cpuinfo.max_freq)
|
||||
return -ENODEV;
|
||||
|
||||
intel_pstate_get_min_max(cpu, &min, &max);
|
||||
|
||||
limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
|
||||
limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
|
||||
limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
|
||||
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
|
||||
|
||||
if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
|
||||
limits.min_perf_pct = 100;
|
||||
limits.min_perf = int_tofp(1);
|
||||
limits.max_perf_pct = 100;
|
||||
limits.max_perf = int_tofp(1);
|
||||
limits.no_turbo = 0;
|
||||
return 0;
|
||||
}
|
||||
limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
|
||||
limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
|
||||
limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
|
||||
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,8 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
|
|||
return kirkwood_freq_table[0].frequency;
|
||||
}
|
||||
|
||||
static void kirkwood_cpufreq_set_cpu_state(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].index;
|
||||
|
@ -63,9 +64,8 @@ static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
|
|||
|
||||
freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
|
||||
freqs.new = kirkwood_freq_table[index].frequency;
|
||||
freqs.cpu = 0; /* Kirkwood is UP */
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n",
|
||||
kirkwood_freq_table[index].frequency);
|
||||
|
@ -99,7 +99,7 @@ static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
|
|||
|
||||
local_irq_enable();
|
||||
}
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
};
|
||||
|
||||
static int kirkwood_cpufreq_verify(struct cpufreq_policy *policy)
|
||||
|
@ -117,7 +117,7 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
|
|||
target_freq, relation, &index))
|
||||
return -EINVAL;
|
||||
|
||||
kirkwood_cpufreq_set_cpu_state(index);
|
||||
kirkwood_cpufreq_set_cpu_state(policy, index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -175,11 +175,9 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "Cannot get memory resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
priv.base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!priv.base) {
|
||||
dev_err(&pdev->dev, "Cannot ioremap\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
priv.base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv.base))
|
||||
return PTR_ERR(priv.base);
|
||||
|
||||
np = of_find_node_by_path("/cpus/cpu@0");
|
||||
if (!np)
|
||||
|
|
|
@ -242,7 +242,8 @@ static void do_powersaver(int cx_address, unsigned int mults_index,
|
|||
* Sets a new clock ratio.
|
||||
*/
|
||||
|
||||
static void longhaul_setstate(unsigned int table_index)
|
||||
static void longhaul_setstate(struct cpufreq_policy *policy,
|
||||
unsigned int table_index)
|
||||
{
|
||||
unsigned int mults_index;
|
||||
int speed, mult;
|
||||
|
@ -267,9 +268,8 @@ static void longhaul_setstate(unsigned int table_index)
|
|||
|
||||
freqs.old = calc_speed(longhaul_get_cpu_mult());
|
||||
freqs.new = speed;
|
||||
freqs.cpu = 0; /* longhaul.c is UP only driver */
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
|
||||
fsb, mult/10, mult%10, print_speed(speed/1000));
|
||||
|
@ -386,7 +386,7 @@ retry_loop:
|
|||
}
|
||||
}
|
||||
/* Report true CPU frequency */
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
if (!bm_timeout)
|
||||
printk(KERN_INFO PFX "Warning: Timeout while waiting for "
|
||||
|
@ -648,7 +648,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
|
|||
return 0;
|
||||
|
||||
if (!can_scale_voltage)
|
||||
longhaul_setstate(table_index);
|
||||
longhaul_setstate(policy, table_index);
|
||||
else {
|
||||
/* On test system voltage transitions exceeding single
|
||||
* step up or down were turning motherboard off. Both
|
||||
|
@ -663,7 +663,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
|
|||
while (i != table_index) {
|
||||
vid = (longhaul_table[i].index >> 8) & 0x1f;
|
||||
if (vid != current_vid) {
|
||||
longhaul_setstate(i);
|
||||
longhaul_setstate(policy, i);
|
||||
current_vid = vid;
|
||||
msleep(200);
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
|
|||
else
|
||||
i--;
|
||||
}
|
||||
longhaul_setstate(table_index);
|
||||
longhaul_setstate(policy, table_index);
|
||||
}
|
||||
longhaul_index = table_index;
|
||||
return 0;
|
||||
|
@ -998,15 +998,17 @@ static int __init longhaul_init(void)
|
|||
|
||||
static void __exit longhaul_exit(void)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numscales; i++) {
|
||||
if (mults[i] == maxmult) {
|
||||
longhaul_setstate(i);
|
||||
longhaul_setstate(policy, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
cpufreq_unregister_driver(&longhaul_driver);
|
||||
kfree(longhaul_table);
|
||||
}
|
||||
|
|
|
@ -61,9 +61,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
|
|||
struct cpufreq_freqs freqs;
|
||||
unsigned int freq;
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
return -ENODEV;
|
||||
|
||||
cpus_allowed = current->cpus_allowed;
|
||||
set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
||||
|
||||
|
@ -80,7 +77,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
|
|||
|
||||
pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
|
||||
|
||||
freqs.cpu = cpu;
|
||||
freqs.old = loongson2_cpufreq_get(cpu);
|
||||
freqs.new = freq;
|
||||
freqs.flags = 0;
|
||||
|
@ -89,7 +85,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
|
|||
return 0;
|
||||
|
||||
/* notifiers */
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||
|
||||
|
@ -97,7 +93,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
|
|||
clk_set_rate(cpuclk, freq);
|
||||
|
||||
/* notifiers */
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
pr_debug("cpufreq: set frequency %u kHz\n", freq);
|
||||
|
||||
|
@ -110,9 +106,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
if (!cpu_online(policy->cpu))
|
||||
return -ENODEV;
|
||||
|
||||
cpuclk = clk_get(NULL, "cpu_clk");
|
||||
if (IS_ERR(cpuclk)) {
|
||||
printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
|
|
@ -158,11 +158,10 @@ static int maple_cpufreq_target(struct cpufreq_policy *policy,
|
|||
|
||||
freqs.old = maple_cpu_freqs[maple_pmode_cur].frequency;
|
||||
freqs.new = maple_cpu_freqs[newstate].frequency;
|
||||
freqs.cpu = 0;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
rc = maple_scom_switch_freq(newstate);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
mutex_unlock(&maple_switch_mutex);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/opp.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <asm/smp_plat.h>
|
||||
|
@ -88,16 +89,12 @@ static int omap_target(struct cpufreq_policy *policy,
|
|||
}
|
||||
|
||||
freqs.old = omap_getspeed(policy->cpu);
|
||||
freqs.cpu = policy->cpu;
|
||||
|
||||
if (freqs.old == freqs.new && policy->cur == freqs.new)
|
||||
return ret;
|
||||
|
||||
/* notifiers */
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
freq = freqs.new * 1000;
|
||||
ret = clk_round_rate(mpu_clk, freq);
|
||||
|
@ -157,10 +154,7 @@ static int omap_target(struct cpufreq_policy *policy,
|
|||
|
||||
done:
|
||||
/* notifiers */
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -184,7 +178,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
|
|||
goto fail_ck;
|
||||
}
|
||||
|
||||
policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
|
||||
policy->cur = omap_getspeed(policy->cpu);
|
||||
|
||||
if (!freq_table)
|
||||
result = opp_init_cpufreq_table(mpu_dev, &freq_table);
|
||||
|
@ -203,8 +197,6 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
|
||||
|
||||
policy->min = policy->cpuinfo.min_freq;
|
||||
policy->max = policy->cpuinfo.max_freq;
|
||||
policy->cur = omap_getspeed(policy->cpu);
|
||||
|
||||
/*
|
||||
|
@ -252,7 +244,7 @@ static struct cpufreq_driver omap_driver = {
|
|||
.attr = omap_cpufreq_attr,
|
||||
};
|
||||
|
||||
static int __init omap_cpufreq_init(void)
|
||||
static int omap_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
mpu_dev = get_cpu_device(0);
|
||||
if (!mpu_dev) {
|
||||
|
@ -280,12 +272,20 @@ static int __init omap_cpufreq_init(void)
|
|||
return cpufreq_register_driver(&omap_driver);
|
||||
}
|
||||
|
||||
static void __exit omap_cpufreq_exit(void)
|
||||
static int omap_cpufreq_remove(struct platform_device *pdev)
|
||||
{
|
||||
cpufreq_unregister_driver(&omap_driver);
|
||||
return cpufreq_unregister_driver(&omap_driver);
|
||||
}
|
||||
|
||||
static struct platform_driver omap_cpufreq_platdrv = {
|
||||
.driver = {
|
||||
.name = "omap-cpufreq",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = omap_cpufreq_probe,
|
||||
.remove = omap_cpufreq_remove,
|
||||
};
|
||||
module_platform_driver(omap_cpufreq_platdrv);
|
||||
|
||||
MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(omap_cpufreq_init);
|
||||
module_exit(omap_cpufreq_exit);
|
||||
|
|
|
@ -58,8 +58,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
|
|||
{
|
||||
u32 l, h;
|
||||
|
||||
if (!cpu_online(cpu) ||
|
||||
(newstate > DC_DISABLE) || (newstate == DC_RESV))
|
||||
if ((newstate > DC_DISABLE) || (newstate == DC_RESV))
|
||||
return -EINVAL;
|
||||
|
||||
rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
|
||||
|
@ -125,10 +124,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
|
|||
return 0;
|
||||
|
||||
/* notifiers */
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* run on each logical CPU,
|
||||
* see section 13.15.3 of IA32 Intel Architecture Software
|
||||
|
@ -138,10 +134,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
|
|||
cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
|
||||
|
||||
/* notifiers */
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -215,8 +215,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
|
|||
(pcch_virt_addr + pcc_cpu_data->input_offset));
|
||||
|
||||
freqs.new = target_freq;
|
||||
freqs.cpu = cpu;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
input_buffer = 0x1 | (((target_freq * 100)
|
||||
/ (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
|
||||
|
@ -237,7 +236,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
|
|||
}
|
||||
iowrite16(0, &pcch_hdr->status);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
|
||||
spin_unlock(&pcc_lock);
|
||||
|
||||
|
|
|
@ -68,7 +68,8 @@ static int powernow_k6_get_cpu_multiplier(void)
|
|||
*
|
||||
* Tries to change the PowerNow! multiplier
|
||||
*/
|
||||
static void powernow_k6_set_state(unsigned int best_i)
|
||||
static void powernow_k6_set_state(struct cpufreq_policy *policy,
|
||||
unsigned int best_i)
|
||||
{
|
||||
unsigned long outvalue = 0, invalue = 0;
|
||||
unsigned long msrval;
|
||||
|
@ -81,9 +82,8 @@ static void powernow_k6_set_state(unsigned int best_i)
|
|||
|
||||
freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
|
||||
freqs.new = busfreq * clock_ratio[best_i].index;
|
||||
freqs.cpu = 0; /* powernow-k6.c is UP only driver */
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* we now need to transform best_i to the BVC format, see AMD#23446 */
|
||||
|
||||
|
@ -98,7 +98,7 @@ static void powernow_k6_set_state(unsigned int best_i)
|
|||
msrval = POWERNOW_IOPORT + 0x0;
|
||||
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
|
|||
target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
powernow_k6_set_state(newstate);
|
||||
powernow_k6_set_state(policy, newstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -182,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_set_state(i);
|
||||
powernow_k6_set_state(policy, i);
|
||||
}
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
return 0;
|
||||
|
|
|
@ -248,7 +248,7 @@ static void change_VID(int vid)
|
|||
}
|
||||
|
||||
|
||||
static void change_speed(unsigned int index)
|
||||
static void change_speed(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
u8 fid, vid;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
@ -263,15 +263,13 @@ static void change_speed(unsigned int index)
|
|||
fid = powernow_table[index].index & 0xFF;
|
||||
vid = (powernow_table[index].index & 0xFF00) >> 8;
|
||||
|
||||
freqs.cpu = 0;
|
||||
|
||||
rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
cfid = fidvidstatus.bits.CFID;
|
||||
freqs.old = fsb * fid_codes[cfid] / 10;
|
||||
|
||||
freqs.new = powernow_table[index].frequency;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* Now do the magic poking into the MSRs. */
|
||||
|
||||
|
@ -292,7 +290,7 @@ static void change_speed(unsigned int index)
|
|||
if (have_a0 == 1)
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -546,7 +544,7 @@ static int powernow_target(struct cpufreq_policy *policy,
|
|||
relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
change_speed(newstate);
|
||||
change_speed(policy, newstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -928,9 +928,10 @@ static int get_transition_latency(struct powernow_k8_data *data)
|
|||
static int transition_frequency_fidvid(struct powernow_k8_data *data,
|
||||
unsigned int index)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
u32 fid = 0;
|
||||
u32 vid = 0;
|
||||
int res, i;
|
||||
int res;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
|
||||
|
@ -959,10 +960,10 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
|
|||
freqs.old = find_khz_freq_from_fid(data->currfid);
|
||||
freqs.new = find_khz_freq_from_fid(fid);
|
||||
|
||||
for_each_cpu(i, data->available_cores) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
}
|
||||
policy = cpufreq_cpu_get(smp_processor_id());
|
||||
cpufreq_cpu_put(policy);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
res = transition_fid_vid(data, fid, vid);
|
||||
if (res)
|
||||
|
@ -970,10 +971,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
|
|||
|
||||
freqs.new = find_khz_freq_from_fid(data->currfid);
|
||||
|
||||
for_each_cpu(i, data->available_cores) {
|
||||
freqs.cpu = i;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1104,9 +1102,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
struct init_on_cpu init_on_cpu;
|
||||
int rc;
|
||||
|
||||
if (!cpu_online(pol->cpu))
|
||||
return -ENODEV;
|
||||
|
||||
smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
|
||||
if (rc)
|
||||
return -ENODEV;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue