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 commit a8e39c3 from pm-cpuidle)
	drivers/cpufreq/cpufreq_governor.h (with commit beb0ff3)
This commit is contained in:
Rafael J. Wysocki 2013-04-28 02:10:46 +02:00
commit 885f925eef
122 changed files with 2769 additions and 1239 deletions

View file

@ -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.

View file

@ -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
=============================================

View file

@ -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>;
};
};

View file

@ -32,7 +32,7 @@ cpus {
396000 950000
198000 850000
>;
transition-latency = <61036>; /* two CLK32 periods */
clock-latency = <61036>; /* two CLK32 periods */
};
cpu@1 {

View file

@ -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>;
};

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
#include "../../generic.h"

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -0,0 +1 @@
#include "../../generic.h"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -3,7 +3,6 @@
#
obj-y := dma.o pinmux.o io.o arbiter.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
clean:

View file

@ -3,7 +3,6 @@
#
obj-y := dma.o pinmux.o io.o arbiter.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
clean:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,2 +0,0 @@
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -1,5 +0,0 @@
#
# Makefile for the Linux/MIPS cpufreq.
#
obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o

View file

@ -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).

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 },

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View 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");

View 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);

View 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 */

View 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");

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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 */

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View 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");

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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");

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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