Merge branch 'pm-cpufreq'

Merge cpufreq updates for 7.2:

 - Fix a race between cpufreq suspend and CPU hotplug during system
   shutdown (Tianxiang Chen)

 - Avoid redundant target() calls for unchanged limits and fix a typo
   in a comment in the cpufreq core (Viresh Kumar)

 - Fix concurrency issues related to sysfs attributes access that affect
   cpufreq governors using the common governor code (Zhongqiu Han)

 - Simplify frequency limit handling in the conservative cpufreq
   governor (Lifeng Zheng)

 - Fix descriptions of the conservative governor freq_step tunable and
   the ondemand governor sampling_down_factor tunable in the cpufreq
   documentation (Pengjie Zhang)

 - Fix use-after-free and double free during _OSC evaluation in the PCC
   cpufreq driver (Yuho Choi)

 - Rework the handling of policy min and max frequency values in the
   cpufreq core to allow drivers to specify special initial values for
   the scaling_min_freq and scaling_max_freq sysfs attributes (Pierre
   Gondois)

 - Add cpufreq scaling support for Qualcomm Shikra SoC (Taniya Das,
   Imran Shaik).

 - Improve the warning message on HWP-disabled hybrid processors printed
   by the intel_pstate driver and sync policy->cur during CPU offline in
   it (Yohei Kojima, Fushuai Wang)

 - Drop cpufreq support for AMD Elan SC4* (Sean Young)

 - Minor fixes for cpufreq drivers (Krzysztof Kozlowski, Akashdeep Kaur,
   Hans Zhang, Guangshuo Li, Xueqin Luo)

 - Clean up dead dependencies on X86 in the cpufreq Kconfig (Julian
   Braha)

* pm-cpufreq: (25 commits)
  cpufreq: Use policy->min/max init as QoS request
  cpufreq: Remove driver default policy->min/max init
  cpufreq: Set default policy->min/max values for all drivers
  cpufreq: Extract cpufreq_policy_init_qos() function
  cpufreq: Documentation: fix conservative governor freq_step description
  cpufreq: ti: Add EPROBE_DEFER for K3 SoCs
  cpufreq: qcom: Add cpufreq scaling support for Qualcomm Shikra SoC
  dt-bindings: cpufreq: Document Qualcomm Shikra SoC EPSS
  cpufreq: governor: Fix stale prev_cpu_nice spike when enabling ignore_nice_load
  cpufreq: governor: Fix data races on per-CPU idle/nice baselines
  cpufreq: intel_pstate: Improve warning message on HWP-disabled hybrid CPUs
  cpufreq: elanfreq: Drop support for AMD Elan SC4*
  cpufreq: clean up dead dependencies on X86 in Kconfig
  cpufreq: conservative: Simplify frequency limit handling
  cpufreq: Avoid redundant target() calls for unchanged limits
  cpufreq: Fix typo in comment
  cpufreq: intel_pstate: Sync policy->cur during CPU offline
  cpufreq: Documentation: fix sampling_down_factor range
  cpufreq: Fix hotplug-suspend race during reboot
  cpufreq: pcc: fix use-after-free and double free in _OSC evaluation
  ...
This commit is contained in:
Rafael J. Wysocki
2026-06-11 21:19:13 +02:00
25 changed files with 318 additions and 376 deletions

View File

@@ -1651,10 +1651,6 @@ Kernel parameters
very early in the boot process. For early debugging
via a serial port see kgdboc_earlycon instead.
elanfreq= [X86-32]
See comment before function elanfreq_setup() in
arch/x86/kernel/cpu/cpufreq/elanfreq.c.
elfcorehdr=[size[KMG]@]offset[KMG] [PPC,SH,X86,S390,EARLY]
Specifies physical address of start of kernel core
image elf header and optionally the size. Generally

View File

@@ -516,7 +516,7 @@ This governor exposes the following tunables:
of those tasks above 0 and set this attribute to 1.
``sampling_down_factor``
Temporary multiplier, between 1 (default) and 100 inclusive, to apply to
Temporary multiplier, between 1 (default) and 100000 inclusive, to apply to
the ``sampling_rate`` value if the CPU load goes above ``up_threshold``.
This causes the next execution of the governor's worker routine (after
@@ -586,8 +586,8 @@ This governor exposes the following tunables:
100 (5 by default).
This is how much the frequency is allowed to change in one go. Setting
it to 0 will cause the default frequency step (5 percent) to be used
and setting it to 100 effectively causes the governor to periodically
it to 0 disables frequency changes by the governor entirely and setting
it to 100 effectively causes the governor to periodically
switch the frequency between the ``scaling_min_freq`` and
``scaling_max_freq`` policy limits.

View File

@@ -114,8 +114,13 @@ Then, the driver must fill in the following values:
|policy->cur | The current operating frequency of |
| | this CPU (if appropriate) |
+-----------------------------------+--------------------------------------+
|policy->min, | |
|policy->max, | |
|policy->min, | The min/max scaling frequency. |
|policy->max | If set by the driver in ->init(), |
| | used as the lower/upper bound for |
| | policy frequency QoS requests; |
| | otherwise, reflects the min/max |
| | frequency the driver can set |
+-----------------------------------+--------------------------------------+
|policy->policy and, if necessary, | |
|policy->governor | must contain the "default policy" for|
| | this CPU. A few moments later, |

