mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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, |
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, ®, pstate);
|
||||
reg |= APPLE_DVFS_CMD_SET;
|
||||
|
||||
writeq_relaxed(reg, priv->reg_base + APPLE_DVFS_CMD);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user