From e6f50e602e373583423654ec000cad8b8d08f7bc Mon Sep 17 00:00:00 2001 From: Christian Loehle Date: Tue, 3 Nov 2026 18:19:03 +0000 Subject: cpufreq: Hold the policy write lock when changing boost state The per-policy boost sysfs handler calls policy_set_boost() under policy->rwsem, but the global boost handler and cpufreq_online() do not. Consequently, global and per-policy boost changes can concurrently update policy->boost_enabled, invoke the driver callback and update the boost frequency QoS request. The driver callbacks also access policy state, e.g. CPPC updates cpuinfo.max_freq that assumes policy->rw_sem held. Take policy->rwsem around policy_set_boost() in both unlocked callers. Keep locking at the call sites because the per-policy sysfs handler already holds the lock. Fixes: 218a06a79d9a ("cpufreq: Support per-policy performance boost") Signed-off-by: Christian Loehle Link: https://patch.msgid.link/be3739f8-e668-4711-912c-91459d77ed35@arm.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 54dde8419bdc..015962e6c1fe 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -576,6 +576,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 +1631,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 */ @@ -2830,6 +2834,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; -- cgit v1.2.3 From eee2a44e4e2b41c0699919a550d41cc38daa4f42 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Nov 2026 20:45:38 +0100 Subject: cpufreq: Improve suspend-resume synchronization The suspend-resume synchronization in the cpufreq core is not perfect because the global cpufreq_suspended variable is set at the end of cpufreq_suspend() after stopping governors for all of the active policies, so the governor .limits() callback may run via cpufreq_governor_limits() after stopping the governor and before setting cpufreq_suspended which is questionable. Likewise, the governor .limits() callback may run between clearing cpufreq_suspended in cpufreq_resume() and starting the governor. Address this by adding a per-policy "suspended" flag that is always read under the policy rwsem and is updated under it when the governor is stopped in cpufreq_suspend() and when the governor is restarted in cpufreq_resume(). Also make cpufreq_resume() use the cpus_read_lock guard to reflect what is done in cpufreq_suspend() and call cpufreq_exit_governor() for policies that were suspended during a system suspend transition and are inactive during the subsequent system resume (to avoid leaking an inactive policy with a stopped governor that has not exited yet). Fixes: 8e30444e1530 ("cpufreq: fix cpufreq suspend/resume for intel_pstate") Fixes: b1b12babe3b7 ("cpufreq: update 'cpufreq_suspended' after stopping governors") Cc: All applicable Signed-off-by: Rafael J. Wysocki Tested-by: Zak Brighton Knight Reviewed-by: Zhongqiu Han Acked-by: Viresh Kumar Tested-by: Doug Smythies Tested-by: Christian Loehle Link: https://patch.msgid.link/4796894.LvFx2qVVIh@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 86 ++++++++++++++++++++++++++++++++++------------- include/linux/cpufreq.h | 3 ++ 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 015962e6c1fe..7b93cbf313bc 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)) @@ -1960,6 +1963,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. * @@ -1982,11 +1993,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__, @@ -1998,6 +2006,32 @@ 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; + + 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. * @@ -2007,11 +2041,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; @@ -2022,19 +2057,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); } } @@ -2416,12 +2450,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 @@ -2464,7 +2503,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); @@ -2479,7 +2518,7 @@ int cpufreq_start_governor(struct cpufreq_policy *policy) { int ret; - if (cpufreq_suspended) + if (cpufreq_is_suspended(policy)) return 0; if (!policy->governor) @@ -2503,7 +2542,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); @@ -2514,7 +2553,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); @@ -2751,7 +2790,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); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index d3d0d9d02aa4..20a6863b640a 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -149,6 +149,9 @@ struct cpufreq_policy { /* Pending policy->min/max update for the driver */ bool update_limits; + /* The policy has been suspended. */ + bool suspended; + /* Cached frequency lookup from cpufreq_driver_resolve_freq. */ unsigned int cached_target_freq; unsigned int cached_resolved_idx; -- cgit v1.2.3 From 342d3a73c5dbc2f1cd0c5142e2d11bda4dc54cd7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Nov 2026 20:47:48 +0100 Subject: cpufreq: Force passing target frequency to driver during resume The policy->cur value preserved across a system suspend-resume cycle may become stale in some cases and it may prevent the CPU performance scaling logic from being updated due to the target_freq == policy->cur check in __cpufreq_driver_target() [1]. To address this, adjust the existing mechanism to force the invocation of the driver .target() callback in __cpufreq_driver_target() and make cpufreq_resume_policy() use it. This involves renaming update_limits in struct cpufreq_policy to force_target and moving the driver CPUFREQ_NEED_UPDATE_LIMITS flag check from __cpufreq_driver_target() to cpufreq_set_policy(), where it is used as a condition for setting policy->force_target. In cpufreq_resume_policy(), policy->force_target is set for drivers that implement the .target() callback, but don't implement the .get() one, which is the case when the driver callback needs to run if policy->cur becomes stale while suspended. Fixes: 2f0aea936360 ("cpufreq: suspend governors on system suspend/hibernate") Link: https://lore.kernel.org/linux-pm/20261027143725.3763827-1-zakbrightonknight@gmail.com/ [1] Reported-by: Zak Brighton Knight Reported-by: Doug Smythies Cc: All applicable # eee2a44e4e2b cpufreq: Improve suspend-resume synchronization Signed-off-by: Rafael J. Wysocki Tested-by: Zak Brighton Knight Reviewed-by: Zhongqiu Han Acked-by: Viresh Kumar Tested-by: Doug Smythies Tested-by: Christian Loehle Link: https://patch.msgid.link/1995295.tdWV9SEqCh@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 33 +++++++++++++++++++++------------ include/linux/cpufreq.h | 4 ++-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7b93cbf313bc..c8ab23afa66d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2027,6 +2027,15 @@ static void cpufreq_resume_policy(struct cpufreq_policy *policy, bool start) 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); @@ -2404,17 +2413,14 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, 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) { @@ -2673,6 +2679,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; @@ -2712,7 +2719,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, CPUFREQ_RELATION_H); 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, @@ -2720,7 +2728,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, 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); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 20a6863b640a..be1eaa43aeb0 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -146,8 +146,8 @@ 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; -- cgit v1.2.3 From 02e77af824d5be3a94fdd885835a352f90d24c5c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Nov 2026 20:49:06 +0100 Subject: cpufreq: intel_pstate: Clear last written P-state value on suspend Preserving cpu->pstate.current_pstate across system suspend-resume cycles, when running in the passive mode with HWP disabled, is a mistake because its value from before system suspend may become stale after the subsequent system resume and in some cases it prevents MSR_IA32_PERF_CTL from being updated properly after system resume [1]. Address this by clearing cpu->pstate.current_pstate after the governor has been stopped during system suspend. Fixes: 001c76f05b01 ("cpufreq: intel_pstate: Generic governors support") Fixes: 4adcf2e5829f ("cpufreq: intel_pstate: Add ->offline and ->online callbacks") Link: https://lore.kernel.org/linux-pm/20261027143725.3763827-1-zakbrightonknight@gmail.com/ [1] Reported-by: Zak Brighton Knight Reported-by: Doug Smythies Cc: All applicable # 342d3a73c5db cpufreq: Force passing target frequency to driver during resume Signed-off-by: Rafael J. Wysocki Tested-by: Zak Brighton Knight Reviewed-by: Zhongqiu Han Acked-by: Viresh Kumar Tested-by: Doug Smythies Tested-by: Christian Loehle Link: https://patch.msgid.link/14150222.uLZWGnKmhe@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 0e6ae4cdda5d..dd1bca5e27f1 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; -- cgit v1.2.3 From 2c0e6f2858d235c99f7ba4621bd176cd67226f00 Mon Sep 17 00:00:00 2001 From: Li Zhaoxin Date: Wed, 4 Nov 2026 15:01:49 +0800 Subject: cpufreq: intel_pstate: Use rdmsrq_safe() to read MSR_MISC_PWR_MGMT Commit ed7cad0504e3 ("cpufreq: intel_pstate: Relocate platform preference check") moved the intel_pstate_platform_pwr_mgmt_exists() call to the beginning of intel_pstate_init(), right after the vendor check, so it now runs before "no_load" (intel_pstate=disable) and the other checks. MSR_MISC_PWR_MGMT is model-specific and KVM does not emulate it. In a KVM guest using a CPU model listed in intel_pstate_cpu_oob_ids[] (for example "-cpu host" on Emerald Rapids), reading it raises #GP and the unchecked rdmsrq() emits a warning with a call trace on every boot, even with intel_pstate=disable: unchecked MSR access error: RDMSR from 0x1aa at rIP: 0xffffffffa4009342 (native_read_msr+0x2/0x50) Call Trace: intel_pstate_platform_pwr_mgmt_exists+0x3b/0x220 intel_pstate_init+0x1e/0x500 do_one_initcall+0x59/0x350 ... Before that commit, such guests typically returned from intel_pstate_init() earlier, either because of intel_pstate=disable or because intel_pstate_msrs_not_valid() failed on the zero ratios that KVM reports in MSR_PLATFORM_INFO by default, so the MSR was not read. Use rdmsrq_safe() and treat a failing read as "no OOB mode". The exception fixup already zeroes the result of a failed unchecked read, so apart from the warning going away there is no functional change. Fixes: ed7cad0504e3 ("cpufreq: intel_pstate: Relocate platform preference check") Cc: All applicable Signed-off-by: Li Zhaoxin Link: https://patch.msgid.link/20261104070149.41393-1-lizhaoxin04@baidu.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index dd1bca5e27f1..c78dcd681511 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -3661,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"); -- cgit v1.2.3 From 1f65b45f0f16e1c80a68a5757c9556f78bb39f19 Mon Sep 17 00:00:00 2001 From: Zhou Minqiang Date: Wed, 4 Nov 2026 19:56:41 +0800 Subject: PM: runtime: Fix check_flush_dependency warning from pm_runtime_remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a WQ_MEM_RECLAIM workqueue (e.g. iscsi_ctrl) triggers device removal via device_del -> pm_runtime_remove, the unconditional flush_work inside pm_runtime_remove can trigger a check_flush_dependency warning: CPU1: pm_wq worker CPU2: iscsi_ctrl wq -------- -------- pm_runtime_work(starget) pm_runtime_remove(starget) spin_lock_irq(&starget->lock) __pm_runtime_disable(starget, false) request_pending = false spin_lock_irq(&starget->lock) (blocked, CPU1 holds the lock) rpm_suspend(starget, RPM_NOWAIT) status = RPM_SUSPENDING rpm_callback(cb, starget) spin_unlock_irq(&starget->lock) (acquires lock) disable_depth 0→1 __pm_runtime_barrier(): request_pending == false → skip cancel_work_sync status == RPM_SUSPENDING → enter wait_queue, sleep spin_unlock_irq(&starget->lock) cb(starget) → 0 spin_lock_irq(&starget->lock) status = RPM_SUSPENDED wake_up_all(&wait_queue) (woken up, waiting for lock) spin_unlock(&starget->lock) spin_lock_irq(&starget->lock) status == RPM_SUSPENDED spin_lock(&parent->lock) → exit wait_queue rpm_idle(parent, RPM_ASYNC) barrier returns spin_unlock(&parent->lock) flush_work(&starget->work) spin_lock(&starget->lock) __flush_work(from_cancel=false) spin_unlock_irq(&starget->lock) check_flush_dependency() ← WARNING! Replace flush_work with cancel_work_sync in pm_runtime_remove. cancel_work_sync internally calls __flush_work with from_cancel=true, which causes check_flush_dependency to return early before the warning. This preserves the use-after-free fix from commit 29ab76827761 ("PM: runtime: Fix a race condition related to device removal") without the warning. Fixes: 29ab76827761 ("PM: runtime: Fix a race condition related to device removal") Signed-off-by: Zhou Minqiang Link: https://patch.msgid.link/20261104115641.2682786-1-zhouminqiang2@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 304a2b123420..2a27b7a6f760 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1910,7 +1910,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); } -- cgit v1.2.3 From bd56424ce808fb1f92a4dc5bdeedc45b85c5d6cd Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 3 Nov 2026 14:14:39 -0800 Subject: PM: runtime: Only queue an idle check for RPM-linked suppliers (part 2) Commit be5755f023e7 ("PM: runtime: Only queue an idle check for RPM-linked suppliers") was incomplete. There are two other cases where we perform idle checks on non-DL_FLAG_PM_RUNTIME suppliers -- in pm_runtime_set_suspended(), and in cases where we failed to resume suppliers. Fixes: be5755f023e7 ("PM: runtime: Only queue an idle check for RPM-linked suppliers") Fixes: 5244f5e2d801 ("PM: runtime: Defer suspending suppliers") Signed-off-by: Brian Norris Link: https://patch.msgid.link/20261103141442.v2.1.If69ddc515c2e9fd4338441e87688b9d690d2ef36@changeid Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 2a27b7a6f760..bad224e0386a 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); -- cgit v1.2.3 From 7a93f7e30a3f7c8dd4f5fe4cde54d01c8018e2bc Mon Sep 17 00:00:00 2001 From: Stanley Jhu Date: Wed, 4 Nov 2026 23:16:51 +0800 Subject: PM: runtime: Update runtime_pm.rst for non-fatal resume errors Since commit eef1d74bf88f ("PM: runtime: Only set runtime_error on suspend callback failures"), rpm_callback() no longer sets dev->power.runtime_error when ->runtime_resume() returns an error. However, Documentation/power/runtime_pm.rst still states in both the resume callback rules and the ->runtime_idle() comparison that the PM core treats ->runtime_resume() errors as fatal device errors and blocks runtime PM helper functions until the status is manually reset. Update the resume callback semantics bullet to state that on error the PM core resets the runtime PM status to 'suspended', returns the error code from synchronous resume helpers, and unlike with the suspend callback never treats resume failures as fatal, leaving the Section 4 runtime PM helpers unblocked so a subsequent resume request can run ->runtime_resume() again. Also drop ->runtime_resume() from the ->runtime_idle() fatal-error comparison. Fixes: eef1d74bf88f ("PM: runtime: Only set runtime_error on suspend callback failures") Fixes: aedc51762a0d ("PM: runtime: Clarify ->runtime_idle() callback return value handling") Signed-off-by: Stanley Jhu Reviewed-by: Brian Norris Reviewed-by: Bart Van Assche [ rjw: Adjustment of the resume callback errors bullet point ] Link: https://patch.msgid.link/20261104151651.3035537-1-stanleyjhu@google.com Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 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 ----------------------------------------- -- cgit v1.2.3 From a0cde2b601bc32b76d61e50141c619790e5e2e41 Mon Sep 17 00:00:00 2001 From: Christian Loehle Date: Thu, 5 Nov 2026 21:52:22 +0000 Subject: cpufreq: Preserve global boost state on failed updates cpufreq_boost_trigger_state() restores the opposite of the requested state when updating policy boost state fails. For example, a failed write of 0 when global boost is already disabled enables the global flag without enabling any policies. Save the original global boost state and restore it on failure. Fixes: 121baab7b88e ("cpufreq: Force sync policy boost with global boost on sysfs update") Signed-off-by: Christian Loehle Reviewed-by: Pengjie Zhang Reviewed-by: Zhongqiu Han Reviewed-by: Sumit Gupta Link: https://patch.msgid.link/20261105215223.1263415-2-christian.loehle@arm.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c8ab23afa66d..f0943ba3c84d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2867,6 +2867,7 @@ static int cpufreq_boost_trigger_state(int state) { struct cpufreq_policy *policy; unsigned long flags; + bool boost_enabled; int ret = -EOPNOTSUPP; /* @@ -2875,6 +2876,7 @@ static int cpufreq_boost_trigger_state(int state) */ 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); @@ -2896,7 +2898,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", -- cgit v1.2.3 From 3d5720dff09f3b90d9ab2a6707e4bb8d69542f4a Mon Sep 17 00:00:00 2001 From: Christian Loehle Date: Thu, 5 Nov 2026 21:52:23 +0000 Subject: cpufreq: Serialize global boost updates Concurrent global boost sysfs writes can interleave their global flag and per-policy updates. An enabling write can set the global flag, then a disabling write can clear it and finish before the enabling write updates the policies. Both writes succeed, leaving boost enabled on the policies while the global flag is disabled. Serialize the complete global boost update, including rollback on failure, with a mutex. Fixes: 6f19efc0a1ca ("cpufreq: Add boost frequency support in core") Signed-off-by: Christian Loehle Reviewed-by: Pengjie Zhang Reviewed-by: Zhongqiu Han Reviewed-by: Sumit Gupta Link: https://patch.msgid.link/20261105215223.1263415-3-christian.loehle@arm.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f0943ba3c84d..c246e5f7510d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2863,6 +2863,8 @@ 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; @@ -2870,6 +2872,8 @@ static int cpufreq_boost_trigger_state(int state) 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. -- cgit v1.2.3 From 6bc092a0fc4d331a4adbbb664078af149c580834 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Thu, 10 Sep 2026 19:13:28 +0800 Subject: cpufreq: acpi-cpufreq: fix P-state index mismatch in extract_io() When policy->freq_table is built in acpi_cpufreq_cpu_init(), entries that are not lower in frequency than the previous one are skipped. For each remaining entry, freq_table[].driver_data stores the original ACPI P-state index, so the index space of freq_table no longer matches perf->states[]. extract_io() currently walks perf->states[] with index i and uses the same i to index policy->freq_table[i]. When duplicate frequencies exist, this can associate a P-state status with the frequency of a different P-state. It can also access an invalid or sentinel entry in freq_table when the number of entries in perf->states[] is greater than the number of entries remaining in the frequency table. extract_io() is used on ACPI_ADR_SPACE_SYSTEM_IO platforms by the frequency verification path, which is enabled by the acpi_pstate_strict module parameter. With the mismatched lookup, check_freqs() can fail to match the frequency of the P-state that drv_write() has already programmed. It then sleeps through all 100 iterations - at least ~1 ms of usleep_range() plus 100 cross-CPU calls and I/O port reads, all with policy->rwsem held, and .target_index() returns -EAGAIN, leaving perf->state at its previous value while the hardware is running at the newly requested P-state. The cpufreq core consequently keeps policy->cur at the old frequency. Since __cpufreq_driver_target() returns early when the requested frequency equals policy->cur, the driver is not called again for that frequency and the control register is not rewritten. The hardware can therefore remain at a frequency that differs from the frequency known to the cpufreq core. Fix this by iterating over policy->freq_table and using pos->driver_data as the original ACPI P-state index when accessing perf->states[], as extract_msr() already does. Fixes: fe27cb358835 ("[CPUFREQ][2/8] acpi: reorganize code to make MSR support addition easier") Signed-off-by: Li RongQing Reviewed-by: Zhongqiu Han Cc: All applicable Link: https://patch.msgid.link/20260910111329.2220-2-lirongqing@baidu.com Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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; } -- cgit v1.2.3 From 166207cac45191637c47a457a5c16ca6b6773a16 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 6 Nov 2026 16:04:05 +0100 Subject: cpufreq: Cache post-resolution target frequency in __resolve_freq() get_next_freq() in the schedutil governor returns the resolved frequency from cpufreq_driver_resolve_freq(), and that resolved value is then passed to cpufreq_driver_fast_switch(). The only reader of cached_target_freq, acpi_cpufreq_fast_switch(), compares it with the post-resolution target frequency, but it holds the pre-resolution clamped frequency, so any request that falls between table entries misses the cache and falls back to a table scan. Address this by making __resolve_freq() store the post-resolution frequency in cached_target_freq. Fixes: e3c062360870 ("cpufreq: add cpufreq_driver_resolve_freq()") Cc: All applicable Signed-off-by: Rafael J. Wysocki Reviewed-by: Christian Loehle Tested-by: Christian Loehle Link: https://patch.msgid.link/14161745.uLZWGnKmhe@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c246e5f7510d..6370d0e71331 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -488,8 +488,8 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy, idx = cpufreq_frequency_table_target(policy, target_freq, min, max, relation); policy->cached_resolved_idx = idx; - policy->cached_target_freq = target_freq; - return policy->freq_table[idx].frequency; + policy->cached_target_freq = policy->freq_table[idx].frequency; + return policy->cached_target_freq; } /** -- cgit v1.2.3 From 75120f31aed010c326b28d7c80d22314df34d9a8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 6 Nov 2026 16:05:06 +0100 Subject: cpufreq: Fix updates of cached resolved frequency and index The cached resolved frequency and index, cached_target_freq and cached_resolved_idx, respectively, may be updated concurrently if cpufreq_driver_resolve_freq() is called by the schedutil governor while cpufreq_set_policy() is running for the same policy. Those concurrent updates are not synchronized in any way and the values written by cpufreq_set_policy(), if it wins the race, may confuse drivers using those policy fields [1]. To address this, use the observation that the only place where cached_target_freq and cached_resolved_idx need to be updated is cpufreq_driver_resolve_freq() because the only legitimate users of them are .fast_switch() driver callbacks. Although cached_resolved_idx is also used in __cpufreq_driver_target(), that is in fact unnecessary and it is better to use a local variable for storing the frequency table index in that function. Accordingly, rearrange __resolve_freq() and its callers so that cached_target_freq and cached_resolved_idx are only updated in cpufreq_driver_resolve_freq(). The cached_target_freq initialization in cpufreq_set_policy() is still needed, but move it after stopping the old governor and before starting the new one to avoid racing with cpufreq_driver_resolve_freq(). Fixes: f9ccdec24d91 ("cpufreq: Reuse cpufreq_driver_resolve_freq() in __cpufreq_driver_target()") Fixes: 151717690694 ("cpufreq: Make policy min/max hard requirements") Reported-by: Zhongqiu Han Closes: https://lore.kernel.org/linux-pm/20261105140357.1331894-1-zhongqiu.han@oss.qualcomm.com/ [1] Co-developed-by: Zhongqiu Han Signed-off-by: Zhongqiu Han Signed-off-by: Rafael J. Wysocki Reviewed-by: Christian Loehle Tested-by: Christian Loehle Cc: All applicable # 342d3a73c5db cpufreq: Force passing target frequency to driver during resume Cc: All applicable # 166207cac451 cpufreq: Cache post-resolution target frequency in __resolve_freq() Link: https://patch.msgid.link/3472677.aeNJFYEL58@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 6370d0e71331..24319b214d7b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -477,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; @@ -487,9 +487,10 @@ 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 = policy->freq_table[idx].frequency; - return policy->cached_target_freq; + if (idx_p) + *idx_p = idx; + + return policy->freq_table[idx].frequency; } /** @@ -520,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); @@ -2402,12 +2406,13 @@ 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); @@ -2437,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); @@ -2716,7 +2721,7 @@ 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); if (need_update_limits) @@ -2724,7 +2729,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, } 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); @@ -2736,8 +2741,6 @@ static int cpufreq_set_policy(struct cpufreq_policy *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); @@ -2763,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); -- cgit v1.2.3 From 55b2b8af704f845e01fa2f31ee259b07641ce3a9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 6 Nov 2026 12:31:41 +0100 Subject: PM: runtime: Update last_busy in rpm_resume() for active devices Setting an autosuspend delay for a device can be expected to cause a runtime suspend of the device after calling, say, pm_runtime_put() to be deferred, so the time between the last successful attempt to resume the device and its subsequent suspend is at least equal to the autosuspend delay. However, that expectation is only met after the device has been actually resumed in rpm_resume() by invoking its runtime resume callback. If the runtime PM status of the device is already "active" when rpm_resume() runs for it, the device's last_busy timestamp is not updated which may allow a subsequent pm_runtime_put() invocation (or similar) to suspend it right away. This is arguably inconsistent and confusing, so make rpm_resume() also update the device's last_busy timestamp when it finds that the device is already "active" and it is about to return 1 early. Fixes: 56f487c78015 ("PM / Runtime: Update last_busy in rpm_resume") Link: https://lore.kernel.org/linux-pm/CAJZ5v0jTX1FgeS9FCV=+V4uacSgLQBVsSPnU27ybgUGg57GUOA@mail.gmail.com/ Reported-by: Brian Norris Cc: All applicable Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern Reviewed-by: Brian Norris Tested-by: Brian Norris Link: https://patch.msgid.link/13032301.O9o76ZdvQC@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index bad224e0386a..4e9c23059a40 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -822,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; } -- cgit v1.2.3 From a74c332aaf46270101b32a32311275d86953a2b5 Mon Sep 17 00:00:00 2001 From: Dennis Chen Date: Fri, 6 Nov 2026 15:31:15 -0500 Subject: Revert "powercap: intel_rapl: Expose all package CPUs in PMU cpumask" Commit 525e0064f3d8 ("powercap: intel_rapl: Expose all package CPUs in PMU cpumask") expanded cpumask to include all CPUs in the package. Since perf opens an event for every CPU in cpumask, the value returned for power/energy-pkg/ is roughly scaled by the number of CPUs. On a single-socket 72-core DMR machine the reported value is roughly 72x higher than when perf is restricted to reading from a single CPU: $ perf stat -e power/energy-pkg/ -- sleep 1 Performance counter stats for 'system wide': 8,052.48 Joules power/energy-pkg/ 1.010483558 seconds time elapsed $ perf stat -C 5 -e power/energy-pkg/ -- sleep 1 Performance counter stats for 'CPU(s) 5': 112.15 Joules power/energy-pkg/ 1.009685587 seconds time elapsed Reverting this commit restores the expected behavior for perf. Fixes: 525e0064f3d8 ("powercap: intel_rapl: Expose all package CPUs in PMU cpumask") Cc: All applicable Signed-off-by: Dennis Chen Link: https://patch.msgid.link/20261106203115.237269-1-dechen@redhat.com Signed-off-by: Rafael J. Wysocki --- drivers/powercap/intel_rapl_common.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) 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(); -- cgit v1.2.3