View File

@@ -0,0 +1,96 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/cpufreq/qcom,shikra-epss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Shikra SoC EPSS
maintainers:
- Imran Shaik <imran.shaik@oss.qualcomm.com>
- Taniya Das <taniya.das@oss.qualcomm.com>
description: |
EPSS is a hardware engine used by some Qualcomm SoCs to manage
frequency in hardware. It is capable of controlling frequency for
multiple clusters.
The Qualcomm Shikra SoC EPSS supports up to 12 frequency lookup table
(LUT) entries.
properties:
compatible:
enum:
- qcom,shikra-epss
reg:
items:
- description: Frequency domain 0 register region
- description: Frequency domain 1 register region
reg-names:
items:
- const: freq-domain0
- const: freq-domain1
clocks:
items:
- description: XO Clock
- description: GPLL0 Clock
clock-names:
items:
- const: xo
- const: alternate
interrupts:
items:
- description: IRQ line for DCVSH 0
- description: IRQ line for DCVSH 1
interrupt-names:
items:
- const: dcvsh-irq-0
- const: dcvsh-irq-1
'#freq-domain-cells':
const: 1
'#clock-cells':
const: 1
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
- interrupt-names
- '#freq-domain-cells'
- '#clock-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <1>;
#size-cells = <1>;
cpufreq@fd91000 {
compatible = "qcom,shikra-epss";
reg = <0x0fd91000 0x1000>, <0x0fd92000 0x1000>;
reg-names = "freq-domain0", "freq-domain1";
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&gpll0>;
clock-names = "xo", "alternate";
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "dcvsh-irq-0", "dcvsh-irq-1";
#freq-domain-cells = <1>;
#clock-cells = <1>;
};
};
...

View File

@@ -153,7 +153,7 @@ config ARM_QCOM_CPUFREQ_NVMEM
If in doubt, say N.
config ARM_QCOM_CPUFREQ_HW
tristate "QCOM CPUFreq HW driver"
tristate "Qualcomm CPUFreq HW driver"
depends on ARCH_QCOM || COMPILE_TEST
depends on COMMON_CLK
help

View File

@@ -5,7 +5,6 @@
config X86_INTEL_PSTATE
bool "Intel P state control"
depends on X86
select ACPI_PROCESSOR if ACPI
select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
select CPU_FREQ_GOV_PERFORMANCE
@@ -36,7 +35,7 @@ config X86_PCC_CPUFREQ
config X86_AMD_PSTATE
bool "AMD Processor P-State driver"
depends on X86 && ACPI
depends on ACPI
select ACPI_PROCESSOR
select ACPI_CPPC_LIB if X86_64
select CPU_FREQ_GOV_SCHEDUTIL if SMP
@@ -72,7 +71,7 @@ config X86_AMD_PSTATE_DEFAULT_MODE
config X86_AMD_PSTATE_UT
tristate "selftest for AMD Processor P-State driver"
depends on X86 && ACPI_PROCESSOR
depends on ACPI_PROCESSOR
depends on X86_AMD_PSTATE
default n
help
@@ -114,21 +113,6 @@ config X86_ACPI_CPUFREQ_CPB
By enabling this option the acpi_cpufreq driver provides the old
entry in addition to the new boost ones, for compatibility reasons.
config ELAN_CPUFREQ
tristate "AMD Elan SC400 and SC410"
depends on MELAN
help
This adds the CPUFreq driver for AMD Elan SC400 and SC410
processors.
You need to specify the processor maximum speed as boot
parameter: elanfreq=maxspeed (in kHz) or as module
parameter "max_freq".
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
config SC520_CPUFREQ
tristate "AMD Elan SC520"
depends on MELAN

View File

@@ -40,7 +40,6 @@ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o
obj-$(CONFIG_X86_LONGRUN) += longrun.o
obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o

View File

@@ -242,12 +242,10 @@ static int msr_update_perf(struct cpufreq_policy *policy, u8 min_perf,
value = prev = READ_ONCE(cpudata->cppc_req_cached);
value &= ~(AMD_CPPC_MAX_PERF_MASK | AMD_CPPC_MIN_PERF_MASK |
AMD_CPPC_DES_PERF_MASK | AMD_CPPC_EPP_PERF_MASK);
value |= FIELD_PREP(AMD_CPPC_MAX_PERF_MASK, max_perf);
value |= FIELD_PREP(AMD_CPPC_DES_PERF_MASK, des_perf);
value |= FIELD_PREP(AMD_CPPC_MIN_PERF_MASK, min_perf);
value |= FIELD_PREP(AMD_CPPC_EPP_PERF_MASK, epp);
FIELD_MODIFY(AMD_CPPC_MAX_PERF_MASK, &value, max_perf);
FIELD_MODIFY(AMD_CPPC_DES_PERF_MASK, &value, des_perf);
FIELD_MODIFY(AMD_CPPC_MIN_PERF_MASK, &value, min_perf);
FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &value, epp);
if (trace_amd_pstate_epp_perf_enabled()) {
union perf_cached perf = READ_ONCE(cpudata->perf);
@@ -296,8 +294,7 @@ static int msr_set_epp(struct cpufreq_policy *policy, u8 epp)
int ret;
value = prev = READ_ONCE(cpudata->cppc_req_cached);
value &= ~AMD_CPPC_EPP_PERF_MASK;
value |= FIELD_PREP(AMD_CPPC_EPP_PERF_MASK, epp);
FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &value, epp);
if (trace_amd_pstate_epp_perf_enabled()) {
union perf_cached perf = cpudata->perf;
@@ -437,8 +434,7 @@ static int shmem_set_epp(struct cpufreq_policy *policy, u8 epp)
}
value = READ_ONCE(cpudata->cppc_req_cached);
value &= ~AMD_CPPC_EPP_PERF_MASK;
value |= FIELD_PREP(AMD_CPPC_EPP_PERF_MASK, epp);
FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &value, epp);
WRITE_ONCE(cpudata->cppc_req_cached, value);
return ret;
@@ -571,12 +567,10 @@ static int shmem_update_perf(struct cpufreq_policy *policy, u8 min_perf,
value = prev = READ_ONCE(cpudata->cppc_req_cached);
value &= ~(AMD_CPPC_MAX_PERF_MASK | AMD_CPPC_MIN_PERF_MASK |
AMD_CPPC_DES_PERF_MASK | AMD_CPPC_EPP_PERF_MASK);
value |= FIELD_PREP(AMD_CPPC_MAX_PERF_MASK, max_perf);
value |= FIELD_PREP(AMD_CPPC_DES_PERF_MASK, des_perf);
value |= FIELD_PREP(AMD_CPPC_MIN_PERF_MASK, min_perf);
value |= FIELD_PREP(AMD_CPPC_EPP_PERF_MASK, epp);
FIELD_MODIFY(AMD_CPPC_MAX_PERF_MASK, &value, max_perf);
FIELD_MODIFY(AMD_CPPC_DES_PERF_MASK, &value, des_perf);
FIELD_MODIFY(AMD_CPPC_MIN_PERF_MASK, &value, min_perf);
FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &value, epp);
if (trace_amd_pstate_epp_perf_enabled()) {
union perf_cached perf = READ_ONCE(cpudata->perf);
@@ -1086,10 +1080,9 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
perf = READ_ONCE(cpudata->perf);
policy->cpuinfo.min_freq = policy->min = perf_to_freq(perf,
cpudata->nominal_freq,
perf.lowest_perf);
policy->cpuinfo.max_freq = policy->max = cpudata->max_freq;
policy->cpuinfo.min_freq = perf_to_freq(perf, cpudata->nominal_freq,
perf.lowest_perf);
policy->cpuinfo.max_freq = cpudata->max_freq;
policy->driver_data = cpudata;
ret = amd_pstate_cppc_enable(policy);
@@ -1915,10 +1908,9 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
perf = READ_ONCE(cpudata->perf);
policy->cpuinfo.min_freq = policy->min = perf_to_freq(perf,
cpudata->nominal_freq,
perf.lowest_perf);
policy->cpuinfo.max_freq = policy->max = cpudata->max_freq;
policy->cpuinfo.min_freq = perf_to_freq(perf, cpudata->nominal_freq,
perf.lowest_perf);
policy->cpuinfo.max_freq = cpudata->max_freq;
policy->driver_data = cpudata;
ret = amd_pstate_cppc_enable(policy);

View File

@@ -187,10 +187,8 @@ static int apple_soc_cpufreq_set_target(struct cpufreq_policy *policy,
reg &= ~priv->info->ps1_mask;
reg |= pstate << priv->info->ps1_shift;
if (priv->info->has_ps2) {
reg &= ~APPLE_DVFS_CMD_PS2;
reg |= FIELD_PREP(APPLE_DVFS_CMD_PS2, pstate);
}
if (priv->info->has_ps2)
FIELD_MODIFY(APPLE_DVFS_CMD_PS2, &reg, pstate);
reg |= APPLE_DVFS_CMD_SET;
writeq_relaxed(reg, priv->reg_base + APPLE_DVFS_CMD);

View File

@@ -660,8 +660,6 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
* Section 8.4.7.1.1.5 of ACPI 6.1 spec)
*/
policy->min = cppc_perf_to_khz(caps, caps->lowest_nonlinear_perf);
policy->max = cppc_perf_to_khz(caps, policy->boost_enabled ?
caps->highest_perf : caps->nominal_perf);
/*
* Set cpuinfo.min_freq to Lowest to make the full range of performance
@@ -669,7 +667,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
* nonlinear perf
*/
policy->cpuinfo.min_freq = cppc_perf_to_khz(caps, caps->lowest_perf);
policy->cpuinfo.max_freq = policy->max;
policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, policy->boost_enabled ?
caps->highest_perf : caps->nominal_perf);
policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu);
policy->shared_type = cpu_data->shared_type;
@@ -982,7 +981,34 @@ store_energy_performance_preference_val(struct cpufreq_policy *policy,
return count;
}
CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited,
static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited)
{
struct cpufreq_policy *policy;
struct cppc_cpudata *cpu_data;
int ret;
ret = cppc_get_perf_limited(cpu, perf_limited);
if (ret)
return ret;
policy = cpufreq_cpu_get_raw(cpu);
if (!policy)
return -EINVAL;
cpu_data = policy->driver_data;
/*
* Desired Excursion is ignored when autonomous selection is
* enabled. Clear the bit to avoid exposing meaningless state
* to userspace.
*/
if (cpu_data && cpu_data->perf_ctrls.auto_sel)
*perf_limited &= ~CPPC_PERF_LIMITED_DESIRED_EXCURSION;
return 0;
}
CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited_filtered,
cppc_set_perf_limited)
cpufreq_freq_attr_ro(freqdomain_cpus);

View File

@@ -355,8 +355,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
min_fsb = NFORCE2_MIN_FSB;
/* cpuinfo and default policy values */
policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
policy->cpuinfo.min_freq = min_fsb * fid * 100;
policy->cpuinfo.max_freq = max_fsb * fid * 100;
return 0;
}

View File

@@ -1397,6 +1397,40 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
kfree(policy);
}
static int cpufreq_policy_init_qos(struct cpufreq_policy *policy)
{
unsigned int min_freq, max_freq;
int ret;
/* Use policy->min/max set by the driver as QoS requests. */
min_freq = max(FREQ_QOS_MIN_DEFAULT_VALUE, policy->min);
if (policy->max)
max_freq = min(FREQ_QOS_MAX_DEFAULT_VALUE, policy->max);
else
max_freq = FREQ_QOS_MAX_DEFAULT_VALUE;
if (policy->boost_supported) {
ret = freq_qos_add_request(&policy->constraints,
&policy->boost_freq_req,
FREQ_QOS_MAX,
policy->cpuinfo.max_freq);
if (ret < 0)
return ret;
}
ret = freq_qos_add_request(&policy->constraints, &policy->min_freq_req,
FREQ_QOS_MIN, min_freq);
if (ret < 0)
return ret;
ret = freq_qos_add_request(&policy->constraints, &policy->max_freq_req,
FREQ_QOS_MAX, max_freq);
if (ret < 0)
return ret;
return 0;
}
static int cpufreq_policy_online(struct cpufreq_policy *policy,
unsigned int cpu, bool new_policy)
{
@@ -1442,6 +1476,19 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
if (ret)
goto out_offline_policy;
if (new_policy) {
ret = cpufreq_policy_init_qos(policy);
if (ret < 0)
goto out_offline_policy;
}
/*
* If the driver hasn't set policy->min/max, set them as they
* are used for clamping frequency requests.
*/
policy->min = policy->min ? policy->min : policy->cpuinfo.min_freq;
policy->max = policy->max ? policy->max : policy->cpuinfo.max_freq;
/* related_cpus should at least include policy->cpus. */
cpumask_copy(policy->related_cpus, policy->cpus);
}
@@ -1458,27 +1505,6 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
add_cpu_dev_symlink(policy, j, get_cpu_device(j));
}
if (policy->boost_supported) {
ret = freq_qos_add_request(&policy->constraints,
&policy->boost_freq_req,
FREQ_QOS_MAX,
policy->cpuinfo.max_freq);
if (ret < 0)
goto out_destroy_policy;
}
ret = freq_qos_add_request(&policy->constraints,
&policy->min_freq_req, FREQ_QOS_MIN,
FREQ_QOS_MIN_DEFAULT_VALUE);
if (ret < 0)
goto out_destroy_policy;
ret = freq_qos_add_request(&policy->constraints,
&policy->max_freq_req, FREQ_QOS_MAX,
FREQ_QOS_MAX_DEFAULT_VALUE);
if (ret < 0)
goto out_destroy_policy;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_CREATE_POLICY, policy);
}
@@ -1972,6 +1998,7 @@ void cpufreq_suspend(void)
if (!cpufreq_driver)
return;
cpus_read_lock();
if (!has_target() && !cpufreq_driver->suspend)
goto suspend;
@@ -1991,6 +2018,7 @@ void cpufreq_suspend(void)
suspend:
cpufreq_suspended = true;
cpus_read_unlock();
}
/**
@@ -2366,9 +2394,13 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
* exactly same freq is called again and so we can save on few function
* calls.
*/
if (target_freq == policy->cur &&
!(cpufreq_driver->flags & CPUFREQ_NEED_UPDATE_LIMITS))
return 0;
if (target_freq == policy->cur) {
if (!(cpufreq_driver->flags & CPUFREQ_NEED_UPDATE_LIMITS) ||
!policy->update_limits)
return 0;
policy->update_limits = false;
}
if (cpufreq_driver->target) {
/*
@@ -2620,6 +2652,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
{
struct cpufreq_policy_data new_data;
struct cpufreq_governor *old_gov;
unsigned int freq;
int ret;
memcpy(&new_data.cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
@@ -2652,12 +2685,20 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
* compiler optimizations around them because they may be accessed
* concurrently by cpufreq_driver_resolve_freq() during the update.
*/
WRITE_ONCE(policy->max, __resolve_freq(policy, new_data.max,
new_data.min, new_data.max,
CPUFREQ_RELATION_H));
new_data.min = __resolve_freq(policy, new_data.min, new_data.min,
new_data.max, CPUFREQ_RELATION_L);
WRITE_ONCE(policy->min, new_data.min > policy->max ? policy->max : new_data.min);
freq = __resolve_freq(policy, new_data.max, new_data.min, new_data.max,
CPUFREQ_RELATION_H);
if (freq != policy->max) {
WRITE_ONCE(policy->max, freq);
policy->update_limits = true;
}
freq = __resolve_freq(policy, new_data.min, new_data.min, new_data.max,
CPUFREQ_RELATION_L);
freq = min(freq, policy->max);
if (freq != policy->min) {
WRITE_ONCE(policy->min, freq);
policy->update_limits = true;
}
trace_cpu_frequency_limits(policy);

View File

@@ -103,10 +103,6 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
if (load > dbs_data->up_threshold) {
dbs_info->down_skip = 0;
/* if we are already at full speed then break out early */
if (requested_freq == policy->max)
goto out;
requested_freq += freq_step;
if (requested_freq > policy->max)
requested_freq = policy->max;
@@ -124,13 +120,7 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
/* Check for frequency decrease */
if (load < cs_tuners->down_threshold) {
/*
* if we cannot reduce the frequency anymore, break out early
*/
if (requested_freq == policy->min)
goto out;
if (requested_freq > freq_step)
if (requested_freq > policy->min + freq_step)
requested_freq -= freq_step;
else
requested_freq = policy->min;

View File

@@ -90,7 +90,14 @@ EXPORT_SYMBOL_GPL(sampling_rate_store);
* (that may be a single policy or a bunch of them if governor tunables are
* system-wide).
*
* Call under the @dbs_data mutex.
* Call under the @dbs_data->attr_set.update_lock. The per-policy
* update_mutex is acquired and released internally for each policy.
*
* Note: prev_cpu_nice is reset here unconditionally alongside prev_cpu_idle.
* When io_is_busy changes, both baselines must be advanced to the same
* timestamp so that the next dbs_update() computes idle_time and nice_delta
* over the same interval, preventing an artificially inflated idle_time when
* ignore_nice_load is enabled.
*/
void gov_update_cpu_data(struct dbs_data *dbs_data)
{
@@ -99,14 +106,15 @@ void gov_update_cpu_data(struct dbs_data *dbs_data)
list_for_each_entry(policy_dbs, &dbs_data->attr_set.policy_list, list) {
unsigned int j;
mutex_lock(&policy_dbs->update_mutex);
for_each_cpu(j, policy_dbs->policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_update_time,
dbs_data->io_is_busy);
if (dbs_data->ignore_nice_load)
j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
}
mutex_unlock(&policy_dbs->update_mutex);
}
}
EXPORT_SYMBOL_GPL(gov_update_cpu_data);
@@ -118,6 +126,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
unsigned int ignore_nice = dbs_data->ignore_nice_load;
unsigned int max_load = 0, idle_periods = UINT_MAX;
unsigned int sampling_rate, io_busy, j;
u64 cur_nice;
/*
* Sometimes governors may use an additional multiplier to increase
@@ -164,12 +173,18 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
j_cdbs->prev_cpu_idle = cur_idle_time;
if (ignore_nice) {
u64 cur_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
/*
* Always sample cur_nice and advance prev_cpu_nice, regardless
* of ignore_nice. This keeps prev_cpu_nice current so that
* enabling ignore_nice_load via sysfs never produces a
* stale-baseline spike (the delta will be at most one sampling
* interval of accumulated nice time, not since boot).
*/
cur_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
if (ignore_nice)
idle_time += div_u64(cur_nice - j_cdbs->prev_cpu_nice, NSEC_PER_USEC);
j_cdbs->prev_cpu_nice = cur_nice;
}
j_cdbs->prev_cpu_nice = cur_nice;
if (unlikely(!time_elapsed)) {
/*
@@ -516,7 +531,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs = policy->governor_data;
struct dbs_data *dbs_data = policy_dbs->dbs_data;
unsigned int sampling_rate, ignore_nice, j;
unsigned int sampling_rate, j;
unsigned int io_busy;
if (!policy->cur)
@@ -526,9 +541,9 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
policy_dbs->rate_mult = 1;
sampling_rate = dbs_data->sampling_rate;
ignore_nice = dbs_data->ignore_nice_load;
io_busy = dbs_data->io_is_busy;
mutex_lock(&policy_dbs->update_mutex);
io_busy = dbs_data->io_is_busy;
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
@@ -537,10 +552,9 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
* Make the first invocation of dbs_update() compute the load.
*/
j_cdbs->prev_load = 0;
if (ignore_nice)
j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
}
mutex_unlock(&policy_dbs->update_mutex);
gov->start(policy);

View File

@@ -1,226 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* elanfreq: cpufreq driver for the AMD ELAN family
*
* (c) Copyright 2002 Robert Schwebel <r.schwebel@pengutronix.de>
*
* Parts of this code are (c) Sven Geggus <sven@geggus.net>
*
* All Rights Reserved.
*
* 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/cpufreq.h>
#include <asm/cpu_device_id.h>
#include <linux/timex.h>
#include <linux/io.h>
#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */
#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */
/* Module parameter */
static int max_freq;
struct s_elan_multiplier {
int clock; /* frequency in kHz */
int val40h; /* PMU Force Mode register */
int val80h; /* CPU Clock Speed Register */
};
/*
* It is important that the frequencies
* are listed in ascending order here!
*/
static struct s_elan_multiplier elan_multiplier[] = {
{1000, 0x02, 0x18},
{2000, 0x02, 0x10},
{4000, 0x02, 0x08},
{8000, 0x00, 0x00},
{16000, 0x00, 0x02},
{33000, 0x00, 0x04},
{66000, 0x01, 0x04},
{99000, 0x01, 0x05}
};
static struct cpufreq_frequency_table elanfreq_table[] = {
{0, 0, 1000},
{0, 1, 2000},
{0, 2, 4000},
{0, 3, 8000},
{0, 4, 16000},
{0, 5, 33000},
{0, 6, 66000},
{0, 7, 99000},
{0, 0, CPUFREQ_TABLE_END},
};
/**
* elanfreq_get_cpu_frequency: determine current cpu speed
*
* Finds out at which frequency the CPU of the Elan SOC runs
* at the moment. Frequencies from 1 to 33 MHz are generated
* the normal way, 66 and 99 MHz are called "Hyperspeed Mode"
* and have the rest of the chip running with 33 MHz.
*/
static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
{
u8 clockspeed_reg; /* Clock Speed Register */
local_irq_disable();
outb_p(0x80, REG_CSCIR);
clockspeed_reg = inb_p(REG_CSCDR);
local_irq_enable();
if ((clockspeed_reg & 0xE0) == 0xE0)
return 0;
/* Are we in CPU clock multiplied mode (66/99 MHz)? */
if ((clockspeed_reg & 0xE0) == 0xC0) {
if ((clockspeed_reg & 0x01) == 0)
return 66000;
else
return 99000;
}
/* 33 MHz is not 32 MHz... */
if ((clockspeed_reg & 0xE0) == 0xA0)
return 33000;
return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000;
}
static int elanfreq_target(struct cpufreq_policy *policy,
unsigned int state)
{
/*
* Access to the Elan's internal registers is indexed via
* 0x22: Chip Setup & Control Register Index Register (CSCI)
* 0x23: Chip Setup & Control Register Data Register (CSCD)
*
*/
/*
* 0x40 is the Power Management Unit's Force Mode Register.
* Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency)
*/
local_irq_disable();
outb_p(0x40, REG_CSCIR); /* Disable hyperspeed mode */
outb_p(0x00, REG_CSCDR);
local_irq_enable(); /* wait till internal pipelines and */
udelay(1000); /* buffers have cleaned up */
local_irq_disable();
/* now, set the CPU clock speed register (0x80) */
outb_p(0x80, REG_CSCIR);
outb_p(elan_multiplier[state].val80h, REG_CSCDR);
/* now, the hyperspeed bit in PMU Force Mode Register (0x40) */
outb_p(0x40, REG_CSCIR);
outb_p(elan_multiplier[state].val40h, REG_CSCDR);
udelay(10000);
local_irq_enable();
return 0;
}
/*
* Module init and exit code
*/
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = &cpu_data(0);
struct cpufreq_frequency_table *pos;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
(c->x86 != 4) || (c->x86_model != 10))
return -ENODEV;
/* max freq */
if (!max_freq)
max_freq = elanfreq_get_cpu_frequency(0);
/* table init */
cpufreq_for_each_entry(pos, elanfreq_table)
if (pos->frequency > max_freq)
pos->frequency = CPUFREQ_ENTRY_INVALID;
policy->freq_table = elanfreq_table;
return 0;
}
#ifndef MODULE
/**
* elanfreq_setup - elanfreq command line parameter parsing
*
* elanfreq command line parameter. Use:
* elanfreq=66000
* to set the maximum CPU frequency to 66 MHz. Note that in
* case you do not give this boot parameter, the maximum
* frequency will fall back to _current_ CPU frequency which
* might be lower. If you build this as a module, use the
* max_freq module parameter instead.
*/
static int __init elanfreq_setup(char *str)
{
max_freq = simple_strtoul(str, &str, 0);
pr_warn("You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n");
return 1;
}
__setup("elanfreq=", elanfreq_setup);
#endif
static struct cpufreq_driver elanfreq_driver = {
.get = elanfreq_get_cpu_frequency,
.flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
.verify = cpufreq_generic_frequency_table_verify,
.target_index = elanfreq_target,
.init = elanfreq_cpu_init,
.name = "elanfreq",
};
static const struct x86_cpu_id elan_id[] = {
X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 10, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, elan_id);
static int __init elanfreq_init(void)
{
if (!x86_match_cpu(elan_id))
return -ENODEV;
return cpufreq_register_driver(&elanfreq_driver);
}
static void __exit elanfreq_exit(void)
{
cpufreq_unregister_driver(&elanfreq_driver);
}
module_param(max_freq, int, 0444);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, "
"Sven Geggus <sven@geggus.net>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
module_init(elanfreq_init);
module_exit(elanfreq_exit);

View File

@@ -49,16 +49,15 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy)
max_freq = freq;
}
policy->min = policy->cpuinfo.min_freq = min_freq;
policy->max = max_freq;
policy->cpuinfo.min_freq = min_freq;
/*
* If the driver has set its own cpuinfo.max_freq above max_freq, leave
* it as is.
*/
if (policy->cpuinfo.max_freq < max_freq)
policy->max = policy->cpuinfo.max_freq = max_freq;
policy->cpuinfo.max_freq = max_freq;
if (policy->min == ~0)
if (min_freq == ~0)
return -EINVAL;
else
return 0;

View File

@@ -421,7 +421,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
policy->min = maxfreq / max_duration;
else
policy->min = maxfreq / POLICY_MIN_DIV;
policy->max = maxfreq;
policy->cpuinfo.min_freq = maxfreq / max_duration;
policy->cpuinfo.max_freq = maxfreq;

View File

@@ -2984,10 +2984,12 @@ static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy)
* from getting to lower performance levels, so force the minimum
* performance on CPU offline to prevent that from happening.
*/
if (hwp_active)
if (hwp_active) {
intel_pstate_hwp_offline(cpu);
else
} else {
intel_pstate_set_min_pstate(cpu);
policy->cur = cpu->pstate.min_freq;
}
intel_pstate_exit_perf_limits(policy);
@@ -3049,9 +3051,6 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq = READ_ONCE(global.no_turbo) ?
cpu->pstate.max_freq : cpu->pstate.turbo_freq;
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
intel_pstate_init_acpi_perf_limits(policy);
policy->fast_switch_possible = true;
@@ -3824,6 +3823,12 @@ static int __init intel_pstate_init(void)
if (no_load)
return -ENODEV;
id = x86_match_cpu(intel_hybrid_scaling_factor);
if (id) {
pr_info("HWP-disabled hybrid CPU is not supported\n");
return -ENODEV;
}
id = x86_match_cpu(intel_pstate_cpu_ids);
if (!id) {
pr_info("CPU model not supported\n");

View File

@@ -352,6 +352,8 @@ static int __init pcc_cpufreq_do_osc(acpi_handle *handle)
}
kfree(output.pointer);
output.pointer = NULL;
output.length = ACPI_ALLOCATE_BUFFER;
capabilities[0] = 0x0;
capabilities[1] = 0x1;
@@ -551,13 +553,11 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto out;
}
policy->max = policy->cpuinfo.max_freq =
ioread32(&pcch_hdr->nominal) * 1000;
policy->min = policy->cpuinfo.min_freq =
ioread32(&pcch_hdr->minimum_frequency) * 1000;
policy->cpuinfo.max_freq = ioread32(&pcch_hdr->nominal) * 1000;
policy->cpuinfo.min_freq = ioread32(&pcch_hdr->minimum_frequency) * 1000;
pr_debug("init: policy->max is %d, policy->min is %d\n",
policy->max, policy->min);
pr_debug("init: max_freq is %d, min_freq is %d\n",
policy->cpuinfo.max_freq, policy->cpuinfo.min_freq);
out:
return result;
}

