Skip to content

Commit e75080f

Browse files
committed
Merge tag 'pm-fixes-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull two power management fixes from Rafael Wysocki: "This is the change making /proc/cpuinfo on x86 report current CPU frequency in "cpu MHz" again in all cases and an additional one dealing with an overzealous check in one of the helper routines in the runtime PM framework" * tag 'pm-fixes-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: PM / runtime: Drop children check from __pm_runtime_set_status() x86 / CPU: Always show current CPU frequency in /proc/cpuinfo
2 parents f6705bf + 3e4c9e6 commit e75080f

File tree

8 files changed

+80
-46
lines changed

8 files changed

+80
-46
lines changed

Documentation/power/runtime_pm.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
435435
PM status to 'suspended' and update its parent's counter of 'active'
436436
children as appropriate (it is only valid to use this function if
437437
'power.runtime_error' is set or 'power.disable_depth' is greater than
438-
zero); it will fail and return an error code if the device has a child
439-
which is active and the 'power.ignore_children' flag is unset
438+
zero)
440439

441440
bool pm_runtime_active(struct device *dev);
442441
- return true if the device's runtime PM status is 'active' or its

arch/x86/kernel/cpu/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ obj-y += common.o
2222
obj-y += rdrand.o
2323
obj-y += match.o
2424
obj-y += bugs.o
25-
obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
25+
obj-y += aperfmperf.o
2626
obj-y += cpuid-deps.o
2727

2828
obj-$(CONFIG_PROC_FS) += proc.o

arch/x86/kernel/cpu/aperfmperf.c

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <linux/percpu.h>
1515
#include <linux/smp.h>
1616

17+
#include "cpu.h"
18+
1719
struct aperfmperf_sample {
1820
unsigned int khz;
1921
ktime_t time;
@@ -24,7 +26,7 @@ struct aperfmperf_sample {
2426
static DEFINE_PER_CPU(struct aperfmperf_sample, samples);
2527

2628
#define APERFMPERF_CACHE_THRESHOLD_MS 10
27-
#define APERFMPERF_REFRESH_DELAY_MS 20
29+
#define APERFMPERF_REFRESH_DELAY_MS 10
2830
#define APERFMPERF_STALE_THRESHOLD_MS 1000
2931

3032
/*
@@ -38,8 +40,6 @@ static void aperfmperf_snapshot_khz(void *dummy)
3840
u64 aperf, aperf_delta;
3941
u64 mperf, mperf_delta;
4042
struct aperfmperf_sample *s = this_cpu_ptr(&samples);
41-
ktime_t now = ktime_get();
42-
s64 time_delta = ktime_ms_delta(now, s->time);
4343
unsigned long flags;
4444

4545
local_irq_save(flags);
@@ -57,38 +57,68 @@ static void aperfmperf_snapshot_khz(void *dummy)
5757
if (mperf_delta == 0)
5858
return;
5959

60-
s->time = now;
60+
s->time = ktime_get();
6161
s->aperf = aperf;
6262
s->mperf = mperf;
63-
64-
/* If the previous iteration was too long ago, discard it. */
65-
if (time_delta > APERFMPERF_STALE_THRESHOLD_MS)
66-
s->khz = 0;
67-
else
68-
s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
63+
s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
6964
}
7065

71-
unsigned int arch_freq_get_on_cpu(int cpu)
66+
static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait)
7267
{
73-
s64 time_delta;
74-
unsigned int khz;
68+
s64 time_delta = ktime_ms_delta(now, per_cpu(samples.time, cpu));
69+
70+
/* Don't bother re-computing within the cache threshold time. */
71+
if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
72+
return true;
73+
74+
smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, wait);
75+
76+
/* Return false if the previous iteration was too long ago. */
77+
return time_delta <= APERFMPERF_STALE_THRESHOLD_MS;
78+
}
7579

