Commit c47b3bd0 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-cpufreq'

* pm-cpufreq: (63 commits)
  intel_pstate: Clean up get_target_pstate_use_performance()
  intel_pstate: Use sample.core_avg_perf in get_avg_pstate()
  intel_pstate: Clarify average performance computation
  intel_pstate: Avoid unnecessary synchronize_sched() during initialization
  cpufreq: schedutil: Make default depend on CONFIG_SMP
  cpufreq: powernv: del_timer_sync when global and local pstate are equal
  cpufreq: powernv: Move smp_call_function_any() out of irq safe block
  intel_pstate: Clean up intel_pstate_get()
  cpufreq: schedutil: Make it depend on CONFIG_SMP
  cpufreq: governor: Fix handling of special cases in dbs_update()
  cpufreq: intel_pstate: Ignore _PPC processing under HWP
  cpufreq: arm_big_little: use generic OPP functions for {init, free}_opp_table
  cpufreq: tango: Use generic platdev driver
  cpufreq: Fix GOV_LIMITS handling for the userspace governor
  cpufreq: mvebu: Move cpufreq code into drivers/cpufreq/
  cpufreq: dt: Kill platform-data
  mvebu: Use dev_pm_opp_set_sharing_cpus() to mark OPP tables as shared
  cpufreq: dt: Identify cpu-sharing for platforms without operating-points-v2
  cpufreq: governor: Change confusing struct field and variable names
  cpufreq: intel_pstate: Enable PPC enforcement for servers
  ...
