diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-28 02:10:46 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-28 02:10:46 +0200 |
commit | 885f925eef411f549f17bc64dd054a3269cf66cd (patch) | |
tree | 6bac783d573a51e497ad28c19b5a71defac85f39 | |
parent | e4f5a3adc454745fea35f1c312e14cbeba6e0ea4 (diff) | |
parent | 45c009a9a447655aecbdb06c86126f05d0272171 (diff) | |
download | linux-885f925eef411f549f17bc64dd054a3269cf66cd.tar.bz2 |
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)
122 files changed, 2770 insertions, 1240 deletions
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 72f70b16d299..a3585eac83b6 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -108,8 +108,9 @@ policy->governor must contain the "default policy" for cpufreq_driver.target is called with these values. -For setting some of these values, the frequency table helpers might be -helpful. See the section 2 for more information on them. +For setting some of these values (cpuinfo.min[max]_freq, policy->min[max]), the +frequency table helpers might be helpful. See the section 2 for more information +on them. SMP systems normally have same clock source for a group of cpus. For these the .init() would be called only once for the first online cpu. Here the .init() @@ -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. diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index c7a2eb8450c2..66f9cc310686 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -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 ============================================= diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt new file mode 100644 index 000000000000..0715695e94a9 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt @@ -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>; + }; +}; diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index 4416ccc33472..051f764bedb8 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@ -32,7 +32,7 @@ cpus { 396000 950000 198000 850000 >; - transition-latency = <61036>; /* two CLK32 periods */ + clock-latency = <61036>; /* two CLK32 periods */ }; cpu@1 { diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt new file mode 100644 index 000000000000..caff1a57436f --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt @@ -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>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 1bef08d407f3..8faa946d0c10 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2200,12 +2200,25 @@ F: drivers/net/ethernet/ti/cpmac.c CPU FREQUENCY DRIVERS M: Rafael J. Wysocki <rjw@sisk.pl> +M: Viresh Kumar <viresh.kumar@linaro.org> L: cpufreq@vger.kernel.org L: linux-pm@vger.kernel.org S: Maintained +T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git F: drivers/cpufreq/ F: include/linux/cpufreq.h +CPU FREQUENCY DRIVERS - ARM BIG LITTLE +M: Viresh Kumar <viresh.kumar@linaro.org> +M: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com> +L: cpufreq@vger.kernel.org +L: linux-pm@vger.kernel.org +W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php +S: Maintained +F: drivers/cpufreq/arm_big_little.h +F: drivers/cpufreq/arm_big_little.c +F: drivers/cpufreq/arm_big_little_dt.c + CPUIDLE DRIVERS M: Rafael J. Wysocki <rjw@sisk.pl> M: Daniel Lezcano <daniel.lezcano@linaro.org> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1cacda426a0e..cdb83225f3ea 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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 diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index fb5c1aa98a63..dd1ffccc75e9 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -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 diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 70f94c87479d..d5dde0727339 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -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 diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c index d8c75c3c925d..387dc4cceca2 100644 --- a/arch/arm/mach-imx/cpufreq.c +++ b/arch/arm/mach-imx/cpufreq.c @@ -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); diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index 5521d18bf19a..d14d6b76f4c2 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -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 diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 673a4c1d1d76..8d15f9ae19ff 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -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 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 12c500558387..648867a8caa8 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -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 diff --git a/arch/arm/mach-pxa/include/mach/generic.h b/arch/arm/mach-pxa/include/mach/generic.h new file mode 100644 index 000000000000..665542e0c9e2 --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/generic.h @@ -0,0 +1 @@ +#include "../../generic.h" diff --git a/arch/arm/mach-s3c24xx/cpufreq.c b/arch/arm/mach-s3c24xx/cpufreq.c index 5f181e733eee..3c0e78ede0da 100644 --- a/arch/arm/mach-s3c24xx/cpufreq.c +++ b/arch/arm/mach-s3c24xx/cpufreq.c @@ -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; diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index ca14dbdcfb22..04f9784ff0ed 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -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 diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 1aed9e70465d..2732eef48966 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -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 diff --git a/arch/arm/mach-sa1100/include/mach/generic.h b/arch/arm/mach-sa1100/include/mach/generic.h new file mode 100644 index 000000000000..665542e0c9e2 --- /dev/null +++ b/arch/arm/mach-sa1100/include/mach/generic.h @@ -0,0 +1 @@ +#include "../../generic.h" diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index f6b46ae2b7f8..09b578f9eb84 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -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 diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index c1a868d398bd..22c40308360b 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -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 diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig index f4025db184ff..d5aff36ade92 100644 --- a/arch/avr32/configs/atngw100_defconfig +++ b/arch/avr32/configs/atngw100_defconfig @@ -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 diff --git a/arch/avr32/configs/atngw100_evklcd100_defconfig b/arch/avr32/configs/atngw100_evklcd100_defconfig index c76a49b9e9d0..4abcf435d599 100644 --- a/arch/avr32/configs/atngw100_evklcd100_defconfig +++ b/arch/avr32/configs/atngw100_evklcd100_defconfig @@ -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 diff --git a/arch/avr32/configs/atngw100_evklcd101_defconfig b/arch/avr32/configs/atngw100_evklcd101_defconfig index 2d8ab089a64e..18f3fa0470ff 100644 --- a/arch/avr32/configs/atngw100_evklcd101_defconfig +++ b/arch/avr32/configs/atngw100_evklcd101_defconfig @@ -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 diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig index b189e0cab04b..06e389cfcd12 100644 --- a/arch/avr32/configs/atngw100_mrmt_defconfig +++ b/arch/avr32/configs/atngw100_mrmt_defconfig @@ -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 diff --git a/arch/avr32/configs/atngw100mkii_defconfig b/arch/avr32/configs/atngw100mkii_defconfig index 2e4de42a53c4..2518a1368d7c 100644 --- a/arch/avr32/configs/atngw100mkii_defconfig +++ b/arch/avr32/configs/atngw100mkii_defconfig @@ -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 diff --git a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig index fad3cd22dfd3..245ef6bd0fa6 100644 --- a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig +++ b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig @@ -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 diff --git a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig index 29986230aaa5..fa6cbac6e418 100644 --- a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig +++ b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig @@ -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 diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig index a582465e1cef..bbd5131021a5 100644 --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig @@ -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 diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig index 57a79df2ce5d..c1cd726f9012 100644 --- a/arch/avr32/configs/atstk1003_defconfig +++ b/arch/avr32/configs/atstk1003_defconfig @@ -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 diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig index 1a49bd8c6340..754ae56b2767 100644 --- a/arch/avr32/configs/atstk1004_defconfig +++ b/arch/avr32/configs/atstk1004_defconfig @@ -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 diff --git a/arch/avr32/configs/atstk1006_defconfig b/arch/avr32/configs/atstk1006_defconfig index 206a1b67f763..58589d8cc0ac 100644 --- a/arch/avr32/configs/atstk1006_defconfig +++ b/arch/avr32/configs/atstk1006_defconfig @@ -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 diff --git a/arch/avr32/configs/favr-32_defconfig b/arch/avr32/configs/favr-32_defconfig index 0421498d666b..57788a42ff83 100644 --- a/arch/avr32/configs/favr-32_defconfig +++ b/arch/avr32/configs/favr-32_defconfig @@ -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 diff --git a/arch/avr32/configs/hammerhead_defconfig b/arch/avr32/configs/hammerhead_defconfig index 82f24eb251bd..ba7c31e269cb 100644 --- a/arch/avr32/configs/hammerhead_defconfig +++ b/arch/avr32/configs/hammerhead_defconfig @@ -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 diff --git a/arch/avr32/configs/mimc200_defconfig b/arch/avr32/configs/mimc200_defconfig index 1bee51f22154..0a8bfdc420e0 100644 --- a/arch/avr32/configs/mimc200_defconfig +++ b/arch/avr32/configs/mimc200_defconfig @@ -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 diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile index 514c9a9b009a..fc09ec4bc725 100644 --- a/arch/avr32/mach-at32ap/Makefile +++ b/arch/avr32/mach-at32ap/Makefile @@ -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) diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile index 75f0ba29ebb9..675466d490d4 100644 --- a/arch/blackfin/mach-common/Makefile +++ b/arch/blackfin/mach-common/Makefile @@ -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 diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile index d366e0891988..18a227196a41 100644 --- a/arch/cris/arch-v32/mach-a3/Makefile +++ b/arch/cris/arch-v32/mach-a3/Makefile @@ -3,7 +3,6 @@ # obj-y := dma.o pinmux.o io.o arbiter.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o clean: diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile index d366e0891988..18a227196a41 100644 --- a/arch/cris/arch-v32/mach-fs/Makefile +++ b/arch/cris/arch-v32/mach-fs/Makefile @@ -3,7 +3,6 @@ # obj-y := dma.o pinmux.o io.o arbiter.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o clean: diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 9a02f71c6b1f..152b5f29d048 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -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 diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index d959c84904be..20678a9ed11a 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -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 diff --git a/arch/ia64/kernel/cpufreq/Kconfig b/arch/ia64/kernel/cpufreq/Kconfig deleted file mode 100644 index 2d9d5279b981..000000000000 --- a/arch/ia64/kernel/cpufreq/Kconfig +++ /dev/null @@ -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 - diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile deleted file mode 100644 index 4838f2a57c7a..000000000000 --- a/arch/ia64/kernel/cpufreq/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o - diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 51244bf97271..26d21d3d6a98 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -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" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index de75fb50562b..520a908d45d6 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -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 diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig deleted file mode 100644 index 58c601eee6fd..000000000000 --- a/arch/mips/kernel/cpufreq/Kconfig +++ /dev/null @@ -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 diff --git a/arch/mips/kernel/cpufreq/Makefile b/arch/mips/kernel/cpufreq/Makefile deleted file mode 100644 index 05a5715ee38c..000000000000 --- a/arch/mips/kernel/cpufreq/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the Linux/MIPS cpufreq. -# - -obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 53aaefeb3386..9978f594cac0 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -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). diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index a4a89350bcfc..fe053e7c73ee 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -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 diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 890f30e70f98..be1e7958909e 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -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; diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 311b804353b1..3104fad82480 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -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; diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c index 9650c6029c82..7ba423431cfe 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -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); diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5e859633ce69..06e3163bdc11 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -624,25 +624,7 @@ config SH_CLK_CPG_LEGACY endmenu menu "CPU Frequency scaling" - source "drivers/cpufreq/Kconfig" - -config SH_CPU_FREQ - tristate "SuperH CPU Frequency driver" - depends on CPU_FREQ - select CPU_FREQ_TABLE - help - This adds the cpufreq driver for SuperH. Any CPU that supports - clock rate rounding through the clock framework can use this - driver. While it will make the kernel slightly larger, this is - harmless for CPUs that don't support rate rounding. The driver - will also generate a notice in the boot log before disabling - itself if the CPU in question is not capable of rate rounding. - - For details, take a look at <file:Documentation/cpu-freq>. - - If unsure, say N. - endmenu source "arch/sh/drivers/Kconfig" diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index f259b37874e9..261c8bfd75ce 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o obj-$(CONFIG_KGDB) += kgdb.o -obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 3d361f236308..c85b76100e3f 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -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 diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 6cf591b7e1c6..5276fd4e9d03 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -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 diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile index fa497e0efe5a..607a72f2ae35 100644 --- a/arch/unicore32/kernel/Makefile +++ b/arch/unicore32/kernel/Makefile @@ -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 diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 93fe929d1cee..9e22520a97ee 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -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 */ diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index ee8e9abc859f..d92b5dad15dd 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -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 }, diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index cbcb21e32771..a1488f58f6ca 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -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 diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 030ddf6dd3f1..f3af18b9acc5 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -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. - - If in doubt, say N. +config ARM_SA1100_CPUFREQ + bool -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. diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc index e76992f79683..9c926ca0d718 100644 --- a/drivers/cpufreq/Kconfig.powerpc +++ b/drivers/cpufreq/Kconfig.powerpc @@ -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 diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index d7dc0ed6adb0..2b8a8c374548 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -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 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 863fd1865d45..315b9231feb1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -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_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_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o -obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-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 diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 57a8774f0b4e..11b8b4b54ceb 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -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: diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c new file mode 100644 index 000000000000..f6b79ab0070b --- /dev/null +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -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"); diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c new file mode 100644 index 000000000000..dbdf677d2f36 --- /dev/null +++ b/drivers/cpufreq/arm_big_little.c @@ -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); diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h new file mode 100644 index 000000000000..70f18fc12d4a --- /dev/null +++ b/drivers/cpufreq/arm_big_little.h @@ -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 */ diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c new file mode 100644 index 000000000000..44be3115375c --- /dev/null +++ b/drivers/cpufreq/arm_big_little_dt.c @@ -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"); diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c index 18b765629a0c..654488723cb5 100644 --- a/arch/avr32/mach-at32ap/cpufreq.c +++ b/drivers/cpufreq/at32ap-cpufreq.c @@ -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); diff --git a/arch/blackfin/mach-common/cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c index d88bd31319e6..995511e80bef 100644 --- a/arch/blackfin/mach-common/cpufreq.c +++ b/drivers/cpufreq/blackfin-cpufreq.c @@ -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; - } + 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); + 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; + 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); + 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; diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index 37d23a0f8c56..3ab8294eab04 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -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: diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c index 13d311ee08b3..af1542d41440 100644 --- a/drivers/cpufreq/cpufreq-nforce2.c +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -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; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b02824d092e7..a6f65954b0ab 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -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; - - if (!cpufreq_driver) + struct cpufreq_driver *driver; + bool has_setpolicy; + bool has_target; + + 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,18 +1853,31 @@ 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); } ret = -EINVAL; @@ -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; } diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 4fd0006b1291..0ceb2eff5a7e 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -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); - -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); - -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, +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); + +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_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); } diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 5a76086ff09b..443442df113b 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -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; + + 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; - if (dbs_data->governor == GOV_CONSERVATIVE) { - cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu); - sampling_rate = &cs_tuners->sampling_rate; + /* 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; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index cc4bd2f6838a..8ac33538d0bd 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -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 */ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index f3eb26cd848f..b0ffef96bf77 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -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); - -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); - -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, +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); + +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_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_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 = { - .attrs = dbs_attributes, +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); } diff --git a/arch/cris/arch-v32/mach-a3/cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c index ee391ecb5bc9..ee142c490575 100644 --- a/arch/cris/arch-v32/mach-a3/cpufreq.c +++ b/drivers/cpufreq/cris-artpec3-cpufreq.c @@ -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; } diff --git a/arch/cris/arch-v32/mach-fs/cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c index d92cf70d1cbe..12952235d5db 100644 --- a/arch/cris/arch-v32/mach-fs/cpufreq.c +++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c @@ -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; } diff --git a/arch/arm/mach-davinci/cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 4729eaab0f40..c33c76c360fa 100644 --- a/arch/arm/mach-davinci/cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c @@ -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 diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 72f0c3efa76e..6ec6539ae041 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c @@ -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) diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index 3fffbe6025cd..37380fb92621 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -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; diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c index 960671fd3d7e..658d860344b0 100644 --- a/drivers/cpufreq/elanfreq.c +++ b/drivers/cpufreq/elanfreq.c @@ -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; } diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 78057a357ddb..475b4f607f0d 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -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; diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c new file mode 100644 index 000000000000..0c74018eda47 --- /dev/null +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -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"); diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c index 456bee058fe6..3dfc99b9ca86 100644 --- a/drivers/cpufreq/gx-suspmod.c +++ b/drivers/cpufreq/gx-suspmod.c @@ -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; } diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index f09b174244d5..c0075dbaa633 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -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); } diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 54e336de373b..b78bc35973ba 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -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; } diff --git a/arch/arm/mach-integrator/cpu.c b/drivers/cpufreq/integrator-cpufreq.c index 590c192cdf4d..f7c99df0880b 100644 --- a/arch/arm/mach-integrator/cpu.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -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; } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 6133ef5cf671..cc3a8e6c92be 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -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; } diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index 0e83e3c24f5b..d36ea8dc96eb 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -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) diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 1180d536d1eb..b448638e34de 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -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); } diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index 3237c5235f9c..84889573b566 100644 --- a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -61,9 +61,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, struct cpufreq_freqs freqs; unsigned int freq; - if (!cpu_online(cpu)) - return -ENODEV; - cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -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"); diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c index d4c4989823dc..cdd62915efaf 100644 --- a/drivers/cpufreq/maple-cpufreq.c +++ b/drivers/cpufreq/maple-cpufreq.c @@ -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); diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 9128c07bafba..0279d18a57f9 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -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); diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index 827629c9aad7..421ef37d0bb3 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c @@ -58,8 +58,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) { u32 l, h; - if (!cpu_online(cpu) || - (newstate > DC_DISABLE) || (newstate == DC_RESV)) + if ((newstate > DC_DISABLE) || (newstate == DC_RESV)) return -EINVAL; rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); @@ -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; } diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 503996a94a6a..0de00081a81e 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -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); diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index af23e0b9ec92..ea0222a45b7b 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -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; diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 334cc2f1e9f1..53888dacbe58 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -248,7 +248,7 @@ static void change_VID(int vid) } -static void change_speed(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; } diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index d13a13678b5f..b828efe4b2f8 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -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; diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index d4c39e32f147..e577a1dbbfcd 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c @@ -27,7 +27,8 @@ #include <asm/machdep.h> #include <asm/prom.h> #include <asm/cell-regs.h> -#include "cbe_cpufreq.h" + +#include "ppc_cbe_cpufreq.h" static DEFINE_MUTEX(cbe_switch_mutex); @@ -156,10 +157,9 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, freqs.old = policy->cur; freqs.new = cbe_freqs[cbe_pmode_new].frequency; - freqs.cpu = policy->cpu; mutex_lock(&cbe_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", @@ -169,7 +169,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, rc = set_pmode(policy->cpu, cbe_pmode_new); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); mutex_unlock(&cbe_switch_mutex); return rc; diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.h b/drivers/cpufreq/ppc_cbe_cpufreq.h index c1d86bfa92ff..b4c00a5a6a59 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.h +++ b/drivers/cpufreq/ppc_cbe_cpufreq.h @@ -1,5 +1,5 @@ /* - * cbe_cpufreq.h + * ppc_cbe_cpufreq.h * * This file contains the definitions used by the cbe_cpufreq driver. * @@ -17,7 +17,7 @@ int cbe_cpufreq_get_pmode(int cpu); int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode); -#if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE) +#if defined(CONFIG_CPU_FREQ_CBE_PMI) || defined(CONFIG_CPU_FREQ_CBE_PMI_MODULE) extern bool cbe_cpufreq_has_pmi; #else #define cbe_cpufreq_has_pmi (0) diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/drivers/cpufreq/ppc_cbe_cpufreq_pervasive.c index 20472e487b6f..84d2f2cf5ba7 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pervasive.c @@ -30,7 +30,7 @@ #include <asm/hw_irq.h> #include <asm/cell-regs.h> -#include "cbe_cpufreq.h" +#include "ppc_cbe_cpufreq.h" /* to write to MIC register */ static u64 MIC_Slow_Fast_Timer_table[] = { diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c index 60a07a4f9326..d29e8da396a0 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c @@ -35,7 +35,7 @@ #include <asm/time.h> #endif -#include "cbe_cpufreq.h" +#include "ppc_cbe_cpufreq.h" static u8 pmi_slow_mode_limit[MAX_CBE]; diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 6a7aeab42f6c..9e5bc8e388a0 100644 --- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -1,6 +1,4 @@ /* - * linux/arch/arm/mach-pxa/cpufreq-pxa2xx.c - * * Copyright (C) 2002,2003 Intrinsyc Software * * This program is free software; you can redistribute it and/or modify @@ -223,10 +221,11 @@ static void find_freq_tables(struct cpufreq_frequency_table **freq_table, *pxa_freqs = pxa255_turbo_freqs; *freq_table = pxa255_turbo_freq_table; } - } - if (cpu_is_pxa27x()) { + } else if (cpu_is_pxa27x()) { *pxa_freqs = pxa27x_freqs; *freq_table = pxa27x_freq_table; + } else { + BUG(); } } @@ -311,7 +310,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, new_freq_mem = pxa_freq_settings[idx].membus; freqs.old = policy->cur; freqs.new = new_freq_cpu; - freqs.cpu = policy->cpu; if (freq_debug) pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", @@ -327,7 +325,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, * you should add a notify client with any platform specific * Vcc changing capability */ - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); /* Calculate the next MDREFR. If we're slowing down the SDRAM clock * we need to preset the smaller DRI before the change. If we're @@ -382,7 +380,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, * you should add a notify client with any platform specific * SDRAM refresh timer adjustments */ - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); /* * Even if voltage setting fails, we don't report it, as the frequency diff --git a/arch/arm/mach-pxa/cpufreq-pxa3xx.c b/drivers/cpufreq/pxa3xx-cpufreq.c index b85b4ab7aac6..15d60f857ad5 100644 --- a/arch/arm/mach-pxa/cpufreq-pxa3xx.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -1,6 +1,4 @@ /* - * linux/arch/arm/mach-pxa/cpufreq-pxa3xx.c - * * Copyright (C) 2008 Marvell International Ltd. * * This program is free software; you can redistribute it and/or modify @@ -17,10 +15,9 @@ #include <linux/slab.h> #include <linux/io.h> +#include <mach/generic.h> #include <mach/pxa3xx-regs.h> -#include "generic.h" - #define HSS_104M (0) #define HSS_156M (1) #define HSS_208M (2) @@ -184,7 +181,6 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, freqs.old = policy->cur; freqs.new = next->cpufreq_mhz * 1000; - freqs.cpu = policy->cpu; pr_debug("CPU frequency from %d MHz to %d MHz%s\n", freqs.old / 1000, freqs.new / 1000, @@ -193,14 +189,14 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, if (freqs.old == target_freq) return 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); local_irq_save(flags); __update_core_freq(next); __update_bus_freq(next); local_irq_restore(flags); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index bcc053bc02c4..4f1881eee3f1 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -256,7 +256,6 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, goto out; } - freqs.cpu = 0; freqs.flags = 0; freqs.old = s3c_freq->is_dvs ? FREQ_DVS : clk_get_rate(s3c_freq->armclk) / 1000; @@ -274,7 +273,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, if (!to_dvs && freqs.old == freqs.new) goto out; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (to_dvs) { pr_debug("cpufreq: enter dvs\n"); @@ -287,7 +286,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new); } - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); out: mutex_unlock(&cpufreq_lock); diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 6f9490b3c356..27cacb524796 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -84,7 +84,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, if (ret != 0) return ret; - freqs.cpu = 0; freqs.old = clk_get_rate(armclk) / 1000; freqs.new = s3c64xx_freq_table[i].frequency; freqs.flags = 0; @@ -95,7 +94,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); #ifdef CONFIG_REGULATOR if (vddarm && freqs.new > freqs.old) { @@ -117,7 +116,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, goto err; } - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); #ifdef CONFIG_REGULATOR if (vddarm && freqs.new < freqs.old) { @@ -141,7 +140,7 @@ err_clk: if (clk_set_rate(armclk, freqs.old * 1000) < 0) pr_err("Failed to restore original clock rate\n"); err: - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return ret; } diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index a484aaea9809..5c7757073793 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -229,7 +229,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, } freqs.new = s5pv210_freq_table[index].frequency; - freqs.cpu = 0; if (freqs.new == freqs.old) goto exit; @@ -256,7 +255,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, goto exit; } - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); /* Check if there need to change PLL */ if ((index == L0) || (priv_index == L0)) @@ -468,7 +467,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } } - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); if (freqs.new < freqs.old) { regulator_set_voltage(int_regulator, diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/drivers/cpufreq/sa1100-cpufreq.c index e8f4d1e19233..cff18e87ca58 100644 --- a/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/drivers/cpufreq/sa1100-cpufreq.c @@ -91,10 +91,9 @@ #include <asm/cputype.h> +#include <mach/generic.h> #include <mach/hardware.h> -#include "generic.h" - struct sa1100_dram_regs { int speed; u32 mdcnfg; @@ -201,9 +200,8 @@ static int sa1100_target(struct cpufreq_policy *policy, freqs.old = cur; freqs.new = sa11x0_ppcr_to_freq(new_ppcr); - freqs.cpu = 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (freqs.new > cur) sa1100_update_dram_timings(cur, freqs.new); @@ -213,7 +211,7 @@ static int sa1100_target(struct cpufreq_policy *policy, if (freqs.new < cur) sa1100_update_dram_timings(cur, freqs.new); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/drivers/cpufreq/sa1110-cpufreq.c index 48c45b0c92bb..39c90b6f4286 100644 --- a/arch/arm/mach-sa1100/cpu-sa1110.c +++ b/drivers/cpufreq/sa1110-cpufreq.c @@ -27,10 +27,9 @@ #include <asm/cputype.h> #include <asm/mach-types.h> +#include <mach/generic.h> #include <mach/hardware.h> -#include "generic.h" - #undef DEBUG struct sdram_params { @@ -258,7 +257,6 @@ static int sa1110_target(struct cpufreq_policy *policy, freqs.old = sa11x0_getspeed(0); freqs.new = sa11x0_ppcr_to_freq(ppcr); - freqs.cpu = 0; sdram_calculate_timing(&sd, freqs.new, sdram); @@ -279,7 +277,7 @@ static int sa1110_target(struct cpufreq_policy *policy, sd.mdcas[2] = 0xaaaaaaaa; #endif - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); /* * The clock could be going away for some time. Set the SDRAMs @@ -327,7 +325,7 @@ static int sa1110_target(struct cpufreq_policy *policy, */ sdram_update_refresh(freqs.new, sdram); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c index e42e073cd9b8..f740b134d27b 100644 --- a/drivers/cpufreq/sc520_freq.c +++ b/drivers/cpufreq/sc520_freq.c @@ -53,7 +53,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) } } -static void sc520_freq_set_cpu_state(unsigned int state) +static void sc520_freq_set_cpu_state(struct cpufreq_policy *policy, + unsigned int state) { struct cpufreq_freqs freqs; @@ -61,9 +62,8 @@ static void sc520_freq_set_cpu_state(unsigned int state) freqs.old = sc520_freq_get_cpu_frequency(0); freqs.new = sc520_freq_table[state].frequency; - freqs.cpu = 0; /* AMD Elan is UP */ - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); pr_debug("attempting to set frequency to %i kHz\n", sc520_freq_table[state].frequency); @@ -75,7 +75,7 @@ static void sc520_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 sc520_freq_verify(struct cpufreq_policy *policy) @@ -93,7 +93,7 @@ static int sc520_freq_target(struct cpufreq_policy *policy, target_freq, relation, &newstate)) return -EINVAL; - sc520_freq_set_cpu_state(newstate); + sc520_freq_set_cpu_state(policy, newstate); return 0; } diff --git a/arch/sh/kernel/cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index e68b45b6f3f9..73adb64651e8 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -1,6 +1,4 @@ /* - * arch/sh/kernel/cpufreq.c - * * cpufreq driver for the SuperH processors. * * Copyright (C) 2002 - 2012 Paul Mundt @@ -51,9 +49,6 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, struct device *dev; long freq; - if (!cpu_online(cpu)) - return -ENODEV; - cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -69,15 +64,14 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); - freqs.cpu = cpu; freqs.old = sh_cpufreq_get(cpu); freqs.new = (freq + 500) / 1000; freqs.flags = 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); set_cpus_allowed_ptr(current, &cpus_allowed); clk_set_rate(cpuclk, freq); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); dev_dbg(dev, "set frequency %lu Hz\n", freq); @@ -112,9 +106,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) struct cpufreq_frequency_table *freq_table; struct device *dev; - if (!cpu_online(cpu)) - return -ENODEV; - dev = get_cpu_device(cpu); cpuclk = clk_get(dev, "cpu_clk"); @@ -123,7 +114,7 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) return PTR_ERR(cpuclk); } - policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu); + policy->cur = sh_cpufreq_get(cpu); freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; if (freq_table) { @@ -136,15 +127,12 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) dev_notice(dev, "no frequency table found, falling back " "to rate rounding.\n"); - policy->cpuinfo.min_freq = + policy->min = policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; - policy->cpuinfo.max_freq = + policy->max = policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; } - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c index 489fc15f3194..306ae462bba6 100644 --- a/arch/sparc/kernel/us2e_cpufreq.c +++ b/drivers/cpufreq/sparc-us2e-cpufreq.c @@ -234,9 +234,6 @@ static unsigned int us2e_freq_get(unsigned int cpu) cpumask_t cpus_allowed; unsigned long clock_tick, estar; - if (!cpu_online(cpu)) - return 0; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -248,16 +245,15 @@ static unsigned int us2e_freq_get(unsigned int cpu) return clock_tick / estar_to_divisor(estar); } -static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) +static void us2e_set_cpu_divider_index(struct cpufreq_policy *policy, + unsigned int index) { + unsigned int cpu = policy->cpu; unsigned long new_bits, new_freq; unsigned long clock_tick, divisor, old_divisor, estar; cpumask_t cpus_allowed; struct cpufreq_freqs freqs; - if (!cpu_online(cpu)) - return; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -272,14 +268,13 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) freqs.old = clock_tick / old_divisor; freqs.new = new_freq; - freqs.cpu = cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (old_divisor != divisor) us2e_transition(estar, new_bits, clock_tick * 1000, old_divisor, divisor); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); set_cpus_allowed_ptr(current, &cpus_allowed); } @@ -295,7 +290,7 @@ static int us2e_freq_target(struct cpufreq_policy *policy, target_freq, relation, &new_index)) return -EINVAL; - us2e_set_cpu_divider_index(policy->cpu, new_index); + us2e_set_cpu_divider_index(policy, new_index); return 0; } @@ -335,7 +330,7 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) static int us2e_freq_cpu_exit(struct cpufreq_policy *policy) { if (cpufreq_us2e_driver) - us2e_set_cpu_divider_index(policy->cpu, 0); + us2e_set_cpu_divider_index(policy, 0); return 0; } diff --git a/arch/sparc/kernel/us3_cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index eb1624b931d9..c71ee142347a 100644 --- a/arch/sparc/kernel/us3_cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c @@ -82,9 +82,6 @@ static unsigned int us3_freq_get(unsigned int cpu) unsigned long reg; unsigned int ret; - if (!cpu_online(cpu)) - return 0; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -96,15 +93,14 @@ static unsigned int us3_freq_get(unsigned int cpu) return ret; } -static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) +static void us3_set_cpu_divider_index(struct cpufreq_policy *policy, + unsigned int index) { + unsigned int cpu = policy->cpu; unsigned long new_bits, new_freq, reg; cpumask_t cpus_allowed; struct cpufreq_freqs freqs; - if (!cpu_online(cpu)) - return; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -131,14 +127,13 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) freqs.old = get_current_freq(cpu, reg); freqs.new = new_freq; - freqs.cpu = cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); reg &= ~SAFARI_CFG_DIV_MASK; reg |= new_bits; write_safari_cfg(reg); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); set_cpus_allowed_ptr(current, &cpus_allowed); } @@ -156,7 +151,7 @@ static int us3_freq_target(struct cpufreq_policy *policy, &new_index)) return -EINVAL; - us3_set_cpu_divider_index(policy->cpu, new_index); + us3_set_cpu_divider_index(policy, new_index); return 0; } @@ -192,7 +187,7 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) static int us3_freq_cpu_exit(struct cpufreq_policy *policy) { if (cpufreq_us3_driver) - us3_set_cpu_divider_index(policy->cpu, 0); + us3_set_cpu_divider_index(policy, 0); return 0; } diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index 7e4d77327957..156829f4576d 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -121,7 +121,6 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, target_freq, relation, &index)) return -EINVAL; - freqs.cpu = policy->cpu; freqs.old = spear_cpufreq_get(0); newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; @@ -158,8 +157,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, freqs.new = newfreq / 1000; freqs.new /= mult; - for_each_cpu(freqs.cpu, policy->cpus) - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (mult == 2) ret = spear1340_set_cpu_rate(srcclk, newfreq); @@ -172,8 +170,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000; } - for_each_cpu(freqs.cpu, policy->cpus) - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return ret; } diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index 3a953d519f46..618e6f417b1c 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c @@ -457,7 +457,7 @@ static int centrino_target (struct cpufreq_policy *policy, unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; struct cpufreq_freqs freqs; int retval = 0; - unsigned int j, k, first_cpu, tmp; + unsigned int j, first_cpu, tmp; cpumask_var_t covered_cpus; if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) @@ -481,10 +481,6 @@ static int centrino_target (struct cpufreq_policy *policy, for_each_cpu(j, policy->cpus) { int good_cpu; - /* cpufreq holds the hotplug lock, so we are safe here */ - if (!cpu_online(j)) - continue; - /* * Support for SMP systems. * Make sure we are running on CPU that wants to change freq @@ -522,13 +518,8 @@ static int centrino_target (struct cpufreq_policy *policy, pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); - for_each_cpu(k, policy->cpus) { - if (!cpu_online(k)) - continue; - freqs.cpu = k; - cpufreq_notify_transition(&freqs, + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - } first_cpu = 0; /* all but 16 LSB are reserved, treat them with care */ @@ -544,12 +535,7 @@ static int centrino_target (struct cpufreq_policy *policy, cpumask_set_cpu(j, covered_cpus); } - for_each_cpu(k, policy->cpus) { - if (!cpu_online(k)) - continue; - freqs.cpu = k; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); if (unlikely(retval)) { /* @@ -565,12 +551,8 @@ static int centrino_target (struct cpufreq_policy *policy, tmp = freqs.new; freqs.new = freqs.old; freqs.old = tmp; - for_each_cpu(j, policy->cpus) { - if (!cpu_online(j)) - continue; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); } retval = 0; diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index e29b59aa68a8..e2e5aa971452 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c @@ -263,7 +263,6 @@ static int speedstep_target(struct cpufreq_policy *policy, { unsigned int newstate = 0, policy_cpu; struct cpufreq_freqs freqs; - int i; if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) @@ -272,7 +271,6 @@ static int speedstep_target(struct cpufreq_policy *policy, policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); freqs.old = speedstep_get(policy_cpu); freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = policy->cpu; pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); @@ -280,18 +278,12 @@ static int speedstep_target(struct cpufreq_policy *policy, if (freqs.old == freqs.new) return 0; - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, true); - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index 6a457fcaaad5..f5a6b70ee6c0 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -252,14 +252,13 @@ static int speedstep_target(struct cpufreq_policy *policy, freqs.old = speedstep_freqs[speedstep_get_state()].frequency; freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = 0; /* speedstep.c is UP only driver */ if (freqs.old == freqs.new) return 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); speedstep_set_state(newstate); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/drivers/cpufreq/tegra-cpufreq.c index e3d6e15ff188..c74c0e130ef4 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/drivers/cpufreq/tegra-cpufreq.c @@ -1,6 +1,4 @@ /* - * arch/arm/mach-tegra/cpu-tegra.c - * * Copyright (C) 2010 Google, Inc. * * Author: @@ -106,7 +104,8 @@ out: return ret; } -static int tegra_update_cpu_speed(unsigned long rate) +static int tegra_update_cpu_speed(struct cpufreq_policy *policy, + unsigned long rate) { int ret = 0; struct cpufreq_freqs freqs; @@ -128,8 +127,7 @@ static int tegra_update_cpu_speed(unsigned long rate) else clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ - for_each_online_cpu(freqs.cpu) - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); #ifdef CONFIG_CPU_FREQ_DEBUG printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n", @@ -143,8 +141,7 @@ static int tegra_update_cpu_speed(unsigned long rate) return ret; } - for_each_online_cpu(freqs.cpu) - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } @@ -181,7 +178,7 @@ static int tegra_target(struct cpufreq_policy *policy, target_cpu_speed[policy->cpu] = freq; - ret = tegra_update_cpu_speed(tegra_cpu_highest_speed()); + ret = tegra_update_cpu_speed(policy, tegra_cpu_highest_speed()); out: mutex_unlock(&tegra_cpu_lock); @@ -193,10 +190,12 @@ static int tegra_pm_notify(struct notifier_block *nb, unsigned long event, { mutex_lock(&tegra_cpu_lock); if (event == PM_SUSPEND_PREPARE) { + struct cpufreq_policy *policy = cpufreq_cpu_get(0); is_suspended = true; pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n", freq_table[0].frequency); - tegra_update_cpu_speed(freq_table[0].frequency); + tegra_update_cpu_speed(policy, freq_table[0].frequency); + cpufreq_cpu_put(policy); } else if (event == PM_POST_SUSPEND) { is_suspended = false; } diff --git a/arch/unicore32/kernel/cpu-ucv2.c b/drivers/cpufreq/unicore2-cpufreq.c index 4a99f62584c7..12fc904d7dab 100644 --- a/arch/unicore32/kernel/cpu-ucv2.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -1,5 +1,5 @@ /* - * linux/arch/unicore32/kernel/cpu-ucv2.c: clock scaling for the UniCore-II + * clock scaling for the UniCore-II * * Code specific to PKUnity SoC and UniCore ISA * @@ -52,15 +52,14 @@ static int ucv2_target(struct cpufreq_policy *policy, struct cpufreq_freqs freqs; struct clk *mclk = clk_get(NULL, "MAIN_CLK"); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (!clk_set_rate(mclk, target_freq * 1000)) { freqs.old = cur; freqs.new = target_freq; - freqs.cpu = 0; } - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return 0; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index a22944ca0526..037d36ae63e5 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -106,6 +106,7 @@ struct cpufreq_policy { * governors are used */ unsigned int policy; /* see above */ struct cpufreq_governor *governor; /* see below */ + void *governor_data; struct work_struct update; /* if update_policy() needs to be * called, but you're in IRQ context */ @@ -178,9 +179,11 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu * CPUFREQ GOVERNORS * *********************************************************************/ -#define CPUFREQ_GOV_START 1 -#define CPUFREQ_GOV_STOP 2 -#define CPUFREQ_GOV_LIMITS 3 +#define CPUFREQ_GOV_START 1 +#define CPUFREQ_GOV_STOP 2 +#define CPUFREQ_GOV_LIMITS 3 +#define CPUFREQ_GOV_POLICY_INIT 4 +#define CPUFREQ_GOV_POLICY_EXIT 5 struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; @@ -229,6 +232,13 @@ struct cpufreq_driver { struct module *owner; char name[CPUFREQ_NAME_LEN]; u8 flags; + /* + * This should be set by platforms having multiple clock-domains, i.e. + * supporting multiple policies. With this sysfs directories of governor + * would be created in cpu/cpu<num>/cpufreq/ directory and so they can + * use the same governor with different tunables for different clusters. + */ + bool have_governor_per_policy; /* needed by all drivers */ int (*init) (struct cpufreq_policy *policy); @@ -268,8 +278,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); -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); static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) { @@ -329,6 +339,7 @@ const char *cpufreq_get_current_driver(void); *********************************************************************/ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); int cpufreq_update_policy(unsigned int cpu); +bool have_governor_per_policy(void); #ifdef CONFIG_CPU_FREQ /* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */ |