mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
Power management fixes for 7.2-rc6
- Allow fast frequency switching in the ACPI CPPC library only when
every supported control used by the driver callback has an address
space already accepted for fast access (Christian Loehle)
- Skip writes to unsupported performance controls in the ACPI CPPC
library (Christian Loehle)
- Update cppc_cpufreq_update_perf_limits() to read policy->min and
policy->max once and, if the lockless snapshot is inconsistent,
reduce the minimum to the observed maximum, along the lines of
cpufreq_driver_resolve_freq() (Christian Loehle)
- Fix a possible memory leak in the powernowk8_cpu_init() error
paths (Abdun Nihaal)
- Loosen the requirement on lowest nonlinear frequency != min freq in
the amd-pstate driver that is too tight for new systems some of
which actually have the lowest nonlinear frequency identical to the
minimum frequency (Mario Limonciello)
- Prevent amd-pstate from loading on unsupported hardware (Rong Zhang)
- Address an initialization race in the schedutil governor when it
runs on multi-CPU cpufreq policies, by making it initialize all
per-CPU structures first and only then publish the per-CPU
utilization update hooks (Zhongqiu Han)
-----BEGIN PGP SIGNATURE-----
iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmprmRgSHHJqd0Byand5
c29ja2kubmV0AAoJEO5fvZ0v1OO1Ro0H/3llnBhbu9nq7QcFmlPqcRh2yqWozPoG
oJTYEc/FEvPTEy65b6YxPFm64heiVTpv2gSZk0NVLnsXmDc3qNfoVFN7BvY8soPV
X4hEZbVi/ZE84l2gmc3t9HjK+j9mxfyWiWj/QDqZvZzf3v0QN8Klo9SvzlwXlnXX
1KdBpPPZYv7H0xIIOiL7K17JbvVTAXIwsV2SidOkm+29xArMYnHnzxqaIoh70kx7
vvRLR0NwubHzPZt66L5TFQCwixa+O71YaQ2l1k6TOzZ5G2BEtriXjAaimAd88iAu
Ogpie91bcERZdmoBIGtBCg9jSrHIqJE8ItugBsZw21BnIBsAKpgpJgw=
=U/2b
-----END PGP SIGNATURE-----
Merge tag 'pm-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael Wysocki:
"These fix issues related to cpufreq, in the ACPI CPPC library and the
generic CPPC cpufreq driver, in the powernow-k8 and amd-pstate
drivers, and in the schedutil governor:
- Allow fast frequency switching in the ACPI CPPC library only when
every supported control used by the driver callback has an address
space already accepted for fast access (Christian Loehle)
- Skip writes to unsupported performance controls in the ACPI CPPC
library (Christian Loehle)
- Update cppc_cpufreq_update_perf_limits() to read policy->min and
policy->max once and, if the lockless snapshot is inconsistent,
reduce the minimum to the observed maximum, along the lines of
cpufreq_driver_resolve_freq() (Christian Loehle)
- Fix a possible memory leak in the powernowk8_cpu_init() error paths
(Abdun Nihaal)
- Loosen the requirement on lowest nonlinear frequency != min freq in
the amd-pstate driver that is too tight for new systems some of
which actually have the lowest nonlinear frequency identical to the
minimum frequency (Mario Limonciello)
- Prevent amd-pstate from loading on unsupported hardware (Rong
Zhang)
- Address an initialization race in the schedutil governor when it
runs on multi-CPU cpufreq policies, by making it initialize all
per-CPU structures first and only then publish the per-CPU
utilization update hooks (Zhongqiu Han)"
* tag 'pm-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
cpufreq: powernow-k8: Fix possible memory leak in powernowk8_cpu_init()
ACPI: CPPC: Skip writes to unsupported performance controls
cpufreq/amd-pstate: Prevent the driver from loading on unsupported hardware
cpufreq/amd-pstate: Loosen requirement on lowest nonlinear frequency != min freq
cpufreq: schedutil: Publish util hooks only after all sg_cpu are initialized
cpufreq: cppc: Sanitize lockless policy limit snapshots
ACPI: CPPC: Check all controls for fast switching
This commit is contained in:
commit
3708dd9488
|
|
@ -475,17 +475,29 @@ bool acpi_cpc_valid(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_cpc_valid);
|
||||
|
||||
bool cppc_allow_fast_switch(void)
|
||||
bool cppc_allow_fast_switch(const struct cpumask *cpus)
|
||||
{
|
||||
struct cpc_register_resource *desired_reg;
|
||||
struct cpc_register_resource *desired_reg, *min_reg, *max_reg;
|
||||
struct cpc_desc *cpc_ptr;
|
||||
int cpu;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
for_each_cpu(cpu, cpus) {
|
||||
cpc_ptr = per_cpu(cpc_desc_ptr, cpu);
|
||||
if (!cpc_ptr)
|
||||
return false;
|
||||
desired_reg = &cpc_ptr->cpc_regs[DESIRED_PERF];
|
||||
if (!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
|
||||
!CPC_IN_SYSTEM_IO(desired_reg))
|
||||
min_reg = &cpc_ptr->cpc_regs[MIN_PERF];
|
||||
max_reg = &cpc_ptr->cpc_regs[MAX_PERF];
|
||||
|
||||
if (!CPC_SUPPORTED(desired_reg) ||
|
||||
(!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
|
||||
!CPC_IN_SYSTEM_IO(desired_reg)) ||
|
||||
(CPC_SUPPORTED(min_reg) &&
|
||||
!CPC_IN_SYSTEM_MEMORY(min_reg) &&
|
||||
!CPC_IN_SYSTEM_IO(min_reg)) ||
|
||||
(CPC_SUPPORTED(max_reg) &&
|
||||
!CPC_IN_SYSTEM_MEMORY(max_reg) &&
|
||||
!CPC_IN_SYSTEM_IO(max_reg)))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1951,16 +1963,17 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
|
|||
cpc_desc->write_cmd_status = 0;
|
||||
}
|
||||
|
||||
cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
|
||||
if (CPC_SUPPORTED(desired_reg))
|
||||
cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
|
||||
|
||||
/*
|
||||
* Only write if min_perf and max_perf not zero. Some drivers pass zero
|
||||
* value to min and max perf, but they don't mean to set the zero value,
|
||||
* they just don't want to write to those registers.
|
||||
*/
|
||||
if (perf_ctrls->min_perf)
|
||||
if (perf_ctrls->min_perf && CPC_SUPPORTED(min_perf_reg))
|
||||
cpc_write(cpu, min_perf_reg, perf_ctrls->min_perf);
|
||||
if (perf_ctrls->max_perf)
|
||||
if (perf_ctrls->max_perf && CPC_SUPPORTED(max_perf_reg))
|
||||
cpc_write(cpu, max_perf_reg, perf_ctrls->max_perf);
|
||||
|
||||
if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg))
|
||||
|
|
|
|||
|
|
@ -1031,7 +1031,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lowest_nonlinear_freq <= min_freq || lowest_nonlinear_freq > nominal_freq) {
|
||||
if (lowest_nonlinear_freq < min_freq || lowest_nonlinear_freq > nominal_freq) {
|
||||
pr_err("lowest_nonlinear_freq(%d) value is out of range [min_freq(%d), nominal_freq(%d)]\n",
|
||||
lowest_nonlinear_freq, min_freq, nominal_freq);
|
||||
return -EINVAL;
|
||||
|
|
@ -2167,6 +2167,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
|
|||
};
|
||||
|
||||
/*
|
||||
* Processors without frequency scaling support can't do CPPC.
|
||||
* CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F.
|
||||
* show the debug message that helps to check if the CPU has CPPC support for loading issue.
|
||||
*/
|
||||
|
|
@ -2175,6 +2176,11 @@ static bool amd_cppc_supported(void)
|
|||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
bool warn = false;
|
||||
|
||||
if (!cpu_feature_enabled(X86_FEATURE_HW_PSTATE)) {
|
||||
pr_debug_once("frequency scaling is not supported by the processor\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((boot_cpu_data.x86 == 0x17) && (boot_cpu_data.x86_model < 0x30)) {
|
||||
pr_debug_once("CPPC feature is not supported by the processor\n");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -290,19 +290,32 @@ static inline void cppc_freq_invariance_exit(void)
|
|||
}
|
||||
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
|
||||
|
||||
static void cppc_cpufreq_get_perf_limits(struct cppc_cpudata *cpu_data,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 *min_perf, u32 *max_perf)
|
||||
{
|
||||
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
|
||||
unsigned int min_freq, max_freq;
|
||||
u32 min, max;
|
||||
|
||||
min_freq = READ_ONCE(policy->min);
|
||||
max_freq = READ_ONCE(policy->max);
|
||||
if (unlikely(min_freq > max_freq))
|
||||
min_freq = max_freq;
|
||||
|
||||
min = cppc_khz_to_perf(caps, min_freq);
|
||||
max = cppc_khz_to_perf(caps, max_freq);
|
||||
|
||||
*min_perf = clamp_t(u32, min, caps->lowest_perf, caps->highest_perf);
|
||||
*max_perf = clamp_t(u32, max, caps->lowest_perf, caps->highest_perf);
|
||||
}
|
||||
|
||||
static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
|
||||
u32 min_perf, max_perf;
|
||||
|
||||
min_perf = cppc_khz_to_perf(caps, policy->min);
|
||||
max_perf = cppc_khz_to_perf(caps, policy->max);
|
||||
|
||||
cpu_data->perf_ctrls.min_perf =
|
||||
clamp_t(u32, min_perf, caps->lowest_perf, caps->highest_perf);
|
||||
cpu_data->perf_ctrls.max_perf =
|
||||
clamp_t(u32, max_perf, caps->lowest_perf, caps->highest_perf);
|
||||
cppc_cpufreq_get_perf_limits(cpu_data, policy,
|
||||
&cpu_data->perf_ctrls.min_perf,
|
||||
&cpu_data->perf_ctrls.max_perf);
|
||||
}
|
||||
|
||||
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
|
|
@ -693,7 +706,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|||
goto out;
|
||||
}
|
||||
|
||||
policy->fast_switch_possible = cppc_allow_fast_switch();
|
||||
policy->fast_switch_possible = cppc_allow_fast_switch(policy->cpus);
|
||||
policy->dvfs_possible_from_any_cpu = true;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1084,6 +1084,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
|
||||
err_out_exit_acpi:
|
||||
powernow_k8_cpu_exit_acpi(data);
|
||||
kfree(data->powernow_table);
|
||||
|
||||
err_out:
|
||||
kfree(data);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ extern u64 cppc_get_dmi_max_khz(void);
|
|||
extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
|
||||
extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
|
||||
extern bool acpi_cpc_valid(void);
|
||||
extern bool cppc_allow_fast_switch(void);
|
||||
bool cppc_allow_fast_switch(const struct cpumask *cpus);
|
||||
extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
|
||||
extern int cppc_get_transition_latency(int cpu);
|
||||
extern bool cpc_ffh_supported(void);
|
||||
|
|
@ -234,7 +234,8 @@ static inline bool acpi_cpc_valid(void)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool cppc_allow_fast_switch(void)
|
||||
|
||||
static inline bool cppc_allow_fast_switch(const struct cpumask *cpus)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -870,8 +870,19 @@ static int sugov_start(struct cpufreq_policy *policy)
|
|||
memset(sg_cpu, 0, sizeof(*sg_cpu));
|
||||
sg_cpu->cpu = cpu;
|
||||
sg_cpu->sg_policy = sg_policy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Publish the hooks only after all per-CPU data is initialized, so a
|
||||
* shared policy's sugov_update_shared() never reads an uninitialized
|
||||
* sibling sugov_cpu.
|
||||
*/
|
||||
for_each_cpu(cpu, policy->cpus) {
|
||||
struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
|
||||
|
||||
cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, uu);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user