diff options
33 files changed, 2774 insertions, 1153 deletions
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 723e1ad937da..940707d095cc 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -31,7 +31,9 @@ Optional properties: - domain-idle-states : A phandle of an idle-state that shall be soaked into a generic domain power state. The idle state definitions are - compatible with domain-idle-state specified in [1]. + compatible with domain-idle-state specified in [1]. phandles + that are not compatible with domain-idle-state will be + ignored. The domain-idle-state property reflects the idle state of this PM domain and not the idle states of the devices or sub-domains in the PM domain. Devices and sub-domains have their own idle-states independent of the parent diff --git a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt index d23dc002a87e..d3a5a93a65cd 100644 --- a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt +++ b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt @@ -33,6 +33,7 @@ Required properties: - compatible: should be one of: - "rockchip,rk3188-io-voltage-domain" for rk3188 - "rockchip,rk3288-io-voltage-domain" for rk3288 + - "rockchip,rk3328-io-voltage-domain" for rk3328 - "rockchip,rk3368-io-voltage-domain" for rk3368 - "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains - "rockchip,rk3399-io-voltage-domain" for rk3399 diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 64546eb9a16a..ee69d7532172 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -478,15 +478,23 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: - set the power.last_busy field to the current time void pm_runtime_use_autosuspend(struct device *dev); - - set the power.use_autosuspend flag, enabling autosuspend delays + - set the power.use_autosuspend flag, enabling autosuspend delays; call + pm_runtime_get_sync if the flag was previously cleared and + power.autosuspend_delay is negative void pm_runtime_dont_use_autosuspend(struct device *dev); - - clear the power.use_autosuspend flag, disabling autosuspend delays + - clear the power.use_autosuspend flag, disabling autosuspend delays; + decrement the device's usage counter if the flag was previously set and + power.autosuspend_delay is negative; call pm_runtime_idle void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); - set the power.autosuspend_delay value to 'delay' (expressed in milliseconds); if 'delay' is negative then runtime suspends are - prevented + prevented; if power.use_autosuspend is set, pm_runtime_get_sync may be + called or the device's usage counter may be decremented and + pm_runtime_idle called depending on if power.autosuspend_delay is + changed to or from a negative value; if power.use_autosuspend is clear, + pm_runtime_idle is called unsigned long pm_runtime_autosuspend_expiration(struct device *dev); - calculate the time when the current autosuspend delay period will expire, @@ -836,9 +844,8 @@ of the non-autosuspend counterparts: Instead of: pm_runtime_put_sync use: pm_runtime_put_sync_autosuspend. Drivers may also continue to use the non-autosuspend helper functions; they -will behave normally, not taking the autosuspend delay into account. -Similarly, if the power.use_autosuspend field isn't set then the autosuspend -helper functions will behave just like the non-autosuspend counterparts. +will behave normally, which means sometimes taking the autosuspend delay into +account (see pm_runtime_idle). Under some circumstances a driver or subsystem may want to prevent a device from autosuspending immediately, even though the usage counter is zero and the diff --git a/MAINTAINERS b/MAINTAINERS index 6e8897594291..0f6df84fec54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3471,6 +3471,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git T: git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates) B: https://bugzilla.kernel.org F: Documentation/cpu-freq/ +F: Documentation/devicetree/bindings/cpufreq/ F: drivers/cpufreq/ F: include/linux/cpufreq.h F: tools/testing/selftests/cpufreq/ diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 162e1eb5373d..6c5affe2d0f5 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -1189,11 +1189,6 @@ status = "disabled"; }; - cpufreq-cooling { - compatible = "stericsson,db8500-cpufreq-cooling"; - status = "disabled"; - }; - mcde@a0350000 { compatible = "stericsson,mcde"; reg = <0xa0350000 0x1000>, /* MCDE */ diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e697dec9d25b..ad196427b4f2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -121,7 +121,9 @@ static const struct genpd_lock_ops genpd_spin_ops = { #define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p) #define genpd_unlock(p) p->lock_ops->unlock(p) +#define genpd_status_on(genpd) (genpd->status == GPD_STATE_ACTIVE) #define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE) +#define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, struct generic_pm_domain *genpd) @@ -130,8 +132,12 @@ static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd); - /* Warn once if IRQ safe dev in no sleep domain */ - if (ret) + /* + * Warn once if an IRQ safe device is attached to a no sleep domain, as + * to indicate a suboptimal configuration for PM. For an always on + * domain this isn't case, thus don't warn. + */ + if (ret && !genpd_is_always_on(genpd)) dev_warn_once(dev, "PM domain %s will not be powered off\n", genpd->name); @@ -296,11 +302,15 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, * (1) The domain is already in the "power off" state. * (2) System suspend is in progress. */ - if (genpd->status == GPD_STATE_POWER_OFF - || genpd->prepared_count > 0) + if (!genpd_status_on(genpd) || genpd->prepared_count > 0) return 0; - if (atomic_read(&genpd->sd_count) > 0) + /* + * Abort power off for the PM domain in the following situations: + * (1) The domain is configured as always on. + * (2) When the domain has a subdomain being powered on. + */ + if (genpd_is_always_on(genpd) || atomic_read(&genpd->sd_count) > 0) return -EBUSY; list_for_each_entry(pdd, &genpd->dev_list, list_node) { @@ -373,7 +383,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) struct gpd_link *link; int ret = 0; - if (genpd->status == GPD_STATE_ACTIVE) + if (genpd_status_on(genpd)) return 0; /* @@ -752,7 +762,7 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, { struct gpd_link *link; - if (genpd->status == GPD_STATE_POWER_OFF) + if (!genpd_status_on(genpd) || genpd_is_always_on(genpd)) return; if (genpd->suspended_count != genpd->device_count @@ -761,7 +771,8 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, /* Choose the deepest state when suspending */ genpd->state_idx = genpd->state_count - 1; - _genpd_power_off(genpd, false); + if (_genpd_power_off(genpd, false)) + return; genpd->status = GPD_STATE_POWER_OFF; @@ -793,7 +804,7 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, { struct gpd_link *link; - if (genpd->status == GPD_STATE_ACTIVE) + if (genpd_status_on(genpd)) return; list_for_each_entry(link, &genpd->slave_links, slave_node) { @@ -1329,8 +1340,7 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd, genpd_lock(subdomain); genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING); - if (genpd->status == GPD_STATE_POWER_OFF - && subdomain->status != GPD_STATE_POWER_OFF) { + if (!genpd_status_on(genpd) && genpd_status_on(subdomain)) { ret = -EINVAL; goto out; } @@ -1346,7 +1356,7 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd, list_add_tail(&link->master_node, &genpd->master_links); link->slave = subdomain; list_add_tail(&link->slave_node, &subdomain->slave_links); - if (subdomain->status != GPD_STATE_POWER_OFF) + if (genpd_status_on(subdomain)) genpd_sd_counter_inc(genpd); out: @@ -1406,7 +1416,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, list_del(&link->master_node); list_del(&link->slave_node); kfree(link); - if (subdomain->status != GPD_STATE_POWER_OFF) + if (genpd_status_on(subdomain)) genpd_sd_counter_dec(genpd); ret = 0; @@ -1492,6 +1502,10 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->dev_ops.start = pm_clk_resume; } + /* Always-on domains must be powered on at initialization. */ + if (genpd_is_always_on(genpd) && !genpd_status_on(genpd)) + return -EINVAL; + /* Use only one "off" state if there were no states declared */ if (genpd->state_count == 0) { ret = genpd_set_default_power_state(genpd); @@ -1700,12 +1714,12 @@ int of_genpd_add_provider_simple(struct device_node *np, mutex_lock(&gpd_list_lock); - if (pm_genpd_present(genpd)) + if (pm_genpd_present(genpd)) { ret = genpd_add_provider(np, genpd_xlate_simple, genpd); - - if (!ret) { - genpd->provider = &np->fwnode; - genpd->has_provider = true; + if (!ret) { + genpd->provider = &np->fwnode; + genpd->has_provider = true; + } } mutex_unlock(&gpd_list_lock); @@ -2079,11 +2093,6 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, int err; u32 residency; u32 entry_latency, exit_latency; - const struct of_device_id *match_id; - - match_id = of_match_node(idle_state_match, state_node); - if (!match_id) - return -EINVAL; err = of_property_read_u32(state_node, "entry-latency-us", &entry_latency); @@ -2132,6 +2141,7 @@ int of_genpd_parse_idle_states(struct device_node *dn, int err, ret; int count; struct of_phandle_iterator it; + const struct of_device_id *match_id; count = of_count_phandle_with_args(dn, "domain-idle-states", NULL); if (count <= 0) @@ -2144,6 +2154,9 @@ int of_genpd_parse_idle_states(struct device_node *dn, /* Loop over the phandles until all the requested entry is found */ of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) { np = it.node; + match_id = of_match_node(idle_state_match, np); + if (!match_id) + continue; ret = genpd_parse_state(&st[i++], np); if (ret) { pr_err @@ -2155,8 +2168,11 @@ int of_genpd_parse_idle_states(struct device_node *dn, } } - *n = count; - *states = st; + *n = i; + if (!i) + kfree(st); + else + *states = st; return 0; } @@ -2221,7 +2237,7 @@ static int pm_genpd_summary_one(struct seq_file *s, if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) goto exit; - if (genpd->status == GPD_STATE_POWER_OFF) + if (!genpd_status_on(genpd)) snprintf(state, sizeof(state), "%s-%u", status_lookup[genpd->status], genpd->state_idx); else diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 74fa5c5904d3..74ed7e9a7f27 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -247,6 +247,12 @@ config ARM_TEGRA124_CPUFREQ help This adds the CPUFreq driver support for Tegra124 SOCs. +config ARM_TEGRA186_CPUFREQ + tristate "Tegra186 CPUFreq support" + depends on ARCH_TEGRA && TEGRA_BPMP + help + This adds the CPUFreq driver support for Tegra186 SOCs. + config ARM_TI_CPUFREQ bool "Texas Instruments CPUFreq support" depends on ARCH_OMAP2PLUS diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 9f5a8045f36d..b7e78f063c4f 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o +obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 5c3ec1dd4921..3575b82210ba 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/cpufreq.h> +#include <linux/cpu_cooling.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/platform_device.h> @@ -18,6 +19,7 @@ static struct cpufreq_frequency_table *freq_table; static struct clk *armss_clk; +static struct thermal_cooling_device *cdev; static int dbx500_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) @@ -32,6 +34,22 @@ static int dbx500_cpufreq_init(struct cpufreq_policy *policy) return cpufreq_generic_init(policy, freq_table, 20 * 1000); } +static int dbx500_cpufreq_exit(struct cpufreq_policy *policy) +{ + if (!IS_ERR(cdev)) + cpufreq_cooling_unregister(cdev); + return 0; +} + +static void dbx500_cpufreq_ready(struct cpufreq_policy *policy) +{ + cdev = cpufreq_cooling_register(policy->cpus); + if (IS_ERR(cdev)) + pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev)); + else + pr_info("Cooling device registered: %s\n", cdev->type); +} + static struct cpufreq_driver dbx500_cpufreq_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_INITIAL_FREQ_CHECK, @@ -39,6 +57,8 @@ static struct cpufreq_driver dbx500_cpufreq_driver = { .target_index = dbx500_cpufreq_target, .get = cpufreq_generic_get, .init = dbx500_cpufreq_init, + .exit = dbx500_cpufreq_exit, + .ready = dbx500_cpufreq_ready, .name = "DBX500", .attr = cpufreq_generic_attr, }; diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 7719b02e04f5..9c13f097fd8c 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -161,8 +161,13 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) static int imx6q_cpufreq_init(struct cpufreq_policy *policy) { + int ret; + policy->clk = arm_clk; - return cpufreq_generic_init(policy, freq_table, transition_latency); + ret = cpufreq_generic_init(policy, freq_table, transition_latency); + policy->suspend_freq = policy->max; + + return ret; } static struct cpufreq_driver imx6q_cpufreq_driver = { @@ -173,6 +178,7 @@ static struct cpufreq_driver imx6q_cpufreq_driver = { .init = imx6q_cpufreq_init, .name = "imx6q-cpufreq", .attr = cpufreq_generic_attr, + .suspend = cpufreq_generic_suspend, }; static int imx6q_cpufreq_probe(struct platform_device *pdev) @@ -222,6 +228,13 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) arm_reg = regulator_get(cpu_dev, "arm"); pu_reg = regulator_get_optional(cpu_dev, "pu"); soc_reg = regulator_get(cpu_dev, "soc"); + if (PTR_ERR(arm_reg) == -EPROBE_DEFER || + PTR_ERR(soc_reg) == -EPROBE_DEFER || + PTR_ERR(pu_reg) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + dev_dbg(cpu_dev, "regulators not ready, defer\n"); + goto put_reg; + } if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) { dev_err(cpu_dev, "failed to get regulators\n"); ret = -ENOENT; @@ -255,7 +268,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); if (ret) { dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); - goto put_reg; + goto out_free_opp; } /* Make imx6_soc_volt array's size same as arm opp number */ diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 283491f742d3..b7de5bd76a31 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -37,7 +37,11 @@ #include <asm/cpufeature.h> #include <asm/intel-family.h> +#define INTEL_PSTATE_DEFAULT_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC) +#define INTEL_PSTATE_HWP_SAMPLING_INTERVAL (50 * NSEC_PER_MSEC) + #define INTEL_CPUFREQ_TRANSITION_LATENCY 20000 +#define INTEL_CPUFREQ_TRANSITION_DELAY 500 #ifdef CONFIG_ACPI #include <acpi/processor.h> @@ -74,6 +78,11 @@ static inline int ceiling_fp(int32_t x) return ret; } +static inline int32_t percent_fp(int percent) +{ + return div_fp(percent, 100); +} + static inline u64 mul_ext_fp(u64 x, u64 y) { return (x * y) >> EXT_FRAC_BITS; @@ -186,45 +195,22 @@ struct _pid { }; /** - * struct perf_limits - Store user and policy limits - * @no_turbo: User requested turbo state from intel_pstate sysfs - * @turbo_disabled: Platform turbo status either from msr - * MSR_IA32_MISC_ENABLE or when maximum available pstate - * matches the maximum turbo pstate - * @max_perf_pct: Effective maximum performance limit in percentage, this - * is minimum of either limits enforced by cpufreq policy - * or limits from user set limits via intel_pstate sysfs - * @min_perf_pct: Effective minimum performance limit in percentage, this - * is maximum of either limits enforced by cpufreq policy - * or limits from user set limits via intel_pstate sysfs - * @max_perf: This is a scaled value between 0 to 255 for max_perf_pct - * This value is used to limit max pstate - * @min_perf: This is a scaled value between 0 to 255 for min_perf_pct - * This value is used to limit min pstate - * @max_policy_pct: The maximum performance in percentage enforced by - * cpufreq setpolicy interface - * @max_sysfs_pct: The maximum performance in percentage enforced by - * intel pstate sysfs interface, unused when per cpu - * controls are enforced - * @min_policy_pct: The minimum performance in percentage enforced by - * cpufreq setpolicy interface - * @min_sysfs_pct: The minimum performance in percentage enforced by - * intel pstate sysfs interface, unused when per cpu - * controls are enforced - * - * Storage for user and policy defined limits. + * struct global_params - Global parameters, mostly tunable via sysfs. + * @no_turbo: Whether or not to use turbo P-states. + * @turbo_disabled: Whethet or not turbo P-states are available at all, + * based on the MSR_IA32_MISC_ENABLE value and whether or + * not the maximum reported turbo P-state is different from + * the maximum reported non-turbo one. + * @min_perf_pct: Minimum capacity limit in percent of the maximum turbo + * P-state capacity. + * @max_perf_pct: Maximum capacity limit in percent of the maximum turbo + * P-state capacity. */ -struct perf_limits { - int no_turbo; - int turbo_disabled; +struct global_params { + bool no_turbo; + bool turbo_disabled; int max_perf_pct; int min_perf_pct; - int32_t max_perf; - int32_t min_perf; - int max_policy_pct; - int max_sysfs_pct; - int min_policy_pct; - int min_sysfs_pct; }; /** @@ -245,9 +231,10 @@ struct perf_limits { * @prev_cummulative_iowait: IO Wait time difference from last and * current sample * @sample: Storage for storing last Sample data - * @perf_limits: Pointer to perf_limit unique to this CPU - * Not all field in the structure are applicable - * when per cpu controls are enforced + * @min_perf: Minimum capacity limit as a fraction of the maximum + * turbo P-state capacity. + * @max_perf: Maximum capacity limit as a fraction of the maximum + * turbo P-state capacity. * @acpi_perf_data: Stores ACPI perf information read from _PSS * @valid_pss_table: Set to true for valid ACPI _PSS entries found * @epp_powersave: Last saved HWP energy performance preference @@ -279,7 +266,8 @@ struct cpudata { u64 prev_tsc; u64 prev_cummulative_iowait; struct sample sample; - struct perf_limits *perf_limits; + int32_t min_perf; + int32_t max_perf; #ifdef CONFIG_ACPI struct acpi_processor_performance acpi_perf_data; bool valid_pss_table; @@ -324,7 +312,7 @@ struct pstate_adjust_policy { * @get_scaling: Callback to get frequency scaling factor * @get_val: Callback to convert P state to actual MSR write value * @get_vid: Callback to get VID data for Atom platforms - * @get_target_pstate: Callback to a function to calculate next P state to use + * @update_util: Active mode utilization update callback. * * Core and Atom CPU models have different way to get P State limits. This * structure is used to store those callbacks. @@ -337,43 +325,31 @@ struct pstate_funcs { int (*get_scaling)(void); u64 (*get_val)(struct cpudata*, int pstate); void (*get_vid)(struct cpudata *); - int32_t (*get_target_pstate)(struct cpudata *); + void (*update_util)(struct update_util_data *data, u64 time, + unsigned int flags); }; -/** - * struct cpu_defaults- Per CPU model default config data - * @pid_policy: PID config data - * @funcs: Callback function data - */ -struct cpu_defaults { - struct pstate_adjust_policy pid_policy; - struct pstate_funcs funcs; +static struct pstate_funcs pstate_funcs __read_mostly; +static struct pstate_adjust_policy pid_params __read_mostly = { + .sample_rate_ms = 10, + .sample_rate_ns = 10 * NSEC_PER_MSEC, + .deadband = 0, + .setpoint = 97, + .p_gain_pct = 20, + .d_gain_pct = 0, + .i_gain_pct = 0, }; -static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu); -static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu); - -static struct pstate_adjust_policy pid_params __read_mostly; -static struct pstate_funcs pstate_funcs __read_mostly; static int hwp_active __read_mostly; static bool per_cpu_limits __read_mostly; -static bool driver_registered __read_mostly; +static struct cpufreq_driver *intel_pstate_driver __read_mostly; #ifdef CONFIG_ACPI static bool acpi_ppc; #endif -static struct perf_limits global; - -static void intel_pstate_init_limits(struct perf_limits *limits) -{ - memset(limits, 0, sizeof(*limits)); - limits->max_perf_pct = 100; - limits->max_perf = int_ext_tofp(1); - limits->max_policy_pct = 100; - limits->max_sysfs_pct = 100; -} +static struct global_params global; static DEFINE_MUTEX(intel_pstate_driver_lock); static DEFINE_MUTEX(intel_pstate_limits_lock); @@ -530,29 +506,6 @@ static inline void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy) } #endif -static inline void pid_reset(struct _pid *pid, int setpoint, int busy, - int deadband, int integral) { - pid->setpoint = int_tofp(setpoint); - pid->deadband = int_tofp(deadband); - pid->integral = int_tofp(integral); - pid->last_err = int_tofp(setpoint) - int_tofp(busy); -} - -static inline void pid_p_gain_set(struct _pid *pid, int percent) -{ - pid->p_gain = div_fp(percent, 100); -} - -static inline void pid_i_gain_set(struct _pid *pid, int percent) -{ - pid->i_gain = div_fp(percent, 100); -} - -static inline void pid_d_gain_set(struct _pid *pid, int percent) -{ - pid->d_gain = div_fp(percent, 100); -} - static signed int pid_calc(struct _pid *pid, int32_t busy) { signed int result; @@ -590,23 +543,17 @@ static signed int pid_calc(struct _pid *pid, int32_t busy) return (signed int)fp_toint(result); } -static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu) -{ - pid_p_gain_set(&cpu->pid, pid_params.p_gain_pct); - pid_d_gain_set(&cpu->pid, pid_params.d_gain_pct); - pid_i_gain_set(&cpu->pid, pid_params.i_gain_pct); - - pid_reset(&cpu->pid, pid_params.setpoint, 100, pid_params.deadband, 0); -} - -static inline void intel_pstate_reset_all_pid(void) +static inline void intel_pstate_pid_reset(struct cpudata *cpu) { - unsigned int cpu; + struct _pid *pid = &cpu->pid; - for_each_online_cpu(cpu) { - if (all_cpu_data[cpu]) - intel_pstate_busy_pid_reset(all_cpu_data[cpu]); - } + pid->p_gain = percent_fp(pid_params.p_gain_pct); + pid->d_gain = percent_fp(pid_params.d_gain_pct); + pid->i_gain = percent_fp(pid_params.i_gain_pct); + pid->setpoint = int_tofp(pid_params.setpoint); + pid->last_err = pid->setpoint - int_tofp(100); + pid->deadband = int_tofp(pid_params.deadband); + pid->integral = 0; } static inline void update_turbo_state(void) @@ -621,6 +568,14 @@ static inline void update_turbo_state(void) cpu->pstate.max_pstate == cpu->pstate.turbo_pstate); } +static int min_perf_pct_min(void) +{ + struct cpudata *cpu = all_cpu_data[0]; + + return DIV_ROUND_UP(cpu->pstate.min_pstate * 100, + cpu->pstate.turbo_pstate); +} + static s16 intel_pstate_get_epb(struct cpudata *cpu_data) { u64 epb; @@ -838,96 +793,80 @@ static struct freq_attr *hwp_cpufreq_attrs[] = { NULL, }; -static void intel_pstate_hwp_set(struct cpufreq_policy *policy) +static void intel_pstate_hwp_set(unsigned int cpu) { - int min, hw_min, max, hw_max, cpu; - struct perf_limits *perf_limits = &global; + struct cpudata *cpu_data = all_cpu_data[cpu]; + int min, hw_min, max, hw_max; u64 value, cap; + s16 epp; - for_each_cpu(cpu, policy->cpus) { - struct cpudata *cpu_data = all_cpu_data[cpu]; - s16 epp; - - if (per_cpu_limits) - perf_limits = all_cpu_data[cpu]->perf_limits; - - rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); - hw_min = HWP_LOWEST_PERF(cap); - if (global.no_turbo) - hw_max = HWP_GUARANTEED_PERF(cap); - else - hw_max = HWP_HIGHEST_PERF(cap); - - max = fp_ext_toint(hw_max * perf_limits->max_perf); - if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) - min = max; - else - min = fp_ext_toint(hw_max * perf_limits->min_perf); + rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); + hw_min = HWP_LOWEST_PERF(cap); + if (global.no_turbo) + hw_max = HWP_GUARANTEED_PERF(cap); + else + hw_max = HWP_HIGHEST_PERF(cap); - rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); + max = fp_ext_toint(hw_max * cpu_data->max_perf); + if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) + min = max; + else + min = fp_ext_toint(hw_max * cpu_data->min_perf); - value &= ~HWP_MIN_PERF(~0L); - value |= HWP_MIN_PERF(min); + rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); - value &= ~HWP_MAX_PERF(~0L); - value |= HWP_MAX_PERF(max); + value &= ~HWP_MIN_PERF(~0L); + value |= HWP_MIN_PERF(min); - if (cpu_data->epp_policy == cpu_data->policy) - goto skip_epp; + value &= ~HWP_MAX_PERF(~0L); + value |= HWP_MAX_PERF(max); - cpu_data->epp_policy = cpu_data->policy; + if (cpu_data->epp_policy == cpu_data->policy) + goto skip_epp; - if (cpu_data->epp_saved >= 0) { - epp = cpu_data->epp_saved; - cpu_data->epp_saved = -EINVAL; - goto update_epp; - } + cpu_data->epp_policy = cpu_data->policy; - if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) { - epp = intel_pstate_get_epp(cpu_data, value); - cpu_data->epp_powersave = epp; - /* If EPP read was failed, then don't try to write */ - if (epp < 0) - goto skip_epp; + if (cpu_data->epp_saved >= 0) { + epp = cpu_data->epp_saved; + cpu_data->epp_saved = -EINVAL; + goto update_epp; + } + if (cpu_data->policy == CPUFREQ_POLICY_PERFORMANCE) { + epp = intel_pstate_get_epp(cpu_data, value); + cpu_data->epp_powersave = epp; + /* If EPP read was failed, then don't try to write */ + if (epp < 0) + goto skip_epp; - epp = 0; - } else { - /* skip setting EPP, when saved value is invalid */ - if (cpu_data->epp_powersave < 0) - goto skip_epp; + epp = 0; + } else { + /* skip setting EPP, when saved value is invalid */ + if (cp |