parents 29cff184 1aa7a6e2
...@@ -1661,6 +1661,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1661,6 +1661,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
hwp_only hwp_only
Only load intel_pstate on systems which support Only load intel_pstate on systems which support
hardware P state control (HWP) if available. hardware P state control (HWP) if available.
support_acpi_ppc
Enforce ACPI _PPC performance limits. If the Fixed ACPI
Description Table, specifies preferred power management
profile as "Enterprise Server" or "Performance Server",
then this feature is turned on by default.
intremap= [X86-64, Intel-IOMMU] intremap= [X86-64, Intel-IOMMU]
on enable Interrupt Remapping (default) on enable Interrupt Remapping (default)
......
...@@ -1322,6 +1322,7 @@ F: drivers/rtc/rtc-armada38x.c ...@@ -1322,6 +1322,7 @@ F: drivers/rtc/rtc-armada38x.c
F: arch/arm/boot/dts/armada* F: arch/arm/boot/dts/armada*
F: arch/arm/boot/dts/kirkwood* F: arch/arm/boot/dts/kirkwood*
F: arch/arm64/boot/dts/marvell/armada* F: arch/arm64/boot/dts/marvell/armada*
F: drivers/cpufreq/mvebu-cpufreq.c
ARM/Marvell Berlin SoC support ARM/Marvell Berlin SoC support
......
...@@ -18,11 +18,6 @@ ...@@ -18,11 +18,6 @@
#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
static void __init berlin_init_late(void)
{
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
}
static const char * const berlin_dt_compat[] = { static const char * const berlin_dt_compat[] = {
"marvell,berlin", "marvell,berlin",
NULL, NULL,
...@@ -30,7 +25,6 @@ static const char * const berlin_dt_compat[] = { ...@@ -30,7 +25,6 @@ static const char * const berlin_dt_compat[] = {
DT_MACHINE_START(BERLIN_DT, "Marvell Berlin") DT_MACHINE_START(BERLIN_DT, "Marvell Berlin")
.dt_compat = berlin_dt_compat, .dt_compat = berlin_dt_compat,
.init_late = berlin_init_late,
/* /*
* with DT probing for L2CCs, berlin_init_machine can be removed. * with DT probing for L2CCs, berlin_init_machine can be removed.
* Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc * Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc
......
...@@ -213,33 +213,6 @@ static void __init exynos_init_irq(void) ...@@ -213,33 +213,6 @@ static void __init exynos_init_irq(void)
exynos_map_pmu(); exynos_map_pmu();
} }
static const struct of_device_id exynos_cpufreq_matches[] = {
{ .compatible = "samsung,exynos3250", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos4210", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos4212", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos4412", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos5250", .data = "cpufreq-dt" },
#ifndef CONFIG_BL_SWITCHER
{ .compatible = "samsung,exynos5420", .data = "cpufreq-dt" },
{ .compatible = "samsung,exynos5800", .data = "cpufreq-dt" },
#endif
{ /* sentinel */ }
};
static void __init exynos_cpufreq_init(void)
{
struct device_node *root = of_find_node_by_path("/");
const struct of_device_id *match;
match = of_match_node(exynos_cpufreq_matches, root);
if (!match) {
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
return;
}
platform_device_register_simple(match->data, -1, NULL, 0);
}
static void __init exynos_dt_machine_init(void) static void __init exynos_dt_machine_init(void)
{ {
/* /*
...@@ -262,8 +235,6 @@ static void __init exynos_dt_machine_init(void) ...@@ -262,8 +235,6 @@ static void __init exynos_dt_machine_init(void)
of_machine_is_compatible("samsung,exynos5250")) of_machine_is_compatible("samsung,exynos5250"))
platform_device_register(&exynos_cpuidle); platform_device_register(&exynos_cpuidle);
exynos_cpufreq_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
} }
......
...@@ -18,15 +18,6 @@ ...@@ -18,15 +18,6 @@
#include "common.h" #include "common.h"
#include "mx27.h" #include "mx27.h"
static void __init imx27_dt_init(void)
{
struct platform_device_info devinfo = { .name = "cpufreq-dt", };
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register_full(&devinfo);
}
static const char * const imx27_dt_board_compat[] __initconst = { static const char * const imx27_dt_board_compat[] __initconst = {
"fsl,imx27", "fsl,imx27",
NULL NULL
...@@ -36,6 +27,5 @@ DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)") ...@@ -36,6 +27,5 @@ DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)")
.map_io = mx27_map_io, .map_io = mx27_map_io,
.init_early = imx27_init_early, .init_early = imx27_init_early,
.init_irq = mx27_init_irq, .init_irq = mx27_init_irq,
.init_machine = imx27_dt_init,
.dt_compat = imx27_dt_board_compat, .dt_compat = imx27_dt_board_compat,
MACHINE_END MACHINE_END
...@@ -50,13 +50,10 @@ static void __init imx51_ipu_mipi_setup(void) ...@@ -50,13 +50,10 @@ static void __init imx51_ipu_mipi_setup(void)
static void __init imx51_dt_init(void) static void __init imx51_dt_init(void)
{ {
struct platform_device_info devinfo = { .name = "cpufreq-dt", };
imx51_ipu_mipi_setup(); imx51_ipu_mipi_setup();
imx_src_init(); imx_src_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register_full(&devinfo);
} }
static void __init imx51_init_late(void) static void __init imx51_init_late(void)
......
...@@ -40,8 +40,6 @@ static void __init imx53_dt_init(void) ...@@ -40,8 +40,6 @@ static void __init imx53_dt_init(void)
static void __init imx53_init_late(void) static void __init imx53_init_late(void)
{ {
imx53_pm_init(); imx53_pm_init();
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
} }
static const char * const imx53_dt_board_compat[] __initconst = { static const char * const imx53_dt_board_compat[] __initconst = {
......
...@@ -105,11 +105,6 @@ static void __init imx7d_init_irq(void) ...@@ -105,11 +105,6 @@ static void __init imx7d_init_irq(void)
irqchip_init(); irqchip_init();
} }
static void __init imx7d_init_late(void)
{
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
}
static const char *const imx7d_dt_compat[] __initconst = { static const char *const imx7d_dt_compat[] __initconst = {
"fsl,imx7d", "fsl,imx7d",
NULL, NULL,
...@@ -117,7 +112,6 @@ static const char *const imx7d_dt_compat[] __initconst = { ...@@ -117,7 +112,6 @@ static const char *const imx7d_dt_compat[] __initconst = {
DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
.init_irq = imx7d_init_irq, .init_irq = imx7d_init_irq,
.init_late = imx7d_init_late,
.init_machine = imx7d_init_machine, .init_machine = imx7d_init_machine,
.dt_compat = imx7d_dt_compat, .dt_compat = imx7d_dt_compat,
MACHINE_END MACHINE_END
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpu_pm.h> #include <linux/cpu_pm.h>
#include <linux/cpufreq-dt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -29,7 +28,6 @@ ...@@ -29,7 +28,6 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/resource.h> #include <linux/resource.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp.h> #include <linux/smp.h>
...@@ -608,86 +606,3 @@ int mvebu_pmsu_dfs_request(int cpu) ...@@ -608,86 +606,3 @@ int mvebu_pmsu_dfs_request(int cpu)
return 0; return 0;
} }
struct cpufreq_dt_platform_data cpufreq_dt_pd = {
.independent_clocks = true,
};
static int __init armada_xp_pmsu_cpufreq_init(void)
{
struct device_node *np;
struct resource res;
int ret, cpu;
if (!of_machine_is_compatible("marvell,armadaxp"))
return 0;
/*
* In order to have proper cpufreq handling, we need to ensure
* that the Device Tree description of the CPU clock includes
* the definition of the PMU DFS registers. If not, we do not
* register the clock notifier and the cpufreq driver. This
* piece of code is only for compatibility with old Device
* Trees.
*/
np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock");
if (!np)
return 0;
ret = of_address_to_resource(np, 1, &res);
if (ret) {
pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n");
of_node_put(np);
return 0;
}
of_node_put(np);
/*
* For each CPU, this loop registers the operating points
* supported (which are the nominal CPU frequency and half of
* it), and registers the clock notifier that will take care
* of doing the PMSU part of a frequency transition.
*/
for_each_possible_cpu(cpu) {
struct device *cpu_dev;
struct clk *clk;
int ret;
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) {
pr_err("Cannot get CPU %d\n", cpu);
continue;
}
clk = clk_get(cpu_dev, 0);
if (IS_ERR(clk)) {
pr_err("Cannot get clock for CPU %d\n", cpu);
return PTR_ERR(clk);
}
/*
* In case of a failure of dev_pm_opp_add(), we don't
* bother with cleaning up the registered OPP (there's
* no function to do so), and simply cancel the
* registration of the cpufreq device.
*/
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0);
if (ret) {
clk_put(clk);
return ret;
}
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0);
if (ret) {
clk_put(clk);
return ret;
}
}
platform_device_register_data(NULL, "cpufreq-dt", -1,
&cpufreq_dt_pd, sizeof(cpufreq_dt_pd));
return 0;
}
device_initcall(armada_xp_pmsu_cpufreq_init);
...@@ -277,13 +277,10 @@ static void __init omap4_init_voltages(void) ...@@ -277,13 +277,10 @@ static void __init omap4_init_voltages(void)
static inline void omap_init_cpufreq(void) static inline void omap_init_cpufreq(void)
{ {
struct platform_device_info devinfo = { }; struct platform_device_info devinfo = { .name = "omap-cpufreq" };
if (!of_have_populated_dt()) if (!of_have_populated_dt())
devinfo.name = "omap-cpufreq"; platform_device_register_full(&devinfo);
else
devinfo.name = "cpufreq-dt";
platform_device_register_full(&devinfo);
} }
static int __init omap2_common_pm_init(void) static int __init omap2_common_pm_init(void)
......
...@@ -74,7 +74,6 @@ static void __init rockchip_dt_init(void) ...@@ -74,7 +74,6 @@ static void __init rockchip_dt_init(void)
{ {
rockchip_suspend_init(); rockchip_suspend_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register_simple("cpufreq-dt", 0, NULL, 0);
} }
static const char * const rockchip_board_dt_compat[] = { static const char * const rockchip_board_dt_compat[] = {
......
...@@ -38,7 +38,6 @@ smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o ...@@ -38,7 +38,6 @@ smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o
# PM objects # PM objects
obj-$(CONFIG_SUSPEND) += suspend.o obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_PM_RCAR) += pm-rcar.o obj-$(CONFIG_PM_RCAR) += pm-rcar.o
obj-$(CONFIG_PM_RMOBILE) += pm-rmobile.o obj-$(CONFIG_PM_RMOBILE) += pm-rmobile.o
obj-$(CONFIG_ARCH_RCAR_GEN2) += pm-rcar-gen2.o obj-$(CONFIG_ARCH_RCAR_GEN2) += pm-rcar-gen2.o
......
...@@ -25,16 +25,9 @@ static inline int shmobile_suspend_init(void) { return 0; } ...@@ -25,16 +25,9 @@ static inline int shmobile_suspend_init(void) { return 0; }
static inline void shmobile_smp_apmu_suspend_init(void) { } static inline void shmobile_smp_apmu_suspend_init(void) { }
#endif #endif
#ifdef CONFIG_CPU_FREQ
int shmobile_cpufreq_init(void);
#else
static inline int shmobile_cpufreq_init(void) { return 0; }
#endif
static inline void __init shmobile_init_late(void) static inline void __init shmobile_init_late(void)
{ {
shmobile_suspend_init(); shmobile_suspend_init();
shmobile_cpufreq_init();
} }
#endif /* __ARCH_MACH_COMMON_H */ #endif /* __ARCH_MACH_COMMON_H */
/*
* CPUFreq support code for SH-Mobile ARM
*
* Copyright (C) 2014 Gaku Inami
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/platform_device.h>
#include "common.h"
int __init shmobile_cpufreq_init(void)
{
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
return 0;
}
...@@ -17,11 +17,6 @@ ...@@ -17,11 +17,6 @@
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
static void __init sunxi_dt_cpufreq_init(void)
{
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
}
static const char * const sunxi_board_dt_compat[] = { static const char * const sunxi_board_dt_compat[] = {
"allwinner,sun4i-a10", "allwinner,sun4i-a10",
"allwinner,sun5i-a10s", "allwinner,sun5i-a10s",
...@@ -32,7 +27,6 @@ static const char * const sunxi_board_dt_compat[] = { ...@@ -32,7 +27,6 @@ static const char * const sunxi_board_dt_compat[] = {
DT_MACHINE_START(SUNXI_DT, "Allwinner sun4i/sun5i Families") DT_MACHINE_START(SUNXI_DT, "Allwinner sun4i/sun5i Families")
.dt_compat = sunxi_board_dt_compat, .dt_compat = sunxi_board_dt_compat,
.init_late = sunxi_dt_cpufreq_init,
MACHINE_END MACHINE_END
static const char * const sun6i_board_dt_compat[] = { static const char * const sun6i_board_dt_compat[] = {
...@@ -53,7 +47,6 @@ static void __init sun6i_timer_init(void) ...@@ -53,7 +47,6 @@ static void __init sun6i_timer_init(void)
DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family") DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family")
.init_time = sun6i_timer_init, .init_time = sun6i_timer_init,
.dt_compat = sun6i_board_dt_compat, .dt_compat = sun6i_board_dt_compat,
.init_late = sunxi_dt_cpufreq_init,
MACHINE_END MACHINE_END
static const char * const sun7i_board_dt_compat[] = { static const char * const sun7i_board_dt_compat[] = {
...@@ -63,7 +56,6 @@ static const char * const sun7i_board_dt_compat[] = { ...@@ -63,7 +56,6 @@ static const char * const sun7i_board_dt_compat[] = {
DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family") DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
.dt_compat = sun7i_board_dt_compat, .dt_compat = sun7i_board_dt_compat,
.init_late = sunxi_dt_cpufreq_init,
MACHINE_END MACHINE_END
static const char * const sun8i_board_dt_compat[] = { static const char * const sun8i_board_dt_compat[] = {
...@@ -77,7 +69,6 @@ static const char * const sun8i_board_dt_compat[] = { ...@@ -77,7 +69,6 @@ static const char * const sun8i_board_dt_compat[] = {
DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i Family") DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i Family")
.init_time = sun6i_timer_init, .init_time = sun6i_timer_init,
.dt_compat = sun8i_board_dt_compat, .dt_compat = sun8i_board_dt_compat,
.init_late = sunxi_dt_cpufreq_init,
MACHINE_END MACHINE_END
static const char * const sun9i_board_dt_compat[] = { static const char * const sun9i_board_dt_compat[] = {
......
...@@ -110,7 +110,6 @@ static void __init zynq_init_late(void) ...@@ -110,7 +110,6 @@ static void __init zynq_init_late(void)
*/ */
static void __init zynq_init_machine(void) static void __init zynq_init_machine(void)
{ {
struct platform_device_info devinfo = { .name = "cpufreq-dt", };
struct soc_device_attribute *soc_dev_attr; struct soc_device_attribute *soc_dev_attr;
struct soc_device *soc_dev; struct soc_device *soc_dev;
struct device *parent = NULL; struct device *parent = NULL;
...@@ -145,7 +144,6 @@ static void __init zynq_init_machine(void) ...@@ -145,7 +144,6 @@ static void __init zynq_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
platform_device_register(&zynq_cpuidle_device); platform_device_register(&zynq_cpuidle_device);
platform_device_register_full(&devinfo);
} }
static void __init zynq_timer_init(void) static void __init zynq_timer_init(void)
......
...@@ -18,7 +18,11 @@ config CPU_FREQ ...@@ -18,7 +18,11 @@ config CPU_FREQ
if CPU_FREQ if CPU_FREQ
config CPU_FREQ_GOV_ATTR_SET
bool
config CPU_FREQ_GOV_COMMON config CPU_FREQ_GOV_COMMON
select CPU_FREQ_GOV_ATTR_SET
select IRQ_WORK select IRQ_WORK
bool bool
...@@ -103,6 +107,17 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE ...@@ -103,6 +107,17 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
Be aware that not all cpufreq drivers support the conservative Be aware that not all cpufreq drivers support the conservative
governor. If unsure have a look at the help section of the governor. If unsure have a look at the help section of the
driver. Fallback governor will be the performance governor. driver. Fallback governor will be the performance governor.
config CPU_FREQ_DEFAULT_GOV_SCHEDUTIL
bool "schedutil"
depends on SMP
select CPU_FREQ_GOV_SCHEDUTIL
select CPU_FREQ_GOV_PERFORMANCE
help
Use the 'schedutil' CPUFreq governor by default. If unsure,
have a look at the help section of that governor. The fallback
governor will be 'performance'.
endchoice endchoice
config CPU_FREQ_GOV_PERFORMANCE config CPU_FREQ_GOV_PERFORMANCE
...@@ -184,6 +199,26 @@ config CPU_FREQ_GOV_CONSERVATIVE ...@@ -184,6 +199,26 @@ config CPU_FREQ_GOV_CONSERVATIVE
If in doubt, say N. If in doubt, say N.
config CPU_FREQ_GOV_SCHEDUTIL
tristate "'schedutil' cpufreq policy governor"
depends on CPU_FREQ && SMP
select CPU_FREQ_GOV_ATTR_SET
select IRQ_WORK
help
This governor makes decisions based on the utilization data provided
by the scheduler. It sets the CPU frequency to be proportional to
the utilization/capacity ratio coming from the scheduler. If the
utilization is frequency-invariant, the new frequency is also
proportional to the maximum available frequency. If that is not the
case, it is proportional to the current frequency of the CPU. The
frequency tipping point is at utilization/capacity equal to 80% in
both cases.
To compile this driver as a module, choose M here: the module will
be called cpufreq_schedutil.
If in doubt, say N.
comment "CPU frequency scaling drivers" comment "CPU frequency scaling drivers"
config CPUFREQ_DT config CPUFREQ_DT
...@@ -191,6 +226,7 @@ config CPUFREQ_DT ...@@ -191,6 +226,7 @@ config CPUFREQ_DT
depends on HAVE_CLK && OF depends on HAVE_CLK && OF
# if CPU_THERMAL is on and THERMAL=m, CPUFREQ_DT cannot be =y: # if CPU_THERMAL is on and THERMAL=m, CPUFREQ_DT cannot be =y:
depends on !CPU_THERMAL || THERMAL depends on !CPU_THERMAL || THERMAL
select CPUFREQ_DT_PLATDEV
select PM_OPP select PM_OPP
help help
This adds a generic DT based cpufreq driver for frequency management. This adds a generic DT based cpufreq driver for frequency management.
...@@ -199,6 +235,15 @@ config CPUFREQ_DT ...@@ -199,6 +235,15 @@ config CPUFREQ_DT
If in doubt, say N. If in doubt, say N.
config CPUFREQ_DT_PLATDEV
bool
help
This adds a generic DT based cpufreq platdev driver for frequency
management. This creates a 'cpufreq-dt' platform device, on the
supported platforms.
If in doubt, say N.
if X86 if X86
source "drivers/cpufreq/Kconfig.x86" source "drivers/cpufreq/Kconfig.x86"
endif endif
......
...@@ -50,15 +50,6 @@ config ARM_HIGHBANK_CPUFREQ ...@@ -50,15 +50,6 @@ config ARM_HIGHBANK_CPUFREQ
If in doubt, say N. If in doubt, say N.
config ARM_HISI_ACPU_CPUFREQ
tristate "Hisilicon ACPU CPUfreq driver"
depends on ARCH_HISI && CPUFREQ_DT
select PM_OPP
help
This enables the hisilicon ACPU CPUfreq driver.
If in doubt, say N.
config ARM_IMX6Q_CPUFREQ config ARM_IMX6Q_CPUFREQ
tristate "Freescale i.MX6 cpufreq support" tristate "Freescale i.MX6 cpufreq support"
depends on ARCH_MXC depends on ARCH_MXC
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
config X86_INTEL_PSTATE config X86_INTEL_PSTATE
bool "Intel P state control" bool "Intel P state control"
depends on X86 depends on X86
select ACPI_PROCESSOR if ACPI
help help
This driver provides a P state for Intel core processors. This driver provides a P state for Intel core processors.
The driver implements an internal governor and will become The driver implements an internal governor and will become
......
...@@ -11,8 +11,10 @@ obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o ...@@ -11,8 +11,10 @@ obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) += cpufreq_governor_attr_set.o
obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o
obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o
################################################################################## ##################################################################################
# x86 drivers. # x86 drivers.
...@@ -53,7 +55,6 @@ obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o ...@@ -53,7 +55,6 @@ obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
...@@ -78,6 +79,7 @@ obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o ...@@ -78,6 +79,7 @@ obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
################################################################################## ##################################################################################
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -50,8 +52,6 @@ MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); ...@@ -50,8 +52,6 @@ MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_DESCRIPTION("ACPI Processor P-States Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define PFX "acpi-cpufreq: "
enum { enum {
UNDEFINED_CAPABLE = 0, UNDEFINED_CAPABLE = 0,
SYSTEM_INTEL_MSR_CAPABLE, SYSTEM_INTEL_MSR_CAPABLE,
...@@ -65,7 +65,6 @@ enum { ...@@ -65,7 +65,6 @@ enum {
#define MSR_K7_HWCR_CPB_DIS (1ULL << 25) #define MSR_K7_HWCR_CPB_DIS (1ULL << 25)
struct acpi_cpufreq_data { struct acpi_cpufreq_data {
struct cpufreq_frequency_table *freq_table;
unsigned int resume; unsigned int resume;
unsigned int cpu_feature; unsigned int cpu_feature;
unsigned int acpi_perf_cpu; unsigned int acpi_perf_cpu;
...@@ -200,8 +199,9 @@ static int check_amd_hwpstate_cpu(unsigned int cpuid) ...@@ -200,8 +199,9 @@ static int check_amd_hwpstate_cpu(unsigned int cpuid)
return cpu_has(cpu, X86_FEATURE_HW_PSTATE); return cpu_has(cpu, X86_FEATURE_HW_PSTATE);
} }
static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) static unsigned extract_io(struct cpufreq_policy *policy, u32 value)
{ {
struct acpi_cpufreq_data *data = policy->driver_data;
struct acpi_processor_performance *perf; struct acpi_processor_performance *perf;
int i; int i;
...@@ -209,13 +209,14 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) ...@@ -209,13 +209,14 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
for (i = 0; i < perf->state_count; i++) { for (i = 0; i < perf->state_count; i++) {
if (value == perf->states[i].status) if (value == perf->states[i].status)
return data->freq_table[i].frequency; return policy->freq_table[i].frequency;
} }
return 0; return 0;
} }
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) static unsigned extract_msr(struct cpufreq_policy *policy, u32 msr)
{ {
struct acpi_cpufreq_data *data = policy->driver_data;
struct cpufreq_frequency_table *pos; struct cpufreq_frequency_table *pos;
struct acpi_processor_performance *perf; struct acpi_processor_performance *perf;
...@@ -226,20 +227,22 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) ...@@ -226,20 +227,22 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
perf = to_perf_data(data); perf = to_perf_data(data);
cpufreq_for_each_entry(pos, data->freq_table) cpufreq_for_each_entry(pos, policy->freq_table)
if (msr == perf->states[pos->driver_data].status) if (msr == perf->states[pos->driver_data].status)
return pos->frequency; return pos->frequency;
return data->freq_table[0].frequency; return policy->freq_table[0].frequency;
} }
static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data) static unsigned extract_freq(struct cpufreq_policy *policy, u32 val)
{ {
struct acpi_cpufreq_data *data = policy->driver_data;
switch (data->cpu_feature) { switch (data->cpu_feature) {
case SYSTEM_INTEL_MSR_CAPABLE: case SYSTEM_INTEL_MSR_CAPABLE:
case SYSTEM_AMD_MSR_CAPABLE: case SYSTEM_AMD_MSR_CAPABLE:
return extract_msr(val, data); return extract_msr(policy, val);
case SYSTEM_IO_CAPABLE: case SYSTEM_IO_CAPABLE:
return extract_io(val, data); return extract_io(policy, val);
default: default:
return 0; return 0;
} }
...@@ -374,11 +377,11 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) ...@@ -374,11 +377,11 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
return 0; return 0;
data = policy->driver_data; data = policy->driver_data;
if (unlikely(!data || !data->freq_table)) if (unlikely(!data || !policy->freq_table))
return 0; return 0;
cached_freq = data->freq_table[to_perf_data(data)->state].frequency; cached_freq = policy->freq_table[to_perf_data(data)->state].frequency;
freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data); freq = extract_freq(policy, get_cur_val(cpumask_of(cpu), data));
if (freq != cached_freq) { if (freq != cached_freq) {
/* /*
* The dreaded BIOS frequency change behind our back. * The dreaded BIOS frequency change behind our back.
...@@ -392,14 +395,15 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) ...@@ -392,14 +395,15 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
return freq; return freq;
} }
static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, static unsigned int check_freqs(struct cpufreq_policy *policy,
struct acpi_cpufreq_data *data) const struct cpumask *mask, unsigned int freq)
{ {
struct acpi_cpufreq_data *data = policy->driver_data;
unsigned int cur_freq; unsigned int cur_freq;
unsigned int i; unsigned int i;
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
cur_freq = extract_freq(get_cur_val(mask, data), data); cur_freq = extract_freq(policy, get_cur_val(mask, data));
if (cur_freq == freq) if (cur_freq == freq)
return 1; return 1;
udelay(10); udelay(10);
...@@ -416,12 +420,12 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -416,12 +420,12 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
unsigned int next_perf_state = 0; /* Index into perf table */ unsigned int next_perf_state = 0; /* Index into perf table */
int result = 0; int result = 0;
if (unlikely(data == NULL || data->freq_table == NULL)) { if (unlikely(!data)) {
return -ENODEV; return -ENODEV;
} }
perf = to_perf_data(data); perf = to_perf_data(data);
next_perf_state = data->freq_table[index].driver_data; next_perf_state = policy->freq_table[index].driver_data;
if (perf->state == next_perf_state) { if (perf->state == next_perf_state) {
if (unlikely(data->resume)) { if (unlikely(data->resume)) {
pr_debug("Called after resume, resetting to P%d\n", pr_debug("Called after resume, resetting to P%d\n",
...@@ -444,8 +448,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -444,8 +448,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
drv_write(data, mask, perf->states[next_perf_state].control); drv_write(data, mask, perf->states[next_perf_state].control);
if (acpi_pstate_strict) { if (acpi_pstate_strict) {
if (!check_freqs(mask, data->freq_table[index].frequency, if (!check_freqs(policy, mask,
data)) { policy->freq_table[index].frequency)) {
pr_debug("acpi_cpufreq_target failed (%d)\n", pr_debug("acpi_cpufreq_target failed (%d)\n",
policy->cpu); policy->cpu);
result = -EAGAIN; result = -EAGAIN;
...@@ -458,6 +462,43 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -458,6 +462,43 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
return result; return result;
} }
unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
struct acpi_cpufreq_data *data = policy->driver_data;
struct acpi_processor_performance *perf;
struct cpufreq_frequency_table *entry;
unsigned int next_perf_state, next_freq, freq;
/*
* Find the closest frequency above target_freq.
*
* The table is sorted in the reverse order with respect to the
* frequency and all of the entries are valid (see the initialization).
*/
entry = policy->freq_table;
do {
entry++;
freq = entry->frequency;
} while (freq >= target_freq && freq != CPUFREQ_TABLE_END);
entry--;
next_freq = entry->frequency;
next_perf_state = entry->driver_data;
perf = to_perf_data(data);
if (perf->state == next_perf_state) {
if (unlikely(data->resume))
data->resume = 0;
else
return next_freq;
}
data->cpu_freq_write(&perf->control_register,
perf->states[next_perf_state].control);
perf->state = next_perf_state;
return next_freq;
}
static unsigned long static unsigned long
acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
{ {
...@@ -611,10 +652,7 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) ...@@ -611,10 +652,7 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c)
if ((c->x86 == 15) && if ((c->x86 == 15) &&
(c->x86_model == 6) && (c->x86_model == 6) &&
(c->x86_mask == 8)) { (c->x86_mask == 8)) {
printk(KERN_INFO "acpi-cpufreq: Intel(R) " pr_info("Intel(R) Xeon(R) 7100 Errata AL30, processors may lock up on frequency changes: disabling acpi-cpufreq\n");
"Xeon(R) 7100 Errata AL30, processors may "
"lock up on frequency changes: disabling "
"acpi-cpufreq.\n");
return -ENODEV; return -ENODEV;
} }
} }
...@@ -631,6 +669,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -631,6 +669,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
unsigned int result = 0; unsigned int result = 0;
struct cpuinfo_x86 *c = &cpu_data(policy->cpu); struct cpuinfo_x86 *c = &cpu_data(policy->cpu);
struct acpi_processor_performance *perf; struct acpi_processor_performance *perf;
struct cpufreq_frequency_table *freq_table;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static int blacklisted; static int blacklisted;
#endif #endif
...@@ -690,7 +729,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -690,7 +729,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpumask_copy(data->freqdomain_cpus, cpumask_copy(data->freqdomain_cpus,
topology_sibling_cpumask(cpu)); topology_sibling_cpumask(cpu));
policy->shared_type = CPUFREQ_SHARED_TYPE_HW; policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
pr_info_once(PFX "overriding BIOS provided _PSD data\n"); pr_info_once("overriding BIOS provided _PSD data\n");
} }
#endif #endif
...@@ -742,9 +781,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -742,9 +781,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto err_unreg; goto err_unreg;
} }
data->freq_table = kzalloc(sizeof(*data->freq_table) * freq_table = kzalloc(sizeof(*freq_table) *
(perf->state_count+1), GFP_KERNEL); (perf->state_count+1), GFP_KERNEL);
if (!data->freq_table) { if (!freq_table) {
result = -ENOMEM; result = -ENOMEM;
goto err_unreg; goto err_unreg;
} }
...@@ -762,30 +801,29 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -762,30 +801,29 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (perf->control_register.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE && if (perf->control_register.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE &&
policy->cpuinfo.transition_latency > 20 * 1000) { policy->cpuinfo.transition_latency > 20 * 1000) {
policy->cpuinfo.transition_latency = 20 * 1000; policy->cpuinfo.transition_latency = 20 * 1000;
printk_once(KERN_INFO pr_info_once("P-state transition latency capped at 20 uS\n");
"P-state transition latency capped at 20 uS\n");
} }
/* table init */ /* table init */
for (i = 0; i < perf->state_count; i++) { for (i = 0; i < perf->state_count; i++) {
if (i > 0 && perf->states[i].core_frequency >= if (i > 0 && perf->states[i].core_frequency >=
data->freq_table[valid_states-1].frequency / 1000) freq_table[valid_states-1].frequency / 1000)
continue; continue;
data->freq_table[valid_states].driver_data = i; freq_table[valid_states].driver_data = i;
data->freq_table[valid_states].frequency = freq_table[valid_states].frequency =
perf->states[i].core_frequency * 1000; perf->states[i].core_frequency * 1000;
valid_states++; valid_states++;
} }
data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END; freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
perf->state = 0; perf->state = 0;
result = cpufreq_table_validate_and_show(policy, data->freq_table); result = cpufreq_table_validate_and_show(policy, freq_table);
if (result) if (result)
goto err_freqfree; goto err_freqfree;
if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq) if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq)
printk(KERN_WARNING FW_WARN "P-state 0 is not max freq\n"); pr_warn(FW_WARN "P-state 0 is not max freq\n");
switch (perf->control_register.space_id) { switch (perf->control_register.space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO: case ACPI_ADR_SPACE_SYSTEM_IO:
...@@ -821,10 +859,13 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -821,10 +859,13 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
*/ */
data->resume = 1; data->resume = 1;
policy->fast_switch_possible = !acpi_pstate_strict &&
!(policy_is_shared(policy) && policy->shared_type != CPUFREQ_SHARED_TYPE_ANY);
return result; return result;
err_freqfree: err_freqfree:
kfree(data->freq_table); kfree(freq_table);
err_unreg: err_unreg:
acpi_processor_unregister_performance(cpu); acpi_processor_unregister_performance(cpu);
err_free_mask: err_free_mask:
...@@ -842,13 +883,12 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) ...@@ -842,13 +883,12 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
pr_debug("acpi_cpufreq_cpu_exit\n"); pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) { policy->fast_switch_possible = false;
policy->driver_data = NULL; policy->driver_data = NULL;
acpi_processor_unregister_performance(data->acpi_perf_cpu); acpi_processor_unregister_performance(data->acpi_perf_cpu);
free_cpumask_var(data->freqdomain_cpus); free_cpumask_var(data->freqdomain_cpus);
kfree(data->freq_table); kfree(policy->freq_table);
kfree(data); kfree(data);
}
return 0; return 0;
} }
...@@ -876,6 +916,7 @@ static struct freq_attr *acpi_cpufreq_attr[] = { ...@@ -876,6 +916,7 @@ static struct freq_attr *acpi_cpufreq_attr[] = {
static struct cpufreq_driver acpi_cpufreq_driver = { static struct cpufreq_driver acpi_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = acpi_cpufreq_target, .target_index = acpi_cpufreq_target,
.fast_switch = acpi_cpufreq_fast_switch,
.bios_limit = acpi_processor_get_bios_limit, .bios_limit = acpi_processor_get_bios_limit,
.init = acpi_cpufreq_cpu_init, .init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit, .exit = acpi_cpufreq_cpu_exit,
......
...@@ -298,7 +298,8 @@ static int merge_cluster_tables(void) ...@@ -298,7 +298,8 @@ static int merge_cluster_tables(void)
return 0; return 0;
} }
static void _put_cluster_clk_and_freq_table(struct device *cpu_dev) static void _put_cluster_clk_and_freq_table(struct device *cpu_dev,
const struct cpumask *cpumask)
{ {
u32 cluster = raw_cpu_to_cluster(cpu_dev->id); u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
...@@ -308,11 +309,12 @@ static void _put_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -308,11 +309,12 @@ static void _put_cluster_clk_and_freq_table(struct device *cpu_dev)
clk_put(clk[cluster]); clk_put(clk[cluster]);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
if (arm_bL_ops->free_opp_table) if (arm_bL_ops->free_opp_table)
arm_bL_ops->free_opp_table(cpu_dev); arm_bL_ops->free_opp_table(cpumask);
dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster); dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
} }
static void put_cluster_clk_and_freq_table(struct device *cpu_dev) static void put_cluster_clk_and_freq_table(struct device *cpu_dev,
const struct cpumask *cpumask)
{ {
u32 cluster = cpu_to_cluster(cpu_dev->id); u32 cluster = cpu_to_cluster(cpu_dev->id);
int i; int i;
...@@ -321,7 +323,7 @@ static void put_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -321,7 +323,7 @@ static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
return; return;
if (cluster < MAX_CLUSTERS) if (cluster < MAX_CLUSTERS)
return _put_cluster_clk_and_freq_table(cpu_dev); return _put_cluster_clk_and_freq_table(cpu_dev, cpumask);
for_each_present_cpu(i) { for_each_present_cpu(i) {
struct device *cdev = get_cpu_device(i); struct device *cdev = get_cpu_device(i);
...@@ -330,14 +332,15 @@ static void put_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -330,14 +332,15 @@ static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
return; return;
} }
_put_cluster_clk_and_freq_table(cdev); _put_cluster_clk_and_freq_table(cdev, cpumask);
} }
/* free virtual table */ /* free virtual table */
kfree(freq_table[cluster]); kfree(freq_table[cluster]);
} }
static int _get_cluster_clk_and_freq_table(struct device *cpu_dev) static int _get_cluster_clk_and_freq_table(struct device *cpu_dev,
const struct cpumask *cpumask)
{ {
u32 cluster = raw_cpu_to_cluster(cpu_dev->id); u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
int ret; int ret;
...@@ -345,7 +348,7 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -345,7 +348,7 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
if (freq_table[cluster]) if (freq_table[cluster])
return 0; return 0;
ret = arm_bL_ops->init_opp_table(cpu_dev); ret = arm_bL_ops->init_opp_table(cpumask);
if (ret) { if (ret) {
dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n", dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
__func__, cpu_dev->id, ret); __func__, cpu_dev->id, ret);
...@@ -374,14 +377,15 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -374,14 +377,15 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
free_opp_table: free_opp_table:
if (arm_bL_ops->free_opp_table) if (arm_bL_ops->free_opp_table)
arm_bL_ops->free_opp_table(cpu_dev); arm_bL_ops->free_opp_table(cpumask);
out: out:
dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__, dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
cluster); cluster);
return ret; return ret;
} }
static int get_cluster_clk_and_freq_table(struct device *cpu_dev) static int get_cluster_clk_and_freq_table(struct device *cpu_dev,
const struct cpumask *cpumask)
{ {
u32 cluster = cpu_to_cluster(cpu_dev->id); u32 cluster = cpu_to_cluster(cpu_dev->id);
int i, ret; int i, ret;
...@@ -390,7 +394,7 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -390,7 +394,7 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
return 0; return 0;
if (cluster < MAX_CLUSTERS) { if (cluster < MAX_CLUSTERS) {
ret = _get_cluster_clk_and_freq_table(cpu_dev); ret = _get_cluster_clk_and_freq_table(cpu_dev, cpumask);
if (ret) if (ret)
atomic_dec(&cluster_usage[cluster]); atomic_dec(&cluster_usage[cluster]);
return ret; return ret;
...@@ -407,7 +411,7 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -407,7 +411,7 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
return -ENODEV; return -ENODEV;
} }
ret = _get_cluster_clk_and_freq_table(cdev); ret = _get_cluster_clk_and_freq_table(cdev, cpumask);
if (ret) if (ret)
goto put_clusters; goto put_clusters;
} }
...@@ -433,7 +437,7 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -433,7 +437,7 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
return -ENODEV; return -ENODEV;
} }
_put_cluster_clk_and_freq_table(cdev); _put_cluster_clk_and_freq_table(cdev, cpumask);
} }
atomic_dec(&cluster_usage[cluster]); atomic_dec(&cluster_usage[cluster]);
...@@ -455,18 +459,6 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) ...@@ -455,18 +459,6 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
return -ENODEV; return -ENODEV;
} }
ret = get_cluster_clk_and_freq_table(cpu_dev);
if (ret)
return ret;
ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]);
if (ret) {
dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
policy->cpu, cur_cluster);
put_cluster_clk_and_freq_table(cpu_dev);
return ret;
}
if (cur_cluster < MAX_CLUSTERS) { if (cur_cluster < MAX_CLUSTERS) {
int cpu; int cpu;
...@@ -479,6 +471,18 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) ...@@ -479,6 +471,18 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER; per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
} }
ret = get_cluster_clk_and_freq_table(cpu_dev, policy->cpus);
if (ret)
return ret;
ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]);
if (ret) {
dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
policy->cpu, cur_cluster);
put_cluster_clk_and_freq_table(cpu_dev, policy->cpus);
return ret;
}
if (arm_bL_ops->get_transition_latency) if (arm_bL_ops->get_transition_latency)
policy->cpuinfo.transition_latency = policy->cpuinfo.transition_latency =
arm_bL_ops->get_transition_latency(cpu_dev); arm_bL_ops->get_transition_latency(cpu_dev);
...@@ -509,7 +513,7 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy) ...@@ -509,7 +513,7 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
return -ENODEV; return -ENODEV;
} }
put_cluster_clk_and_freq_table(cpu_dev); put_cluster_clk_and_freq_table(cpu_dev, policy->related_cpus);
dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu); dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
return 0; return 0;
......
...@@ -30,11 +30,11 @@ struct cpufreq_arm_bL_ops { ...@@ -30,11 +30,11 @@ struct cpufreq_arm_bL_ops {
* This must set opp table for cpu_dev in a similar way as done by * This must set opp table for cpu_dev in a similar way as done by
* dev_pm_opp_of_add_table(). * dev_pm_opp_of_add_table().
*/ */
int (*init_opp_table)(struct device *cpu_dev); int (*init_opp_table)(const struct cpumask *cpumask);
/* Optional */ /* Optional */
int (*get_transition_latency)(struct device *cpu_dev); int (*get_transition_latency)(struct device *cpu_dev);
void (*free_opp_table)(struct device *cpu_dev); void (*free_opp_table)(const struct cpumask *cpumask);
}; };
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
......
...@@ -43,23 +43,6 @@ static struct device_node *get_cpu_node_with_valid_op(int cpu) ...@@ -43,23 +43,6 @@ static struct device_node *get_cpu_node_with_valid_op(int cpu)
return np; return np;
} }
static int dt_init_opp_table(struct device *cpu_dev)
{
struct device_node *np;
int ret;
np = of_node_get(cpu_dev->of_node);
if (!np) {
pr_err("failed to find cpu%d node\n", cpu_dev->id);
return -ENOENT;
}
ret = dev_pm_opp_of_add_table(cpu_dev);
of_node_put(np);
return ret;
}
static int dt_get_transition_latency(struct device *cpu_dev) static int dt_get_transition_latency(struct device *cpu_dev)
{ {
struct device_node *np; struct device_node *np;
...@@ -81,8 +64,8 @@ static int dt_get_transition_latency(struct device *cpu_dev) ...@@ -81,8 +64,8 @@ static int dt_get_transition_latency(struct device *cpu_dev)
static struct cpufreq_arm_bL_ops dt_bL_ops = { static struct cpufreq_arm_bL_ops dt_bL_ops = {
.name = "dt-bl", .name = "dt-bl",
.get_transition_latency = dt_get_transition_latency, .get_transition_latency = dt_get_transition_latency,
.init_opp_table = dt_init_opp_table, .init_opp_table = dev_pm_opp_of_cpumask_add_table,
.free_opp_table = dev_pm_opp_of_remove_table, .free_opp_table = dev_pm_opp_of_cpumask_remove_table,
}; };
static int generic_bL_probe(struct platform_device *pdev) static int generic_bL_probe(struct platform_device *pdev)
......
...@@ -173,4 +173,25 @@ static int __init cppc_cpufreq_init(void) ...@@ -173,4 +173,25 @@ static int __init cppc_cpufreq_init(void)
return -ENODEV; return -ENODEV;
} }
static void __exit cppc_cpufreq_exit(void)
{
struct cpudata *cpu;
int i;
cpufreq_unregister_driver(&cppc_cpufreq_driver);
for_each_possible_cpu(i) {
cpu = all_cpu_data[i];
free_cpumask_var(cpu->shared_cpu_map);
kfree(cpu);
}
kfree(all_cpu_data);
}
module_exit(cppc_cpufreq_exit);
MODULE_AUTHOR("Ashwin Chaugule");
MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
MODULE_LICENSE("GPL");
late_initcall(cppc_cpufreq_init); late_initcall(cppc_cpufreq_init);
/*
* Copyright (C) 2016 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.
*/
#include <linux/err.h>
#include <linux/of.h>
#include <linux/platform_device.h>
static const struct of_device_id machines[] __initconst = {
{ .compatible = "allwinner,sun4i-a10", },
{ .compatible = "allwinner,sun5i-a10s", },
{ .compatible = "allwinner,sun5i-a13", },
{ .compatible = "allwinner,sun5i-r8", },
{ .compatible = "allwinner,sun6i-a31", },
{ .compatible = "allwinner,sun6i-a31s", },
{ .compatible = "allwinner,sun7i-a20", },
{ .compatible = "allwinner,sun8i-a23", },
{ .compatible = "allwinner,sun8i-a33", },
{ .compatible = "allwinner,sun8i-a83t", },
{ .compatible = "allwinner,sun8i-h3", },
{ .compatible = "hisilicon,hi6220", },
{ .compatible = "fsl,imx27", },
{ .compatible = "fsl,imx51", },
{ .compatible = "fsl,imx53", },
{ .compatible = "fsl,imx7d", },
{ .compatible = "marvell,berlin", },
{ .compatible = "samsung,exynos3250", },
{ .compatible = "samsung,exynos4210", },
{ .compatible = "samsung,exynos4212", },
{ .compatible = "samsung,exynos4412", },
{ .compatible = "samsung,exynos5250", },
#ifndef CONFIG_BL_SWITCHER
{ .compatible = "samsung,exynos5420", },
{ .compatible = "samsung,exynos5800", },
#endif
{ .compatible = "renesas,emev2", },
{ .compatible = "renesas,r7s72100", },
{ .compatible = "renesas,r8a73a4", },
{ .compatible = "renesas,r8a7740", },
{ .compatible = "renesas,r8a7778", },
{ .compatible = "renesas,r8a7779", },
{ .compatible = "renesas,r8a7790", },
{ .compatible = "renesas,r8a7791", },
{ .compatible = "renesas,r8a7793", },
{ .compatible = "renesas,r8a7794", },
{ .compatible = "renesas,sh73a0", },
{ .compatible = "rockchip,rk2928", },
{ .compatible = "rockchip,rk3036", },
{ .compatible = "rockchip,rk3066a", },
{ .compatible = "rockchip,rk3066b", },
{ .compatible = "rockchip,rk3188", },
{ .compatible = "rockchip,rk3228", },
{ .compatible = "rockchip,rk3288", },
{ .compatible = "rockchip,rk3366", },
{ .compatible = "rockchip,rk3368", },
{ .compatible = "rockchip,rk3399", },
{ .compatible = "sigma,tango4" },
{ .compatible = "ti,omap2", },
{ .compatible = "ti,omap3", },
{ .compatible = "ti,omap4", },
{ .compatible = "ti,omap5", },
{ .compatible = "xlnx,zynq-7000", },
};
static int __init cpufreq_dt_platdev_init(void)
{
struct device_node *np = of_find_node_by_path("/");
if (!np)
return -ENODEV;
if (!of_match_node(machines, np))
return -ENODEV;
of_node_put(of_root);
return PTR_ERR_OR_ZERO(platform_device_register_simple("cpufreq-dt", -1,
NULL, 0));
}
device_initcall(cpufreq_dt_platdev_init);
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/cpu_cooling.h> #include <linux/cpu_cooling.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/cpufreq-dt.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -147,7 +146,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -147,7 +146,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
struct clk *cpu_clk; struct clk *cpu_clk;
struct dev_pm_opp *suspend_opp; struct dev_pm_opp *suspend_opp;
unsigned int transition_latency; unsigned int transition_latency;
bool opp_v1 = false; bool fallback = false;
const char *name; const char *name;
int ret; int ret;
...@@ -167,14 +166,16 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -167,14 +166,16 @@ static int cpufreq_init(struct cpufreq_policy *policy)
/* Get OPP-sharing information from "operating-points-v2" bindings */ /* Get OPP-sharing information from "operating-points-v2" bindings */
ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus);
if (ret) { if (ret) {
if (ret != -ENOENT)
goto out_put_clk;
/* /*
* operating-points-v2 not supported, fallback to old method of * operating-points-v2 not supported, fallback to old method of
* finding shared-OPPs for backward compatibility. * finding shared-OPPs for backward compatibility if the
* platform hasn't set sharing CPUs.
*/ */
if (ret == -ENOENT) if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus))
opp_v1 = true; fallback = true;
else
goto out_put_clk;
} }
/* /*
...@@ -214,11 +215,8 @@ static int cpufreq_init(struct cpufreq_policy *policy) ...@@ -214,11 +215,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
goto out_free_opp; goto out_free_opp;
} }
if (opp_v1) { if (fallback) {
struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data(); cpumask_setall(policy->cpus);
if (!pd || !pd->independent_clocks)
cpumask_setall(policy->cpus);
/* /*
* OPP tables are initialized only for policy->cpu, do it for * OPP tables are initialized only for policy->cpu, do it for
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -56,8 +58,6 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); ...@@ -56,8 +58,6 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
MODULE_PARM_DESC(min_fsb, MODULE_PARM_DESC(min_fsb,
"Minimum FSB to use, if not defined: current FSB - 50"); "Minimum FSB to use, if not defined: current FSB - 50");
#define PFX "cpufreq-nforce2: "
/** /**
* nforce2_calc_fsb - calculate FSB * nforce2_calc_fsb - calculate FSB
* @pll: PLL value * @pll: PLL value
...@@ -174,13 +174,13 @@ static int nforce2_set_fsb(unsigned int fsb) ...@@ -174,13 +174,13 @@ static int nforce2_set_fsb(unsigned int fsb)
int pll = 0; int pll = 0;
if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) { if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
printk(KERN_ERR PFX "FSB %d is out of range!\n", fsb); pr_err("FSB %d is out of range!\n", fsb);
return -EINVAL; return -EINVAL;
} }
tfsb = nforce2_fsb_read(0); tfsb = nforce2_fsb_read(0);
if (!tfsb) { if (!tfsb) {
printk(KERN_ERR PFX "Error while reading the FSB\n"); pr_err("Error while reading the FSB\n");
return -EINVAL; return -EINVAL;
} }
...@@ -276,8 +276,7 @@ static int nforce2_target(struct cpufreq_policy *policy, ...@@ -276,8 +276,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
/* local_irq_save(flags); */ /* local_irq_save(flags); */
if (nforce2_set_fsb(target_fsb) < 0) if (nforce2_set_fsb(target_fsb) < 0)
printk(KERN_ERR PFX "Changing FSB to %d failed\n", pr_err("Changing FSB to %d failed\n", target_fsb);
target_fsb);
else else
pr_debug("Changed FSB successfully to %d\n", pr_debug("Changed FSB successfully to %d\n",
target_fsb); target_fsb);
...@@ -325,8 +324,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) ...@@ -325,8 +324,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
/* FIX: Get FID from CPU */ /* FIX: Get FID from CPU */
if (!fid) { if (!fid) {
if (!cpu_khz) { if (!cpu_khz) {
printk(KERN_WARNING PFX pr_warn("cpu_khz not set, can't calculate multiplier!\n");
"cpu_khz not set, can't calculate multiplier!\n");
return -ENODEV; return -ENODEV;
} }
...@@ -341,8 +339,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) ...@@ -341,8 +339,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
} }
} }
printk(KERN_INFO PFX "FSB currently at %i MHz, FID %d.%d\n", fsb, pr_info("FSB currently at %i MHz, FID %d.%d\n",
fid / 10, fid % 10); fsb, fid / 10, fid % 10);
/* Set maximum FSB to FSB at boot time */ /* Set maximum FSB to FSB at boot time */
max_fsb = nforce2_fsb_read(1); max_fsb = nforce2_fsb_read(1);
...@@ -401,11 +399,9 @@ static int nforce2_detect_chipset(void) ...@@ -401,11 +399,9 @@ static int nforce2_detect_chipset(void)
if (nforce2_dev == NULL) if (nforce2_dev == NULL)
return -ENODEV; return -ENODEV;
printk(KERN_INFO PFX "Detected nForce2 chipset revision %X\n", pr_info("Detected nForce2 chipset revision %X\n",
nforce2_dev->revision); nforce2_dev->revision);
printk(KERN_INFO PFX pr_info("FSB changing is maybe unstable and can lead to crashes and data loss\n");
"FSB changing is maybe unstable and can lead to "
"crashes and data loss.\n");
return 0; return 0;
} }
...@@ -423,7 +419,7 @@ static int __init nforce2_init(void) ...@@ -423,7 +419,7 @@ static int __init nforce2_init(void)
/* detect chipset */ /* detect chipset */
if (nforce2_detect_chipset()) { if (nforce2_detect_chipset()) {
printk(KERN_INFO PFX "No nForce2 chipset.\n"); pr_info("No nForce2 chipset\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -78,6 +78,11 @@ static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); ...@@ -78,6 +78,11 @@ static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
static unsigned int __cpufreq_get(struct cpufreq_policy *policy); static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
static int cpufreq_start_governor(struct cpufreq_policy *policy); static int cpufreq_start_governor(struct cpufreq_policy *policy);
static inline int cpufreq_exit_governor(struct cpufreq_policy *policy)
{
return cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
}
/** /**
* Two notifier lists: the "policy" list is involved in the * Two notifier lists: the "policy" list is involved in the
* validation process for a new CPU frequency policy; the * validation process for a new CPU frequency policy; the
...@@ -429,6 +434,73 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, ...@@ -429,6 +434,73 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
} }
EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end); EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end);
/*
* Fast frequency switching status count. Positive means "enabled", negative
* means "disabled" and 0 means "not decided yet".
*/
static int cpufreq_fast_switch_count;
static DEFINE_MUTEX(cpufreq_fast_switch_lock);
static void cpufreq_list_transition_notifiers(void)
{
struct notifier_block *nb;
pr_info("Registered transition notifiers:\n");
mutex_lock(&cpufreq_transition_notifier_list.mutex);
for (nb = cpufreq_transition_notifier_list.head; nb; nb = nb->next)
pr_info("%pF\n", nb->notifier_call);
mutex_unlock(&cpufreq_transition_notifier_list.mutex);
}
/**
* cpufreq_enable_fast_switch - Enable fast frequency switching for policy.
* @policy: cpufreq policy to enable fast frequency switching for.
*
* Try to enable fast frequency switching for @policy.
*
* The attempt will fail if there is at least one transition notifier registered
* at this point, as fast frequency switching is quite fundamentally at odds
* with transition notifiers. Thus if successful, it will make registration of
* transition notifiers fail going forward.
*/
void cpufreq_enable_fast_switch(struct cpufreq_policy *policy)
{
lockdep_assert_held(&policy->rwsem);
if (!policy->fast_switch_possible)
return;
mutex_lock(&cpufreq_fast_switch_lock);
if (cpufreq_fast_switch_count >= 0) {
cpufreq_fast_switch_count++;
policy->fast_switch_enabled = true;
} else {
pr_warn("CPU%u: Fast frequency switching not enabled\n",
policy->cpu);
cpufreq_list_transition_notifiers();
}
mutex_unlock(&cpufreq_fast_switch_lock);
}
EXPORT_SYMBOL_GPL(cpufreq_enable_fast_switch);
/**
* cpufreq_disable_fast_switch - Disable fast frequency switching for policy.
* @policy: cpufreq policy to disable fast frequency switching for.
*/
void cpufreq_disable_fast_switch(struct cpufreq_policy *policy)
{
mutex_lock(&cpufreq_fast_switch_lock);
if (policy->fast_switch_enabled) {
policy->fast_switch_enabled = false;
if (!WARN_ON(cpufreq_fast_switch_count <= 0))
cpufreq_fast_switch_count--;
}
mutex_unlock(&cpufreq_fast_switch_lock);
}
EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch);
/********************************************************************* /*********************************************************************
* SYSFS INTERFACE * * SYSFS INTERFACE *
...@@ -1248,26 +1320,24 @@ static int cpufreq_online(unsigned int cpu) ...@@ -1248,26 +1320,24 @@ static int cpufreq_online(unsigned int cpu)
*/ */
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{ {
struct cpufreq_policy *policy;
unsigned cpu = dev->id; unsigned cpu = dev->id;
int ret;
dev_dbg(dev, "%s: adding CPU%u\n", __func__, cpu); dev_dbg(dev, "%s: adding CPU%u\n", __func__, cpu);
if (cpu_online(cpu)) { if (cpu_online(cpu))
ret = cpufreq_online(cpu); return cpufreq_online(cpu);
} else {
/*
* A hotplug notifier will follow and we will handle it as CPU
* online then. For now, just create the sysfs link, unless
* there is no policy or the link is already present.
*/
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
ret = policy && !cpumask_test_and_set_cpu(cpu, policy->real_cpus) /*
? add_cpu_dev_symlink(policy, cpu) : 0; * A hotplug notifier will follow and we will handle it as CPU online
} * then. For now, just create the sysfs link, unless there is no policy
* or the link is already present.
*/
policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus))
return 0;
return ret; return add_cpu_dev_symlink(policy, cpu);
} }
static void cpufreq_offline(unsigned int cpu) static void cpufreq_offline(unsigned int cpu)
...@@ -1319,7 +1389,7 @@ static void cpufreq_offline(unsigned int cpu) ...@@ -1319,7 +1389,7 @@ static void cpufreq_offline(unsigned int cpu)
/* If cpu is last user of policy, free policy */ /* If cpu is last user of policy, free policy */
if (has_target()) { if (has_target()) {
ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); ret = cpufreq_exit_governor(policy);
if (ret) if (ret)
pr_err("%s: Failed to exit governor\n", __func__); pr_err("%s: Failed to exit governor\n", __func__);
} }
...@@ -1447,8 +1517,12 @@ static unsigned int __cpufreq_get(struct cpufreq_policy *policy) ...@@ -1447,8 +1517,12 @@ static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
ret_freq = cpufreq_driver->get(policy->cpu); ret_freq = cpufreq_driver->get(policy->cpu);
/* Updating inactive policies is invalid, so avoid doing that. */ /*
if (unlikely(policy_is_inactive(policy))) * Updating inactive policies is invalid, so avoid doing that. Also
* if fast frequency switching is used with the given policy, the check
* against policy->cur is pointless, so skip it in that case too.
*/
if (unlikely(policy_is_inactive(policy)) || policy->fast_switch_enabled)
return ret_freq; return ret_freq;
if (ret_freq && policy->cur && if (ret_freq && policy->cur &&
...@@ -1679,8 +1753,18 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) ...@@ -1679,8 +1753,18 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
switch (list) { switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER: case CPUFREQ_TRANSITION_NOTIFIER:
mutex_lock(&cpufreq_fast_switch_lock);
if (cpufreq_fast_switch_count > 0) {
mutex_unlock(&cpufreq_fast_switch_lock);
return -EBUSY;
}
ret = srcu_notifier_chain_register( ret = srcu_notifier_chain_register(
&cpufreq_transition_notifier_list, nb); &cpufreq_transition_notifier_list, nb);
if (!ret)
cpufreq_fast_switch_count--;
mutex_unlock(&cpufreq_fast_switch_lock);
break; break;
case CPUFREQ_POLICY_NOTIFIER: case CPUFREQ_POLICY_NOTIFIER:
ret = blocking_notifier_chain_register( ret = blocking_notifier_chain_register(
...@@ -1713,8 +1797,14 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) ...@@ -1713,8 +1797,14 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
switch (list) { switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER: case CPUFREQ_TRANSITION_NOTIFIER:
mutex_lock(&cpufreq_fast_switch_lock);
ret = srcu_notifier_chain_unregister( ret = srcu_notifier_chain_unregister(
&cpufreq_transition_notifier_list, nb); &cpufreq_transition_notifier_list, nb);
if (!ret && !WARN_ON(cpufreq_fast_switch_count >= 0))
cpufreq_fast_switch_count++;
mutex_unlock(&cpufreq_fast_switch_lock);
break; break;
case CPUFREQ_POLICY_NOTIFIER: case CPUFREQ_POLICY_NOTIFIER:
ret = blocking_notifier_chain_unregister( ret = blocking_notifier_chain_unregister(
...@@ -1733,6 +1823,37 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier); ...@@ -1733,6 +1823,37 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS * * GOVERNORS *
*********************************************************************/ *********************************************************************/
/**
* cpufreq_driver_fast_switch - Carry out a fast CPU frequency switch.
* @policy: cpufreq policy to switch the frequency for.
* @target_freq: New frequency to set (may be approximate).
*
* Carry out a fast frequency switch without sleeping.
*
* The driver's ->fast_switch() callback invoked by this function must be
* suitable for being called from within RCU-sched read-side critical sections
* and it is expected to select the minimum available frequency greater than or
* equal to @target_freq (CPUFREQ_RELATION_L).
*
* This function must not be called if policy->fast_switch_enabled is unset.
*
* Governors calling this function must guarantee that it will never be invoked
* twice in parallel for the same policy and that it will never be called in
* parallel with either ->target() or ->target_index() for the same policy.
*
* If CPUFREQ_ENTRY_INVALID is returned by the driver's ->fast_switch()
* callback to indicate an error condition, the hardware configuration must be
* preserved.
*/
unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
clamp_val(target_freq, policy->min, policy->max);
return cpufreq_driver->fast_switch(policy, target_freq);
}
EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
/* Must set freqs->new to intermediate frequency */ /* Must set freqs->new to intermediate frequency */
static int __target_intermediate(struct cpufreq_policy *policy, static int __target_intermediate(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int index) struct cpufreq_freqs *freqs, int index)
...@@ -2108,7 +2229,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, ...@@ -2108,7 +2229,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
return ret; return ret;
} }
ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); ret = cpufreq_exit_governor(policy);
if (ret) { if (ret) {
pr_err("%s: Failed to Exit Governor: %s (%d)\n", pr_err("%s: Failed to Exit Governor: %s (%d)\n",
__func__, old_gov->name, ret); __func__, old_gov->name, ret);
...@@ -2125,7 +2246,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, ...@@ -2125,7 +2246,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
pr_debug("cpufreq: governor change\n"); pr_debug("cpufreq: governor change\n");
return 0; return 0;
} }
cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); cpufreq_exit_governor(policy);
} }
/* new governor failed, so re-start old one */ /* new governor failed, so re-start old one */
...@@ -2193,16 +2314,13 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, ...@@ -2193,16 +2314,13 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
switch (action & ~CPU_TASKS_FROZEN) { switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE: case CPU_ONLINE:
case CPU_DOWN_FAILED:
cpufreq_online(cpu); cpufreq_online(cpu);
break; break;
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
cpufreq_offline(cpu); cpufreq_offline(cpu);
break; break;
case CPU_DOWN_FAILED:
cpufreq_online(cpu);
break;
} }
return NOTIFY_OK; return NOTIFY_OK;
} }
......
...@@ -129,9 +129,10 @@ static struct notifier_block cs_cpufreq_notifier_block = { ...@@ -129,9 +129,10 @@ static struct notifier_block cs_cpufreq_notifier_block = {
/************************** sysfs interface ************************/ /************************** sysfs interface ************************/
static struct dbs_governor cs_dbs_gov; static struct dbs_governor cs_dbs_gov;
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
...@@ -143,9 +144,10 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, ...@@ -143,9 +144,10 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
return count; return count;
} }
static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, static ssize_t store_up_threshold(struct gov_attr_set *attr_set,
size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input; unsigned int input;
int ret; int ret;
...@@ -158,9 +160,10 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, ...@@ -158,9 +160,10 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
return count; return count;
} }
static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf, static ssize_t store_down_threshold(struct gov_attr_set *attr_set,
size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input; unsigned int input;
int ret; int ret;
...@@ -175,9 +178,10 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf, ...@@ -175,9 +178,10 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
return count; return count;
} }
static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, static ssize_t store_ignore_nice_load(struct gov_attr_set *attr_set,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
unsigned int input; unsigned int input;
int ret; int ret;
...@@ -199,9 +203,10 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, ...@@ -199,9 +203,10 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
return count; return count;
} }
static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf, static ssize_t store_freq_step(struct gov_attr_set *attr_set, const char *buf,
size_t count) size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input; unsigned int input;
int ret; int ret;
......
...@@ -43,9 +43,10 @@ static DEFINE_MUTEX(gov_dbs_data_mutex); ...@@ -43,9 +43,10 @@ static DEFINE_MUTEX(gov_dbs_data_mutex);
* This must be called with dbs_data->mutex held, otherwise traversing * This must be called with dbs_data->mutex held, otherwise traversing
* policy_dbs_list isn't safe. * policy_dbs_list isn't safe.
*/ */
ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf,
size_t count) size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
struct policy_dbs_info *policy_dbs; struct policy_dbs_info *policy_dbs;
unsigned int rate; unsigned int rate;
int ret; int ret;
...@@ -59,7 +60,7 @@ ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, ...@@ -59,7 +60,7 @@ ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
* We are operating under dbs_data->mutex and so the list and its * We are operating under dbs_data->mutex and so the list and its
* entries can't be freed concurrently. * entries can't be freed concurrently.
*/ */
list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) { list_for_each_entry(policy_dbs, &attr_set->policy_list, list) {
mutex_lock(&policy_dbs->timer_mutex); mutex_lock(&policy_dbs->timer_mutex);
/* /*
* On 32-bit architectures this may race with the * On 32-bit architectures this may race with the
...@@ -96,13 +97,13 @@ void gov_update_cpu_data(struct dbs_data *dbs_data) ...@@ -96,13 +97,13 @@ void gov_update_cpu_data(struct dbs_data *dbs_data)
{ {
struct policy_dbs_info *policy_dbs; struct policy_dbs_info *policy_dbs;
list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) { list_for_each_entry(policy_dbs, &dbs_data->attr_set.policy_list, list) {
unsigned int j; unsigned int j;
for_each_cpu(j, policy_dbs->policy->cpus) { for_each_cpu(j, policy_dbs->policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j); struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_update_time,
dbs_data->io_is_busy); dbs_data->io_is_busy);
if (dbs_data->ignore_nice_load) if (dbs_data->ignore_nice_load)
j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE];
...@@ -111,54 +112,6 @@ void gov_update_cpu_data(struct dbs_data *dbs_data) ...@@ -111,54 +112,6 @@ void gov_update_cpu_data(struct dbs_data *dbs_data)
} }
EXPORT_SYMBOL_GPL(gov_update_cpu_data); EXPORT_SYMBOL_GPL(gov_update_cpu_data);
static inline struct dbs_data *to_dbs_data(struct kobject *kobj)
{
return container_of(kobj, struct dbs_data, kobj);
}
static inline struct governor_attr *to_gov_attr(struct attribute *attr)
{
return container_of(attr, struct governor_attr, attr);
}
static ssize_t governor_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct dbs_data *dbs_data = to_dbs_data(kobj);
struct governor_attr *gattr = to_gov_attr(attr);
return gattr->show(dbs_data, buf);
}
static ssize_t governor_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct dbs_data *dbs_data = to_dbs_data(kobj);
struct governor_attr *gattr = to_gov_attr(attr);
int ret = -EBUSY;
mutex_lock(&dbs_data->mutex);
if (dbs_data->usage_count)
ret = gattr->store(dbs_data, buf, count);
mutex_unlock(&dbs_data->mutex);
return ret;
}
/*
* Sysfs Ops for accessing governor attributes.
*
* All show/store invocations for governor specific sysfs attributes, will first
* call the below show/store callbacks and the attribute specific callback will
* be called from within it.
*/
static const struct sysfs_ops governor_sysfs_ops = {
.show = governor_show,
.store = governor_store,
};
unsigned int dbs_update(struct cpufreq_policy *policy) unsigned int dbs_update(struct cpufreq_policy *policy)
{ {
struct policy_dbs_info *policy_dbs = policy->governor_data; struct policy_dbs_info *policy_dbs = policy->governor_data;
...@@ -184,14 +137,14 @@ unsigned int dbs_update(struct cpufreq_policy *policy) ...@@ -184,14 +137,14 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
/* Get Absolute Load */ /* Get Absolute Load */
for_each_cpu(j, policy->cpus) { for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j); struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
u64 cur_wall_time, cur_idle_time; u64 update_time, cur_idle_time;
unsigned int idle_time, wall_time; unsigned int idle_time, time_elapsed;
unsigned int load; unsigned int load;
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time, io_busy); cur_idle_time = get_cpu_idle_time(j, &update_time, io_busy);
wall_time = cur_wall_time - j_cdbs->prev_cpu_wall; time_elapsed = update_time - j_cdbs->prev_update_time;
j_cdbs->prev_cpu_wall = cur_wall_time; j_cdbs->prev_update_time = update_time;
idle_time = cur_idle_time - j_cdbs->prev_cpu_idle; idle_time = cur_idle_time - j_cdbs->prev_cpu_idle;
j_cdbs->prev_cpu_idle = cur_idle_time; j_cdbs->prev_cpu_idle = cur_idle_time;
...@@ -203,47 +156,62 @@ unsigned int dbs_update(struct cpufreq_policy *policy) ...@@ -203,47 +156,62 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
j_cdbs->prev_cpu_nice = cur_nice; j_cdbs->prev_cpu_nice = cur_nice;
} }
if (unlikely(!wall_time || wall_time < idle_time)) if (unlikely(!time_elapsed)) {
continue; /*
* That can only happen when this function is called
/* * twice in a row with a very short interval between the
* If the CPU had gone completely idle, and a task just woke up * calls, so the previous load value can be used then.
* on this CPU now, it would be unfair to calculate 'load' the */
* usual way for this elapsed time-window, because it will show
* near-zero load, irrespective of how CPU intensive that task
* actually is. This is undesirable for latency-sensitive bursty
* workloads.
*
* To avoid this, we reuse the 'load' from the previous
* time-window and give this task a chance to start with a
* reasonably high CPU frequency. (However, we shouldn't over-do
* this copy, lest we get stuck at a high load (high frequency)
* for too long, even when the current system load has actually
* dropped down. So we perform the copy only once, upon the
* first wake-up from idle.)
*
* Detecting this situation is easy: the governor's utilization
* update handler would not have run during CPU-idle periods.
* Hence, an unusually large 'wall_time' (as compared to the
* sampling rate) indicates this scenario.
*
* prev_load can be zero in two cases and we must recalculate it
* for both cases:
* - during long idle intervals
* - explicitly set to zero
*/
if (unlikely(wall_time > (2 * sampling_rate) &&
j_cdbs->prev_load)) {
load = j_cdbs->prev_load; load = j_cdbs->prev_load;
} else if (unlikely(time_elapsed > 2 * sampling_rate &&
j_cdbs->prev_load)) {
/* /*
* Perform a destructive copy, to ensure that we copy * If the CPU had gone completely idle and a task has
* the previous load only once, upon the first wake-up * just woken up on this CPU now, it would be unfair to
* from idle. * calculate 'load' the usual way for this elapsed
* time-window, because it would show near-zero load,
* irrespective of how CPU intensive that task actually
* was. This is undesirable for latency-sensitive bursty
* workloads.
*
* To avoid this, reuse the 'load' from the previous
* time-window and give this task a chance to start with
* a reasonably high CPU frequency. However, that
* shouldn't be over-done, lest we get stuck at a high
* load (high frequency) for too long, even when the
* current system load has actually dropped down, so
* clear prev_load to guarantee that the load will be
* computed again next time.
*
* Detecting this situation is easy: the governor's
* utilization update handler would not have run during
* CPU-idle periods. Hence, an unusually large
* 'time_elapsed' (as compared to the sampling rate)
* indicates this scenario.
*/ */
load = j_cdbs->prev_load;
j_cdbs->prev_load = 0; j_cdbs->prev_load = 0;
} else { } else {
load = 100 * (wall_time - idle_time) / wall_time; if (time_elapsed >= idle_time) {
load = 100 * (time_elapsed - idle_time) / time_elapsed;
} else {
/*
* That can happen if idle_time is returned by
* get_cpu_idle_time_jiffy(). In that case
* idle_time is roughly equal to the difference
* between time_elapsed and "busy time" obtained
* from CPU statistics. Then, the "busy time"
* can end up being greater than time_elapsed
* (for example, if jiffies_64 and the CPU
* statistics are updated by different CPUs),
* so idle_time may in fact be negative. That
* means, though, that the CPU was busy all
* the time (on the rough average) during the
* last sampling interval and 100 can be
* returned as the load.
*/
load = (int)idle_time < 0 ? 100 : 0;
}
j_cdbs->prev_load = load; j_cdbs->prev_load = load;
} }
...@@ -254,43 +222,6 @@ unsigned int dbs_update(struct cpufreq_policy *policy) ...@@ -254,43 +222,6 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
} }
EXPORT_SYMBOL_GPL(dbs_update); EXPORT_SYMBOL_GPL(dbs_update);
static void gov_set_update_util(struct policy_dbs_info *policy_dbs,
unsigned int delay_us)
{
struct cpufreq_policy *policy = policy_dbs->policy;
int cpu;
gov_update_sample_delay(policy_dbs, delay_us);
policy_dbs->last_sample_time = 0;
for_each_cpu(cpu, policy->cpus) {
struct cpu_dbs_info *cdbs = &per_cpu(cpu_dbs, cpu);
cpufreq_set_update_util_data(cpu, &cdbs->update_util);
}
}
static inline void gov_clear_update_util(struct cpufreq_policy *policy)
{
int i;
for_each_cpu(i, policy->cpus)
cpufreq_set_update_util_data(i, NULL);
synchronize_sched();
}
static void gov_cancel_work(struct cpufreq_policy *policy)
{
struct policy_dbs_info *policy_dbs = policy->governor_data;
gov_clear_update_util(policy_dbs->policy);
irq_work_sync(&policy_dbs->irq_work);
cancel_work_sync(&policy_dbs->work);
atomic_set(&policy_dbs->work_count, 0);
policy_dbs->work_in_progress = false;
}
static void dbs_work_handler(struct work_struct *work) static void dbs_work_handler(struct work_struct *work)
{ {
struct policy_dbs_info *policy_dbs; struct policy_dbs_info *policy_dbs;
...@@ -378,6 +309,44 @@ static void dbs_update_util_handler(struct update_util_data *data, u64 time, ...@@ -378,6 +309,44 @@ static void dbs_update_util_handler(struct update_util_data *data, u64 time,
irq_work_queue(&policy_dbs->irq_work); irq_work_queue(&policy_dbs->irq_work);
} }
static void gov_set_update_util(struct policy_dbs_info *policy_dbs,
unsigned int delay_us)
{
struct cpufreq_policy *policy = policy_dbs->policy;
int cpu;
gov_update_sample_delay(policy_dbs, delay_us);
policy_dbs->last_sample_time = 0;
for_each_cpu(cpu, policy->cpus) {
struct cpu_dbs_info *cdbs = &per_cpu(cpu_dbs, cpu);
cpufreq_add_update_util_hook(cpu, &cdbs->update_util,
dbs_update_util_handler);
}
}
static inline void gov_clear_update_util(struct cpufreq_policy *policy)
{
int i;
for_each_cpu(i, policy->cpus)
cpufreq_remove_update_util_hook(i);
synchronize_sched();
}
static void gov_cancel_work(struct cpufreq_policy *policy)
{
struct policy_dbs_info *policy_dbs = policy->governor_data;
gov_clear_update_util(policy_dbs->policy);
irq_work_sync(&policy_dbs->irq_work);
cancel_work_sync(&policy_dbs->work);
atomic_set(&policy_dbs->work_count, 0);
policy_dbs->work_in_progress = false;
}
static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *policy, static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *policy,
struct dbs_governor *gov) struct dbs_governor *gov)
{ {
...@@ -400,7 +369,6 @@ static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *poli ...@@ -400,7 +369,6 @@ static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *poli
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j); struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
j_cdbs->policy_dbs = policy_dbs; j_cdbs->policy_dbs = policy_dbs;
j_cdbs->update_util.func = dbs_update_util_handler;
} }
return policy_dbs; return policy_dbs;
} }
...@@ -449,10 +417,7 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy) ...@@ -449,10 +417,7 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy)
policy_dbs->dbs_data = dbs_data; policy_dbs->dbs_data = dbs_data;
policy->governor_data = policy_dbs; policy->governor_data = policy_dbs;
mutex_lock(&dbs_data->mutex); gov_attr_set_get(&dbs_data->attr_set, &policy_dbs->list);
dbs_data->usage_count++;
list_add(&policy_dbs->list, &dbs_data->policy_dbs_list);
mutex_unlock(&dbs_data->mutex);
goto out; goto out;
} }
...@@ -462,8 +427,7 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy) ...@@ -462,8 +427,7 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy)
goto free_policy_dbs_info; goto free_policy_dbs_info;
} }
INIT_LIST_HEAD(&dbs_data->policy_dbs_list); gov_attr_set_init(&dbs_data->attr_set, &policy_dbs->list);
mutex_init(&dbs_data->mutex);
ret = gov->init(dbs_data, !policy->governor->initialized); ret = gov->init(dbs_data, !policy->governor->initialized);
if (ret) if (ret)
...@@ -483,14 +447,11 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy) ...@@ -483,14 +447,11 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy)
if (!have_governor_per_policy()) if (!have_governor_per_policy())
gov->gdbs_data = dbs_data; gov->gdbs_data = dbs_data;
policy->governor_data = policy_dbs;
policy_dbs->dbs_data = dbs_data; policy_dbs->dbs_data = dbs_data;
dbs_data->usage_count = 1; policy->governor_data = policy_dbs;
list_add(&policy_dbs->list, &dbs_data->policy_dbs_list);
gov->kobj_type.sysfs_ops = &governor_sysfs_ops; gov->kobj_type.sysfs_ops = &governor_sysfs_ops;
ret = kobject_init_and_add(&dbs_data->kobj, &gov->kobj_type, ret = kobject_init_and_add(&dbs_data->attr_set.kobj, &gov->kobj_type,
get_governor_parent_kobj(policy), get_governor_parent_kobj(policy),
"%s", gov->gov.name); "%s", gov->gov.name);
if (!ret) if (!ret)
...@@ -519,29 +480,21 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy) ...@@ -519,29 +480,21 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy)
struct dbs_governor *gov = dbs_governor_of(policy); struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs = policy->governor_data; struct policy_dbs_info *policy_dbs = policy->governor_data;
struct dbs_data *dbs_data = policy_dbs->dbs_data; struct dbs_data *dbs_data = policy_dbs->dbs_data;
int count; unsigned int count;
/* Protect gov->gdbs_data against concurrent updates. */ /* Protect gov->gdbs_data against concurrent updates. */
mutex_lock(&gov_dbs_data_mutex); mutex_lock(&gov_dbs_data_mutex);
mutex_lock(&dbs_data->mutex); count = gov_attr_set_put(&dbs_data->attr_set, &policy_dbs->list);
list_del(&policy_dbs->list);
count = --dbs_data->usage_count;
mutex_unlock(&dbs_data->mutex);
if (!count) { policy->governor_data = NULL;
kobject_put(&dbs_data->kobj);
policy->governor_data = NULL;
if (!count) {
if (!have_governor_per_policy()) if (!have_governor_per_policy())
gov->gdbs_data = NULL; gov->gdbs_data = NULL;
gov->exit(dbs_data, policy->governor->initialized == 1); gov->exit(dbs_data, policy->governor->initialized == 1);
mutex_destroy(&dbs_data->mutex);
kfree(dbs_data); kfree(dbs_data);
} else {
policy->governor_data = NULL;
} }
free_policy_dbs_info(policy_dbs, gov); free_policy_dbs_info(policy_dbs, gov);
...@@ -570,12 +523,12 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy) ...@@ -570,12 +523,12 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy)
for_each_cpu(j, policy->cpus) { for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j); struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
unsigned int prev_load;
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_update_time, io_busy);
/*
prev_load = j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle; * Make the first invocation of dbs_update() compute the load.
j_cdbs->prev_load = 100 * prev_load / (unsigned int)j_cdbs->prev_cpu_wall; */
j_cdbs->prev_load = 0;
if (ignore_nice) if (ignore_nice)
j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE];
......
...@@ -24,20 +24,6 @@ ...@@ -24,20 +24,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
/*
* The polling frequency depends on the capability of the processor. Default
* polling frequency is 1000 times the transition latency of the processor. The
* governor will work on any processor with transition latency <= 10ms, using
* appropriate sampling rate.
*
* For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL)
* this governor will not work. All times here are in us (micro seconds).
*/
#define MIN_SAMPLING_RATE_RATIO (2)
#define LATENCY_MULTIPLIER (1000)
#define MIN_LATENCY_MULTIPLIER (20)
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
/* Ondemand Sampling types */ /* Ondemand Sampling types */
enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE}; enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
...@@ -52,7 +38,7 @@ enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE}; ...@@ -52,7 +38,7 @@ enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
/* Governor demand based switching data (per-policy or global). */ /* Governor demand based switching data (per-policy or global). */
struct dbs_data { struct dbs_data {
int usage_count; struct gov_attr_set attr_set;
void *tuners; void *tuners;
unsigned int min_sampling_rate; unsigned int min_sampling_rate;
unsigned int ignore_nice_load; unsigned int ignore_nice_load;
...@@ -60,37 +46,27 @@ struct dbs_data { ...@@ -60,37 +46,27 @@ struct dbs_data {
unsigned int sampling_down_factor; unsigned int sampling_down_factor;
unsigned int up_threshold; unsigned int up_threshold;
unsigned int io_is_busy; unsigned int io_is_busy;
struct kobject kobj;
struct list_head policy_dbs_list;
/*
* Protect concurrent updates to governor tunables from sysfs,
* policy_dbs_list and usage_count.
*/
struct mutex mutex;
}; };
/* Governor's specific attributes */ static inline struct dbs_data *to_dbs_data(struct gov_attr_set *attr_set)
struct dbs_data; {
struct governor_attr { return container_of(attr_set, struct dbs_data, attr_set);
struct attribute attr; }
ssize_t (*show)(struct dbs_data *dbs_data, char *buf);
ssize_t (*store)(struct dbs_data *dbs_data, const char *buf,
size_t count);
};
#define gov_show_one(_gov, file_name) \ #define gov_show_one(_gov, file_name) \
static ssize_t show_##file_name \ static ssize_t show_##file_name \
(struct dbs_data *dbs_data, char *buf) \ (struct gov_attr_set *attr_set, char *buf) \
{ \ { \
struct dbs_data *dbs_data = to_dbs_data(attr_set); \
struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \ struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \ return sprintf(buf, "%u\n", tuners->file_name); \
} }
#define gov_show_one_common(file_name) \ #define gov_show_one_common(file_name) \
static ssize_t show_##file_name \ static ssize_t show_##file_name \
(struct dbs_data *dbs_data, char *buf) \ (struct gov_attr_set *attr_set, char *buf) \
{ \ { \
struct dbs_data *dbs_data = to_dbs_data(attr_set); \
return sprintf(buf, "%u\n", dbs_data->file_name); \ return sprintf(buf, "%u\n", dbs_data->file_name); \
} }
...@@ -135,7 +111,7 @@ static inline void gov_update_sample_delay(struct policy_dbs_info *policy_dbs, ...@@ -135,7 +111,7 @@ static inline void gov_update_sample_delay(struct policy_dbs_info *policy_dbs,
/* Per cpu structures */ /* Per cpu structures */
struct cpu_dbs_info { struct cpu_dbs_info {
u64 prev_cpu_idle; u64 prev_cpu_idle;
u64 prev_cpu_wall; u64 prev_update_time;
u64 prev_cpu_nice; u64 prev_cpu_nice;
/* /*
* Used to keep track of load in the previous interval. However, when * Used to keep track of load in the previous interval. However, when
...@@ -184,7 +160,7 @@ void od_register_powersave_bias_handler(unsigned int (*f) ...@@ -184,7 +160,7 @@ void od_register_powersave_bias_handler(unsigned int (*f)
(struct cpufreq_policy *, unsigned int, unsigned int), (struct cpufreq_policy *, unsigned int, unsigned int),
unsigned int powersave_bias); unsigned int powersave_bias);
void od_unregister_powersave_bias_handler(void); void od_unregister_powersave_bias_handler(void);
ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf,
size_t count); size_t count);
void gov_update_cpu_data(struct dbs_data *dbs_data); void gov_update_cpu_data(struct dbs_data *dbs_data);
#endif /* _CPUFREQ_GOVERNOR_H */ #endif /* _CPUFREQ_GOVERNOR_H */
/*
* Abstract code for CPUFreq governor tunable sysfs attributes.
*
* Copyright (C) 2016, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.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 "cpufreq_governor.h"
static inline struct gov_attr_set *to_gov_attr_set(struct kobject *kobj)
{
return container_of(kobj, struct gov_attr_set, kobj);
}
static inline struct governor_attr *to_gov_attr(struct attribute *attr)
{
return container_of(attr, struct governor_attr, attr);
}
static ssize_t governor_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct governor_attr *gattr = to_gov_attr(attr);
return gattr->show(to_gov_attr_set(kobj), buf);
}
static ssize_t governor_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct gov_attr_set *attr_set = to_gov_attr_set(kobj);
struct governor_attr *gattr = to_gov_attr(attr);
int ret;
mutex_lock(&attr_set->update_lock);
ret = attr_set->usage_count ? gattr->store(attr_set, buf, count) : -EBUSY;
mutex_unlock(&attr_set->update_lock);
return ret;
}
const struct sysfs_ops governor_sysfs_ops = {
.show = governor_show,
.store = governor_store,
};
EXPORT_SYMBOL_GPL(governor_sysfs_ops);
void gov_attr_set_init(struct gov_attr_set *attr_set, struct list_head *list_node)
{
INIT_LIST_HEAD(&attr_set->policy_list);
mutex_init(&attr_set->update_lock);
attr_set->usage_count = 1;
list_add(list_node, &attr_set->policy_list);
}
EXPORT_SYMBOL_GPL(gov_attr_set_init);
void gov_attr_set_get(struct gov_attr_set *attr_set, struct list_head *list_node)
{
mutex_lock(&attr_set->update_lock);
attr_set->usage_count++;
list_add(list_node, &attr_set->policy_list);
mutex_unlock(&attr_set->update_lock);
}
EXPORT_SYMBOL_GPL(gov_attr_set_get);
unsigned int gov_attr_set_put(struct gov_attr_set *attr_set, struct list_head *list_node)
{
unsigned int count;
mutex_lock(&attr_set->update_lock);
list_del(list_node);
count = --attr_set->usage_count;
mutex_unlock(&attr_set->update_lock);
if (count)
return count;
kobject_put(&attr_set->kobj);
mutex_destroy(&attr_set->update_lock);
return 0;
}
EXPORT_SYMBOL_GPL(gov_attr_set_put);
...@@ -207,9 +207,10 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy) ...@@ -207,9 +207,10 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy)
/************************** sysfs interface ************************/ /************************** sysfs interface ************************/
static struct dbs_governor od_dbs_gov; static struct dbs_governor od_dbs_gov;
static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf, static ssize_t store_io_is_busy(struct gov_attr_set *attr_set, const char *buf,
size_t count) size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
unsigned int input; unsigned int input;
int ret; int ret;
...@@ -224,9 +225,10 @@ static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf, ...@@ -224,9 +225,10 @@ static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf,
return count; return count;
} }
static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, static ssize_t store_up_threshold(struct gov_attr_set *attr_set,
size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
...@@ -240,9 +242,10 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, ...@@ -240,9 +242,10 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
return count; return count;
} }
static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
struct policy_dbs_info *policy_dbs; struct policy_dbs_info *policy_dbs;
unsigned int input; unsigned int input;
int ret; int ret;
...@@ -254,7 +257,7 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, ...@@ -254,7 +257,7 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
dbs_data->sampling_down_factor = input; dbs_data->sampling_down_factor = input;
/* Reset down sampling multiplier in case it was active */ /* Reset down sampling multiplier in case it was active */
list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) { list_for_each_entry(policy_dbs, &attr_set->policy_list, list) {
/* /*
* Doing this without locking might lead to using different * Doing this without locking might lead to using different
* rate_mult values in od_update() and od_dbs_timer(). * rate_mult values in od_update() and od_dbs_timer().
...@@ -267,9 +270,10 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, ...@@ -267,9 +270,10 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
return count; return count;
} }
static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, static ssize_t store_ignore_nice_load(struct gov_attr_set *attr_set,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
unsigned int input; unsigned int input;
int ret; int ret;
...@@ -291,9 +295,10 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, ...@@ -291,9 +295,10 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
return count; return count;
} }
static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf, static ssize_t store_powersave_bias(struct gov_attr_set *attr_set,
size_t count) const char *buf, size_t count)
{ {
struct dbs_data *dbs_data = to_dbs_data(attr_set);
struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct od_dbs_tuners *od_tuners = dbs_data->tuners;
struct policy_dbs_info *policy_dbs; struct policy_dbs_info *policy_dbs;
unsigned int input; unsigned int input;
...@@ -308,7 +313,7 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf, ...@@ -308,7 +313,7 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
od_tuners->powersave_bias = input; od_tuners->powersave_bias = input;
list_for_each_entry(policy_dbs, &dbs_data->policy_dbs_list, list) list_for_each_entry(policy_dbs, &attr_set->policy_list, list)
ondemand_powersave_bias_init(policy_dbs->policy); ondemand_powersave_bias_init(policy_dbs->policy);
return count; return count;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h>
static DEFINE_PER_CPU(unsigned int, cpu_is_managed); static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
static DEFINE_MUTEX(userspace_mutex); static DEFINE_MUTEX(userspace_mutex);
...@@ -31,6 +32,7 @@ static DEFINE_MUTEX(userspace_mutex); ...@@ -31,6 +32,7 @@ static DEFINE_MUTEX(userspace_mutex);
static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
{ {
int ret = -EINVAL; int ret = -EINVAL;
unsigned int *setspeed = policy->governor_data;
pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
...@@ -38,6 +40,8 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) ...@@ -38,6 +40,8 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
if (!per_cpu(cpu_is_managed, policy->cpu)) if (!per_cpu(cpu_is_managed, policy->cpu))
goto err; goto err;
*setspeed = freq;
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
err: err:
mutex_unlock(&userspace_mutex); mutex_unlock(&userspace_mutex);
...@@ -49,19 +53,45 @@ static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) ...@@ -49,19 +53,45 @@ static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
return sprintf(buf, "%u\n", policy->cur); return sprintf(buf, "%u\n", policy->cur);
} }
static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy)
{
unsigned int *setspeed;
setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL);
if (!setspeed)
return -ENOMEM;
policy->governor_data = setspeed;
return 0;
}
static int cpufreq_governor_userspace(struct cpufreq_policy *policy, static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
unsigned int event) unsigned int event)
{ {
unsigned int *setspeed = policy->governor_data;
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
int rc = 0; int rc = 0;
if (event == CPUFREQ_GOV_POLICY_INIT)
return cpufreq_userspace_policy_init(policy);
if (!setspeed)
return -EINVAL;
switch (event) { switch (event) {
case CPUFREQ_GOV_POLICY_EXIT:
mutex_lock(&userspace_mutex);
policy->governor_data = NULL;
kfree(setspeed);
mutex_unlock(&userspace_mutex);
break;
case CPUFREQ_GOV_START: case CPUFREQ_GOV_START:
BUG_ON(!policy->cur); BUG_ON(!policy->cur);
pr_debug("started managing cpu %u\n", cpu); pr_debug("started managing cpu %u\n", cpu);
mutex_lock(&userspace_mutex); mutex_lock(&userspace_mutex);
per_cpu(cpu_is_managed, cpu) = 1; per_cpu(cpu_is_managed, cpu) = 1;
*setspeed = policy->cur;
mutex_unlock(&userspace_mutex); mutex_unlock(&userspace_mutex);
break; break;
case CPUFREQ_GOV_STOP: case CPUFREQ_GOV_STOP:
...@@ -69,20 +99,23 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, ...@@ -69,20 +99,23 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
mutex_lock(&userspace_mutex); mutex_lock(&userspace_mutex);
per_cpu(cpu_is_managed, cpu) = 0; per_cpu(cpu_is_managed, cpu) = 0;
*setspeed = 0;
mutex_unlock(&userspace_mutex); mutex_unlock(&userspace_mutex);
break; break;
case CPUFREQ_GOV_LIMITS: case CPUFREQ_GOV_LIMITS:
mutex_lock(&userspace_mutex); mutex_lock(&userspace_mutex);
pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n", pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
cpu, policy->min, policy->max, cpu, policy->min, policy->max, policy->cur, *setspeed);
policy->cur);
if (policy->max < policy->cur) if (policy->max < *setspeed)
__cpufreq_driver_target(policy, policy->max, __cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H); CPUFREQ_RELATION_H);
else if (policy->min > policy->cur) else if (policy->min > *setspeed)
__cpufreq_driver_target(policy, policy->min, __cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L); CPUFREQ_RELATION_L);
else
__cpufreq_driver_target(policy, *setspeed,
CPUFREQ_RELATION_L);
mutex_unlock(&userspace_mutex); mutex_unlock(&userspace_mutex);
break; break;
} }
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -20,7 +22,7 @@ ...@@ -20,7 +22,7 @@
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/tsc.h> #include <asm/tsc.h>
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
#include <linux/acpi.h> #include <linux/acpi.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#endif #endif
...@@ -33,7 +35,7 @@ ...@@ -33,7 +35,7 @@
struct eps_cpu_data { struct eps_cpu_data {
u32 fsb; u32 fsb;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
u32 bios_limit; u32 bios_limit;
#endif #endif
struct cpufreq_frequency_table freq_table[]; struct cpufreq_frequency_table freq_table[];
...@@ -46,7 +48,7 @@ static int freq_failsafe_off; ...@@ -46,7 +48,7 @@ static int freq_failsafe_off;
static int voltage_failsafe_off; static int voltage_failsafe_off;
static int set_max_voltage; static int set_max_voltage;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
static int ignore_acpi_limit; static int ignore_acpi_limit;
static struct acpi_processor_performance *eps_acpi_cpu_perf; static struct acpi_processor_performance *eps_acpi_cpu_perf;
...@@ -141,11 +143,9 @@ static int eps_set_state(struct eps_cpu_data *centaur, ...@@ -141,11 +143,9 @@ static int eps_set_state(struct eps_cpu_data *centaur,
/* Print voltage and multiplier */ /* Print voltage and multiplier */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi); rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
current_voltage = lo & 0xff; current_voltage = lo & 0xff;
printk(KERN_INFO "eps: Current voltage = %dmV\n", pr_info("Current voltage = %dmV\n", current_voltage * 16 + 700);
current_voltage * 16 + 700);
current_multiplier = (lo >> 8) & 0xff; current_multiplier = (lo >> 8) & 0xff;
printk(KERN_INFO "eps: Current multiplier = %d\n", pr_info("Current multiplier = %d\n", current_multiplier);
current_multiplier);
} }
#endif #endif
return 0; return 0;
...@@ -166,7 +166,7 @@ static int eps_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -166,7 +166,7 @@ static int eps_target(struct cpufreq_policy *policy, unsigned int index)
dest_state = centaur->freq_table[index].driver_data & 0xffff; dest_state = centaur->freq_table[index].driver_data & 0xffff;
ret = eps_set_state(centaur, policy, dest_state); ret = eps_set_state(centaur, policy, dest_state);
if (ret) if (ret)
printk(KERN_ERR "eps: Timeout!\n"); pr_err("Timeout!\n");
return ret; return ret;
} }
...@@ -186,7 +186,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -186,7 +186,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
int k, step, voltage; int k, step, voltage;
int ret; int ret;
int states; int states;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
unsigned int limit; unsigned int limit;
#endif #endif
...@@ -194,36 +194,36 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -194,36 +194,36 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
return -ENODEV; return -ENODEV;
/* Check brand */ /* Check brand */
printk(KERN_INFO "eps: Detected VIA "); pr_info("Detected VIA ");
switch (c->x86_model) { switch (c->x86_model) {
case 10: case 10:
rdmsr(0x1153, lo, hi); rdmsr(0x1153, lo, hi);
brand = (((lo >> 2) ^ lo) >> 18) & 3; brand = (((lo >> 2) ^ lo) >> 18) & 3;
printk(KERN_CONT "Model A "); pr_cont("Model A ");
break; break;
case 13: case 13:
rdmsr(0x1154, lo, hi); rdmsr(0x1154, lo, hi);
brand = (((lo >> 4) ^ (lo >> 2))) & 0x000000ff; brand = (((lo >> 4) ^ (lo >> 2))) & 0x000000ff;
printk(KERN_CONT "Model D "); pr_cont("Model D ");
break; break;
} }
switch (brand) { switch (brand) {
case EPS_BRAND_C7M: case EPS_BRAND_C7M:
printk(KERN_CONT "C7-M\n"); pr_cont("C7-M\n");
break; break;
case EPS_BRAND_C7: case EPS_BRAND_C7:
printk(KERN_CONT "C7\n"); pr_cont("C7\n");
break; break;
case EPS_BRAND_EDEN: case EPS_BRAND_EDEN:
printk(KERN_CONT "Eden\n"); pr_cont("Eden\n");
break; break;
case EPS_BRAND_C7D: case EPS_BRAND_C7D:
printk(KERN_CONT "C7-D\n"); pr_cont("C7-D\n");
break; break;
case EPS_BRAND_C3: case EPS_BRAND_C3:
printk(KERN_CONT "C3\n"); pr_cont("C3\n");
return -ENODEV; return -ENODEV;
break; break;
} }
...@@ -235,7 +235,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -235,7 +235,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
/* Can be locked at 0 */ /* Can be locked at 0 */
rdmsrl(MSR_IA32_MISC_ENABLE, val); rdmsrl(MSR_IA32_MISC_ENABLE, val);
if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) {
printk(KERN_INFO "eps: Can't enable Enhanced PowerSaver\n"); pr_info("Can't enable Enhanced PowerSaver\n");
return -ENODEV; return -ENODEV;
} }
} }
...@@ -243,22 +243,19 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -243,22 +243,19 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
/* Print voltage and multiplier */ /* Print voltage and multiplier */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi); rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
current_voltage = lo & 0xff; current_voltage = lo & 0xff;
printk(KERN_INFO "eps: Current voltage = %dmV\n", pr_info("Current voltage = %dmV\n", current_voltage * 16 + 700);
current_voltage * 16 + 700);
current_multiplier = (lo >> 8) & 0xff; current_multiplier = (lo >> 8) & 0xff;
printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier); pr_info("Current multiplier = %d\n", current_multiplier);
/* Print limits */ /* Print limits */
max_voltage = hi & 0xff; max_voltage = hi & 0xff;
printk(KERN_INFO "eps: Highest voltage = %dmV\n", pr_info("Highest voltage = %dmV\n", max_voltage * 16 + 700);
max_voltage * 16 + 700);
max_multiplier = (hi >> 8) & 0xff; max_multiplier = (hi >> 8) & 0xff;
printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier); pr_info("Highest multiplier = %d\n", max_multiplier);
min_voltage = (hi >> 16) & 0xff; min_voltage = (hi >> 16) & 0xff;
printk(KERN_INFO "eps: Lowest voltage = %dmV\n", pr_info("Lowest voltage = %dmV\n", min_voltage * 16 + 700);
min_voltage * 16 + 700);
min_multiplier = (hi >> 24) & 0xff; min_multiplier = (hi >> 24) & 0xff;
printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier); pr_info("Lowest multiplier = %d\n", min_multiplier);
/* Sanity checks */ /* Sanity checks */
if (current_multiplier == 0 || max_multiplier == 0 if (current_multiplier == 0 || max_multiplier == 0
...@@ -276,34 +273,30 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -276,34 +273,30 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
/* Check for systems using underclocked CPU */ /* Check for systems using underclocked CPU */
if (!freq_failsafe_off && max_multiplier != current_multiplier) { if (!freq_failsafe_off && max_multiplier != current_multiplier) {
printk(KERN_INFO "eps: Your processor is running at different " pr_info("Your processor is running at different frequency then its maximum. Aborting.\n");
"frequency then its maximum. Aborting.\n"); pr_info("You can use freq_failsafe_off option to disable this check.\n");
printk(KERN_INFO "eps: You can use freq_failsafe_off option "
"to disable this check.\n");
return -EINVAL; return -EINVAL;
} }
if (!voltage_failsafe_off && max_voltage != current_voltage) { if (!voltage_failsafe_off && max_voltage != current_voltage) {
printk(KERN_INFO "eps: Your processor is running at different " pr_info("Your processor is running at different voltage then its maximum. Aborting.\n");
"voltage then its maximum. Aborting.\n"); pr_info("You can use voltage_failsafe_off option to disable this check.\n");
printk(KERN_INFO "eps: You can use voltage_failsafe_off "
"option to disable this check.\n");
return -EINVAL; return -EINVAL;
} }
/* Calc FSB speed */ /* Calc FSB speed */
fsb = cpu_khz / current_multiplier; fsb = cpu_khz / current_multiplier;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
/* Check for ACPI processor speed limit */ /* Check for ACPI processor speed limit */
if (!ignore_acpi_limit && !eps_acpi_init()) { if (!ignore_acpi_limit && !eps_acpi_init()) {
if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) { if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) {
printk(KERN_INFO "eps: ACPI limit %u.%uGHz\n", pr_info("ACPI limit %u.%uGHz\n",
limit/1000000, limit/1000000,
(limit%1000000)/10000); (limit%1000000)/10000);
eps_acpi_exit(policy); eps_acpi_exit(policy);
/* Check if max_multiplier is in BIOS limits */ /* Check if max_multiplier is in BIOS limits */
if (limit && max_multiplier * fsb > limit) { if (limit && max_multiplier * fsb > limit) {
printk(KERN_INFO "eps: Aborting.\n"); pr_info("Aborting\n");
return -EINVAL; return -EINVAL;
} }
} }
...@@ -319,8 +312,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -319,8 +312,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
v = (set_max_voltage - 700) / 16; v = (set_max_voltage - 700) / 16;
/* Check if voltage is within limits */ /* Check if voltage is within limits */
if (v >= min_voltage && v <= max_voltage) { if (v >= min_voltage && v <= max_voltage) {
printk(KERN_INFO "eps: Setting %dmV as maximum.\n", pr_info("Setting %dmV as maximum\n", v * 16 + 700);
v * 16 + 700);
max_voltage = v; max_voltage = v;
} }
} }
...@@ -341,7 +333,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -341,7 +333,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
/* Copy basic values */ /* Copy basic values */
centaur->fsb = fsb; centaur->fsb = fsb;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
centaur->bios_limit = limit; centaur->bios_limit = limit;
#endif #endif
...@@ -426,7 +418,7 @@ module_param(freq_failsafe_off, int, 0644); ...@@ -426,7 +418,7 @@ module_param(freq_failsafe_off, int, 0644);
MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check"); MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check");
module_param(voltage_failsafe_off, int, 0644); module_param(voltage_failsafe_off, int, 0644);
MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check"); MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check");
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE #if IS_ENABLED(CONFIG_ACPI_PROCESSOR)
module_param(ignore_acpi_limit, int, 0644); module_param(ignore_acpi_limit, int, 0644);
MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit"); MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit");
#endif #endif
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -185,7 +187,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) ...@@ -185,7 +187,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
static int __init elanfreq_setup(char *str) static int __init elanfreq_setup(char *str)
{ {
max_freq = simple_strtoul(str, &str, 0); max_freq = simple_strtoul(str, &str, 0);
printk(KERN_WARNING "You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n"); pr_warn("You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n");
return 1; return 1;
} }
__setup("elanfreq=", elanfreq_setup); __setup("elanfreq=", elanfreq_setup);
......
/*
* Hisilicon Platforms Using ACPU CPUFreq Support
*
* Copyright (c) 2015 Hisilicon Limited.
* Copyright (c) 2015 Linaro Limited.
*
* Leo Yan <leo.yan@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/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
static int __init hisi_acpu_cpufreq_driver_init(void)
{
struct platform_device *pdev;
if (!of_machine_is_compatible("hisilicon,hi6220"))
return -ENODEV;
pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
return PTR_ERR_OR_ZERO(pdev);
}
module_init(hisi_acpu_cpufreq_driver_init);
MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
MODULE_DESCRIPTION("Hisilicon acpu cpufreq driver");
MODULE_LICENSE("GPL v2");
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -118,8 +120,7 @@ processor_get_freq ( ...@@ -118,8 +120,7 @@ processor_get_freq (
if (ret) { if (ret) {
set_cpus_allowed_ptr(current, &saved_mask); set_cpus_allowed_ptr(current, &saved_mask);
printk(KERN_WARNING "get performance failed with error %d\n", pr_warn("get performance failed with error %d\n", ret);
ret);
ret = 0; ret = 0;
goto migrate_end; goto migrate_end;
} }
...@@ -177,7 +178,7 @@ processor_set_freq ( ...@@ -177,7 +178,7 @@ processor_set_freq (
ret = processor_set_pstate(value); ret = processor_set_pstate(value);
if (ret) { if (ret) {
printk(KERN_WARNING "Transition failed with error %d\n", ret); pr_warn("Transition failed with error %d\n", ret);
retval = -ENODEV; retval = -ENODEV;
goto migrate_end; goto migrate_end;
} }
...@@ -291,8 +292,7 @@ acpi_cpufreq_cpu_init ( ...@@ -291,8 +292,7 @@ acpi_cpufreq_cpu_init (
/* notify BIOS that we exist */ /* notify BIOS that we exist */
acpi_processor_notify_smm(THIS_MODULE); acpi_processor_notify_smm(THIS_MODULE);
printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management " pr_info("CPU%u - ACPI performance management activated\n", cpu);
"activated.\n", cpu);
for (i = 0; i < data->acpi_data.state_count; i++) for (i = 0; i < data->acpi_data.state_count; i++)
pr_debug(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", pr_debug(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* of the License. * of the License.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -39,10 +41,17 @@ ...@@ -39,10 +41,17 @@
#define ATOM_TURBO_RATIOS 0x66c #define ATOM_TURBO_RATIOS 0x66c
#define ATOM_TURBO_VIDS 0x66d #define ATOM_TURBO_VIDS 0x66d
#ifdef CONFIG_ACPI
#include <acpi/processor.h>
#endif
#define FRAC_BITS 8 #define FRAC_BITS 8
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
#define fp_toint(X) ((X) >> FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS)
#define EXT_BITS 6
#define EXT_FRAC_BITS (EXT_BITS + FRAC_BITS)
static inline int32_t mul_fp(int32_t x, int32_t y) static inline int32_t mul_fp(int32_t x, int32_t y)
{ {
return ((int64_t)x * (int64_t)y) >> FRAC_BITS; return ((int64_t)x * (int64_t)y) >> FRAC_BITS;
...@@ -64,12 +73,22 @@ static inline int ceiling_fp(int32_t x) ...@@ -64,12 +73,22 @@ static inline int ceiling_fp(int32_t x)
return ret; return ret;
} }
static inline u64 mul_ext_fp(u64 x, u64 y)
{
return (x * y) >> EXT_FRAC_BITS;
}
static inline u64 div_ext_fp(u64 x, u64 y)
{
return div64_u64(x << EXT_FRAC_BITS, y);
}
/** /**
* struct sample - Store performance sample * struct sample - Store performance sample
* @core_pct_busy: Ratio of APERF/MPERF in percent, which is actual * @core_avg_perf: Ratio of APERF/MPERF which is the actual average
* performance during last sample period * performance during last sample period
* @busy_scaled: Scaled busy value which is used to calculate next * @busy_scaled: Scaled busy value which is used to calculate next
* P state. This can be different than core_pct_busy * P state. This can be different than core_avg_perf
* to account for cpu idle period * to account for cpu idle period
* @aperf: Difference of actual performance frequency clock count * @aperf: Difference of actual performance frequency clock count
* read from APERF MSR between last and current sample * read from APERF MSR between last and current sample
...@@ -84,7 +103,7 @@ static inline int ceiling_fp(int32_t x) ...@@ -84,7 +103,7 @@ static inline int ceiling_fp(int32_t x)
* data for choosing next P State. * data for choosing next P State.
*/ */
struct sample { struct sample {
int32_t core_pct_busy; int32_t core_avg_perf;
int32_t busy_scaled; int32_t busy_scaled;
u64 aperf; u64 aperf;
u64 mperf; u64 mperf;
...@@ -162,6 +181,7 @@ struct _pid { ...@@ -162,6 +181,7 @@ struct _pid {
* struct cpudata - Per CPU instance data storage * struct cpudata - Per CPU instance data storage
* @cpu: CPU number for this instance data * @cpu: CPU number for this instance data
* @update_util: CPUFreq utility callback information * @update_util: CPUFreq utility callback information
* @update_util_set: CPUFreq utility callback is set
* @pstate: Stores P state limits for this CPU * @pstate: Stores P state limits for this CPU
* @vid: Stores VID limits for this CPU * @vid: Stores VID limits for this CPU
* @pid: Stores PID parameters for this CPU * @pid: Stores PID parameters for this CPU
...@@ -172,6 +192,8 @@ struct _pid { ...@@ -172,6 +192,8 @@ struct _pid {
* @prev_cummulative_iowait: IO Wait time difference from last and * @prev_cummulative_iowait: IO Wait time difference from last and
* current sample * current sample
* @sample: Storage for storing last Sample data * @sample: Storage for storing last Sample data
* @acpi_perf_data: Stores ACPI perf information read from _PSS
* @valid_pss_table: Set to true for valid ACPI _PSS entries found
* *
* This structure stores per CPU instance data for all CPUs. * This structure stores per CPU instance data for all CPUs.
*/ */
...@@ -179,6 +201,7 @@ struct cpudata { ...@@ -179,6 +201,7 @@ struct cpudata {
int cpu; int cpu;
struct update_util_data update_util; struct update_util_data update_util;
bool update_util_set;
struct pstate_data pstate; struct pstate_data pstate;
struct vid_data vid; struct vid_data vid;
...@@ -190,6 +213,10 @@ struct cpudata { ...@@ -190,6 +213,10 @@ struct cpudata {
u64 prev_tsc; u64 prev_tsc;
u64 prev_cummulative_iowait; u64 prev_cummulative_iowait;
struct sample sample; struct sample sample;
#ifdef CONFIG_ACPI
struct acpi_processor_performance acpi_perf_data;
bool valid_pss_table;
#endif
}; };
static struct cpudata **all_cpu_data; static struct cpudata **all_cpu_data;
...@@ -258,6 +285,9 @@ static struct pstate_adjust_policy pid_params; ...@@ -258,6 +285,9 @@ static struct pstate_adjust_policy pid_params;
static struct pstate_funcs pstate_funcs; static struct pstate_funcs pstate_funcs;
static int hwp_active; static int hwp_active;
#ifdef CONFIG_ACPI
static bool acpi_ppc;
#endif
/** /**
* struct perf_limits - Store user and policy limits * struct perf_limits - Store user and policy limits
...@@ -331,6 +361,124 @@ static struct perf_limits *limits = &performance_limits; ...@@ -331,6 +361,124 @@ static struct perf_limits *limits = &performance_limits;
static struct perf_limits *limits = &powersave_limits; static struct perf_limits *limits = &powersave_limits;
#endif #endif
#ifdef CONFIG_ACPI
static bool intel_pstate_get_ppc_enable_status(void)
{
if (acpi_gbl_FADT.preferred_profile == PM_ENTERPRISE_SERVER ||
acpi_gbl_FADT.preferred_profile == PM_PERFORMANCE_SERVER)
return true;
return acpi_ppc;
}
/*
* The max target pstate ratio is a 8 bit value in both PLATFORM_INFO MSR and
* in TURBO_RATIO_LIMIT MSR, which pstate driver stores in max_pstate and
* max_turbo_pstate fields. The PERF_CTL MSR contains 16 bit value for P state
* ratio, out of it only high 8 bits are used. For example 0x1700 is setting
* target ratio 0x17. The _PSS control value stores in a format which can be
* directly written to PERF_CTL MSR. But in intel_pstate driver this shift
* occurs during write to PERF_CTL (E.g. for cores core_set_pstate()).
* This function converts the _PSS control value to intel pstate driver format
* for comparison and assignment.
*/
static int convert_to_native_pstate_format(struct cpudata *cpu, int index)
{
return cpu->acpi_perf_data.states[index].control >> 8;
}
static void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
{
struct cpudata *cpu;
int turbo_pss_ctl;
int ret;
int i;
if (hwp_active)
return;
if (!intel_pstate_get_ppc_enable_status())
return;
cpu = all_cpu_data[policy->cpu];
ret = acpi_processor_register_performance(&cpu->acpi_perf_data,
policy->cpu);
if (ret)
return;
/*
* Check if the control value in _PSS is for PERF_CTL MSR, which should
* guarantee that the states returned by it map to the states in our
* list directly.
*/
if (cpu->acpi_perf_data.control_register.space_id !=
ACPI_ADR_SPACE_FIXED_HARDWARE)
goto err;
/*
* If there is only one entry _PSS, simply ignore _PSS and continue as
* usual without taking _PSS into account
*/
if (cpu->acpi_perf_data.state_count < 2)
goto err;
pr_debug("CPU%u - ACPI _PSS perf data\n", policy->cpu);
for (i = 0; i < cpu->acpi_perf_data.state_count; i++) {
pr_debug(" %cP%d: %u MHz, %u mW, 0x%x\n",
(i == cpu->acpi_perf_data.state ? '*' : ' '), i,
(u32) cpu->acpi_perf_data.states[i].core_frequency,
(u32) cpu->acpi_perf_data.states[i].power,
(u32) cpu->acpi_perf_data.states[i].control);
}
/*
* The _PSS table doesn't contain whole turbo frequency range.
* This just contains +1 MHZ above the max non turbo frequency,
* with control value corresponding to max turbo ratio. But
* when cpufreq set policy is called, it will call with this
* max frequency, which will cause a reduced performance as
* this driver uses real max turbo frequency as the max
* frequency. So correct this frequency in _PSS table to
* correct max turbo frequency based on the turbo ratio.
* Also need to convert to MHz as _PSS freq is in MHz.
*/
turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
if (turbo_pss_ctl > cpu->pstate.max_pstate)
cpu->acpi_perf_data.states[0].core_frequency =
policy->cpuinfo.max_freq / 1000;
cpu->valid_pss_table = true;
pr_info("_PPC limits will be enforced\n");
return;
err:
cpu->valid_pss_table = false;
acpi_processor_unregister_performance(policy->cpu);
}
static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
{
struct cpudata *cpu;
cpu = all_cpu_data[policy->cpu];
if (!cpu->valid_pss_table)
return;
acpi_processor_unregister_performance(policy->cpu);
}
#else
static void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
{
}
static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
{
}
#endif
static inline void pid_reset(struct _pid *pid, int setpoint, int busy, static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
int deadband, int integral) { int deadband, int integral) {
pid->setpoint = int_tofp(setpoint); pid->setpoint = int_tofp(setpoint);
...@@ -341,17 +489,17 @@ static inline void pid_reset(struct _pid *pid, int setpoint, int busy, ...@@ -341,17 +489,17 @@ static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
static inline void pid_p_gain_set(struct _pid *pid, int percent) static inline void pid_p_gain_set(struct _pid *pid, int percent)
{ {
pid->p_gain = div_fp(int_tofp(percent), int_tofp(100)); pid->p_gain = div_fp(percent, 100);
} }
static inline void pid_i_gain_set(struct _pid *pid, int percent) static inline void pid_i_gain_set(struct _pid *pid, int percent)
{ {
pid->i_gain = div_fp(int_tofp(percent), int_tofp(100)); pid->i_gain = div_fp(percent, 100);
} }
static inline void pid_d_gain_set(struct _pid *pid, int percent) static inline void pid_d_gain_set(struct _pid *pid, int percent)
{ {
pid->d_gain = div_fp(int_tofp(percent), int_tofp(100)); pid->d_gain = div_fp(percent, 100);
} }
static signed int pid_calc(struct _pid *pid, int32_t busy) static signed int pid_calc(struct _pid *pid, int32_t busy)
...@@ -537,7 +685,7 @@ static ssize_t show_turbo_pct(struct kobject *kobj, ...@@ -537,7 +685,7 @@ static ssize_t show_turbo_pct(struct kobject *kobj,
total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1; no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1;
turbo_fp = div_fp(int_tofp(no_turbo), int_tofp(total)); turbo_fp = div_fp(no_turbo, total);
turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100))); turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100)));
return sprintf(buf, "%u\n", turbo_pct); return sprintf(buf, "%u\n", turbo_pct);
} }
...@@ -579,7 +727,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, ...@@ -579,7 +727,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
update_turbo_state(); update_turbo_state();
if (limits->turbo_disabled) { if (limits->turbo_disabled) {
pr_warn("intel_pstate: Turbo disabled by BIOS or unavailable on processor\n"); pr_warn("Turbo disabled by BIOS or unavailable on processor\n");
return -EPERM; return -EPERM;
} }
...@@ -608,8 +756,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, ...@@ -608,8 +756,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
limits->max_perf_pct); limits->max_perf_pct);
limits->max_perf_pct = max(limits->min_perf_pct, limits->max_perf_pct = max(limits->min_perf_pct,
limits->max_perf_pct); limits->max_perf_pct);
limits->max_perf = div_fp(int_tofp(limits->max_perf_pct), limits->max_perf = div_fp(limits->max_perf_pct, 100);
int_tofp(100));
if (hwp_active) if (hwp_active)
intel_pstate_hwp_set_online_cpus(); intel_pstate_hwp_set_online_cpus();
...@@ -633,8 +780,7 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, ...@@ -633,8 +780,7 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
limits->min_perf_pct); limits->min_perf_pct);
limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct = min(limits->max_perf_pct,
limits->min_perf_pct); limits->min_perf_pct);
limits->min_perf = div_fp(int_tofp(limits->min_perf_pct), limits->min_perf = div_fp(limits->min_perf_pct, 100);
int_tofp(100));
if (hwp_active) if (hwp_active)
intel_pstate_hwp_set_online_cpus(); intel_pstate_hwp_set_online_cpus();
...@@ -1019,15 +1165,11 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) ...@@ -1019,15 +1165,11 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
intel_pstate_set_min_pstate(cpu); intel_pstate_set_min_pstate(cpu);
} }
static inline void intel_pstate_calc_busy(struct cpudata *cpu) static inline void intel_pstate_calc_avg_perf(struct cpudata *cpu)
{ {
struct sample *sample = &cpu->sample; struct sample *sample = &cpu->sample;
int64_t core_pct;
core_pct = int_tofp(sample->aperf) * int_tofp(100); sample->core_avg_perf = div_ext_fp(sample->aperf, sample->mperf);
core_pct = div64_u64(core_pct, int_tofp(sample->mperf));
sample->core_pct_busy = (int32_t)core_pct;
} }
static inline bool intel_pstate_sample(struct cpudata *cpu, u64 time) static inline bool intel_pstate_sample(struct cpudata *cpu, u64 time)
...@@ -1070,9 +1212,14 @@ static inline bool intel_pstate_sample(struct cpudata *cpu, u64 time) ...@@ -1070,9 +1212,14 @@ static inline bool intel_pstate_sample(struct cpudata *cpu, u64 time)
static inline int32_t get_avg_frequency(struct cpudata *cpu) static inline int32_t get_avg_frequency(struct cpudata *cpu)
{ {
return fp_toint(mul_fp(cpu->sample.core_pct_busy, return mul_ext_fp(cpu->sample.core_avg_perf,
int_tofp(cpu->pstate.max_pstate_physical * cpu->pstate.max_pstate_physical * cpu->pstate.scaling);
cpu->pstate.scaling / 100))); }
static inline int32_t get_avg_pstate(struct cpudata *cpu)
{
return mul_ext_fp(cpu->pstate.max_pstate_physical,
cpu->sample.core_avg_perf);
} }
static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
...@@ -1107,49 +1254,43 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) ...@@ -1107,49 +1254,43 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
cpu_load = div64_u64(int_tofp(100) * mperf, sample->tsc); cpu_load = div64_u64(int_tofp(100) * mperf, sample->tsc);
cpu->sample.busy_scaled = cpu_load; cpu->sample.busy_scaled = cpu_load;
return cpu->pstate.current_pstate - pid_calc(&cpu->pid, cpu_load); return get_avg_pstate(cpu) - pid_calc(&cpu->pid, cpu_load);
} }
static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
{ {
int32_t core_busy, max_pstate, current_pstate, sample_ratio; int32_t perf_scaled, max_pstate, current_pstate, sample_ratio;
u64 duration_ns; u64 duration_ns;
/* /*
* core_busy is the ratio of actual performance to max * perf_scaled is the average performance during the last sampling
* max_pstate is the max non turbo pstate available * period scaled by the ratio of the maximum P-state to the P-state
* current_pstate was the pstate that was requested during * requested last time (in percent). That measures the system's
* the last sample period. * response to the previous P-state selection.
*
* We normalize core_busy, which was our actual percent
* performance to what we requested during the last sample
* period. The result will be a percentage of busy at a
* specified pstate.
*/ */
core_busy = cpu->sample.core_pct_busy; max_pstate = cpu->pstate.max_pstate_physical;
max_pstate = int_tofp(cpu->pstate.max_pstate_physical); current_pstate = cpu->pstate.current_pstate;
current_pstate = int_tofp(cpu->pstate.current_pstate); perf_scaled = mul_ext_fp(cpu->sample.core_avg_perf,
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); div_fp(100 * max_pstate, current_pstate));
/* /*
* Since our utilization update callback will not run unless we are * Since our utilization update callback will not run unless we are
* in C0, check if the actual elapsed time is significantly greater (3x) * in C0, check if the actual elapsed time is significantly greater (3x)
* than our sample interval. If it is, then we were idle for a long * than our sample interval. If it is, then we were idle for a long
* enough period of time to adjust our busyness. * enough period of time to adjust our performance metric.
*/ */
duration_ns = cpu->sample.time - cpu->last_sample_time; duration_ns = cpu->sample.time - cpu->last_sample_time;
if ((s64)duration_ns > pid_params.sample_rate_ns * 3) { if ((s64)duration_ns > pid_params.sample_rate_ns * 3) {
sample_ratio = div_fp(int_tofp(pid_params.sample_rate_ns), sample_ratio = div_fp(pid_params.sample_rate_ns, duration_ns);
int_tofp(duration_ns)); perf_scaled = mul_fp(perf_scaled, sample_ratio);
core_busy = mul_fp(core_busy, sample_ratio);
} else { } else {
sample_ratio = div_fp(100 * cpu->sample.mperf, cpu->sample.tsc); sample_ratio = div_fp(100 * cpu->sample.mperf, cpu->sample.tsc);
if (sample_ratio < int_tofp(1)) if (sample_ratio < int_tofp(1))
core_busy = 0; perf_scaled = 0;
} }
cpu->sample.busy_scaled = core_busy; cpu->sample.busy_scaled = perf_scaled;
return cpu->pstate.current_pstate - pid_calc(&cpu->pid, core_busy); return cpu->pstate.current_pstate - pid_calc(&cpu->pid, perf_scaled);
} }
static inline void intel_pstate_update_pstate(struct cpudata *cpu, int pstate) static inline void intel_pstate_update_pstate(struct cpudata *cpu, int pstate)
...@@ -1179,7 +1320,7 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) ...@@ -1179,7 +1320,7 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
intel_pstate_update_pstate(cpu, target_pstate); intel_pstate_update_pstate(cpu, target_pstate);
sample = &cpu->sample; sample = &cpu->sample;
trace_pstate_sample(fp_toint(sample->core_pct_busy), trace_pstate_sample(mul_ext_fp(100, sample->core_avg_perf),
fp_toint(sample->busy_scaled), fp_toint(sample->busy_scaled),
from, from,
cpu->pstate.current_pstate, cpu->pstate.current_pstate,
...@@ -1199,7 +1340,7 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time, ...@@ -1199,7 +1340,7 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time,
bool sample_taken = intel_pstate_sample(cpu, time); bool sample_taken = intel_pstate_sample(cpu, time);
if (sample_taken) { if (sample_taken) {
intel_pstate_calc_busy(cpu); intel_pstate_calc_avg_perf(cpu);
if (!hwp_active) if (!hwp_active)
intel_pstate_adjust_busy_pstate(cpu); intel_pstate_adjust_busy_pstate(cpu);
} }
...@@ -1261,23 +1402,16 @@ static int intel_pstate_init_cpu(unsigned int cpunum) ...@@ -1261,23 +1402,16 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
intel_pstate_busy_pid_reset(cpu); intel_pstate_busy_pid_reset(cpu);
cpu->update_util.func = intel_pstate_update_util; pr_debug("controlling: cpu %d\n", cpunum);
pr_debug("intel_pstate: controlling: cpu %d\n", cpunum);
return 0; return 0;
} }
static unsigned int intel_pstate_get(unsigned int cpu_num) static unsigned int intel_pstate_get(unsigned int cpu_num)
{ {
struct sample *sample; struct cpudata *cpu = all_cpu_data[cpu_num];
struct cpudata *cpu;
cpu = all_cpu_data[cpu_num]; return cpu ? get_avg_frequency(cpu) : 0;
if (!cpu)
return 0;
sample = &cpu->sample;
return get_avg_frequency(cpu);
} }
static void intel_pstate_set_update_util_hook(unsigned int cpu_num) static void intel_pstate_set_update_util_hook(unsigned int cpu_num)
...@@ -1286,12 +1420,20 @@ static void intel_pstate_set_update_util_hook(unsigned int cpu_num) ...@@ -1286,12 +1420,20 @@ static void intel_pstate_set_update_util_hook(unsigned int cpu_num)
/* Prevent intel_pstate_update_util() from using stale data. */ /* Prevent intel_pstate_update_util() from using stale data. */
cpu->sample.time = 0; cpu->sample.time = 0;
cpufreq_set_update_util_data(cpu_num, &cpu->update_util); cpufreq_add_update_util_hook(cpu_num, &cpu->update_util,
intel_pstate_update_util);
cpu->update_util_set = true;
} }
static void intel_pstate_clear_update_util_hook(unsigned int cpu) static void intel_pstate_clear_update_util_hook(unsigned int cpu)
{ {
cpufreq_set_update_util_data(cpu, NULL); struct cpudata *cpu_data = all_cpu_data[cpu];
if (!cpu_data->update_util_set)
return;
cpufreq_remove_update_util_hook(cpu);
cpu_data->update_util_set = false;
synchronize_sched(); synchronize_sched();
} }
...@@ -1311,20 +1453,31 @@ static void intel_pstate_set_performance_limits(struct perf_limits *limits) ...@@ -1311,20 +1453,31 @@ static void intel_pstate_set_performance_limits(struct perf_limits *limits)
static int intel_pstate_set_policy(struct cpufreq_policy *policy) static int intel_pstate_set_policy(struct cpufreq_policy *policy)
{ {
struct cpudata *cpu;
if (!policy->cpuinfo.max_freq) if (!policy->cpuinfo.max_freq)
return -ENODEV; return -ENODEV;
intel_pstate_clear_update_util_hook(policy->cpu); intel_pstate_clear_update_util_hook(policy->cpu);
cpu = all_cpu_data[0];
if (cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate) {
if (policy->max < policy->cpuinfo.max_freq &&
policy->max > cpu->pstate.max_pstate * cpu->pstate.scaling) {
pr_debug("policy->max > max non turbo frequency\n");
policy->max = policy->cpuinfo.max_freq;
}
}
if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
limits = &performance_limits; limits = &performance_limits;
if (policy->max >= policy->cpuinfo.max_freq) { if (policy->max >= policy->cpuinfo.max_freq) {
pr_debug("intel_pstate: set performance\n"); pr_debug("set performance\n");
intel_pstate_set_performance_limits(limits); intel_pstate_set_performance_limits(limits);
goto out; goto out;
} }
} else { } else {
pr_debug("intel_pstate: set powersave\n"); pr_debug("set powersave\n");
limits = &powersave_limits; limits = &powersave_limits;
} }
...@@ -1348,10 +1501,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) ...@@ -1348,10 +1501,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
/* Make sure min_perf_pct <= max_perf_pct */ /* Make sure min_perf_pct <= max_perf_pct */
limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct); limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct);
limits->min_perf = div_fp(int_tofp(limits->min_perf_pct), limits->min_perf = div_fp(limits->min_perf_pct, 100);
int_tofp(100)); limits->max_perf = div_fp(limits->max_perf_pct, 100);
limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
int_tofp(100));
out: out:
intel_pstate_set_update_util_hook(policy->cpu); intel_pstate_set_update_util_hook(policy->cpu);
...@@ -1377,7 +1528,7 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy) ...@@ -1377,7 +1528,7 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
int cpu_num = policy->cpu; int cpu_num = policy->cpu;
struct cpudata *cpu = all_cpu_data[cpu_num]; struct cpudata *cpu = all_cpu_data[cpu_num];
pr_debug("intel_pstate: CPU %d exiting\n", cpu_num); pr_debug("CPU %d exiting\n", cpu_num);
intel_pstate_clear_update_util_hook(cpu_num); intel_pstate_clear_update_util_hook(cpu_num);
...@@ -1410,12 +1561,20 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy) ...@@ -1410,12 +1561,20 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling; policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
policy->cpuinfo.max_freq = policy->cpuinfo.max_freq =
cpu->pstate.turbo_pstate * cpu->pstate.scaling; cpu->pstate.turbo_pstate * cpu->pstate.scaling;
intel_pstate_init_acpi_perf_limits(policy);
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
cpumask_set_cpu(policy->cpu, policy->cpus); cpumask_set_cpu(policy->cpu, policy->cpus);
return 0; return 0;
} }
static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
{
intel_pstate_exit_perf_limits(policy);
return 0;
}
static struct cpufreq_driver intel_pstate_driver = { static struct cpufreq_driver intel_pstate_driver = {
.flags = CPUFREQ_CONST_LOOPS, .flags = CPUFREQ_CONST_LOOPS,
.verify = intel_pstate_verify_policy, .verify = intel_pstate_verify_policy,
...@@ -1423,6 +1582,7 @@ static struct cpufreq_driver intel_pstate_driver = { ...@@ -1423,6 +1582,7 @@ static struct cpufreq_driver intel_pstate_driver = {
.resume = intel_pstate_hwp_set_policy, .resume = intel_pstate_hwp_set_policy,
.get = intel_pstate_get, .get = intel_pstate_get,
.init = intel_pstate_cpu_init, .init = intel_pstate_cpu_init,
.exit = intel_pstate_cpu_exit,
.stop_cpu = intel_pstate_stop_cpu, .stop_cpu = intel_pstate_stop_cpu,
.name = "intel_pstate", .name = "intel_pstate",
}; };
...@@ -1466,8 +1626,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) ...@@ -1466,8 +1626,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
} }
#if IS_ENABLED(CONFIG_ACPI) #ifdef CONFIG_ACPI
#include <acpi/processor.h>
static bool intel_pstate_no_acpi_pss(void) static bool intel_pstate_no_acpi_pss(void)
{ {
...@@ -1623,7 +1782,7 @@ static int __init intel_pstate_init(void) ...@@ -1623,7 +1782,7 @@ static int __init intel_pstate_init(void)
if (intel_pstate_platform_pwr_mgmt_exists()) if (intel_pstate_platform_pwr_mgmt_exists())
return -ENODEV; return -ENODEV;
pr_info("Intel P-state driver initializing.\n"); pr_info("Intel P-state driver initializing\n");
all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus()); all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus());
if (!all_cpu_data) if (!all_cpu_data)
...@@ -1640,7 +1799,7 @@ static int __init intel_pstate_init(void) ...@@ -1640,7 +1799,7 @@ static int __init intel_pstate_init(void)
intel_pstate_sysfs_expose_params(); intel_pstate_sysfs_expose_params();
if (hwp_active) if (hwp_active)
pr_info("intel_pstate: HWP enabled\n"); pr_info("HWP enabled\n");
return rc; return rc;
out: out:
...@@ -1666,13 +1825,19 @@ static int __init intel_pstate_setup(char *str) ...@@ -1666,13 +1825,19 @@ static int __init intel_pstate_setup(char *str)
if (!strcmp(str, "disable")) if (!strcmp(str, "disable"))
no_load = 1; no_load = 1;
if (!strcmp(str, "no_hwp")) { if (!strcmp(str, "no_hwp")) {
pr_info("intel_pstate: HWP disabled\n"); pr_info("HWP disabled\n");
no_hwp = 1; no_hwp = 1;
} }
if (!strcmp(str, "force")) if (!strcmp(str, "force"))
force_load = 1; force_load = 1;
if (!strcmp(str, "hwp_only")) if (!strcmp(str, "hwp_only"))
hwp_only = 1; hwp_only = 1;
#ifdef CONFIG_ACPI
if (!strcmp(str, "support_acpi_ppc"))
acpi_ppc = true;
#endif
return 0; return 0;
} }
early_param("intel_pstate", intel_pstate_setup); early_param("intel_pstate", intel_pstate_setup);
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -40,8 +42,6 @@ ...@@ -40,8 +42,6 @@
#include "longhaul.h" #include "longhaul.h"
#define PFX "longhaul: "
#define TYPE_LONGHAUL_V1 1 #define TYPE_LONGHAUL_V1 1
#define TYPE_LONGHAUL_V2 2 #define TYPE_LONGHAUL_V2 2
#define TYPE_POWERSAVER 3 #define TYPE_POWERSAVER 3
...@@ -347,14 +347,13 @@ static int longhaul_setstate(struct cpufreq_policy *policy, ...@@ -347,14 +347,13 @@ static int longhaul_setstate(struct cpufreq_policy *policy,
freqs.new = calc_speed(longhaul_get_cpu_mult()); freqs.new = calc_speed(longhaul_get_cpu_mult());
/* Check if requested frequency is set. */ /* Check if requested frequency is set. */
if (unlikely(freqs.new != speed)) { if (unlikely(freqs.new != speed)) {
printk(KERN_INFO PFX "Failed to set requested frequency!\n"); pr_info("Failed to set requested frequency!\n");
/* Revision ID = 1 but processor is expecting revision key /* Revision ID = 1 but processor is expecting revision key
* equal to 0. Jumpers at the bottom of processor will change * equal to 0. Jumpers at the bottom of processor will change
* multiplier and FSB, but will not change bits in Longhaul * multiplier and FSB, but will not change bits in Longhaul
* MSR nor enable voltage scaling. */ * MSR nor enable voltage scaling. */
if (!revid_errata) { if (!revid_errata) {
printk(KERN_INFO PFX "Enabling \"Ignore Revision ID\" " pr_info("Enabling \"Ignore Revision ID\" option\n");
"option.\n");
revid_errata = 1; revid_errata = 1;
msleep(200); msleep(200);
goto retry_loop; goto retry_loop;
...@@ -364,11 +363,10 @@ static int longhaul_setstate(struct cpufreq_policy *policy, ...@@ -364,11 +363,10 @@ static int longhaul_setstate(struct cpufreq_policy *policy,
* but it doesn't change frequency. I tried poking various * but it doesn't change frequency. I tried poking various
* bits in northbridge registers, but without success. */ * bits in northbridge registers, but without success. */
if (longhaul_flags & USE_ACPI_C3) { if (longhaul_flags & USE_ACPI_C3) {
printk(KERN_INFO PFX "Disabling ACPI C3 support.\n"); pr_info("Disabling ACPI C3 support\n");
longhaul_flags &= ~USE_ACPI_C3; longhaul_flags &= ~USE_ACPI_C3;
if (revid_errata) { if (revid_errata) {
printk(KERN_INFO PFX "Disabling \"Ignore " pr_info("Disabling \"Ignore Revision ID\" option\n");
"Revision ID\" option.\n");
revid_errata = 0; revid_errata = 0;
} }
msleep(200); msleep(200);
...@@ -379,7 +377,7 @@ static int longhaul_setstate(struct cpufreq_policy *policy, ...@@ -379,7 +377,7 @@ static int longhaul_setstate(struct cpufreq_policy *policy,
* RevID = 1. RevID errata will make things right. Just * RevID = 1. RevID errata will make things right. Just
* to be 100% sure. */ * to be 100% sure. */
if (longhaul_version == TYPE_LONGHAUL_V2) { if (longhaul_version == TYPE_LONGHAUL_V2) {
printk(KERN_INFO PFX "Switching to Longhaul ver. 1\n"); pr_info("Switching to Longhaul ver. 1\n");
longhaul_version = TYPE_LONGHAUL_V1; longhaul_version = TYPE_LONGHAUL_V1;
msleep(200); msleep(200);
goto retry_loop; goto retry_loop;
...@@ -387,8 +385,7 @@ static int longhaul_setstate(struct cpufreq_policy *policy, ...@@ -387,8 +385,7 @@ static int longhaul_setstate(struct cpufreq_policy *policy,
} }
if (!bm_timeout) { if (!bm_timeout) {
printk(KERN_INFO PFX "Warning: Timeout while waiting for " pr_info("Warning: Timeout while waiting for idle PCI bus\n");
"idle PCI bus.\n");
return -EBUSY; return -EBUSY;
} }
...@@ -433,12 +430,12 @@ static int longhaul_get_ranges(void) ...@@ -433,12 +430,12 @@ static int longhaul_get_ranges(void)
/* Get current frequency */ /* Get current frequency */
mult = longhaul_get_cpu_mult(); mult = longhaul_get_cpu_mult();
if (mult == -1) { if (mult == -1) {
printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n"); pr_info("Invalid (reserved) multiplier!\n");
return -EINVAL; return -EINVAL;
} }
fsb = guess_fsb(mult); fsb = guess_fsb(mult);
if (fsb == 0) { if (fsb == 0) {
printk(KERN_INFO PFX "Invalid (reserved) FSB!\n"); pr_info("Invalid (reserved) FSB!\n");
return -EINVAL; return -EINVAL;
} }
/* Get max multiplier - as we always did. /* Get max multiplier - as we always did.
...@@ -468,11 +465,11 @@ static int longhaul_get_ranges(void) ...@@ -468,11 +465,11 @@ static int longhaul_get_ranges(void)
print_speed(highest_speed/1000)); print_speed(highest_speed/1000));
if (lowest_speed == highest_speed) { if (lowest_speed == highest_speed) {
printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n"); pr_info("highestspeed == lowest, aborting\n");
return -EINVAL; return -EINVAL;
} }
if (lowest_speed > highest_speed) { if (lowest_speed > highest_speed) {
printk(KERN_INFO PFX "nonsense! lowest (%d > %d) !\n", pr_info("nonsense! lowest (%d > %d) !\n",
lowest_speed, highest_speed); lowest_speed, highest_speed);
return -EINVAL; return -EINVAL;
} }
...@@ -538,16 +535,16 @@ static void longhaul_setup_voltagescaling(void) ...@@ -538,16 +535,16 @@ static void longhaul_setup_voltagescaling(void)
rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
if (!(longhaul.bits.RevisionID & 1)) { if (!(longhaul.bits.RevisionID & 1)) {
printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n"); pr_info("Voltage scaling not supported by CPU\n");
return; return;
} }
if (!longhaul.bits.VRMRev) { if (!longhaul.bits.VRMRev) {
printk(KERN_INFO PFX "VRM 8.5\n"); pr_info("VRM 8.5\n");
vrm_mV_table = &vrm85_mV[0]; vrm_mV_table = &vrm85_mV[0];
mV_vrm_table = &mV_vrm85[0]; mV_vrm_table = &mV_vrm85[0];
} else { } else {
printk(KERN_INFO PFX "Mobile VRM\n"); pr_info("Mobile VRM\n");
if (cpu_model < CPU_NEHEMIAH) if (cpu_model < CPU_NEHEMIAH)
return; return;
vrm_mV_table = &mobilevrm_mV[0]; vrm_mV_table = &mobilevrm_mV[0];
...@@ -558,27 +555,21 @@ static void longhaul_setup_voltagescaling(void) ...@@ -558,27 +555,21 @@ static void longhaul_setup_voltagescaling(void)
maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
printk(KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " pr_info("Bogus values Min:%d.%03d Max:%d.%03d - Voltage scaling disabled\n",
"Voltage scaling disabled.\n", minvid.mV/1000, minvid.mV%1000,
minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
maxvid.mV/1000, maxvid.mV%1000);
return; return;
} }
if (minvid.mV == maxvid.mV) { if (minvid.mV == maxvid.mV) {
printk(KERN_INFO PFX "Claims to support voltage scaling but " pr_info("Claims to support voltage scaling but min & max are both %d.%03d - Voltage scaling disabled\n",
"min & max are both %d.%03d. " maxvid.mV/1000, maxvid.mV%1000);
"Voltage scaling disabled\n",
maxvid.mV/1000, maxvid.mV%1000);
return; return;
} }
/* How many voltage steps*/ /* How many voltage steps*/
numvscales = maxvid.pos - minvid.pos + 1; numvscales = maxvid.pos - minvid.pos + 1;
printk(KERN_INFO PFX pr_info("Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n",
"Max VID=%d.%03d "
"Min VID=%d.%03d, "
"%d possible voltage scales\n",
maxvid.mV/1000, maxvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000,
minvid.mV/1000, minvid.mV%1000, minvid.mV/1000, minvid.mV%1000,
numvscales); numvscales);
...@@ -617,12 +608,12 @@ static void longhaul_setup_voltagescaling(void) ...@@ -617,12 +608,12 @@ static void longhaul_setup_voltagescaling(void)
pos = minvid.pos; pos = minvid.pos;
freq_pos->driver_data |= mV_vrm_table[pos] << 8; freq_pos->driver_data |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]]; vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", pr_info("f: %d kHz, index: %d, vid: %d mV\n",
speed, (int)(freq_pos - longhaul_table), vid.mV); speed, (int)(freq_pos - longhaul_table), vid.mV);
} }
can_scale_voltage = 1; can_scale_voltage = 1;
printk(KERN_INFO PFX "Voltage scaling enabled.\n"); pr_info("Voltage scaling enabled\n");
} }
...@@ -720,8 +711,7 @@ static int enable_arbiter_disable(void) ...@@ -720,8 +711,7 @@ static int enable_arbiter_disable(void)
pci_write_config_byte(dev, reg, pci_cmd); pci_write_config_byte(dev, reg, pci_cmd);
pci_read_config_byte(dev, reg, &pci_cmd); pci_read_config_byte(dev, reg, &pci_cmd);
if (!(pci_cmd & 1<<7)) { if (!(pci_cmd & 1<<7)) {
printk(KERN_ERR PFX pr_err("Can't enable access to port 0x22\n");
"Can't enable access to port 0x22.\n");
status = 0; status = 0;
} }
} }
...@@ -758,8 +748,7 @@ static int longhaul_setup_southbridge(void) ...@@ -758,8 +748,7 @@ static int longhaul_setup_southbridge(void)
if (pci_cmd & 1 << 7) { if (pci_cmd & 1 << 7) {
pci_read_config_dword(dev, 0x88, &acpi_regs_addr); pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
acpi_regs_addr &= 0xff00; acpi_regs_addr &= 0xff00;
printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", pr_info("ACPI I/O at 0x%x\n", acpi_regs_addr);
acpi_regs_addr);
} }
pci_dev_put(dev); pci_dev_put(dev);
...@@ -853,14 +842,14 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -853,14 +842,14 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy)
longhaul_version = TYPE_LONGHAUL_V1; longhaul_version = TYPE_LONGHAUL_V1;
} }
printk(KERN_INFO PFX "VIA %s CPU detected. ", cpuname); pr_info("VIA %s CPU detected. ", cpuname);
switch (longhaul_version) { switch (longhaul_version) {
case TYPE_LONGHAUL_V1: case TYPE_LONGHAUL_V1:
case TYPE_LONGHAUL_V2: case TYPE_LONGHAUL_V2:
printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version); pr_cont("Longhaul v%d supported\n", longhaul_version);
break; break;
case TYPE_POWERSAVER: case TYPE_POWERSAVER:
printk(KERN_CONT "Powersaver supported.\n"); pr_cont("Powersaver supported\n");
break; break;
}; };
...@@ -889,15 +878,14 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -889,15 +878,14 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy)
if (!(longhaul_flags & USE_ACPI_C3 if (!(longhaul_flags & USE_ACPI_C3
|| longhaul_flags & USE_NORTHBRIDGE) || longhaul_flags & USE_NORTHBRIDGE)
&& ((pr == NULL) || !(pr->flags.bm_control))) { && ((pr == NULL) || !(pr->flags.bm_control))) {
printk(KERN_ERR PFX pr_err("No ACPI support: Unsupported northbridge\n");
"No ACPI support. Unsupported northbridge.\n");
return -ENODEV; return -ENODEV;
} }
if (longhaul_flags & USE_NORTHBRIDGE) if (longhaul_flags & USE_NORTHBRIDGE)
printk(KERN_INFO PFX "Using northbridge support.\n"); pr_info("Using northbridge support\n");
if (longhaul_flags & USE_ACPI_C3) if (longhaul_flags & USE_ACPI_C3)
printk(KERN_INFO PFX "Using ACPI support.\n"); pr_info("Using ACPI support\n");
ret = longhaul_get_ranges(); ret = longhaul_get_ranges();
if (ret != 0) if (ret != 0)
...@@ -934,20 +922,18 @@ static int __init longhaul_init(void) ...@@ -934,20 +922,18 @@ static int __init longhaul_init(void)
return -ENODEV; return -ENODEV;
if (!enable) { if (!enable) {
printk(KERN_ERR PFX "Option \"enable\" not set. Aborting.\n"); pr_err("Option \"enable\" not set - Aborting\n");
return -ENODEV; return -ENODEV;
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (num_online_cpus() > 1) { if (num_online_cpus() > 1) {
printk(KERN_ERR PFX "More than 1 CPU detected, " pr_err("More than 1 CPU detected, longhaul disabled\n");
"longhaul disabled.\n");
return -ENODEV; return -ENODEV;
} }
#endif #endif
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
if (cpu_has_apic) { if (cpu_has_apic) {
printk(KERN_ERR PFX "APIC detected. Longhaul is currently " pr_err("APIC detected. Longhaul is currently broken in this configuration.\n");
"broken in this configuration.\n");
return -ENODEV; return -ENODEV;
} }
#endif #endif
...@@ -955,7 +941,7 @@ static int __init longhaul_init(void) ...@@ -955,7 +941,7 @@ static int __init longhaul_init(void)
case 6 ... 9: case 6 ... 9:
return cpufreq_register_driver(&longhaul_driver); return cpufreq_register_driver(&longhaul_driver);
case 10: case 10:
printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n"); pr_err("Use acpi-cpufreq driver for VIA C7\n");
default: default:
; ;
} }
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -76,7 +79,7 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -76,7 +79,7 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpuclk = clk_get(NULL, "cpu_clk"); cpuclk = clk_get(NULL, "cpu_clk");
if (IS_ERR(cpuclk)) { if (IS_ERR(cpuclk)) {
printk(KERN_ERR "cpufreq: couldn't get CPU clk\n"); pr_err("couldn't get CPU clk\n");
return PTR_ERR(cpuclk); return PTR_ERR(cpuclk);
} }
...@@ -163,7 +166,7 @@ static int __init cpufreq_init(void) ...@@ -163,7 +166,7 @@ static int __init cpufreq_init(void)
if (ret) if (ret)
return ret; return ret;
pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); pr_info("Loongson-2F CPU frequency driver\n");
cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#undef DEBUG #undef DEBUG
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -174,7 +176,7 @@ static int __init maple_cpufreq_init(void) ...@@ -174,7 +176,7 @@ static int __init maple_cpufreq_init(void)
/* Get first CPU node */ /* Get first CPU node */
cpunode = of_cpu_device_node_get(0); cpunode = of_cpu_device_node_get(0);
if (cpunode == NULL) { if (cpunode == NULL) {
printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n"); pr_err("Can't find any CPU 0 node\n");
goto bail_noprops; goto bail_noprops;
} }
...@@ -182,8 +184,7 @@ static int __init maple_cpufreq_init(void) ...@@ -182,8 +184,7 @@ static int __init maple_cpufreq_init(void)
/* we actually don't care on which CPU to access PVR */ /* we actually don't care on which CPU to access PVR */
pvr_hi = PVR_VER(mfspr(SPRN_PVR)); pvr_hi = PVR_VER(mfspr(SPRN_PVR));
if (pvr_hi != 0x3c && pvr_hi != 0x44) { if (pvr_hi != 0x3c && pvr_hi != 0x44) {
printk(KERN_ERR "cpufreq: Unsupported CPU version (%x)\n", pr_err("Unsupported CPU version (%x)\n", pvr_hi);
pvr_hi);
goto bail_noprops; goto bail_noprops;
} }
...@@ -222,8 +223,8 @@ static int __init maple_cpufreq_init(void) ...@@ -222,8 +223,8 @@ static int __init maple_cpufreq_init(void)
maple_pmode_cur = -1; maple_pmode_cur = -1;
maple_scom_switch_freq(maple_scom_query_freq()); maple_scom_switch_freq(maple_scom_query_freq());
printk(KERN_INFO "Registering Maple CPU frequency driver\n"); pr_info("Registering Maple CPU frequency driver\n");
printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", pr_info("Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
maple_cpu_freqs[1].frequency/1000, maple_cpu_freqs[1].frequency/1000,
maple_cpu_freqs[0].frequency/1000, maple_cpu_freqs[0].frequency/1000,
maple_cpu_freqs[maple_pmode_cur].frequency/1000); maple_cpu_freqs[maple_pmode_cur].frequency/1000);
......
...@@ -59,11 +59,8 @@ static LIST_HEAD(dvfs_info_list); ...@@ -59,11 +59,8 @@ static LIST_HEAD(dvfs_info_list);
static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu) static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu)
{ {
struct mtk_cpu_dvfs_info *info; struct mtk_cpu_dvfs_info *info;
struct list_head *list;
list_for_each(list, &dvfs_info_list) {
info = list_entry(list, struct mtk_cpu_dvfs_info, list_head);
list_for_each_entry(info, &dvfs_info_list, list_head) {
if (cpumask_test_cpu(cpu, &info->cpus)) if (cpumask_test_cpu(cpu, &info->cpus))
return info; return info;
} }
...@@ -524,8 +521,7 @@ static struct cpufreq_driver mt8173_cpufreq_driver = { ...@@ -524,8 +521,7 @@ static struct cpufreq_driver mt8173_cpufreq_driver = {
static int mt8173_cpufreq_probe(struct platform_device *pdev) static int mt8173_cpufreq_probe(struct platform_device *pdev)
{ {
struct mtk_cpu_dvfs_info *info; struct mtk_cpu_dvfs_info *info, *tmp;
struct list_head *list, *tmp;
int cpu, ret; int cpu, ret;
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
...@@ -559,11 +555,9 @@ static int mt8173_cpufreq_probe(struct platform_device *pdev) ...@@ -559,11 +555,9 @@ static int mt8173_cpufreq_probe(struct platform_device *pdev)
return 0; return 0;
release_dvfs_info_list: release_dvfs_info_list:
list_for_each_safe(list, tmp, &dvfs_info_list) { list_for_each_entry_safe(info, tmp, &dvfs_info_list, list_head) {
info = list_entry(list, struct mtk_cpu_dvfs_info, list_head);
mtk_cpu_dvfs_info_release(info); mtk_cpu_dvfs_info_release(info);
list_del(list); list_del(&info->list_head);
} }
return ret; return ret;
......
/*
* CPUFreq support for Armada 370/XP platforms.
*
* Copyright (C) 2012-2016 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory Clement <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#define pr_fmt(fmt) "mvebu-pmsu: " fmt
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/resource.h>
static int __init armada_xp_pmsu_cpufreq_init(void)
{
struct device_node *np;
struct resource res;
int ret, cpu;
if (!of_machine_is_compatible("marvell,armadaxp"))
return 0;
/*
* In order to have proper cpufreq handling, we need to ensure
* that the Device Tree description of the CPU clock includes
* the definition of the PMU DFS registers. If not, we do not
* register the clock notifier and the cpufreq driver. This
* piece of code is only for compatibility with old Device
* Trees.
*/
np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock");
if (!np)
return 0;
ret = of_address_to_resource(np, 1, &res);
if (ret) {
pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n");
of_node_put(np);
return 0;
}
of_node_put(np);
/*
* For each CPU, this loop registers the operating points
* supported (which are the nominal CPU frequency and half of
* it), and registers the clock notifier that will take care
* of doing the PMSU part of a frequency transition.
*/
for_each_possible_cpu(cpu) {
struct device *cpu_dev;
struct clk *clk;
int ret;
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) {
pr_err("Cannot get CPU %d\n", cpu);
continue;
}
clk = clk_get(cpu_dev, 0);
if (IS_ERR(clk)) {
pr_err("Cannot get clock for CPU %d\n", cpu);
return PTR_ERR(clk);
}
/*
* In case of a failure of dev_pm_opp_add(), we don't
* bother with cleaning up the registered OPP (there's
* no function to do so), and simply cancel the
* registration of the cpufreq device.
*/
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0);
if (ret) {
clk_put(clk);
return ret;
}
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0);
if (ret) {
clk_put(clk);
return ret;
}
ret = dev_pm_opp_set_sharing_cpus(cpu_dev,
cpumask_of(cpu_dev->id));
if (ret)
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
__func__, ret);
}
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
return 0;
}
device_initcall(armada_xp_pmsu_cpufreq_init);
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -163,13 +166,13 @@ static int omap_cpufreq_probe(struct platform_device *pdev) ...@@ -163,13 +166,13 @@ static int omap_cpufreq_probe(struct platform_device *pdev)
{ {
mpu_dev = get_cpu_device(0); mpu_dev = get_cpu_device(0);
if (!mpu_dev) { if (!mpu_dev) {
pr_warning("%s: unable to get the mpu device\n", __func__); pr_warn("%s: unable to get the MPU device\n", __func__);
return -EINVAL; return -EINVAL;
} }
mpu_reg = regulator_get(mpu_dev, "vcc"); mpu_reg = regulator_get(mpu_dev, "vcc");
if (IS_ERR(mpu_reg)) { if (IS_ERR(mpu_reg)) {
pr_warning("%s: unable to get MPU regulator\n", __func__); pr_warn("%s: unable to get MPU regulator\n", __func__);
mpu_reg = NULL; mpu_reg = NULL;
} else { } else {
/* /*
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -35,8 +37,6 @@ ...@@ -35,8 +37,6 @@
#include "speedstep-lib.h" #include "speedstep-lib.h"
#define PFX "p4-clockmod: "
/* /*
* Duty Cycle (3bits), note DC_DISABLE is not specified in * Duty Cycle (3bits), note DC_DISABLE is not specified in
* intel docs i just use it to mean disable * intel docs i just use it to mean disable
...@@ -124,11 +124,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -124,11 +124,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{ {
if (c->x86 == 0x06) { if (c->x86 == 0x06) {
if (cpu_has(c, X86_FEATURE_EST)) if (cpu_has(c, X86_FEATURE_EST))
printk_once(KERN_WARNING PFX "Warning: EST-capable " pr_warn_once("Warning: EST-capable CPU detected. The acpi-cpufreq module offers voltage scaling in addition to frequency scaling. You should use that instead of p4-clockmod, if possible.\n");
"CPU detected. The acpi-cpufreq module offers "
"voltage scaling in addition to frequency "
"scaling. You should use that instead of "
"p4-clockmod, if possible.\n");
switch (c->x86_model) { switch (c->x86_model) {
case 0x0E: /* Core */ case 0x0E: /* Core */
case 0x0F: /* Core Duo */ case 0x0F: /* Core Duo */
...@@ -152,11 +148,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -152,11 +148,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) { if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) {
printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " pr_warn("Warning: Pentium 4-M detected. The speedstep-ich or acpi cpufreq modules offer voltage scaling in addition of frequency scaling. You should use either one instead of p4-clockmod, if possible.\n");
"The speedstep-ich or acpi cpufreq modules offer "
"voltage scaling in addition of frequency scaling. "
"You should use either one instead of p4-clockmod, "
"if possible.\n");
return speedstep_get_frequency(SPEEDSTEP_CPU_P4M); return speedstep_get_frequency(SPEEDSTEP_CPU_P4M);
} }
...@@ -265,8 +257,7 @@ static int __init cpufreq_p4_init(void) ...@@ -265,8 +257,7 @@ static int __init cpufreq_p4_init(void)
ret = cpufreq_register_driver(&p4clockmod_driver); ret = cpufreq_register_driver(&p4clockmod_driver);
if (!ret) if (!ret)
printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock " pr_info("P4/Xeon(TM) CPU On-Demand Clock Modulation available\n");
"Modulation available\n");
return ret; return ret;
} }
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -481,13 +483,13 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) ...@@ -481,13 +483,13 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
freqs = of_get_property(cpunode, "bus-frequencies", &lenp); freqs = of_get_property(cpunode, "bus-frequencies", &lenp);
lenp /= sizeof(u32); lenp /= sizeof(u32);
if (freqs == NULL || lenp != 2) { if (freqs == NULL || lenp != 2) {
printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); pr_err("bus-frequencies incorrect or missing\n");
return 1; return 1;
} }
ratio = of_get_property(cpunode, "processor-to-bus-ratio*2", ratio = of_get_property(cpunode, "processor-to-bus-ratio*2",
NULL); NULL);
if (ratio == NULL) { if (ratio == NULL) {
printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); pr_err("processor-to-bus-ratio*2 missing\n");
return 1; return 1;
} }
...@@ -550,7 +552,7 @@ static int pmac_cpufreq_init_7447A(struct device_node *cpunode) ...@@ -550,7 +552,7 @@ static int pmac_cpufreq_init_7447A(struct device_node *cpunode)
if (volt_gpio_np) if (volt_gpio_np)
voltage_gpio = read_gpio(volt_gpio_np); voltage_gpio = read_gpio(volt_gpio_np);
if (!voltage_gpio){ if (!voltage_gpio){
printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n"); pr_err("missing cpu-vcore-select gpio\n");
return 1; return 1;
} }
...@@ -675,9 +677,9 @@ static int __init pmac_cpufreq_setup(void) ...@@ -675,9 +677,9 @@ static int __init pmac_cpufreq_setup(void)
pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
ppc_proc_freq = cur_freq * 1000ul; ppc_proc_freq = cur_freq * 1000ul;
printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); pr_info("Registering PowerMac CPU frequency driver\n");
printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", pr_info("Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
low_freq/1000, hi_freq/1000, cur_freq/1000); low_freq/1000, hi_freq/1000, cur_freq/1000);
return cpufreq_register_driver(&pmac_cpufreq_driver); return cpufreq_register_driver(&pmac_cpufreq_driver);
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#undef DEBUG #undef DEBUG
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -138,7 +140,7 @@ static void g5_vdnap_switch_volt(int speed_mode) ...@@ -138,7 +140,7 @@ static void g5_vdnap_switch_volt(int speed_mode)
usleep_range(1000, 1000); usleep_range(1000, 1000);
} }
if (done == 0) if (done == 0)
printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n"); pr_warn("Timeout in clock slewing !\n");
} }
...@@ -266,7 +268,7 @@ static int g5_pfunc_switch_freq(int speed_mode) ...@@ -266,7 +268,7 @@ static int g5_pfunc_switch_freq(int speed_mode)
rc = pmf_call_one(pfunc_cpu_setfreq_low, NULL); rc = pmf_call_one(pfunc_cpu_setfreq_low, NULL);
if (rc) if (rc)
printk(KERN_WARNING "cpufreq: pfunc switch error %d\n", rc); pr_warn("pfunc switch error %d\n", rc);
/* It's an irq GPIO so we should be able to just block here, /* It's an irq GPIO so we should be able to just block here,
* I'll do that later after I've properly tested the IRQ code for * I'll do that later after I've properly tested the IRQ code for
...@@ -282,7 +284,7 @@ static int g5_pfunc_switch_freq(int speed_mode) ...@@ -282,7 +284,7 @@ static int g5_pfunc_switch_freq(int speed_mode)
usleep_range(500, 500); usleep_range(500, 500);
} }
if (done == 0) if (done == 0)
printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n"); pr_warn("Timeout in clock slewing !\n");
/* If frequency is going down, last ramp the voltage */ /* If frequency is going down, last ramp the voltage */
if (speed_mode > g5_pmode_cur) if (speed_mode > g5_pmode_cur)
...@@ -368,7 +370,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode) ...@@ -368,7 +370,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
} }
pvr_hi = (*valp) >> 16; pvr_hi = (*valp) >> 16;
if (pvr_hi != 0x3c && pvr_hi != 0x44) { if (pvr_hi != 0x3c && pvr_hi != 0x44) {
printk(KERN_ERR "cpufreq: Unsupported CPU version\n"); pr_err("Unsupported CPU version\n");
goto bail_noprops; goto bail_noprops;
} }
...@@ -403,8 +405,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode) ...@@ -403,8 +405,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
root = of_find_node_by_path("/"); root = of_find_node_by_path("/");
if (root == NULL) { if (root == NULL) {
printk(KERN_ERR "cpufreq: Can't find root of " pr_err("Can't find root of device tree\n");
"device tree\n");
goto bail_noprops; goto bail_noprops;
} }
pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0"); pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
...@@ -412,8 +413,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode) ...@@ -412,8 +413,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
pmf_find_function(root, "slewing-done"); pmf_find_function(root, "slewing-done");
if (pfunc_set_vdnap0 == NULL || if (pfunc_set_vdnap0 == NULL ||
pfunc_vdnap0_complete == NULL) { pfunc_vdnap0_complete == NULL) {
printk(KERN_ERR "cpufreq: Can't find required " pr_err("Can't find required platform function\n");
"platform function\n");
goto bail_noprops; goto bail_noprops;
} }
...@@ -453,10 +453,10 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode) ...@@ -453,10 +453,10 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
g5_pmode_cur = -1; g5_pmode_cur = -1;
g5_switch_freq(g5_query_freq()); g5_switch_freq(g5_query_freq());
printk(KERN_INFO "Registering G5 CPU frequency driver\n"); pr_info("Registering G5 CPU frequency driver\n");
printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n", pr_info("Frequency method: %s, Voltage method: %s\n",
freq_method, volt_method); freq_method, volt_method);
printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", pr_info("Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
g5_cpu_freqs[1].frequency/1000, g5_cpu_freqs[1].frequency/1000,
g5_cpu_freqs[0].frequency/1000, g5_cpu_freqs[0].frequency/1000,
g5_cpu_freqs[g5_pmode_cur].frequency/1000); g5_cpu_freqs[g5_pmode_cur].frequency/1000);
...@@ -493,7 +493,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -493,7 +493,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
if (cpuid != NULL) if (cpuid != NULL)
eeprom = of_get_property(cpuid, "cpuid", NULL); eeprom = of_get_property(cpuid, "cpuid", NULL);
if (eeprom == NULL) { if (eeprom == NULL) {
printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n"); pr_err("Can't find cpuid EEPROM !\n");
rc = -ENODEV; rc = -ENODEV;
goto bail; goto bail;
} }
...@@ -511,7 +511,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -511,7 +511,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
break; break;
} }
if (hwclock == NULL) { if (hwclock == NULL) {
printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n"); pr_err("Can't find i2c clock chip !\n");
rc = -ENODEV; rc = -ENODEV;
goto bail; goto bail;
} }
...@@ -539,7 +539,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -539,7 +539,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
/* Check we have minimum requirements */ /* Check we have minimum requirements */
if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL || if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL ||
pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) { pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) {
printk(KERN_ERR "cpufreq: Can't find platform functions !\n"); pr_err("Can't find platform functions !\n");
rc = -ENODEV; rc = -ENODEV;
goto bail; goto bail;
} }
...@@ -567,7 +567,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -567,7 +567,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
/* Get max frequency from device-tree */ /* Get max frequency from device-tree */
valp = of_get_property(cpunode, "clock-frequency", NULL); valp = of_get_property(cpunode, "clock-frequency", NULL);
if (!valp) { if (!valp) {
printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n"); pr_err("Can't find CPU frequency !\n");
rc = -ENODEV; rc = -ENODEV;
goto bail; goto bail;
} }
...@@ -583,8 +583,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -583,8 +583,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
/* Check for machines with no useful settings */ /* Check for machines with no useful settings */
if (il == ih) { if (il == ih) {
printk(KERN_WARNING "cpufreq: No low frequency mode available" pr_warn("No low frequency mode available on this model !\n");
" on this model !\n");
rc = -ENODEV; rc = -ENODEV;
goto bail; goto bail;
} }
...@@ -595,7 +594,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -595,7 +594,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
/* Sanity check */ /* Sanity check */
if (min_freq >= max_freq || min_freq < 1000) { if (min_freq >= max_freq || min_freq < 1000) {
printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n"); pr_err("Can't calculate low frequency !\n");
rc = -ENXIO; rc = -ENXIO;
goto bail; goto bail;
} }
...@@ -619,10 +618,10 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode) ...@@ -619,10 +618,10 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
g5_pmode_cur = -1; g5_pmode_cur = -1;
g5_switch_freq(g5_query_freq()); g5_switch_freq(g5_query_freq());
printk(KERN_INFO "Registering G5 CPU frequency driver\n"); pr_info("Registering G5 CPU frequency driver\n");
printk(KERN_INFO "Frequency method: i2c/pfunc, " pr_info("Frequency method: i2c/pfunc, Voltage method: %s\n",
"Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none"); has_volt ? "i2c/pfunc" : "none");
printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", pr_info("Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
g5_cpu_freqs[1].frequency/1000, g5_cpu_freqs[1].frequency/1000,
g5_cpu_freqs[0].frequency/1000, g5_cpu_freqs[0].frequency/1000,
g5_cpu_freqs[g5_pmode_cur].frequency/1000); g5_cpu_freqs[g5_pmode_cur].frequency/1000);
...@@ -654,7 +653,7 @@ static int __init g5_cpufreq_init(void) ...@@ -654,7 +653,7 @@ static int __init g5_cpufreq_init(void)
/* Get first CPU node */ /* Get first CPU node */
cpunode = of_cpu_device_node_get(0); cpunode = of_cpu_device_node_get(0);
if (cpunode == NULL) { if (cpunode == NULL) {
pr_err("cpufreq: Can't find any CPU node\n"); pr_err("Can't find any CPU node\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -22,7 +24,6 @@ ...@@ -22,7 +24,6 @@
#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long #define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
as it is unused */ as it is unused */
#define PFX "powernow-k6: "
static unsigned int busfreq; /* FSB, in 10 kHz */ static unsigned int busfreq; /* FSB, in 10 kHz */
static unsigned int max_multiplier; static unsigned int max_multiplier;
...@@ -141,7 +142,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy, ...@@ -141,7 +142,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
{ {
if (clock_ratio[best_i].driver_data > max_multiplier) { if (clock_ratio[best_i].driver_data > max_multiplier) {
printk(KERN_ERR PFX "invalid target frequency\n"); pr_err("invalid target frequency\n");
return -EINVAL; return -EINVAL;
} }
...@@ -175,13 +176,14 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) ...@@ -175,13 +176,14 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
max_multiplier = param_max_multiplier; max_multiplier = param_max_multiplier;
goto have_max_multiplier; goto have_max_multiplier;
} }
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n"); pr_err("invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
return -EINVAL; return -EINVAL;
} }
if (!max_multiplier) { if (!max_multiplier) {
printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz); pr_warn("unknown frequency %u, cannot determine current multiplier\n",
printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n"); khz);
pr_warn("use module parameters max_multiplier and bus_frequency\n");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -193,7 +195,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) ...@@ -193,7 +195,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
busfreq = param_busfreq / 10; busfreq = param_busfreq / 10;
goto have_busfreq; goto have_busfreq;
} }
printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n"); pr_err("invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n");
return -EINVAL; return -EINVAL;
} }
...@@ -275,7 +277,7 @@ static int __init powernow_k6_init(void) ...@@ -275,7 +277,7 @@ static int __init powernow_k6_init(void)
return -ENODEV; return -ENODEV;
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) { if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
printk(KERN_INFO PFX "PowerNow IOPORT region already used.\n"); pr_info("PowerNow IOPORT region already used\n");
return -EIO; return -EIO;
} }
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* - We disable half multipliers if ACPI is used on A0 stepping CPUs. * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -35,9 +37,6 @@ ...@@ -35,9 +37,6 @@
#include "powernow-k7.h" #include "powernow-k7.h"
#define PFX "powernow: "
struct psb_s { struct psb_s {
u8 signature[10]; u8 signature[10];
u8 tableversion; u8 tableversion;
...@@ -127,14 +126,13 @@ static int check_powernow(void) ...@@ -127,14 +126,13 @@ static int check_powernow(void)
maxei = cpuid_eax(0x80000000); maxei = cpuid_eax(0x80000000);
if (maxei < 0x80000007) { /* Any powernow info ? */ if (maxei < 0x80000007) { /* Any powernow info ? */
#ifdef MODULE #ifdef MODULE
printk(KERN_INFO PFX "No powernow capabilities detected\n"); pr_info("No powernow capabilities detected\n");
#endif #endif
return 0; return 0;
} }
if ((c->x86_model == 6) && (c->x86_mask == 0)) { if ((c->x86_model == 6) && (c->x86_mask == 0)) {
printk(KERN_INFO PFX "K7 660[A0] core detected, " pr_info("K7 660[A0] core detected, enabling errata workarounds\n");
"enabling errata workarounds\n");
have_a0 = 1; have_a0 = 1;
} }
...@@ -144,22 +142,22 @@ static int check_powernow(void) ...@@ -144,22 +142,22 @@ static int check_powernow(void)
if (!(edx & (1 << 1 | 1 << 2))) if (!(edx & (1 << 1 | 1 << 2)))
return 0; return 0;
printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); pr_info("PowerNOW! Technology present. Can scale: ");
if (edx & 1 << 1) { if (edx & 1 << 1) {
printk("frequency"); pr_cont("frequency");
can_scale_bus = 1; can_scale_bus = 1;
} }
if ((edx & (1 << 1 | 1 << 2)) == 0x6) if ((edx & (1 << 1 | 1 << 2)) == 0x6)
printk(" and "); pr_cont(" and ");
if (edx & 1 << 2) { if (edx & 1 << 2) {
printk("voltage"); pr_cont("voltage");
can_scale_vid = 1; can_scale_vid = 1;
} }
printk(".\n"); pr_cont("\n");
return 1; return 1;
} }
...@@ -427,16 +425,14 @@ static int powernow_acpi_init(void) ...@@ -427,16 +425,14 @@ static int powernow_acpi_init(void)
err05: err05:
kfree(acpi_processor_perf); kfree(acpi_processor_perf);
err0: err0:
printk(KERN_WARNING PFX "ACPI perflib can not be used on " pr_warn("ACPI perflib can not be used on this platform\n");
"this platform\n");
acpi_processor_perf = NULL; acpi_processor_perf = NULL;
return retval; return retval;
} }
#else #else
static int powernow_acpi_init(void) static int powernow_acpi_init(void)
{ {
printk(KERN_INFO PFX "no support for ACPI processor found." pr_info("no support for ACPI processor found - please recompile your kernel with ACPI processor\n");
" Please recompile your kernel with ACPI processor\n");
return -EINVAL; return -EINVAL;
} }
#endif #endif
...@@ -468,8 +464,7 @@ static int powernow_decode_bios(int maxfid, int startvid) ...@@ -468,8 +464,7 @@ static int powernow_decode_bios(int maxfid, int startvid)
psb = (struct psb_s *) p; psb = (struct psb_s *) p;
pr_debug("Table version: 0x%x\n", psb->tableversion); pr_debug("Table version: 0x%x\n", psb->tableversion);
if (psb->tableversion != 0x12) { if (psb->tableversion != 0x12) {
printk(KERN_INFO PFX "Sorry, only v1.2 tables" pr_info("Sorry, only v1.2 tables supported right now\n");
" supported right now\n");
return -ENODEV; return -ENODEV;
} }
...@@ -481,10 +476,8 @@ static int powernow_decode_bios(int maxfid, int startvid) ...@@ -481,10 +476,8 @@ static int powernow_decode_bios(int maxfid, int startvid)
latency = psb->settlingtime; latency = psb->settlingtime;
if (latency < 100) { if (latency < 100) {
printk(KERN_INFO PFX "BIOS set settling time " pr_info("BIOS set settling time to %d microseconds. Should be at least 100. Correcting.\n",
"to %d microseconds. " latency);
"Should be at least 100. "
"Correcting.\n", latency);
latency = 100; latency = 100;
} }
pr_debug("Settling Time: %d microseconds.\n", pr_debug("Settling Time: %d microseconds.\n",
...@@ -516,10 +509,9 @@ static int powernow_decode_bios(int maxfid, int startvid) ...@@ -516,10 +509,9 @@ static int powernow_decode_bios(int maxfid, int startvid)
p += 2; p += 2;
} }
} }
printk(KERN_INFO PFX "No PST tables match this cpuid " pr_info("No PST tables match this cpuid (0x%x)\n",
"(0x%x)\n", etuple); etuple);
printk(KERN_INFO PFX "This is indicative of a broken " pr_info("This is indicative of a broken BIOS\n");
"BIOS.\n");
return -EINVAL; return -EINVAL;
} }
...@@ -552,7 +544,7 @@ static int fixup_sgtc(void) ...@@ -552,7 +544,7 @@ static int fixup_sgtc(void)
sgtc = 100 * m * latency; sgtc = 100 * m * latency;
sgtc = sgtc / 3; sgtc = sgtc / 3;
if (sgtc > 0xfffff) { if (sgtc > 0xfffff) {
printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc); pr_warn("SGTC too large %d\n", sgtc);
sgtc = 0xfffff; sgtc = 0xfffff;
} }
return sgtc; return sgtc;
...@@ -574,14 +566,10 @@ static unsigned int powernow_get(unsigned int cpu) ...@@ -574,14 +566,10 @@ static unsigned int powernow_get(unsigned int cpu)
static int acer_cpufreq_pst(const struct dmi_system_id *d) static int acer_cpufreq_pst(const struct dmi_system_id *d)
{ {
printk(KERN_WARNING PFX pr_warn("%s laptop with broken PST tables in BIOS detected\n",
"%s laptop with broken PST tables in BIOS detected.\n",
d->ident); d->ident);
printk(KERN_WARNING PFX pr_warn("You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
"You need to downgrade to 3A21 (09/09/2002), or try a newer " pr_warn("cpufreq scaling has been disabled as a result of this\n");
"BIOS than 3A71 (01/20/2003)\n");
printk(KERN_WARNING PFX
"cpufreq scaling has been disabled as a result of this.\n");
return 0; return 0;
} }
...@@ -616,40 +604,38 @@ static int powernow_cpu_init(struct cpufreq_policy *policy) ...@@ -616,40 +604,38 @@ static int powernow_cpu_init(struct cpufreq_policy *policy)
fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
if (!fsb) { if (!fsb) {
printk(KERN_WARNING PFX "can not determine bus frequency\n"); pr_warn("can not determine bus frequency\n");
return -EINVAL; return -EINVAL;
} }
pr_debug("FSB: %3dMHz\n", fsb/1000); pr_debug("FSB: %3dMHz\n", fsb/1000);
if (dmi_check_system(powernow_dmi_table) || acpi_force) { if (dmi_check_system(powernow_dmi_table) || acpi_force) {
printk(KERN_INFO PFX "PSB/PST known to be broken. " pr_info("PSB/PST known to be broken - trying ACPI instead\n");
"Trying ACPI instead\n");
result = powernow_acpi_init(); result = powernow_acpi_init();
} else { } else {
result = powernow_decode_bios(fidvidstatus.bits.MFID, result = powernow_decode_bios(fidvidstatus.bits.MFID,
fidvidstatus.bits.SVID); fidvidstatus.bits.SVID);
if (result) { if (result) {
printk(KERN_INFO PFX "Trying ACPI perflib\n"); pr_info("Trying ACPI perflib\n");
maximum_speed = 0; maximum_speed = 0;
minimum_speed = -1; minimum_speed = -1;
latency = 0; latency = 0;
result = powernow_acpi_init(); result = powernow_acpi_init();
if (result) { if (result) {
printk(KERN_INFO PFX pr_info("ACPI and legacy methods failed\n");
"ACPI and legacy methods failed\n");
} }
} else { } else {
/* SGTC use the bus clock as timer */ /* SGTC use the bus clock as timer */
latency = fixup_sgtc(); latency = fixup_sgtc();
printk(KERN_INFO PFX "SGTC: %d\n", latency); pr_info("SGTC: %d\n", latency);
} }
} }
if (result) if (result)
return result; return result;
printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", pr_info("Minimum speed %d MHz - Maximum speed %d MHz\n",
minimum_speed/1000, maximum_speed/1000); minimum_speed/1000, maximum_speed/1000);
policy->cpuinfo.transition_latency = policy->cpuinfo.transition_latency =
cpufreq_scale(2000000UL, fsb, latency); cpufreq_scale(2000000UL, fsb, latency);
......
...@@ -36,12 +36,56 @@ ...@@ -36,12 +36,56 @@
#include <asm/reg.h> #include <asm/reg.h>
#include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */ #include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */
#include <asm/opal.h> #include <asm/opal.h>
#include <linux/timer.h>
#define POWERNV_MAX_PSTATES 256 #define POWERNV_MAX_PSTATES 256
#define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_PSAFE_ENABLE (1UL << 30)
#define PMSR_SPR_EM_DISABLE (1UL << 31) #define PMSR_SPR_EM_DISABLE (1UL << 31)
#define PMSR_MAX(x) ((x >> 32) & 0xFF) #define PMSR_MAX(x) ((x >> 32) & 0xFF)
#define MAX_RAMP_DOWN_TIME 5120
/*
* On an idle system we want the global pstate to ramp-down from max value to
* min over a span of ~5 secs. Also we want it to initially ramp-down slowly and
* then ramp-down rapidly later on.
*
* This gives a percentage rampdown for time elapsed in milliseconds.
* ramp_down_percentage = ((ms * ms) >> 18)
* ~= 3.8 * (sec * sec)
*
* At 0 ms ramp_down_percent = 0
* At 5120 ms ramp_down_percent = 100
*/
#define ramp_down_percent(time) ((time * time) >> 18)
/* Interval after which the timer is queued to bring down global pstate */
#define GPSTATE_TIMER_INTERVAL 2000
/**
* struct global_pstate_info - Per policy data structure to maintain history of
* global pstates
* @highest_lpstate: The local pstate from which we are ramping down
* @elapsed_time: Time in ms spent in ramping down from
* highest_lpstate
* @last_sampled_time: Time from boot in ms when global pstates were
* last set
* @last_lpstate,last_gpstate: Last set values for local and global pstates
* @timer: Is used for ramping down if cpu goes idle for
* a long time with global pstate held high
* @gpstate_lock: A spinlock to maintain synchronization between
* routines called by the timer handler and
* governer's target_index calls
*/
struct global_pstate_info {
int highest_lpstate;
unsigned int elapsed_time;
unsigned int last_sampled_time;
int last_lpstate;
int last_gpstate;
spinlock_t gpstate_lock;
struct timer_list timer;
};
static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
static bool rebooting, throttled, occ_reset; static bool rebooting, throttled, occ_reset;
...@@ -94,6 +138,17 @@ static struct powernv_pstate_info { ...@@ -94,6 +138,17 @@ static struct powernv_pstate_info {
int nr_pstates; int nr_pstates;
} powernv_pstate_info; } powernv_pstate_info;
static inline void reset_gpstates(struct cpufreq_policy *policy)
{
struct global_pstate_info *gpstates = policy->driver_data;
gpstates->highest_lpstate = 0;
gpstates->elapsed_time = 0;
gpstates->last_sampled_time = 0;
gpstates->last_lpstate = 0;
gpstates->last_gpstate = 0;
}
/* /*
* Initialize the freq table based on data obtained * Initialize the freq table based on data obtained
* from the firmware passed via device-tree * from the firmware passed via device-tree
...@@ -285,6 +340,7 @@ static inline void set_pmspr(unsigned long sprn, unsigned long val) ...@@ -285,6 +340,7 @@ static inline void set_pmspr(unsigned long sprn, unsigned long val)
struct powernv_smp_call_data { struct powernv_smp_call_data {
unsigned int freq; unsigned int freq;
int pstate_id; int pstate_id;
int gpstate_id;
}; };
/* /*
...@@ -343,19 +399,21 @@ static unsigned int powernv_cpufreq_get(unsigned int cpu) ...@@ -343,19 +399,21 @@ static unsigned int powernv_cpufreq_get(unsigned int cpu)
* (struct powernv_smp_call_data *) and the pstate_id which needs to be set * (struct powernv_smp_call_data *) and the pstate_id which needs to be set
* on this CPU should be present in freq_data->pstate_id. * on this CPU should be present in freq_data->pstate_id.
*/ */
static void set_pstate(void *freq_data) static void set_pstate(void *data)
{ {
unsigned long val; unsigned long val;
unsigned long pstate_ul = struct powernv_smp_call_data *freq_data = data;
((struct powernv_smp_call_data *) freq_data)->pstate_id; unsigned long pstate_ul = freq_data->pstate_id;
unsigned long gpstate_ul = freq_data->gpstate_id;
val = get_pmspr(SPRN_PMCR); val = get_pmspr(SPRN_PMCR);
val = val & 0x0000FFFFFFFFFFFFULL; val = val & 0x0000FFFFFFFFFFFFULL;
pstate_ul = pstate_ul & 0xFF; pstate_ul = pstate_ul & 0xFF;
gpstate_ul = gpstate_ul & 0xFF;
/* Set both global(bits 56..63) and local(bits 48..55) PStates */ /* Set both global(bits 56..63) and local(bits 48..55) PStates */
val = val | (pstate_ul << 56) | (pstate_ul << 48); val = val | (gpstate_ul << 56) | (pstate_ul << 48);
pr_debug("Setting cpu %d pmcr to %016lX\n", pr_debug("Setting cpu %d pmcr to %016lX\n",
raw_smp_processor_id(), val); raw_smp_processor_id(), val);
...@@ -424,6 +482,111 @@ static void powernv_cpufreq_throttle_check(void *data) ...@@ -424,6 +482,111 @@ static void powernv_cpufreq_throttle_check(void *data)
} }
} }
/**
* calc_global_pstate - Calculate global pstate
* @elapsed_time: Elapsed time in milliseconds
* @local_pstate: New local pstate
* @highest_lpstate: pstate from which its ramping down
*
* Finds the appropriate global pstate based on the pstate from which its
* ramping down and the time elapsed in ramping down. It follows a quadratic
* equation which ensures that it reaches ramping down to pmin in 5sec.
*/
static inline int calc_global_pstate(unsigned int elapsed_time,
int highest_lpstate, int local_pstate)
{
int pstate_diff;
/*
* Using ramp_down_percent we get the percentage of rampdown
* that we are expecting to be dropping. Difference between
* highest_lpstate and powernv_pstate_info.min will give a absolute
* number of how many pstates we will drop eventually by the end of
* 5 seconds, then just scale it get the number pstates to be dropped.
*/
pstate_diff = ((int)ramp_down_percent(elapsed_time) *
(highest_lpstate - powernv_pstate_info.min)) / 100;
/* Ensure that global pstate is >= to local pstate */
if (highest_lpstate - pstate_diff < local_pstate)
return local_pstate;
else
return highest_lpstate - pstate_diff;
}
static inline void queue_gpstate_timer(struct global_pstate_info *gpstates)
{
unsigned int timer_interval;
/*
* Setting up timer to fire after GPSTATE_TIMER_INTERVAL ms, But
* if it exceeds MAX_RAMP_DOWN_TIME ms for ramp down time.
* Set timer such that it fires exactly at MAX_RAMP_DOWN_TIME
* seconds of ramp down time.
*/
if ((gpstates->elapsed_time + GPSTATE_TIMER_INTERVAL)
> MAX_RAMP_DOWN_TIME)
timer_interval = MAX_RAMP_DOWN_TIME - gpstates->elapsed_time;
else
timer_interval = GPSTATE_TIMER_INTERVAL;
mod_timer_pinned(&gpstates->timer, jiffies +
msecs_to_jiffies(timer_interval));
}
/**
* gpstate_timer_handler
*
* @data: pointer to cpufreq_policy on which timer was queued
*
* This handler brings down the global pstate closer to the local pstate
* according quadratic equation. Queues a new timer if it is still not equal
* to local pstate
*/
void gpstate_timer_handler(unsigned long data)
{
struct cpufreq_policy *policy = (struct cpufreq_policy *)data;
struct global_pstate_info *gpstates = policy->driver_data;
int gpstate_id;
unsigned int time_diff = jiffies_to_msecs(jiffies)
- gpstates->last_sampled_time;
struct powernv_smp_call_data freq_data;
if (!spin_trylock(&gpstates->gpstate_lock))
return;
gpstates->last_sampled_time += time_diff;
gpstates->elapsed_time += time_diff;
freq_data.pstate_id = gpstates->last_lpstate;
if ((gpstates->last_gpstate == freq_data.pstate_id) ||
(gpstates->elapsed_time > MAX_RAMP_DOWN_TIME)) {
gpstate_id = freq_data.pstate_id;
reset_gpstates(policy);
gpstates->highest_lpstate = freq_data.pstate_id;
} else {
gpstate_id = calc_global_pstate(gpstates->elapsed_time,
gpstates->highest_lpstate,
freq_data.pstate_id);
}
/*
* If local pstate is equal to global pstate, rampdown is over
* So timer is not required to be queued.
*/
if (gpstate_id != freq_data.pstate_id)
queue_gpstate_timer(gpstates);
freq_data.gpstate_id = gpstate_id;
gpstates->last_gpstate = freq_data.gpstate_id;
gpstates->last_lpstate = freq_data.pstate_id;
spin_unlock(&gpstates->gpstate_lock);
/* Timer may get migrated to a different cpu on cpu hot unplug */
smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1);
}
/* /*
* powernv_cpufreq_target_index: Sets the frequency corresponding to * powernv_cpufreq_target_index: Sets the frequency corresponding to
* the cpufreq table entry indexed by new_index on the cpus in the * the cpufreq table entry indexed by new_index on the cpus in the
...@@ -433,6 +596,8 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, ...@@ -433,6 +596,8 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
unsigned int new_index) unsigned int new_index)
{ {
struct powernv_smp_call_data freq_data; struct powernv_smp_call_data freq_data;
unsigned int cur_msec, gpstate_id;
struct global_pstate_info *gpstates = policy->driver_data;
if (unlikely(rebooting) && new_index != get_nominal_index()) if (unlikely(rebooting) && new_index != get_nominal_index())
return 0; return 0;
...@@ -440,28 +605,81 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, ...@@ -440,28 +605,81 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
if (!throttled) if (!throttled)
powernv_cpufreq_throttle_check(NULL); powernv_cpufreq_throttle_check(NULL);
cur_msec = jiffies_to_msecs(get_jiffies_64());
spin_lock(&gpstates->gpstate_lock);
freq_data.pstate_id = powernv_freqs[new_index].driver_data; freq_data.pstate_id = powernv_freqs[new_index].driver_data;
if (!gpstates->last_sampled_time) {
gpstate_id = freq_data.pstate_id;
gpstates->highest_lpstate = freq_data.pstate_id;
goto gpstates_done;
}
if (gpstates->last_gpstate > freq_data.pstate_id) {
gpstates->elapsed_time += cur_msec -
gpstates->last_sampled_time;
/*
* If its has been ramping down for more than MAX_RAMP_DOWN_TIME
* we should be resetting all global pstate related data. Set it
* equal to local pstate to start fresh.
*/
if (gpstates->elapsed_time > MAX_RAMP_DOWN_TIME) {
reset_gpstates(policy);
gpstates->highest_lpstate = freq_data.pstate_id;
gpstate_id = freq_data.pstate_id;
} else {
/* Elaspsed_time is less than 5 seconds, continue to rampdown */
gpstate_id = calc_global_pstate(gpstates->elapsed_time,
gpstates->highest_lpstate,
freq_data.pstate_id);
}
} else {
reset_gpstates(policy);
gpstates->highest_lpstate = freq_data.pstate_id;
gpstate_id = freq_data.pstate_id;
}
/*
* If local pstate is equal to global pstate, rampdown is over
* So timer is not required to be queued.
*/
if (gpstate_id != freq_data.pstate_id)
queue_gpstate_timer(gpstates);
else
del_timer_sync(&gpstates->timer);
gpstates_done:
freq_data.gpstate_id = gpstate_id;
gpstates->last_sampled_time = cur_msec;
gpstates->last_gpstate = freq_data.gpstate_id;
gpstates->last_lpstate = freq_data.pstate_id;
spin_unlock(&gpstates->gpstate_lock);
/* /*
* Use smp_call_function to send IPI and execute the * Use smp_call_function to send IPI and execute the
* mtspr on target CPU. We could do that without IPI * mtspr on target CPU. We could do that without IPI
* if current CPU is within policy->cpus (core) * if current CPU is within policy->cpus (core)
*/ */
smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1); smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1);
return 0; return 0;
} }
static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
{ {
int base, i; int base, i, ret;
struct kernfs_node *kn;
struct global_pstate_info *gpstates;
base = cpu_first_thread_sibling(policy->cpu); base = cpu_first_thread_sibling(policy->cpu);
for (i = 0; i < threads_per_core; i++) for (i = 0; i < threads_per_core; i++)
cpumask_set_cpu(base + i, policy->cpus); cpumask_set_cpu(base + i, policy->cpus);
if (!policy->driver_data) { kn = kernfs_find_and_get(policy->kobj.sd, throttle_attr_grp.name);
if (!kn) {
int ret; int ret;
ret = sysfs_create_group(&policy->kobj, &throttle_attr_grp); ret = sysfs_create_group(&policy->kobj, &throttle_attr_grp);
...@@ -470,13 +688,37 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -470,13 +688,37 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpu); policy->cpu);
return ret; return ret;
} }
/* } else {
* policy->driver_data is used as a flag for one-time kernfs_put(kn);
* creation of throttle sysfs files.
*/
policy->driver_data = policy;
} }
return cpufreq_table_validate_and_show(policy, powernv_freqs);
gpstates = kzalloc(sizeof(*gpstates), GFP_KERNEL);
if (!gpstates)
return -ENOMEM;
policy->driver_data = gpstates;
/* initialize timer */
init_timer_deferrable(&gpstates->timer);
gpstates->timer.data = (unsigned long)policy;
gpstates->timer.function = gpstate_timer_handler;
gpstates->timer.expires = jiffies +
msecs_to_jiffies(GPSTATE_TIMER_INTERVAL);
spin_lock_init(&gpstates->gpstate_lock);
ret = cpufreq_table_validate_and_show(policy, powernv_freqs);
if (ret < 0)
kfree(policy->driver_data);
return ret;
}
static int powernv_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
/* timer is deleted in cpufreq_cpu_stop() */
kfree(policy->driver_data);
return 0;
} }
static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb, static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb,
...@@ -604,15 +846,19 @@ static struct notifier_block powernv_cpufreq_opal_nb = { ...@@ -604,15 +846,19 @@ static struct notifier_block powernv_cpufreq_opal_nb = {
static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy) static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
{ {
struct powernv_smp_call_data freq_data; struct powernv_smp_call_data freq_data;
struct global_pstate_info *gpstates = policy->driver_data;
freq_data.pstate_id = powernv_pstate_info.min; freq_data.pstate_id = powernv_pstate_info.min;
freq_data.gpstate_id = powernv_pstate_info.min;
smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1); smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
del_timer_sync(&gpstates->timer);
} }
static struct cpufreq_driver powernv_cpufreq_driver = { static struct cpufreq_driver powernv_cpufreq_driver = {
.name = "powernv-cpufreq", .name = "powernv-cpufreq",
.flags = CPUFREQ_CONST_LOOPS, .flags = CPUFREQ_CONST_LOOPS,
.init = powernv_cpufreq_cpu_init, .init = powernv_cpufreq_cpu_init,
.exit = powernv_cpufreq_cpu_exit,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = powernv_cpufreq_target_index, .target_index = powernv_cpufreq_target_index,
.get = powernv_cpufreq_get, .get = powernv_cpufreq_get,
......
...@@ -17,7 +17,7 @@ int cbe_cpufreq_get_pmode(int cpu); ...@@ -17,7 +17,7 @@ int cbe_cpufreq_get_pmode(int cpu);
int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode); int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode);
#if defined(CONFIG_CPU_FREQ_CBE_PMI) || defined(CONFIG_CPU_FREQ_CBE_PMI_MODULE) #if IS_ENABLED(CONFIG_CPU_FREQ_CBE_PMI)
extern bool cbe_cpufreq_has_pmi; extern bool cbe_cpufreq_has_pmi;
#else #else
#define cbe_cpufreq_has_pmi (0) #define cbe_cpufreq_has_pmi (0)
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/module.h> #include <linux/init.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -142,15 +142,4 @@ static int __init cbe_cpufreq_pmi_init(void) ...@@ -142,15 +142,4 @@ static int __init cbe_cpufreq_pmi_init(void)
return 0; return 0;
} }
device_initcall(cbe_cpufreq_pmi_init);
static void __exit cbe_cpufreq_pmi_exit(void)
{
cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
pmi_unregister_handler(&cbe_pmi_handler);
}
module_init(cbe_cpufreq_pmi_init);
module_exit(cbe_cpufreq_pmi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -186,8 +188,7 @@ static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq) ...@@ -186,8 +188,7 @@ static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq)
ret = regulator_set_voltage(vcc_core, vmin, vmax); ret = regulator_set_voltage(vcc_core, vmin, vmax);
if (ret) if (ret)
pr_err("cpufreq: Failed to set vcc_core in [%dmV..%dmV]\n", pr_err("Failed to set vcc_core in [%dmV..%dmV]\n", vmin, vmax);
vmin, vmax);
return ret; return ret;
} }
...@@ -195,10 +196,10 @@ static void __init pxa_cpufreq_init_voltages(void) ...@@ -195,10 +196,10 @@ static void __init pxa_cpufreq_init_voltages(void)
{ {
vcc_core = regulator_get(NULL, "vcc_core"); vcc_core = regulator_get(NULL, "vcc_core");
if (IS_ERR(vcc_core)) { if (IS_ERR(vcc_core)) {
pr_info("cpufreq: Didn't find vcc_core regulator\n"); pr_info("Didn't find vcc_core regulator\n");
vcc_core = NULL; vcc_core = NULL;
} else { } else {
pr_info("cpufreq: Found vcc_core regulator\n"); pr_info("Found vcc_core regulator\n");
} }
} }
#else #else
...@@ -233,9 +234,8 @@ static void pxa27x_guess_max_freq(void) ...@@ -233,9 +234,8 @@ static void pxa27x_guess_max_freq(void)
{ {
if (!pxa27x_maxfreq) { if (!pxa27x_maxfreq) {
pxa27x_maxfreq = 416000; pxa27x_maxfreq = 416000;
printk(KERN_INFO "PXA CPU 27x max frequency not defined " pr_info("PXA CPU 27x max frequency not defined (pxa27x_maxfreq), assuming pxa271 with %dkHz maxfreq\n",
"(pxa27x_maxfreq), assuming pxa271 with %dkHz maxfreq\n", pxa27x_maxfreq);
pxa27x_maxfreq);
} else { } else {
pxa27x_maxfreq *= 1000; pxa27x_maxfreq *= 1000;
} }
...@@ -408,7 +408,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) ...@@ -408,7 +408,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
*/ */
if (cpu_is_pxa25x()) { if (cpu_is_pxa25x()) {
find_freq_tables(&pxa255_freq_table, &pxa255_freqs); find_freq_tables(&pxa255_freq_table, &pxa255_freqs);
pr_info("PXA255 cpufreq using %s frequency table\n", pr_info("using %s frequency table\n",
pxa255_turbo_table ? "turbo" : "run"); pxa255_turbo_table ? "turbo" : "run");
cpufreq_table_validate_and_show(policy, pxa255_freq_table); cpufreq_table_validate_and_show(policy, pxa255_freq_table);
...@@ -417,7 +417,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) ...@@ -417,7 +417,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
cpufreq_table_validate_and_show(policy, pxa27x_freq_table); cpufreq_table_validate_and_show(policy, pxa27x_freq_table);
} }
printk(KERN_INFO "PXA CPU frequency change support initialized\n"); pr_info("frequency change support initialized\n");
return 0; return 0;
} }
......
...@@ -301,10 +301,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -301,10 +301,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
return -ENODEV; return -ENODEV;
} }
static int __exit qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy) static int qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{ {
struct cpu_data *data = policy->driver_data; struct cpu_data *data = policy->driver_data;
cpufreq_cooling_unregister(data->cdev);
kfree(data->pclk); kfree(data->pclk);
kfree(data->table); kfree(data->table);
kfree(data); kfree(data);
...@@ -333,8 +334,8 @@ static void qoriq_cpufreq_ready(struct cpufreq_policy *policy) ...@@ -333,8 +334,8 @@ static void qoriq_cpufreq_ready(struct cpufreq_policy *policy)
cpud->cdev = of_cpufreq_cooling_register(np, cpud->cdev = of_cpufreq_cooling_register(np,
policy->related_cpus); policy->related_cpus);
if (IS_ERR(cpud->cdev)) { if (IS_ERR(cpud->cdev) && PTR_ERR(cpud->cdev) != -ENOSYS) {
pr_err("Failed to register cooling device cpu%d: %ld\n", pr_err("cpu%d is not running as cooling device: %ld\n",
policy->cpu, PTR_ERR(cpud->cdev)); policy->cpu, PTR_ERR(cpud->cdev));
cpud->cdev = NULL; cpud->cdev = NULL;
...@@ -348,7 +349,7 @@ static struct cpufreq_driver qoriq_cpufreq_driver = { ...@@ -348,7 +349,7 @@ static struct cpufreq_driver qoriq_cpufreq_driver = {
.name = "qoriq_cpufreq", .name = "qoriq_cpufreq",
.flags = CPUFREQ_CONST_LOOPS, .flags = CPUFREQ_CONST_LOOPS,
.init = qoriq_cpufreq_cpu_init, .init = qoriq_cpufreq_cpu_init,
.exit = __exit_p(qoriq_cpufreq_cpu_exit), .exit = qoriq_cpufreq_cpu_exit,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = qoriq_cpufreq_target, .target_index = qoriq_cpufreq_target,
.get = cpufreq_generic_get, .get = cpufreq_generic_get,
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -197,21 +199,20 @@ static int s3c2412_cpufreq_add(struct device *dev, ...@@ -197,21 +199,20 @@ static int s3c2412_cpufreq_add(struct device *dev,
hclk = clk_get(NULL, "hclk"); hclk = clk_get(NULL, "hclk");
if (IS_ERR(hclk)) { if (IS_ERR(hclk)) {
printk(KERN_ERR "%s: cannot find hclk clock\n", __func__); pr_err("cannot find hclk clock\n");
return -ENOENT; return -ENOENT;
} }
fclk = clk_get(NULL, "fclk"); fclk = clk_get(NULL, "fclk");
if (IS_ERR(fclk)) { if (IS_ERR(fclk)) {
printk(KERN_ERR "%s: cannot find fclk clock\n", __func__); pr_err("cannot find fclk clock\n");
goto err_fclk; goto err_fclk;
} }
fclk_rate = clk_get_rate(fclk); fclk_rate = clk_get_rate(fclk);
if (fclk_rate > 200000000) { if (fclk_rate > 200000000) {
printk(KERN_INFO pr_info("fclk %ld MHz, assuming 266MHz capable part\n",
"%s: fclk %ld MHz, assuming 266MHz capable part\n", fclk_rate / 1000000);
__func__, fclk_rate / 1000000);
s3c2412_cpufreq_info.max.fclk = 266000000; s3c2412_cpufreq_info.max.fclk = 266000000;
s3c2412_cpufreq_info.max.hclk = 133000000; s3c2412_cpufreq_info.max.hclk = 133000000;
s3c2412_cpufreq_info.max.pclk = 66000000; s3c2412_cpufreq_info.max.pclk = 66000000;
...@@ -219,13 +220,13 @@ static int s3c2412_cpufreq_add(struct device *dev, ...@@ -219,13 +220,13 @@ static int s3c2412_cpufreq_add(struct device *dev,
armclk = clk_get(NULL, "armclk"); armclk = clk_get(NULL, "armclk");
if (IS_ERR(armclk)) { if (IS_ERR(armclk)) {
printk(KERN_ERR "%s: cannot find arm clock\n", __func__); pr_err("cannot find arm clock\n");
goto err_armclk; goto err_armclk;
} }
xtal = clk_get(NULL, "xtal"); xtal = clk_get(NULL, "xtal");
if (IS_ERR(xtal)) { if (IS_ERR(xtal)) {
printk(KERN_ERR "%s: cannot find xtal clock\n", __func__); pr_err("cannot find xtal clock\n");
goto err_xtal; goto err_xtal;
} }
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -66,7 +68,7 @@ static int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) ...@@ -66,7 +68,7 @@ static int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
__func__, fclk, armclk, hclk_max); __func__, fclk, armclk, hclk_max);
if (armclk > fclk) { if (armclk > fclk) {
printk(KERN_WARNING "%s: armclk > fclk\n", __func__); pr_warn("%s: armclk > fclk\n", __func__);
armclk = fclk; armclk = fclk;
} }
...@@ -273,7 +275,7 @@ static int s3c2440_cpufreq_add(struct device *dev, ...@@ -273,7 +275,7 @@ static int s3c2440_cpufreq_add(struct device *dev,
armclk = s3c_cpufreq_clk_get(NULL, "armclk"); armclk = s3c_cpufreq_clk_get(NULL, "armclk");
if (IS_ERR(xtal) || IS_ERR(hclk) || IS_ERR(fclk) || IS_ERR(armclk)) { if (IS_ERR(xtal) || IS_ERR(hclk) || IS_ERR(fclk) || IS_ERR(armclk)) {
printk(KERN_ERR "%s: failed to get clocks\n", __func__); pr_err("%s: failed to get clocks\n", __func__);
return -ENOENT; return -ENOENT;
} }
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h> #include <linux/init.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -178,7 +180,7 @@ static int __init s3c_freq_debugfs_init(void) ...@@ -178,7 +180,7 @@ static int __init s3c_freq_debugfs_init(void)
{ {
dbgfs_root = debugfs_create_dir("s3c-cpufreq", NULL); dbgfs_root = debugfs_create_dir("s3c-cpufreq", NULL);
if (IS_ERR(dbgfs_root)) { if (IS_ERR(dbgfs_root)) {
printk(KERN_ERR "%s: error creating debugfs root\n", __func__); pr_err("%s: error creating debugfs root\n", __func__);
return PTR_ERR(dbgfs_root); return PTR_ERR(dbgfs_root);
} }
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -175,7 +177,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy, ...@@ -175,7 +177,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
cpu_new.freq.fclk = cpu_new.pll.frequency; cpu_new.freq.fclk = cpu_new.pll.frequency;
if (s3c_cpufreq_calcdivs(&cpu_new) < 0) { if (s3c_cpufreq_calcdivs(&cpu_new) < 0) {
printk(KERN_ERR "no divisors for %d\n", target_freq); pr_err("no divisors for %d\n", target_freq);
goto err_notpossible; goto err_notpossible;
} }
...@@ -187,7 +189,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy, ...@@ -187,7 +189,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
if (cpu_new.freq.hclk != cpu_cur.freq.hclk) { if (cpu_new.freq.hclk != cpu_cur.freq.hclk) {
if (s3c_cpufreq_calcio(&cpu_new) < 0) { if (s3c_cpufreq_calcio(&cpu_new) < 0) {
printk(KERN_ERR "%s: no IO timings\n", __func__); pr_err("%s: no IO timings\n", __func__);
goto err_notpossible; goto err_notpossible;
} }
} }
...@@ -262,7 +264,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy, ...@@ -262,7 +264,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
return 0; return 0;
err_notpossible: err_notpossible:
printk(KERN_ERR "no compatible settings for %d\n", target_freq); pr_err("no compatible settings for %d\n", target_freq);
return -EINVAL; return -EINVAL;
} }
...@@ -331,7 +333,7 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, ...@@ -331,7 +333,7 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy,
&index); &index);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "%s: no PLL available\n", __func__); pr_err("%s: no PLL available\n", __func__);
goto err_notpossible; goto err_notpossible;
} }
...@@ -346,7 +348,7 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, ...@@ -346,7 +348,7 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy,
return s3c_cpufreq_settarget(policy, target_freq, pll); return s3c_cpufreq_settarget(policy, target_freq, pll);
err_notpossible: err_notpossible:
printk(KERN_ERR "no compatible settings for %d\n", target_freq); pr_err("no compatible settings for %d\n", target_freq);
return -EINVAL; return -EINVAL;
} }
...@@ -356,7 +358,7 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) ...@@ -356,7 +358,7 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name)
clk = clk_get(dev, name); clk = clk_get(dev, name);
if (IS_ERR(clk)) if (IS_ERR(clk))
printk(KERN_ERR "cpufreq: failed to get clock '%s'\n", name); pr_err("failed to get clock '%s'\n", name);
return clk; return clk;
} }
...@@ -378,15 +380,16 @@ static int __init s3c_cpufreq_initclks(void) ...@@ -378,15 +380,16 @@ static int __init s3c_cpufreq_initclks(void)
if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) || if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) ||
IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) { IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) {
printk(KERN_ERR "%s: could not get clock(s)\n", __func__); pr_err("%s: could not get clock(s)\n", __func__);
return -ENOENT; return -ENOENT;
} }
printk(KERN_INFO "%s: clocks f=%lu,h=%lu,p=%lu,a=%lu\n", __func__, pr_info("%s: clocks f=%lu,h=%lu,p=%lu,a=%lu\n",
clk_get_rate(clk_fclk) / 1000, __func__,
clk_get_rate(clk_hclk) / 1000, clk_get_rate(clk_fclk) / 1000,
clk_get_rate(clk_pclk) / 1000, clk_get_rate(clk_hclk) / 1000,
clk_get_rate(clk_arm) / 1000); clk_get_rate(clk_pclk) / 1000,
clk_get_rate(clk_arm) / 1000);
return 0; return 0;
} }
...@@ -424,7 +427,7 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy) ...@@ -424,7 +427,7 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy)
ret = s3c_cpufreq_settarget(NULL, suspend_freq, &suspend_pll); ret = s3c_cpufreq_settarget(NULL, suspend_freq, &suspend_pll);
if (ret) { if (ret) {
printk(KERN_ERR "%s: failed to reset pll/freq\n", __func__); pr_err("%s: failed to reset pll/freq\n", __func__);
return ret; return ret;
} }
...@@ -449,13 +452,12 @@ static struct cpufreq_driver s3c24xx_driver = { ...@@ -449,13 +452,12 @@ static struct cpufreq_driver s3c24xx_driver = {
int s3c_cpufreq_register(struct s3c_cpufreq_info *info) int s3c_cpufreq_register(struct s3c_cpufreq_info *info)
{ {
if (!info || !info->name) { if (!info || !info->name) {
printk(KERN_ERR "%s: failed to pass valid information\n", pr_err("%s: failed to pass valid information\n", __func__);
__func__);
return -EINVAL; return -EINVAL;
} }
printk(KERN_INFO "S3C24XX CPU Frequency driver, %s cpu support\n", pr_info("S3C24XX CPU Frequency driver, %s cpu support\n",
info->name); info->name);
/* check our driver info has valid data */ /* check our driver info has valid data */
...@@ -478,7 +480,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) ...@@ -478,7 +480,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
struct s3c_cpufreq_board *ours; struct s3c_cpufreq_board *ours;
if (!board) { if (!board) {
printk(KERN_INFO "%s: no board data\n", __func__); pr_info("%s: no board data\n", __func__);
return -EINVAL; return -EINVAL;
} }
...@@ -487,7 +489,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) ...@@ -487,7 +489,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
ours = kzalloc(sizeof(*ours), GFP_KERNEL); ours = kzalloc(sizeof(*ours), GFP_KERNEL);
if (ours == NULL) { if (ours == NULL) {
printk(KERN_ERR "%s: no memory\n", __func__); pr_err("%s: no memory\n", __func__);
return -ENOMEM; return -ENOMEM;
} }
...@@ -502,15 +504,15 @@ static int __init s3c_cpufreq_auto_io(void) ...@@ -502,15 +504,15 @@ static int __init s3c_cpufreq_auto_io(void)
int ret; int ret;
if (!cpu_cur.info->get_iotiming) { if (!cpu_cur.info->get_iotiming) {
printk(KERN_ERR "%s: get_iotiming undefined\n", __func__); pr_err("%s: get_iotiming undefined\n", __func__);
return -ENOENT; return -ENOENT;
} }
printk(KERN_INFO "%s: working out IO settings\n", __func__); pr_info("%s: working out IO settings\n", __func__);
ret = (cpu_cur.info->get_iotiming)(&cpu_cur, &s3c24xx_iotiming); ret = (cpu_cur.info->get_iotiming)(&cpu_cur, &s3c24xx_iotiming);
if (ret) if (ret)
printk(KERN_ERR "%s: failed to get timings\n", __func__); pr_err("%s: failed to get timings\n", __func__);
return ret; return ret;
} }
...@@ -561,7 +563,7 @@ static void s3c_cpufreq_update_loctkime(void) ...@@ -561,7 +563,7 @@ static void s3c_cpufreq_update_loctkime(void)
val = calc_locktime(rate, cpu_cur.info->locktime_u) << bits; val = calc_locktime(rate, cpu_cur.info->locktime_u) << bits;
val |= calc_locktime(rate, cpu_cur.info->locktime_m); val |= calc_locktime(rate, cpu_cur.info->locktime_m);
printk(KERN_INFO "%s: new locktime is 0x%08x\n", __func__, val); pr_info("%s: new locktime is 0x%08x\n", __func__, val);
__raw_writel(val, S3C2410_LOCKTIME); __raw_writel(val, S3C2410_LOCKTIME);
} }
...@@ -580,7 +582,7 @@ static int s3c_cpufreq_build_freq(void) ...@@ -580,7 +582,7 @@ static int s3c_cpufreq_build_freq(void)
ftab = kzalloc(sizeof(*ftab) * size, GFP_KERNEL); ftab = kzalloc(sizeof(*ftab) * size, GFP_KERNEL);
if (!ftab) { if (!ftab) {
printk(KERN_ERR "%s: no memory for tables\n", __func__); pr_err("%s: no memory for tables\n", __func__);
return -ENOMEM; return -ENOMEM;
} }
...@@ -608,15 +610,14 @@ static int __init s3c_cpufreq_initcall(void) ...@@ -608,15 +610,14 @@ static int __init s3c_cpufreq_initcall(void)
if (cpu_cur.board->auto_io) { if (cpu_cur.board->auto_io) {
ret = s3c_cpufreq_auto_io(); ret = s3c_cpufreq_auto_io();
if (ret) { if (ret) {
printk(KERN_ERR "%s: failed to get io timing\n", pr_err("%s: failed to get io timing\n",
__func__); __func__);
goto out; goto out;
} }
} }
if (cpu_cur.board->need_io && !cpu_cur.info->set_iotiming) { if (cpu_cur.board->need_io && !cpu_cur.info->set_iotiming) {
printk(KERN_ERR "%s: no IO support registered\n", pr_err("%s: no IO support registered\n", __func__);
__func__);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
...@@ -666,9 +667,9 @@ int s3c_plltab_register(struct cpufreq_frequency_table *plls, ...@@ -666,9 +667,9 @@ int s3c_plltab_register(struct cpufreq_frequency_table *plls,
vals += plls_no; vals += plls_no;
vals->frequency = CPUFREQ_TABLE_END; vals->frequency = CPUFREQ_TABLE_END;
printk(KERN_INFO "cpufreq: %d PLL entries\n", plls_no); pr_info("%d PLL entries\n", plls_no);
} else } else
printk(KERN_ERR "cpufreq: no memory for PLL tables\n"); pr_err("no memory for PLL tables\n");
return vals ? 0 : -ENOMEM; return vals ? 0 : -ENOMEM;
} }
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -205,7 +207,7 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) ...@@ -205,7 +207,7 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
} else if (ch == DMC1) { } else if (ch == DMC1) {
reg = (dmc_base[1] + 0x30); reg = (dmc_base[1] + 0x30);
} else { } else {
printk(KERN_ERR "Cannot find DMC port\n"); pr_err("Cannot find DMC port\n");
return; return;
} }
...@@ -534,7 +536,7 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy) ...@@ -534,7 +536,7 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
mem_type = check_mem_type(dmc_base[0]); mem_type = check_mem_type(dmc_base[0]);
if ((mem_type != LPDDR) && (mem_type != LPDDR2)) { if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
printk(KERN_ERR "CPUFreq doesn't support this memory type\n"); pr_err("CPUFreq doesn't support this memory type\n");
ret = -EINVAL; ret = -EINVAL;
goto out_dmc1; goto out_dmc1;
} }
...@@ -635,13 +637,13 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) ...@@ -635,13 +637,13 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
arm_regulator = regulator_get(NULL, "vddarm"); arm_regulator = regulator_get(NULL, "vddarm");
if (IS_ERR(arm_regulator)) { if (IS_ERR(arm_regulator)) {
pr_err("failed to get regulator vddarm"); pr_err("failed to get regulator vddarm\n");
return PTR_ERR(arm_regulator); return PTR_ERR(arm_regulator);
} }
int_regulator = regulator_get(NULL, "vddint"); int_regulator = regulator_get(NULL, "vddint");
if (IS_ERR(int_regulator)) { if (IS_ERR(int_regulator)) {
pr_err("failed to get regulator vddint"); pr_err("failed to get regulator vddint\n");
regulator_put(arm_regulator); regulator_put(arm_regulator);
return PTR_ERR(int_regulator); return PTR_ERR(int_regulator);
} }
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* 2005-03-30: - initial revision * 2005-03-30: - initial revision
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -30,8 +32,6 @@ ...@@ -30,8 +32,6 @@
static __u8 __iomem *cpuctl; static __u8 __iomem *cpuctl;
#define PFX "sc520_freq: "
static struct cpufreq_frequency_table sc520_freq_table[] = { static struct cpufreq_frequency_table sc520_freq_table[] = {
{0, 0x01, 100000}, {0, 0x01, 100000},
{0, 0x02, 133000}, {0, 0x02, 133000},
...@@ -44,8 +44,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) ...@@ -44,8 +44,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
switch (clockspeed_reg & 0x03) { switch (clockspeed_reg & 0x03) {
default: default:
printk(KERN_ERR PFX "error: cpuctl register has unexpected " pr_err("error: cpuctl register has unexpected value %02x\n",
"value %02x\n", clockspeed_reg); clockspeed_reg);
case 0x01: case 0x01:
return 100000; return 100000;
case 0x02: case 0x02:
...@@ -112,7 +112,7 @@ static int __init sc520_freq_init(void) ...@@ -112,7 +112,7 @@ static int __init sc520_freq_init(void)
cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
if (!cpuctl) { if (!cpuctl) {
printk(KERN_ERR "sc520_freq: error: failed to remap memory\n"); pr_err("sc520_freq: error: failed to remap memory\n");
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpu.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -38,10 +39,20 @@ static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev) ...@@ -38,10 +39,20 @@ static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
return scpi_ops->dvfs_get_info(domain); return scpi_ops->dvfs_get_info(domain);
} }
static int scpi_opp_table_ops(struct device *cpu_dev, bool remove) static int scpi_get_transition_latency(struct device *cpu_dev)
{ {
int idx, ret = 0; struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
if (IS_ERR(info))
return PTR_ERR(info);
return info->latency;
}
static int scpi_init_opp_table(const struct cpumask *cpumask)
{
int idx, ret;
struct scpi_opp *opp; struct scpi_opp *opp;
struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask));
struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev); struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
if (IS_ERR(info)) if (IS_ERR(info))
...@@ -51,11 +62,7 @@ static int scpi_opp_table_ops(struct device *cpu_dev, bool remove) ...@@ -51,11 +62,7 @@ static int scpi_opp_table_ops(struct device *cpu_dev, bool remove)
return -EIO; return -EIO;
for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) { for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
if (remove) ret = dev_pm_opp_add(cpu_dev, opp->freq, opp->m_volt * 1000);
dev_pm_opp_remove(cpu_dev, opp->freq);
else
ret = dev_pm_opp_add(cpu_dev, opp->freq,
opp->m_volt * 1000);
if (ret) { if (ret) {
dev_warn(cpu_dev, "failed to add opp %uHz %umV\n", dev_warn(cpu_dev, "failed to add opp %uHz %umV\n",
opp->freq, opp->m_volt); opp->freq, opp->m_volt);
...@@ -64,33 +71,19 @@ static int scpi_opp_table_ops(struct device *cpu_dev, bool remove) ...@@ -64,33 +71,19 @@ static int scpi_opp_table_ops(struct device *cpu_dev, bool remove)
return ret; return ret;
} }
} }
return ret;
}
static int scpi_get_transition_latency(struct device *cpu_dev) ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask);
{ if (ret)
struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev); dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
__func__, ret);
if (IS_ERR(info)) return ret;
return PTR_ERR(info);
return info->latency;
}
static int scpi_init_opp_table(struct device *cpu_dev)
{
return scpi_opp_table_ops(cpu_dev, false);
}
static void scpi_free_opp_table(struct device *cpu_dev)
{
scpi_opp_table_ops(cpu_dev, true);
} }
static struct cpufreq_arm_bL_ops scpi_cpufreq_ops = { static struct cpufreq_arm_bL_ops scpi_cpufreq_ops = {
.name = "scpi", .name = "scpi",
.get_transition_latency = scpi_get_transition_latency, .get_transition_latency = scpi_get_transition_latency,
.init_opp_table = scpi_init_opp_table, .init_opp_table = scpi_init_opp_table,
.free_opp_table = scpi_free_opp_table, .free_opp_table = dev_pm_opp_cpumask_remove_table,
}; };
static int scpi_cpufreq_probe(struct platform_device *pdev) static int scpi_cpufreq_probe(struct platform_device *pdev)
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org> * Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org>
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -27,7 +29,6 @@ ...@@ -27,7 +29,6 @@
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
#define PFX "speedstep-centrino: "
#define MAINTAINER "linux-pm@vger.kernel.org" #define MAINTAINER "linux-pm@vger.kernel.org"
#define INTEL_MSR_RANGE (0xffff) #define INTEL_MSR_RANGE (0xffff)
...@@ -386,8 +387,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -386,8 +387,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
/* check to see if it stuck */ /* check to see if it stuck */
rdmsr(MSR_IA32_MISC_ENABLE, l, h); rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) {
printk(KERN_INFO PFX pr_info("couldn't enable Enhanced SpeedStep\n");
"couldn't enable Enhanced SpeedStep\n");
return -ENODEV; return -ENODEV;
} }
} }
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
* SPEEDSTEP - DEFINITIONS * * SPEEDSTEP - DEFINITIONS *
*********************************************************************/ *********************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -68,13 +70,13 @@ static int speedstep_find_register(void) ...@@ -68,13 +70,13 @@ static int speedstep_find_register(void)
/* get PMBASE */ /* get PMBASE */
pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
if (!(pmbase & 0x01)) { if (!(pmbase & 0x01)) {
printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); pr_err("could not find speedstep register\n");
return -ENODEV; return -ENODEV;
} }
pmbase &= 0xFFFFFFFE; pmbase &= 0xFFFFFFFE;
if (!pmbase) { if (!pmbase) {
printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); pr_err("could not find speedstep register\n");
return -ENODEV; return -ENODEV;
} }
...@@ -136,7 +138,7 @@ static void speedstep_set_state(unsigned int state) ...@@ -136,7 +138,7 @@ static void speedstep_set_state(unsigned int state)
pr_debug("change to %u MHz succeeded\n", pr_debug("change to %u MHz succeeded\n",
speedstep_get_frequency(speedstep_processor) / 1000); speedstep_get_frequency(speedstep_processor) / 1000);
else else
printk(KERN_ERR "cpufreq: change failed - I/O error\n"); pr_err("change failed - I/O error\n");
return; return;
} }
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -153,7 +155,7 @@ static unsigned int pentium_core_get_frequency(void) ...@@ -153,7 +155,7 @@ static unsigned int pentium_core_get_frequency(void)
fsb = 333333; fsb = 333333;
break; break;
default: default:
printk(KERN_ERR "PCORE - MSR_FSB_FREQ undefined value"); pr_err("PCORE - MSR_FSB_FREQ undefined value\n");
} }
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
...@@ -453,11 +455,8 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, ...@@ -453,11 +455,8 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
*/ */
if (*transition_latency > 10000000 || if (*transition_latency > 10000000 ||
*transition_latency < 50000) { *transition_latency < 50000) {
printk(KERN_WARNING PFX "frequency transition " pr_warn("frequency transition measured seems out of range (%u nSec), falling back to a safe one of %u nSec\n",
"measured seems out of range (%u " *transition_latency, 500000);
"nSec), falling back to a safe one of"
"%u nSec.\n",
*transition_latency, 500000);
*transition_latency = 500000; *transition_latency = 500000;
} }
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
* SPEEDSTEP - DEFINITIONS * * SPEEDSTEP - DEFINITIONS *
*********************************************************************/ *********************************************************************/
#define pr_fmt(fmt) "cpufreq: " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -204,9 +206,8 @@ static void speedstep_set_state(unsigned int state) ...@@ -204,9 +206,8 @@ static void speedstep_set_state(unsigned int state)
(speedstep_freqs[new_state].frequency / 1000), (speedstep_freqs[new_state].frequency / 1000),
retry, result); retry, result);
else else
printk(KERN_ERR "cpufreq: change to state %u " pr_err("change to state %u failed with new_state %u and result %u\n",
"failed with new_state %u and result %u\n", state, new_state, result);
state, new_state, result);
return; return;
} }
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpufreq-dt.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -69,10 +68,6 @@ static void tegra124_cpu_switch_to_pllx(struct tegra124_cpufreq_priv *priv) ...@@ -69,10 +68,6 @@ static void tegra124_cpu_switch_to_pllx(struct tegra124_cpufreq_priv *priv)
clk_set_parent(priv->cpu_clk, priv->pllx_clk); clk_set_parent(priv->cpu_clk, priv->pllx_clk);
} }
static struct cpufreq_dt_platform_data cpufreq_dt_pd = {
.independent_clocks = false,
};
static int tegra124_cpufreq_probe(struct platform_device *pdev) static int tegra124_cpufreq_probe(struct platform_device *pdev)
{ {
struct tegra124_cpufreq_priv *priv; struct tegra124_cpufreq_priv *priv;
...@@ -129,8 +124,6 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev) ...@@ -129,8 +124,6 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
cpufreq_dt_devinfo.name = "cpufreq-dt"; cpufreq_dt_devinfo.name = "cpufreq-dt";
cpufreq_dt_devinfo.parent = &pdev->dev; cpufreq_dt_devinfo.parent = &pdev->dev;
cpufreq_dt_devinfo.data = &cpufreq_dt_pd;
cpufreq_dt_devinfo.size_data = sizeof(cpufreq_dt_pd);
priv->cpufreq_dt_pdev = priv->cpufreq_dt_pdev =
platform_device_register_full(&cpufreq_dt_devinfo); platform_device_register_full(&cpufreq_dt_devinfo);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpu.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -26,8 +27,9 @@ ...@@ -26,8 +27,9 @@
#include "arm_big_little.h" #include "arm_big_little.h"
static int ve_spc_init_opp_table(struct device *cpu_dev) static int ve_spc_init_opp_table(const struct cpumask *cpumask)
{ {
struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask));
/* /*
* platform specific SPC code must initialise the opp table * platform specific SPC code must initialise the opp table
* so just check if the OPP count is non-zero * so just check if the OPP count is non-zero
......
/*
* Copyright (C) 2014 Marvell
* Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
*/
#ifndef __CPUFREQ_DT_H__
#define __CPUFREQ_DT_H__
struct cpufreq_dt_platform_data {
/*
* True when each CPU has its own clock to control its
* frequency, false when all CPUs are controlled by a single
* clock.
*/
bool independent_clocks;
};
#endif /* __CPUFREQ_DT_H__ */
...@@ -102,6 +102,17 @@ struct cpufreq_policy { ...@@ -102,6 +102,17 @@ struct cpufreq_policy {
*/ */
struct rw_semaphore rwsem; struct rw_semaphore rwsem;
/*
* Fast switch flags:
* - fast_switch_possible should be set by the driver if it can
* guarantee that frequency can be changed on any CPU sharing the
* policy and that the change will affect all of the policy CPUs then.
* - fast_switch_enabled is to be set by governors that support fast
* freqnency switching with the help of cpufreq_enable_fast_switch().
*/
bool fast_switch_possible;
bool fast_switch_enabled;
/* Synchronization for frequency transitions */ /* Synchronization for frequency transitions */
bool transition_ongoing; /* Tracks transition status */ bool transition_ongoing; /* Tracks transition status */
spinlock_t transition_lock; spinlock_t transition_lock;
...@@ -156,6 +167,8 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); ...@@ -156,6 +167,8 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu); int cpufreq_update_policy(unsigned int cpu);
bool have_governor_per_policy(void); bool have_governor_per_policy(void);
struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy); struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy);
void cpufreq_enable_fast_switch(struct cpufreq_policy *policy);
void cpufreq_disable_fast_switch(struct cpufreq_policy *policy);
#else #else
static inline unsigned int cpufreq_get(unsigned int cpu) static inline unsigned int cpufreq_get(unsigned int cpu)
{ {
...@@ -236,6 +249,8 @@ struct cpufreq_driver { ...@@ -236,6 +249,8 @@ struct cpufreq_driver {
unsigned int relation); /* Deprecated */ unsigned int relation); /* Deprecated */
int (*target_index)(struct cpufreq_policy *policy, int (*target_index)(struct cpufreq_policy *policy,
unsigned int index); unsigned int index);
unsigned int (*fast_switch)(struct cpufreq_policy *policy,
unsigned int target_freq);
/* /*
* Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION
* unset. * unset.
...@@ -426,6 +441,20 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, ...@@ -426,6 +441,20 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
#define CPUFREQ_POLICY_POWERSAVE (1) #define CPUFREQ_POLICY_POWERSAVE (1)
#define CPUFREQ_POLICY_PERFORMANCE (2) #define CPUFREQ_POLICY_PERFORMANCE (2)
/*
* The polling frequency depends on the capability of the processor. Default
* polling frequency is 1000 times the transition latency of the processor. The
* ondemand governor will work on any processor with transition latency <= 10ms,
* using appropriate sampling rate.
*
* For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL)
* the ondemand governor will not work. All times here are in us (microseconds).
*/
#define MIN_SAMPLING_RATE_RATIO (2)
#define LATENCY_MULTIPLIER (1000)
#define MIN_LATENCY_MULTIPLIER (20)
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
/* Governor Events */ /* Governor Events */
#define CPUFREQ_GOV_START 1 #define CPUFREQ_GOV_START 1
#define CPUFREQ_GOV_STOP 2 #define CPUFREQ_GOV_STOP 2
...@@ -450,6 +479,8 @@ struct cpufreq_governor { ...@@ -450,6 +479,8 @@ struct cpufreq_governor {
}; };
/* Pass a target to the cpufreq driver */ /* Pass a target to the cpufreq driver */
unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq);
int cpufreq_driver_target(struct cpufreq_policy *policy, int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation); unsigned int relation);
...@@ -462,6 +493,29 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor); ...@@ -462,6 +493,29 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor);
struct cpufreq_governor *cpufreq_default_governor(void); struct cpufreq_governor *cpufreq_default_governor(void);
struct cpufreq_governor *cpufreq_fallback_governor(void); struct cpufreq_governor *cpufreq_fallback_governor(void);
/* Governor attribute set */
struct gov_attr_set {
struct kobject kobj;
struct list_head policy_list;
struct mutex update_lock;
int usage_count;
};
/* sysfs ops for cpufreq governors */
extern const struct sysfs_ops governor_sysfs_ops;
void gov_attr_set_init(struct gov_attr_set *attr_set, struct list_head *list_node);
void gov_attr_set_get(struct gov_attr_set *attr_set, struct list_head *list_node);
unsigned int gov_attr_set_put(struct gov_attr_set *attr_set, struct list_head *list_node);
/* Governor sysfs attribute */
struct governor_attr {
struct attribute attr;
ssize_t (*show)(struct gov_attr_set *attr_set, char *buf);
ssize_t (*store)(struct gov_attr_set *attr_set, const char *buf,
size_t count);
};
/********************************************************************* /*********************************************************************
* FREQUENCY TABLE HELPERS * * FREQUENCY TABLE HELPERS *
*********************************************************************/ *********************************************************************/
......
...@@ -3240,7 +3240,10 @@ struct update_util_data { ...@@ -3240,7 +3240,10 @@ struct update_util_data {
u64 time, unsigned long util, unsigned long max); u64 time, unsigned long util, unsigned long max);
}; };
void cpufreq_set_update_util_data(int cpu, struct update_util_data *data); void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data,
void (*func)(struct update_util_data *data, u64 time,
unsigned long util, unsigned long max));
void cpufreq_remove_update_util_hook(int cpu);
#endif /* CONFIG_CPU_FREQ */ #endif /* CONFIG_CPU_FREQ */
#endif #endif
...@@ -24,3 +24,4 @@ obj-$(CONFIG_SCHEDSTATS) += stats.o ...@@ -24,3 +24,4 @@ obj-$(CONFIG_SCHEDSTATS) += stats.o
obj-$(CONFIG_SCHED_DEBUG) += debug.o obj-$(CONFIG_SCHED_DEBUG) += debug.o
obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
...@@ -14,24 +14,50 @@ ...@@ -14,24 +14,50 @@
DEFINE_PER_CPU(struct update_util_data *, cpufreq_update_util_data); DEFINE_PER_CPU(struct update_util_data *, cpufreq_update_util_data);
/** /**
* cpufreq_set_update_util_data - Populate the CPU's update_util_data pointer. * cpufreq_add_update_util_hook - Populate the CPU's update_util_data pointer.
* @cpu: The CPU to set the pointer for. * @cpu: The CPU to set the pointer for.
* @data: New pointer value. * @data: New pointer value.
* @func: Callback function to set for the CPU.
* *
* Set and publish the update_util_data pointer for the given CPU. That pointer * Set and publish the update_util_data pointer for the given CPU.
* points to a struct update_util_data object containing a callback function
* to call from cpufreq_update_util(). That function will be called from an RCU
* read-side critical section, so it must not sleep.
* *
* Callers must use RCU-sched callbacks to free any memory that might be * The update_util_data pointer of @cpu is set to @data and the callback
* accessed via the old update_util_data pointer or invoke synchronize_sched() * function pointer in the target struct update_util_data is set to @func.
* right after this function to avoid use-after-free. * That function will be called by cpufreq_update_util() from RCU-sched
* read-side critical sections, so it must not sleep. @data will always be
* passed to it as the first argument which allows the function to get to the
* target update_util_data structure and its container.
*
* The update_util_data pointer of @cpu must be NULL when this function is
* called or it will WARN() and return with no effect.
*/ */
void cpufreq_set_update_util_data(int cpu, struct update_util_data *data) void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data,
void (*func)(struct update_util_data *data, u64 time,
unsigned long util, unsigned long max))
{ {
if (WARN_ON(data && !data->func)) if (WARN_ON(!data || !func))
return; return;
if (WARN_ON(per_cpu(cpufreq_update_util_data, cpu)))
return;
data->func = func;
rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), data); rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), data);
} }
EXPORT_SYMBOL_GPL(cpufreq_set_update_util_data); EXPORT_SYMBOL_GPL(cpufreq_add_update_util_hook);
/**
* cpufreq_remove_update_util_hook - Clear the CPU's update_util_data pointer.
* @cpu: The CPU to clear the pointer for.
*
* Clear the update_util_data pointer for the given CPU.
*
* Callers must use RCU-sched callbacks to free any memory that might be
* accessed via the old update_util_data pointer or invoke synchronize_sched()
* right after this function to avoid use-after-free.
*/
void cpufreq_remove_update_util_hook(int cpu)
{
rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), NULL);
}
EXPORT_SYMBOL_GPL(cpufreq_remove_update_util_hook);
/*
* CPUFreq governor based on scheduler-provided CPU utilization data.
*
* Copyright (C) 2016, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.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/cpufreq.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <trace/events/power.h>
#include "sched.h"
struct sugov_tunables {
struct gov_attr_set attr_set;
unsigned int rate_limit_us;
};
struct sugov_policy {
struct cpufreq_policy *policy;
struct sugov_tunables *tunables;
struct list_head tunables_hook;
raw_spinlock_t update_lock; /* For shared policies */
u64 last_freq_update_time;
s64 freq_update_delay_ns;
unsigned int next_freq;
/* The next fields are only needed if fast switch cannot be used. */
struct irq_work irq_work;
struct work_struct work;
struct mutex work_lock;
bool work_in_progress;
bool need_freq_update;
};
struct sugov_cpu {
struct update_util_data update_util;
struct sugov_policy *sg_policy;
/* The fields below are only needed when sharing a policy. */
unsigned long util;
unsigned long max;
u64 last_update;
};
static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
/************************ Governor internals ***********************/
static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
{
s64 delta_ns;
if (sg_policy->work_in_progress)
return false;
if (unlikely(sg_policy->need_freq_update)) {
sg_policy->need_freq_update = false;
/*
* This happens when limits change, so forget the previous
* next_freq value and force an update.
*/
sg_policy->next_freq = UINT_MAX;
return true;
}
delta_ns = time - sg_policy->last_freq_update_time;
return delta_ns >= sg_policy->freq_update_delay_ns;
}
static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time,
unsigned int next_freq)
{
struct cpufreq_policy *policy = sg_policy->policy;
sg_policy->last_freq_update_time = time;
if (policy->fast_switch_enabled) {
if (sg_policy->next_freq == next_freq) {
trace_cpu_frequency(policy->cur, smp_processor_id());
return;
}
sg_policy->next_freq = next_freq;
next_freq = cpufreq_driver_fast_switch(policy, next_freq);
if (next_freq == CPUFREQ_ENTRY_INVALID)
return;
policy->cur = next_freq;
trace_cpu_frequency(next_freq, smp_processor_id());
} else if (sg_policy->next_freq != next_freq) {
sg_policy->next_freq = next_freq;
sg_policy->work_in_progress = true;
irq_work_queue(&sg_policy->irq_work);
}
}
/**
* get_next_freq - Compute a new frequency for a given cpufreq policy.
* @policy: cpufreq policy object to compute the new frequency for.
* @util: Current CPU utilization.
* @max: CPU capacity.
*
* If the utilization is frequency-invariant, choose the new frequency to be
* proportional to it, that is
*
* next_freq = C * max_freq * util / max
*
* Otherwise, approximate the would-be frequency-invariant utilization by
* util_raw * (curr_freq / max_freq) which leads to
*
* next_freq = C * curr_freq * util_raw / max
*
* Take C = 1.25 for the frequency tipping point at (util / max) = 0.8.
*/
static unsigned int get_next_freq(struct cpufreq_policy *policy,
unsigned long util, unsigned long max)
{
unsigned int freq = arch_scale_freq_invariant() ?
policy->cpuinfo.max_freq : policy->cur;
return (freq + (freq >> 2)) * util / max;
}
static void sugov_update_single(struct update_util_data *hook, u64 time,
unsigned long util, unsigned long max)
{
struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
struct cpufreq_policy *policy = sg_policy->policy;
unsigned int next_f;
if (!sugov_should_update_freq(sg_policy, time))
return;
next_f = util == ULONG_MAX ? policy->cpuinfo.max_freq :
get_next_freq(policy, util, max);
sugov_update_commit(sg_policy, time, next_f);
}
static unsigned int sugov_next_freq_shared(struct sugov_policy *sg_policy,
unsigned long util, unsigned long max)
{
struct cpufreq_policy *policy = sg_policy->policy;
unsigned int max_f = policy->cpuinfo.max_freq;
u64 last_freq_update_time = sg_policy->last_freq_update_time;
unsigned int j;
if (util == ULONG_MAX)
return max_f;
for_each_cpu(j, policy->cpus) {
struct sugov_cpu *j_sg_cpu;
unsigned long j_util, j_max;
s64 delta_ns;
if (j == smp_processor_id())
continue;
j_sg_cpu = &per_cpu(sugov_cpu, j);
/*
* If the CPU utilization was last updated before the previous
* frequency update and the time elapsed between the last update
* of the CPU utilization and the last frequency update is long
* enough, don't take the CPU into account as it probably is
* idle now.
*/
delta_ns = last_freq_update_time - j_sg_cpu->last_update;
if (delta_ns > TICK_NSEC)
continue;
j_util = j_sg_cpu->util;
if (j_util == ULONG_MAX)
return max_f;
j_max = j_sg_cpu->max;
if (j_util * max > j_max * util) {
util = j_util;
max = j_max;
}
}
return get_next_freq(policy, util, max);
}
static void sugov_update_shared(struct update_util_data *hook, u64 time,
unsigned long util, unsigned long max)
{
struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util);
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
unsigned int next_f;
raw_spin_lock(&sg_policy->update_lock);
sg_cpu->util = util;
sg_cpu->max = max;
sg_cpu->last_update = time;
if (sugov_should_update_freq(sg_policy, time)) {
next_f = sugov_next_freq_shared(sg_policy, util, max);
sugov_update_commit(sg_policy, time, next_f);
}
raw_spin_unlock(&sg_policy->update_lock);
}
static void sugov_work(struct work_struct *work)
{
struct sugov_policy *sg_policy = container_of(work, struct sugov_policy, work);
mutex_lock(&sg_policy->work_lock);
__cpufreq_driver_target(sg_policy->policy, sg_policy->next_freq,
CPUFREQ_RELATION_L);
mutex_unlock(&sg_policy->work_lock);
sg_policy->work_in_progress = false;
}
static void sugov_irq_work(struct irq_work *irq_work)
{
struct sugov_policy *sg_policy;
sg_policy = container_of(irq_work, struct sugov_policy, irq_work);
schedule_work_on(smp_processor_id(), &sg_policy->work);
}
/************************** sysfs interface ************************/
static struct sugov_tunables *global_tunables;
static DEFINE_MUTEX(global_tunables_lock);
static inline struct sugov_tunables *to_sugov_tunables(struct gov_attr_set *attr_set)
{
return container_of(attr_set, struct sugov_tunables, attr_set);
}
static ssize_t rate_limit_us_show(struct gov_attr_set *attr_set, char *buf)
{
struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
return sprintf(buf, "%u\n", tunables->rate_limit_us);
}
static ssize_t rate_limit_us_store(struct gov_attr_set *attr_set, const char *buf,
size_t count)
{
struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
struct sugov_policy *sg_policy;
unsigned int rate_limit_us;
if (kstrtouint(buf, 10, &rate_limit_us))
return -EINVAL;
tunables->rate_limit_us = rate_limit_us;
list_for_each_entry(sg_policy, &attr_set->policy_list, tunables_hook)
sg_policy->freq_update_delay_ns = rate_limit_us * NSEC_PER_USEC;
return count;
}
static struct governor_attr rate_limit_us = __ATTR_RW(rate_limit_us);
static struct attribute *sugov_attributes[] = {
&rate_limit_us.attr,
NULL
};
static struct kobj_type sugov_tunables_ktype = {
.default_attrs = sugov_attributes,
.sysfs_ops = &governor_sysfs_ops,
};
/********************** cpufreq governor interface *********************/
static struct cpufreq_governor schedutil_gov;
static struct sugov_policy *sugov_policy_alloc(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy;
sg_policy = kzalloc(sizeof(*sg_policy), GFP_KERNEL);
if (!sg_policy)
return NULL;
sg_policy->policy = policy;
init_irq_work(&sg_policy->irq_work, sugov_irq_work);
INIT_WORK(&sg_policy->work, sugov_work);
mutex_init(&sg_policy->work_lock);
raw_spin_lock_init(&sg_policy->update_lock);
return sg_policy;
}
static void sugov_policy_free(struct sugov_policy *sg_policy)
{
mutex_destroy(&sg_policy->work_lock);
kfree(sg_policy);
}
static struct sugov_tunables *sugov_tunables_alloc(struct sugov_policy *sg_policy)
{
struct sugov_tunables *tunables;
tunables = kzalloc(sizeof(*tunables), GFP_KERNEL);
if (tunables) {
gov_attr_set_init(&tunables->attr_set, &sg_policy->tunables_hook);
if (!have_governor_per_policy())
global_tunables = tunables;
}
return tunables;
}
static void sugov_tunables_free(struct sugov_tunables *tunables)
{
if (!have_governor_per_policy())
global_tunables = NULL;
kfree(tunables);
}
static int sugov_init(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy;
struct sugov_tunables *tunables;
unsigned int lat;
int ret = 0;
/* State should be equivalent to EXIT */
if (policy->governor_data)
return -EBUSY;
sg_policy = sugov_policy_alloc(policy);
if (!sg_policy)
return -ENOMEM;
mutex_lock(&global_tunables_lock);
if (global_tunables) {
if (WARN_ON(have_governor_per_policy())) {
ret = -EINVAL;
goto free_sg_policy;
}
policy->governor_data = sg_policy;
sg_policy->tunables = global_tunables;
gov_attr_set_get(&global_tunables->attr_set, &sg_policy->tunables_hook);
goto out;
}
tunables = sugov_tunables_alloc(sg_policy);
if (!tunables) {
ret = -ENOMEM;
goto free_sg_policy;
}
tunables->rate_limit_us = LATENCY_MULTIPLIER;
lat = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
if (lat)
tunables->rate_limit_us *= lat;
policy->governor_data = sg_policy;
sg_policy->tunables = tunables;
ret = kobject_init_and_add(&tunables->attr_set.kobj, &sugov_tunables_ktype,
get_governor_parent_kobj(policy), "%s",
schedutil_gov.name);
if (ret)
goto fail;
out:
mutex_unlock(&global_tunables_lock);
cpufreq_enable_fast_switch(policy);
return 0;
fail:
policy->governor_data = NULL;
sugov_tunables_free(tunables);
free_sg_policy:
mutex_unlock(&global_tunables_lock);
sugov_policy_free(sg_policy);
pr_err("cpufreq: schedutil governor initialization failed (error %d)\n", ret);
return ret;
}
static int sugov_exit(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
struct sugov_tunables *tunables = sg_policy->tunables;
unsigned int count;
cpufreq_disable_fast_switch(policy);
mutex_lock(&global_tunables_lock);
count = gov_attr_set_put(&tunables->attr_set, &sg_policy->tunables_hook);
policy->governor_data = NULL;
if (!count)
sugov_tunables_free(tunables);
mutex_unlock(&global_tunables_lock);
sugov_policy_free(sg_policy);
return 0;
}
static int sugov_start(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
unsigned int cpu;
sg_policy->freq_update_delay_ns = sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
sg_policy->last_freq_update_time = 0;
sg_policy->next_freq = UINT_MAX;
sg_policy->work_in_progress = false;
sg_policy->need_freq_update = false;
for_each_cpu(cpu, policy->cpus) {
struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
sg_cpu->sg_policy = sg_policy;
if (policy_is_shared(policy)) {
sg_cpu->util = ULONG_MAX;
sg_cpu->max = 0;
sg_cpu->last_update = 0;
cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
sugov_update_shared);
} else {
cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
sugov_update_single);
}
}
return 0;
}
static int sugov_stop(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
unsigned int cpu;
for_each_cpu(cpu, policy->cpus)
cpufreq_remove_update_util_hook(cpu);
synchronize_sched();
irq_work_sync(&sg_policy->irq_work);
cancel_work_sync(&sg_policy->work);
return 0;
}
static int sugov_limits(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
if (!policy->fast_switch_enabled) {
mutex_lock(&sg_policy->work_lock);
if (policy->max < policy->cur)
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
else if (policy->min > policy->cur)
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
mutex_unlock(&sg_policy->work_lock);
}
sg_policy->need_freq_update = true;
return 0;
}
int sugov_governor(struct cpufreq_policy *policy, unsigned int event)
{
if (event == CPUFREQ_GOV_POLICY_INIT) {
return sugov_init(policy);
} else if (policy->governor_data) {
switch (event) {
case CPUFREQ_GOV_POLICY_EXIT:
return sugov_exit(policy);
case CPUFREQ_GOV_START:
return sugov_start(policy);
case CPUFREQ_GOV_STOP:
return sugov_stop(policy);
case CPUFREQ_GOV_LIMITS:
return sugov_limits(policy);
}
}
return -EINVAL;
}
static struct cpufreq_governor schedutil_gov = {
.name = "schedutil",
.governor = sugov_governor,
.owner = THIS_MODULE,
};
static int __init sugov_module_init(void)
{
return cpufreq_register_governor(&schedutil_gov);
}
static void __exit sugov_module_exit(void)
{
cpufreq_unregister_governor(&schedutil_gov);
}
MODULE_AUTHOR("Rafael J. Wysocki <rafael.j.wysocki@intel.com>");
MODULE_DESCRIPTION("Utilization-based CPU frequency selection");
MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL
struct cpufreq_governor *cpufreq_default_governor(void)
{
return &schedutil_gov;
}
fs_initcall(sugov_module_init);
#else
module_init(sugov_module_init);
#endif
module_exit(sugov_module_exit);
...@@ -1842,6 +1842,14 @@ static inline void cpufreq_update_util(u64 time, unsigned long util, unsigned lo ...@@ -1842,6 +1842,14 @@ static inline void cpufreq_update_util(u64 time, unsigned long util, unsigned lo
static inline void cpufreq_trigger_update(u64 time) {} static inline void cpufreq_trigger_update(u64 time) {}
#endif /* CONFIG_CPU_FREQ */ #endif /* CONFIG_CPU_FREQ */
#ifdef arch_scale_freq_capacity
#ifndef arch_scale_freq_invariant
#define arch_scale_freq_invariant() (true)
#endif
#else /* arch_scale_freq_capacity */
#define arch_scale_freq_invariant() (false)
#endif
static inline void account_reset_rq(struct rq *rq) static inline void account_reset_rq(struct rq *rq)
{ {
#ifdef CONFIG_IRQ_TIME_ACCOUNTING #ifdef CONFIG_IRQ_TIME_ACCOUNTING
......
...@@ -15,5 +15,6 @@ ...@@ -15,5 +15,6 @@
EXPORT_TRACEPOINT_SYMBOL_GPL(suspend_resume); EXPORT_TRACEPOINT_SYMBOL_GPL(suspend_resume);
EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_idle); EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_idle);
EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_frequency);
EXPORT_TRACEPOINT_SYMBOL_GPL(powernv_throttle); EXPORT_TRACEPOINT_SYMBOL_GPL(powernv_throttle);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment