Merge tag 'pm-7.3-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more power management updates from Rafael Wysocki:
 "These fix two issues in the intel_rapl power capping driver, fix a
  potential issue in the schedutil cpufreq governor on 32-bit systems,
  fix a runtime PM issue related to failing system suspend, and update
  the intel_pstate cpufreq driver:

   - Fix a kernel panic during PMU unbind in the intel_rapl power
     capping driver and sign-extend the PMU delta on counter wraparound
     in it to avoid misreporting energy (Sumeet Pawnikar and Yifan Li)

   - Unblock runtime PM when device prepare fails that was not done by
     mistake (Shibo Zhu)

   - Fix possible rate limit overflow on 32-bit systems in the schedutil
     cpufreq governor (Hui Su)

   - Consolidate HWP P-states initialization in the intel_pstate cpufreq
     driver and make that driver avoid using the DESIRED_PERF HWP hint
     when the Dynamic Efficiency Control (DEC) is enabled in the
     processor to avoid inconsistent behavior (Rafael Wysocki)"

* tag 'pm-7.3-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  powercap: intel_rapl: Fix kernel panic during PMU unbind
  PM: sleep: Unblock runtime PM when device prepare fails
  powercap: intel_rapl: Sign-extend the PMU delta on counter wraparound
  cpufreq: intel_pstate: Avoid using DESIRED_PERF when DEC is enabled
  cpufreq: intel_pstate: Consolidate HWP P-states initialization
  cpufreq: schedutil: Fix rate limit overflow
This commit is contained in:
Linus Torvalds
2026-08-26 14:13:26 -07:00
4 changed files with 90 additions and 67 deletions

View File

@@ -2248,6 +2248,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
if (ret < 0) {
suspend_report_result(dev, callback, ret);
pm_runtime_unblock(dev);
pm_runtime_put(dev);
return ret;
}

View File

@@ -303,6 +303,7 @@ static bool per_cpu_limits __ro_after_init;
static bool hwp_forced __ro_after_init;
static bool hwp_boost __read_mostly;
static bool hwp_is_hybrid;
static u32 hwp_desired_mask __read_mostly = ~0U;
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
@@ -555,47 +556,6 @@ static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq)
return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L);
}
/**
* intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels.
* @cpu: Target CPU.
*
* On hybrid processors, HWP may expose more performance levels than there are
* P-states accessible through the PERF_CTL interface. If that happens, the
* scaling factor between HWP performance levels and CPU frequency will be less
* than the scaling factor between P-state values and CPU frequency.
*
* In that case, adjust the CPU parameters used in computations accordingly.
*/
static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
{
int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu);
int scaling = cpu->pstate.scaling;
int freq;
pr_debug("CPU%d: PERF_CTL max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
pr_debug("CPU%d: PERF_CTL turbo = %d\n", cpu->cpu, perf_ctl_turbo);
pr_debug("CPU%d: PERF_CTL scaling = %d\n", cpu->cpu, perf_ctl_scaling);
pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpu->cpu, cpu->pstate.max_pstate);
pr_debug("CPU%d: HWP_CAP highest = %d\n", cpu->cpu, cpu->pstate.turbo_pstate);
pr_debug("CPU%d: HWP-to-frequency scaling factor: %d\n", cpu->cpu, scaling);
if (scaling == perf_ctl_scaling)
return;
hwp_is_hybrid = true;
freq = perf_ctl_max_phys * perf_ctl_scaling;
cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
/*
* Cast the min P-state value retrieved via pstate_funcs.get_min() to
* the effective range of HWP performance levels.
*/
cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, cpu->pstate.min_freq);
}
static bool turbo_is_disabled(void)
{
u64 misc_en;
@@ -2293,34 +2253,70 @@ static int hwp_get_cpu_scaling(int cpu)
return intel_pstate_cppc_get_scaling(cpu);
}
static void intel_pstate_get_hwp_pstates(struct cpudata *cpu)
{
int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
int perf_ctl_turbo = cpu->pstate.turbo_pstate;
int cpuid = cpu->cpu;
__intel_pstate_get_hwp_cap(cpu);
if (!pstate_funcs.get_cpu_scaling)
return;
pr_debug("CPU%d: PERF_CTL max_phys = %d\n", cpuid, perf_ctl_max_phys);
pr_debug("CPU%d: PERF_CTL turbo = %d\n", cpuid, perf_ctl_turbo);
pr_debug("CPU%d: PERF_CTL scaling = %d\n", cpuid, perf_ctl_scaling);
pr_debug("CPU%d: PERF_CTL min = %d\n", cpuid, cpu->pstate.min_pstate);
pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpuid, cpu->pstate.max_pstate);
pr_debug("CPU%d: HWP_CAP highest = %d\n", cpuid, cpu->pstate.turbo_pstate);
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpuid);
pr_debug("CPU%d: HWP-to-frequency scaling = %d\n", cpuid, cpu->pstate.scaling);
/*
* On hybrid processors, HWP may expose more performance levels than
* there are P-states accessible through the PERF_CTL interface. If
* that happens, the scaling between HWP performance levels and CPU
* frequency will be less than the scaling between P-state values and
* CPU frequency. In that case, update the maximum physical non-turbo
* performance level accordingly.
*/
if (cpu->pstate.scaling != perf_ctl_scaling) {
int freq;
freq = perf_ctl_max_phys * perf_ctl_scaling;
cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
freq = cpu->pstate.min_freq;
cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
hwp_is_hybrid = true;
}
/*
* If the CPU is going online for the first time and it was offline
* initially, asym capacity scaling may need to be updated.
*/
hybrid_update_capacity(cpu);
}
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
int perf_ctl_scaling = pstate_funcs.get_scaling();
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(cpu->cpu);
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu);
cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
cpu->pstate.scaling = perf_ctl_scaling;
if (hwp_active) {
__intel_pstate_get_hwp_cap(cpu);
if (pstate_funcs.get_cpu_scaling) {
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
intel_pstate_hybrid_hwp_adjust(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
}
/*
* If the CPU is going online for the first time and it was
* offline initially, asym capacity scaling needs to be updated.
*/
hybrid_update_capacity(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
if (hwp_active)
intel_pstate_get_hwp_pstates(cpu);
else
cpu->pstate.max_pstate = pstate_funcs.get_max(cpu->cpu);
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
}
intel_pstate_update_freq_limits(cpu);
@@ -3155,7 +3151,7 @@ static void intel_cpufreq_hwp_update(struct cpudata *cpu, u32 min, u32 max,
value |= HWP_MAX_PERF(max);
value &= ~HWP_DESIRED_PERF(~0L);
value |= HWP_DESIRED_PERF(desired);
value |= HWP_DESIRED_PERF(desired & hwp_desired_mask);
if (value == prev)
return;
@@ -3765,9 +3761,9 @@ static bool hwp_check_epp(void)
static bool hwp_check_dec(void)
{
u64 power_ctl;
u64 power_ctl = 0;
rdmsrq(MSR_IA32_POWER_CTL, power_ctl);
rdmsrq_safe(MSR_IA32_POWER_CTL, &power_ctl);
return !!(power_ctl & BIT(POWER_CTL_DEC_ENABLE));
}
@@ -3792,6 +3788,7 @@ static int __init intel_pstate_init(void)
id = x86_match_cpu(hwp_support_ids);
if (id) {
bool epp_present = hwp_check_epp();
bool dec_present = hwp_check_dec();
/*
* If HWP is enabled already, there is no choice but to deal
@@ -3803,7 +3800,7 @@ static int __init intel_pstate_init(void)
no_hwp = 0;
} else if (no_load) {
return -ENODEV;
} else if (!epp_present && !hwp_check_dec()) {
} else if (!epp_present && !dec_present) {
/*
* Avoid enabling HWP for processors without EPP support
* unless the Dynamic Efficiency Control (DEC) enable
@@ -3825,6 +3822,9 @@ static int __init intel_pstate_init(void)
if (!default_driver)
default_driver = &intel_pstate;
if (dec_present)
hwp_desired_mask = 0;
if (!id->driver_data)
pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;

View File

@@ -32,6 +32,9 @@
#define ENERGY_STATUS_MASK GENMASK(31, 0)
/* Width of the RAPL energy counters, see the *_ENERGY_STATUS_MASK defines */
#define RAPL_CNTR_WIDTH 32
#define POWER_UNIT_OFFSET 0x00
#define POWER_UNIT_MASK GENMASK(3, 0)
@@ -1227,6 +1230,7 @@ static u64 rapl_event_update(struct perf_event *event)
struct rapl_package_pmu_data *data = event_to_pmu_data(event);
u64 prev_raw_count, new_raw_count;
s64 delta, sdelta;
int shift = 64 - RAPL_CNTR_WIDTH;
/*
* Follow the generic code to drain hwc->prev_count.
@@ -1243,8 +1247,13 @@ static u64 rapl_event_update(struct perf_event *event)
* Now we have the new raw value and have updated the prev
* timestamp already. We can now calculate the elapsed delta
* (event-)time and add that to the generic event.
*
* Careful, the counter is narrower than u64 and is not
* sign-extended above its physical width. Shift both values up
* so that the subtraction wraps, then shift the result back down.
*/
delta = new_raw_count - prev_raw_count;
delta = (new_raw_count << shift) - (prev_raw_count << shift);
delta >>= shift;
/*
* Scale delta to smallest unit (2^-32)
@@ -1652,7 +1661,9 @@ void rapl_package_remove_pmu_locked(struct rapl_package *rp)
return;
}
perf_pmu_unregister(&rapl_pmu.pmu);
if (rapl_pmu.registered)
perf_pmu_unregister(&rapl_pmu.pmu);
memset(&rapl_pmu, 0, sizeof(struct rapl_pmu));
}
EXPORT_SYMBOL_NS_GPL(rapl_package_remove_pmu_locked, "INTEL_RAPL");

View File

@@ -62,6 +62,17 @@ static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
/************************ Governor internals ***********************/
static void sugov_update_rate_limit_us(struct sugov_policy *sg_policy)
{
/*
* Cast rate_limit_us before multiplication to force 64-bit arithmetic.
* Otherwise, on 32-bit platforms, both operands are converted to
* 32-bit unsigned long and the multiplication may overflow.
*/
sg_policy->freq_update_delay_ns =
(s64)sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
}
static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
{
s64 delta_ns;
@@ -608,7 +619,7 @@ rate_limit_us_store(struct gov_attr_set *attr_set, const char *buf, size_t count
tunables->rate_limit_us = rate_limit_us;
list_for_each_entry(sg_policy, &attr_set->policy_list, tunables_hook)
sg_policy->freq_update_delay_ns = rate_limit_us * NSEC_PER_USEC;
sugov_update_rate_limit_us(sg_policy);
return count;
}
@@ -850,7 +861,7 @@ static int sugov_start(struct cpufreq_policy *policy)
void (*uu)(struct update_util_data *data, u64 time, unsigned int flags);
unsigned int cpu;
sg_policy->freq_update_delay_ns = sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
sugov_update_rate_limit_us(sg_policy);
sg_policy->last_freq_update_time = 0;
sg_policy->next_freq = 0;
sg_policy->work_in_progress = false;