diff options
| -rw-r--r-- | Documentation/power/runtime_pm.rst | 17 | ||||
| -rw-r--r-- | drivers/base/power/runtime.c | 11 | ||||
| -rw-r--r-- | drivers/cpufreq/acpi-cpufreq.c | 9 | ||||
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 162 | ||||
| -rw-r--r-- | drivers/cpufreq/intel_pstate.c | 18 | ||||
| -rw-r--r-- | drivers/powercap/intel_rapl_common.c | 15 | ||||
| -rw-r--r-- | include/linux/cpufreq.h | 7 |
7 files changed, 169 insertions, 70 deletions
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst index 40a5c23d5259..f4723ad6e78d 100644 --- a/Documentation/power/runtime_pm.rst +++ b/Documentation/power/runtime_pm.rst @@ -222,11 +222,12 @@ what to do to handle the device). I/O operations as needed. The runtime PM status of the device is then 'active'. - * If the resume callback returns an error code, the PM core regards this as a - fatal error and will refuse to run the helper functions described in - `Section 4`_ for the device, until its status is directly set to either - 'active', or 'suspended' (by means of special helper functions provided by - the PM core for this purpose). + * If the resume callback returns an error code, the PM core sets the + device's runtime PM status back to 'suspended' and returns the error + code from synchronous resume helpers. Unlike most suspend callback + errors, failures in the resume callback are never considered fatal, + so the helper functions described in `Section 4`_ are not blocked and + a subsequent resume request can run the resume callback again. The idle callback (a subsystem-level one, if present, or the driver one) is executed by the PM core whenever the device appears to be idle, which is @@ -250,9 +251,9 @@ call to pm_runtime_autosuspend(). To prevent this suspension (for example, if the callback routine has scheduled a delayed suspend or determined the device cannot be idle), the routine must return a non-zero value (typically -EBUSY or -EAGAIN). Unlike -->runtime_suspend() and ->runtime_resume(), the PM core does not treat negative -return codes from ->runtime_idle() as a fatal device error; any non-zero value -simply stops the PM core from suspending the device. +->runtime_suspend(), the PM core does not treat negative return codes from +->runtime_idle() as a fatal device error, and any non-zero value simply stops +the PM core from suspending the device. Core Guarantees and Synchronization Rules ----------------------------------------- diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 304a2b123420..4e9c23059a40 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -343,6 +343,9 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend) list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, device_links_read_lock_held()) { + if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) + continue; + pm_runtime_release_supplier(link); if (try_to_suspend) pm_request_idle(link->supplier); @@ -819,6 +822,12 @@ static int rpm_resume(struct device *dev, int rpmflags) pm_runtime_deactivate_timer(dev); if (dev->power.runtime_status == RPM_ACTIVE) { + /* + * The attempt to resume the device means that it is needed for + * something, so update its last_busy timestamp as in the case + * in which it actually resumes below. + */ + pm_runtime_mark_last_busy(dev); retval = 1; goto out; } @@ -1910,7 +1919,7 @@ void pm_runtime_reinit(struct device *dev) void pm_runtime_remove(struct device *dev) { __pm_runtime_disable(dev, false); - flush_work(&dev->power.work); + cancel_work_sync(&dev->power.work); pm_runtime_reinit(dev); } diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 2e74a000cdc7..f64fa379c6b1 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -197,14 +197,13 @@ static unsigned extract_io(struct cpufreq_policy *policy, u32 value) { struct acpi_cpufreq_data *data = policy->driver_data; struct acpi_processor_performance *perf; - int i; + struct cpufreq_frequency_table *pos; perf = to_perf_data(data); - for (i = 0; i < perf->state_count; i++) { - if (value == perf->states[i].status) - return policy->freq_table[i].frequency; - } + cpufreq_for_each_entry(pos, policy->freq_table) + if (value == perf->states[pos->driver_data].status) + return pos->frequency; return 0; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 54dde8419bdc..24319b214d7b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -35,6 +35,9 @@ static LIST_HEAD(cpufreq_policy_list); /* Macros to iterate over CPU policies */ +#define for_each_policy(__policy) \ + list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) + #define for_each_suitable_policy(__policy, __active) \ list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) \ if ((__active) == !policy_is_inactive(__policy)) @@ -474,7 +477,7 @@ EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); static unsigned int __resolve_freq(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int min, unsigned int max, - unsigned int relation) + unsigned int relation, unsigned int *idx_p) { unsigned int idx; @@ -484,8 +487,9 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy, return target_freq; idx = cpufreq_frequency_table_target(policy, target_freq, min, max, relation); - policy->cached_resolved_idx = idx; - policy->cached_target_freq = target_freq; + if (idx_p) + *idx_p = idx; + return policy->freq_table[idx].frequency; } @@ -517,7 +521,10 @@ unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy, if (unlikely(min > max)) min = max; - return __resolve_freq(policy, target_freq, min, max, CPUFREQ_RELATION_LE); + policy->cached_target_freq = __resolve_freq(policy, target_freq, min, max, + CPUFREQ_RELATION_LE, + &policy->cached_resolved_idx); + return policy->cached_target_freq; } EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq); @@ -576,6 +583,8 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable) { int ret; + lockdep_assert_held_write(&policy->rwsem); + if (policy->boost_enabled == enable) return 0; @@ -1629,6 +1638,8 @@ static int cpufreq_online(unsigned int cpu) */ if (cpufreq_driver->set_boost && policy->boost_supported && (new_policy || !cpufreq_boost_enabled())) { + guard(cpufreq_policy_write)(policy); + ret = policy_set_boost(policy, cpufreq_boost_enabled()); if (ret) { /* If the set_boost fails, the online operation is not affected */ @@ -1956,6 +1967,14 @@ int cpufreq_generic_suspend(struct cpufreq_policy *policy) } EXPORT_SYMBOL(cpufreq_generic_suspend); +static void cpufreq_suspend_policy(struct cpufreq_policy *policy) +{ + guard(cpufreq_policy_write)(policy); + + cpufreq_stop_governor(policy); + policy->suspended = true; +} + /** * cpufreq_suspend() - Suspend CPUFreq governors. * @@ -1978,11 +1997,8 @@ void cpufreq_suspend(void) pr_debug("%s: Suspending Governors\n", __func__); for_each_active_policy(policy) { - if (has_target()) { - scoped_guard(cpufreq_policy_write, policy) { - cpufreq_stop_governor(policy); - } - } + if (has_target()) + cpufreq_suspend_policy(policy); if (cpufreq_driver->suspend && cpufreq_driver->suspend(policy)) pr_err("%s: Failed to suspend driver: %s\n", __func__, @@ -1994,6 +2010,41 @@ suspend: cpus_read_unlock(); } +static void cpufreq_resume_policy(struct cpufreq_policy *policy, bool start) +{ + guard(cpufreq_policy_write)(policy); + + if (!policy->suspended) + return; + + policy->suspended = false; + + if (policy_is_inactive(policy)) { + /* + * The policy was active when it was suspended, so its governor + * is still there. Let the governor go. + */ + cpufreq_exit_governor(policy); + return; + } + + if (!start) + return; + + /* + * Force executing the driver .target() callback, if present, in the + * next invocation of __cpufreq_driver_target() in case policy->cur has + * become stale while suspended, but do it only for drivers without a + * .get() callback for which cpufreq_verify_current_freq() is a NOP. + */ + if (cpufreq_driver->target && !cpufreq_driver->get) + policy->force_target = true; + + if (cpufreq_start_governor(policy)) + pr_err("%s: Failed to start governor for CPU%u's policy\n", + __func__, policy->cpu); +} + /** * cpufreq_resume() - Resume CPUFreq governors. * @@ -2003,11 +2054,12 @@ suspend: void cpufreq_resume(void) { struct cpufreq_policy *policy; - int ret; if (!cpufreq_driver) return; + guard(cpus_read_lock)(); + if (unlikely(!cpufreq_suspended)) return; @@ -2018,19 +2070,18 @@ void cpufreq_resume(void) pr_debug("%s: Resuming Governors\n", __func__); - for_each_active_policy(policy) { - if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) { - pr_err("%s: Failed to resume driver: %s\n", __func__, - cpufreq_driver->name); - } else if (has_target()) { - scoped_guard(cpufreq_policy_write, policy) { - ret = cpufreq_start_governor(policy); - } + for_each_policy(policy) { + int ret = 0; + if (cpufreq_driver->resume && !policy_is_inactive(policy)) { + ret = cpufreq_driver->resume(policy); if (ret) - pr_err("%s: Failed to start governor for CPU%u's policy\n", - __func__, policy->cpu); + pr_err("%s: Failed to resume driver: %s\n", __func__, + cpufreq_driver->name); } + + if (has_target()) + cpufreq_resume_policy(policy, ret == 0); } } @@ -2355,28 +2406,26 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation) { unsigned int old_target_freq = target_freq; + unsigned int idx = 0; if (cpufreq_disabled()) return -ENODEV; target_freq = __resolve_freq(policy, target_freq, policy->min, - policy->max, relation); + policy->max, relation, &idx); pr_debug("CPU %u: cur %u kHz -> target %u kHz (req %u kHz, rel %u)\n", policy->cpu, policy->cur, target_freq, old_target_freq, relation); /* - * This might look like a redundant call as we are checking it again - * after finding index. But it is left intentionally for cases where - * exactly same freq is called again and so we can save on few function - * calls. + * Unless invoking the target callback is forced, skip the update if the + * frequency is not really changing. */ - if (target_freq == policy->cur) { - if (!(cpufreq_driver->flags & CPUFREQ_NEED_UPDATE_LIMITS) || - !policy->update_limits) - return 0; - - policy->update_limits = false; + if (policy->force_target) { + /* Avoid forcing the driver callback unnecessarily next time. */ + policy->force_target = false; + } else if (target_freq == policy->cur) { + return 0; } if (cpufreq_driver->target) { @@ -2393,7 +2442,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, if (!cpufreq_driver->target_index) return -EINVAL; - return __target_index(policy, policy->cached_resolved_idx); + return __target_index(policy, idx); } EXPORT_SYMBOL_GPL(__cpufreq_driver_target); @@ -2412,12 +2461,17 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void) return NULL; } +static bool cpufreq_is_suspended(struct cpufreq_policy *policy) +{ + return cpufreq_suspended || policy->suspended; +} + static int cpufreq_init_governor(struct cpufreq_policy *policy) { int ret; - /* Don't start any governor operations if we are entering suspend */ - if (cpufreq_suspended) + /* Don't start any governor operations for suspended policies. */ + if (cpufreq_is_suspended(policy)) return 0; /* * Governor might not be initiated here if ACPI _PPC changed @@ -2460,7 +2514,7 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy) static void cpufreq_exit_governor(struct cpufreq_policy *policy) { - if (cpufreq_suspended || !policy->governor) + if (cpufreq_is_suspended(policy) || !policy->governor) return; pr_debug("%s: for CPU %u\n", __func__, policy->cpu); @@ -2475,7 +2529,7 @@ int cpufreq_start_governor(struct cpufreq_policy *policy) { int ret; - if (cpufreq_suspended) + if (cpufreq_is_suspended(policy)) return 0; if (!policy->governor) @@ -2499,7 +2553,7 @@ int cpufreq_start_governor(struct cpufreq_policy *policy) void cpufreq_stop_governor(struct cpufreq_policy *policy) { - if (cpufreq_suspended || !policy->governor) + if (cpufreq_is_suspended(policy) || !policy->governor) return; pr_debug("%s: for CPU %u\n", __func__, policy->cpu); @@ -2510,7 +2564,7 @@ void cpufreq_stop_governor(struct cpufreq_policy *policy) static void cpufreq_governor_limits(struct cpufreq_policy *policy) { - if (cpufreq_suspended || !policy->governor) + if (cpufreq_is_suspended(policy) || !policy->governor) return; pr_debug("%s: for CPU %u\n", __func__, policy->cpu); @@ -2630,6 +2684,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, struct cpufreq_governor *new_gov, unsigned int new_pol) { + bool need_update_limits = cpufreq_driver->flags & CPUFREQ_NEED_UPDATE_LIMITS; struct cpufreq_policy_data new_data; struct cpufreq_governor *old_gov; unsigned int freq; @@ -2666,26 +2721,26 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, * concurrently by cpufreq_driver_resolve_freq() during the update. */ freq = __resolve_freq(policy, new_data.max, new_data.min, new_data.max, - CPUFREQ_RELATION_H); + CPUFREQ_RELATION_H, NULL); if (freq != policy->max) { WRITE_ONCE(policy->max, freq); - policy->update_limits = true; + if (need_update_limits) + policy->force_target = true; } freq = __resolve_freq(policy, new_data.min, new_data.min, new_data.max, - CPUFREQ_RELATION_L); + CPUFREQ_RELATION_L, NULL); freq = min(freq, policy->max); if (freq != policy->min) { WRITE_ONCE(policy->min, freq); - policy->update_limits = true; + if (need_update_limits) + policy->force_target = true; } trace_cpu_frequency_limits(policy); cpufreq_update_pressure(policy); - policy->cached_target_freq = UINT_MAX; - pr_debug("new min and max freqs are %u - %u kHz\n", policy->min, policy->max); @@ -2711,6 +2766,12 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, cpufreq_exit_governor(policy); } + /* + * Initialize cached_target_freq while no governor is running to avoid + * racing with cpufreq_driver_resolve_freq(), which updates it. + */ + policy->cached_target_freq = UINT_MAX; + /* start new governor */ policy->governor = new_gov; ret = cpufreq_init_governor(policy); @@ -2747,7 +2808,8 @@ static void cpufreq_policy_refresh(struct cpufreq_policy *policy) * -> ask driver for current freq and notify governors about a change */ if (cpufreq_driver->get && has_target() && - (cpufreq_suspended || WARN_ON(!cpufreq_verify_current_freq(policy, false)))) + (cpufreq_is_suspended(policy) || + WARN_ON(!cpufreq_verify_current_freq(policy, false)))) return; refresh_frequency_limits(policy); @@ -2810,18 +2872,24 @@ int cpufreq_boost_set_sw(struct cpufreq_policy *policy, int state) } EXPORT_SYMBOL_GPL(cpufreq_boost_set_sw); +static DEFINE_MUTEX(cpufreq_boost_mutex); + static int cpufreq_boost_trigger_state(int state) { struct cpufreq_policy *policy; unsigned long flags; + bool boost_enabled; int ret = -EOPNOTSUPP; + guard(mutex)(&cpufreq_boost_mutex); + /* * Don't compare 'cpufreq_driver->boost_enabled' with 'state' here to * make sure all policies are in sync with global boost flag. */ write_lock_irqsave(&cpufreq_driver_lock, flags); + boost_enabled = cpufreq_driver->boost_enabled; cpufreq_driver->boost_enabled = state; write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -2830,6 +2898,8 @@ static int cpufreq_boost_trigger_state(int state) if (!policy->boost_supported) continue; + guard(cpufreq_policy_write)(policy); + ret = policy_set_boost(policy, state); if (unlikely(ret)) break; @@ -2841,7 +2911,7 @@ static int cpufreq_boost_trigger_state(int state) return 0; write_lock_irqsave(&cpufreq_driver_lock, flags); - cpufreq_driver->boost_enabled = !state; + cpufreq_driver->boost_enabled = boost_enabled; write_unlock_irqrestore(&cpufreq_driver_lock, flags); pr_err("%s: Cannot %s BOOST\n", diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 0e6ae4cdda5d..c78dcd681511 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -3389,10 +3389,11 @@ static void intel_cpufreq_cpu_exit(struct cpufreq_policy *policy) static int intel_cpufreq_suspend(struct cpufreq_policy *policy) { + struct cpudata *cpu = all_cpu_data[policy->cpu]; + intel_pstate_suspend(policy); if (hwp_active) { - struct cpudata *cpu = all_cpu_data[policy->cpu]; u64 value = READ_ONCE(cpu->hwp_req_cached); /* @@ -3403,6 +3404,17 @@ static int intel_cpufreq_suspend(struct cpufreq_policy *policy) value &= ~HWP_DESIRED_PERF(~0L); wrmsrq_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value); WRITE_ONCE(cpu->hwp_req_cached, value); + } else { + /* + * Invalidate the cached P-state value that may be stale when + * the governor is started again during resume and may prevent + * MSR_IA32_PERF_CTL from being updated. + * + * This does not require synchronization because the core + * prevents frequency updates for suspended policies from + * occurring. + */ + cpu->pstate.current_pstate = 0; } return 0; @@ -3649,12 +3661,12 @@ static struct acpi_platform_list plat_info[] __initdata = { static bool __init intel_pstate_platform_pwr_mgmt_exists(void) { const struct x86_cpu_id *id; - u64 misc_pwr; + u64 misc_pwr = 0; int idx; id = x86_match_cpu(intel_pstate_cpu_oob_ids); if (id) { - rdmsrq(MSR_MISC_PWR_MGMT, misc_pwr); + rdmsrq_safe(MSR_MISC_PWR_MGMT, &misc_pwr); if (misc_pwr & BITMASK_OOB) { pr_debug("Bit 8 or 18 in the MISC_PWR_MGMT MSR set\n"); pr_debug("P states are controlled in Out of Band mode by the firmware/hardware\n"); diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c index 70cab5f08bc6..f58649ff4f53 100644 --- a/drivers/powercap/intel_rapl_common.c +++ b/drivers/powercap/intel_rapl_common.c @@ -1139,21 +1139,23 @@ static struct rapl_pmu rapl_pmu; /* PMU helpers */ -static void set_pmu_cpumask(struct rapl_package *rp, cpumask_var_t mask) +static int get_pmu_cpu(struct rapl_package *rp) { int cpu; if (!rp->has_pmu) - return; + return nr_cpu_ids; /* Only TPMI & MSR RAPL are supported for now */ if (rp->priv->type != RAPL_IF_TPMI && rp->priv->type != RAPL_IF_MSR) - return; + return nr_cpu_ids; /* TPMI/MSR RAPL uses any CPU in the package for PMU */ for_each_online_cpu(cpu) if (topology_physical_package_id(cpu) == rp->id) - cpumask_set_cpu(cpu, mask); + return cpu; + + return nr_cpu_ids; } static bool is_rp_pmu_cpu(struct rapl_package *rp, int cpu) @@ -1435,6 +1437,7 @@ static ssize_t cpumask_show(struct device *dev, { struct rapl_package *rp; cpumask_var_t cpu_mask; + int cpu; int ret; if (!alloc_cpumask_var(&cpu_mask, GFP_KERNEL)) @@ -1446,7 +1449,9 @@ static ssize_t cpumask_show(struct device *dev, /* Choose a cpu for each RAPL Package */ list_for_each_entry(rp, &rapl_packages, plist) { - set_pmu_cpumask(rp, cpu_mask); + cpu = get_pmu_cpu(rp); + if (cpu < nr_cpu_ids) + cpumask_set_cpu(cpu, cpu_mask); } cpus_read_unlock(); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index d3d0d9d02aa4..be1eaa43aeb0 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -146,8 +146,11 @@ struct cpufreq_policy { /* Per policy boost supported flag. */ bool boost_supported; - /* Pending policy->min/max update for the driver */ - bool update_limits; + /* Force passing target frequency to the driver. */ + bool force_target; + + /* The policy has been suspended. */ + bool suspended; /* Cached frequency lookup from cpufreq_driver_resolve_freq. */ unsigned int cached_target_freq; |