80+
unsigned int aperfmperf_get_khz(int cpu)
81+
{
7682
if (!cpu_khz)
7783
return 0;
7884

7985
if (!static_cpu_has(X86_FEATURE_APERFMPERF))
8086
return 0;
8187

82-
/* Don't bother re-computing within the cache threshold time. */
83-
time_delta = ktime_ms_delta(ktime_get(), per_cpu(samples.time, cpu));
84-
khz = per_cpu(samples.khz, cpu);
85-
if (khz && time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
86-
return khz;
88+
aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
89+
return per_cpu(samples.khz, cpu);
90+
}
8791

88-
smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
89-
khz = per_cpu(samples.khz, cpu);
90-
if (khz)
91-
return khz;
92+
void arch_freq_prepare_all(void)
93+
{
94+
ktime_t now = ktime_get();
95+
bool wait = false;
96+
int cpu;
97+
98+
if (!cpu_khz)
99+
return;
100+
101+
if (!static_cpu_has(X86_FEATURE_APERFMPERF))
102+
return;
103+
104+
for_each_online_cpu(cpu)
105+
if (!aperfmperf_snapshot_cpu(cpu, now, false))
106+
wait = true;
107+
108+
if (wait)
109+
msleep(APERFMPERF_REFRESH_DELAY_MS);
110+
}
111+
112+
unsigned int arch_freq_get_on_cpu(int cpu)
113+
{
114+
if (!cpu_khz)
115+
return 0;
116+
117+
if (!static_cpu_has(X86_FEATURE_APERFMPERF))
118+
return 0;
119+
120+
if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
121+
return per_cpu(samples.khz, cpu);
92122

93123
msleep(APERFMPERF_REFRESH_DELAY_MS);
94124
smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);

arch/x86/kernel/cpu/cpu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ extern const struct cpu_dev *const __x86_cpu_dev_start[],
4747

4848
extern void get_cpu_cap(struct cpuinfo_x86 *c);
4949
extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
50+
51+
unsigned int aperfmperf_get_khz(int cpu);
52+
5053
#endif /* ARCH_X86_CPU_H */

arch/x86/kernel/cpu/proc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <linux/seq_file.h>
66
#include <linux/cpufreq.h>
77

8+
#include "cpu.h"
9+
810
/*
911
* Get CPU information for use by the procfs.
1012
*/
@@ -78,8 +80,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
7880
seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
7981

8082
if (cpu_has(c, X86_FEATURE_TSC)) {
81-
unsigned int freq = cpufreq_quick_get(cpu);
83+
unsigned int freq = aperfmperf_get_khz(cpu);
8284

85+
if (!freq)
86+
freq = cpufreq_quick_get(cpu);
8387
if (!freq)
8488
freq = cpu_khz;
8589
seq_printf(m, "cpu MHz\t\t: %u.%03u\n",

drivers/base/power/runtime.c

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,29 +1101,13 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
11011101
goto out;
11021102
}
11031103

1104-
if (dev->power.runtime_status == status)
1104+
if (dev->power.runtime_status == status || !parent)
11051105
goto out_set;
11061106

11071107
if (status == RPM_SUSPENDED) {
1108-
/*
1109-
* It is invalid to suspend a device with an active child,
1110-
* unless it has been set to ignore its children.
1111-
*/
1112-
if (!dev->power.ignore_children &&
1113-
atomic_read(&dev->power.child_count)) {
1114-
dev_err(dev, "runtime PM trying to suspend device but active child\n");
1115-
error = -EBUSY;
1116-
goto out;
1117-
}
1118-
1119-
if (parent) {
1120-
atomic_add_unless(&parent->power.child_count, -1, 0);
1121-
notify_parent = !parent->power.ignore_children;
1122-
}
1123-
goto out_set;
1124-
}
1125-
1126-
if (parent) {
1108+
atomic_add_unless(&parent->power.child_count, -1, 0);
1109+
notify_parent = !parent->power.ignore_children;
1110+
} else {
11271111
spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
11281112

11291113
/*
@@ -1307,6 +1291,13 @@ void pm_runtime_enable(struct device *dev)
13071291
else
13081292
dev_warn(dev, "Unbalanced %s!\n", __func__);
13091293

1294+
WARN(!dev->power.disable_depth &&
1295+
dev->power.runtime_status == RPM_SUSPENDED &&
1296+
!dev->power.ignore_children &&
1297+
atomic_read(&dev->power.child_count) > 0,
1298+
"Enabling runtime PM for inactive device (%s) with active children\n",
1299+
dev_name(dev));
1300+
13101301
spin_unlock_irqrestore(&dev->power.lock, flags);
13111302
}
13121303
EXPORT_SYMBOL_GPL(pm_runtime_enable);

fs/proc/cpuinfo.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/cpufreq.h>
23
#include <linux/fs.h>
34
#include <linux/init.h>
45
#include <linux/proc_fs.h>
56
#include <linux/seq_file.h>
67

8+
__weak void arch_freq_prepare_all(void)
9+
{
10+
}
11+
712
extern const struct seq_operations cpuinfo_op;
813
static int cpuinfo_open(struct inode *inode, struct file *file)
914
{
15+
arch_freq_prepare_all();
1016
return seq_open(file, &cpuinfo_op);
1117
}
1218

include/linux/cpufreq.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
917917
}
918918
#endif
919919

920+
extern void arch_freq_prepare_all(void);
920921
extern unsigned int arch_freq_get_on_cpu(int cpu);
921922

922923
extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,

0 commit comments

Comments
 (0)