View File

@@ -185,9 +185,8 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
int ret = -EINVAL;
/* set default policy and cpuinfo */
policy->min = policy->cpuinfo.min_freq = 104000;
policy->max = policy->cpuinfo.max_freq =
(cpu_is_pxa320()) ? 806000 : 624000;
policy->cpuinfo.min_freq = 104000;
policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000;
policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
if (cpu_is_pxa300() || cpu_is_pxa310())

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/bitfield.h>
@@ -40,6 +41,7 @@ struct qcom_cpufreq_soc_data {
u32 reg_intr_clr;
u32 reg_current_vote;
u32 reg_perf_state;
u32 lut_max_entries;
u8 lut_row_size;
};
@@ -156,7 +158,7 @@ static unsigned int qcom_cpufreq_get_freq(struct cpufreq_policy *policy)
soc_data = qcom_cpufreq.soc_data;
index = readl_relaxed(data->base + soc_data->reg_perf_state);
index = min(index, LUT_MAX_ENTRIES - 1);
index = min(index, soc_data->lut_max_entries - 1);
return policy->freq_table[index].frequency;
}
@@ -211,7 +213,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
struct qcom_cpufreq_data *drv_data = policy->driver_data;
const struct qcom_cpufreq_soc_data *soc_data = qcom_cpufreq.soc_data;
table = kzalloc_objs(*table, LUT_MAX_ENTRIES + 1);
table = kzalloc_objs(*table, soc_data->lut_max_entries + 1);
if (!table)
return -ENOMEM;
@@ -236,7 +238,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
icc_scaling_enabled = false;
}
for (i = 0; i < LUT_MAX_ENTRIES; i++) {
for (i = 0; i < soc_data->lut_max_entries; i++) {
data = readl_relaxed(drv_data->base + soc_data->reg_freq_lut +
i * soc_data->lut_row_size);
src = FIELD_GET(LUT_SRC, data);
@@ -405,6 +407,7 @@ static const struct qcom_cpufreq_soc_data qcom_soc_data = {
.reg_current_vote = 0x704,
.reg_perf_state = 0x920,
.lut_row_size = 32,
.lut_max_entries = LUT_MAX_ENTRIES,
};
static const struct qcom_cpufreq_soc_data epss_soc_data = {
@@ -416,11 +419,25 @@ static const struct qcom_cpufreq_soc_data epss_soc_data = {
.reg_intr_clr = 0x308,
.reg_perf_state = 0x320,
.lut_row_size = 4,
.lut_max_entries = LUT_MAX_ENTRIES,
};
static const struct qcom_cpufreq_soc_data shikra_epss_soc_data = {
.reg_enable = 0x0,
.reg_domain_state = 0x20,
.reg_dcvs_ctrl = 0xb0,
.reg_freq_lut = 0x100,
.reg_volt_lut = 0x200,
.reg_intr_clr = 0x308,
.reg_perf_state = 0x320,
.lut_row_size = 4,
.lut_max_entries = 12,
};
static const struct of_device_id qcom_cpufreq_hw_match[] = {
{ .compatible = "qcom,cpufreq-hw", .data = &qcom_soc_data },
{ .compatible = "qcom,cpufreq-epss", .data = &epss_soc_data },
{ .compatible = "qcom,shikra-epss", .data = &shikra_epss_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
@@ -578,7 +595,6 @@ static void qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
qcom_cpufreq_hw_lmh_exit(data);
kfree(policy->freq_table);
kfree(data);
}
static void qcom_cpufreq_ready(struct cpufreq_policy *policy)

View File

@@ -124,10 +124,8 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
dev_notice(dev, "no frequency table found, falling back "
"to rate rounding.\n");
policy->min = policy->cpuinfo.min_freq =
(clk_round_rate(cpuclk, 1) + 500) / 1000;
policy->max = policy->cpuinfo.max_freq =
(clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
}
return 0;

View File

@@ -99,6 +99,7 @@ struct ti_cpufreq_soc_data {
unsigned long efuse_shift;
unsigned long rev_offset;
bool multi_regulator;
bool needs_k3_socinfo;
/* Backward compatibility hack: Might have missing syscon */
#define TI_QUIRK_SYSCON_MAY_BE_MISSING 0x1
/* Backward compatibility hack: new syscon size is 1 register wide */
@@ -347,6 +348,7 @@ static struct ti_cpufreq_soc_data am625_soc_data = {
.efuse_mask = 0x07c0,
.efuse_shift = 0x6,
.multi_regulator = false,
.needs_k3_socinfo = true,
.quirks = TI_QUIRK_SYSCON_IS_SINGLE_REG,
};
@@ -356,6 +358,7 @@ static struct ti_cpufreq_soc_data am62a7_soc_data = {
.efuse_mask = 0x07c0,
.efuse_shift = 0x6,
.multi_regulator = false,
.needs_k3_socinfo = true,
};
static struct ti_cpufreq_soc_data am62l3_soc_data = {
@@ -364,6 +367,7 @@ static struct ti_cpufreq_soc_data am62l3_soc_data = {
.efuse_mask = 0x07c0,
.efuse_shift = 0x6,
.multi_regulator = false,
.needs_k3_socinfo = true,
};
static struct ti_cpufreq_soc_data am62p5_soc_data = {
@@ -372,6 +376,7 @@ static struct ti_cpufreq_soc_data am62p5_soc_data = {
.efuse_mask = 0x07c0,
.efuse_shift = 0x6,
.multi_regulator = false,
.needs_k3_socinfo = true,
};
/**
@@ -443,6 +448,11 @@ static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
goto done;
}
/* Defer if k3-socinfo hasn't registered the SoC device yet */
if (opp_data->soc_data->needs_k3_socinfo)
return dev_err_probe(opp_data->cpu_dev, -EPROBE_DEFER,
"SoC device not registered by k3-socinfo\n");
ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset,
&revision);
if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) {

View File

@@ -164,10 +164,7 @@ static int virt_cpufreq_get_freq_info(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = 1;
policy->cpuinfo.max_freq = virt_cpufreq_get_perftbl_entry(policy->cpu, 0);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cur = policy->max;
policy->cur = policy->cpuinfo.max_freq;
return 0;
}

View File

@@ -146,6 +146,9 @@ struct cpufreq_policy {
/* Per policy boost supported flag. */
bool boost_supported;
/* Pending policy->min/max update for the driver */
bool update_limits;
/* Cached frequency lookup from cpufreq_driver_resolve_freq. */
unsigned int cached_target_freq;
unsigned int cached_resolved_idx;
@@ -434,7 +437,7 @@ struct cpufreq_driver {
/*
* Set by drivers that need to update internal upper and lower boundaries along
* with the target frequency and so the core and governors should also invoke
* the diver if the target frequency does not change, but the policy min or max
* the driver if the target frequency does not change, but the policy min or max
* may have changed.
*/
#define CPUFREQ_NEED_UPDATE_LIMITS BIT(0)