aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-17 17:49:25 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-17 17:49:25 -0500
commite75080f185c103a638c66d7b65c673769a57cb87 (patch)
treefa8678e324f7e2225b652685162c15c0c932f970
parentf6705bf959efac87bca76d40050d342f1d212587 (diff)
parent3e4c9e637df1fac4123db5f3165b0034226a671b (diff)
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
-rw-r--r--Documentation/power/runtime_pm.txt3
-rw-r--r--arch/x86/kernel/cpu/Makefile2
-rw-r--r--arch/x86/kernel/cpu/aperfmperf.c74
-rw-r--r--arch/x86/kernel/cpu/cpu.h3
-rw-r--r--arch/x86/kernel/cpu/proc.c6
-rw-r--r--drivers/base/power/runtime.c31
-rw-r--r--fs/proc/cpuinfo.c6
-rw-r--r--include/linux/cpufreq.h1
8 files changed, 80 insertions, 46 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 57af2f7963ee..937e33c46211 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -435,8 +435,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
435 PM status to 'suspended' and update its parent's counter of 'active' 435 PM status to 'suspended' and update its parent's counter of 'active'
436 children as appropriate (it is only valid to use this function if 436 children as appropriate (it is only valid to use this function if
437 'power.runtime_error' is set or 'power.disable_depth' is greater than 437 '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 438 zero)
439 which is active and the 'power.ignore_children' flag is unset
440 439
441 bool pm_runtime_active(struct device *dev); 440 bool pm_runtime_active(struct device *dev);
442 - return true if the device's runtime PM status is 'active' or its 441 - return true if the device's runtime PM status is 'active' or its
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 90cb82dbba57..570e8bb1f386 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -22,7 +22,7 @@ obj-y += common.o
22obj-y += rdrand.o 22obj-y += rdrand.o
23obj-y += match.o 23obj-y += match.o
24obj-y += bugs.o 24obj-y += bugs.o
25obj-$(CONFIG_CPU_FREQ) += aperfmperf.o 25obj-y += aperfmperf.o
26obj-y += cpuid-deps.o 26obj-y += cpuid-deps.o
27 27
28obj-$(CONFIG_PROC_FS) += proc.o 28obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/arch/x86/kernel/cpu/aperfmperf.c b/arch/x86/kernel/cpu/aperfmperf.c
index 957813e0180d..7eba34df54c3 100644
--- a/arch/x86/kernel/cpu/aperfmperf.c
+++ b/arch/x86/kernel/cpu/aperfmperf.c
@@ -14,6 +14,8 @@
14#include <linux/percpu.h> 14#include <linux/percpu.h>
15#include <linux/smp.h> 15#include <linux/smp.h>
16 16
17#include "cpu.h"
18
17struct aperfmperf_sample { 19struct aperfmperf_sample {
18 unsigned int khz; 20 unsigned int khz;
19 ktime_t time; 21 ktime_t time;
@@ -24,7 +26,7 @@ struct aperfmperf_sample {
24static DEFINE_PER_CPU(struct aperfmperf_sample, samples); 26static DEFINE_PER_CPU(struct aperfmperf_sample, samples);
25 27
26#define APERFMPERF_CACHE_THRESHOLD_MS 10 28#define APERFMPERF_CACHE_THRESHOLD_MS 10
27#define APERFMPERF_REFRESH_DELAY_MS 20 29#define APERFMPERF_REFRESH_DELAY_MS 10
28#define APERFMPERF_STALE_THRESHOLD_MS 1000 30#define APERFMPERF_STALE_THRESHOLD_MS 1000
29 31
30/* 32/*
@@ -38,8 +40,6 @@ static void aperfmperf_snapshot_khz(void *dummy)
38 u64 aperf, aperf_delta; 40 u64 aperf, aperf_delta;
39 u64 mperf, mperf_delta; 41 u64 mperf, mperf_delta;
40 struct aperfmperf_sample *s = this_cpu_ptr(&samples); 42 struct aperfmperf_sample *s = this_cpu_ptr(&samples);
41 ktime_t now = ktime_get();
42 s64 time_delta = ktime_ms_delta(now, s->time);
43 unsigned long flags; 43 unsigned long flags;
44 44
45 local_irq_save(flags); 45 local_irq_save(flags);
@@ -57,38 +57,68 @@ static void aperfmperf_snapshot_khz(void *dummy)
57 if (mperf_delta == 0) 57 if (mperf_delta == 0)
58 return; 58 return;
59 59
60 s->time = now; 60 s->time = ktime_get();
61 s->aperf = aperf; 61 s->aperf = aperf;
62 s->mperf = mperf; 62 s->mperf = mperf;
63 63 s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
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);
69} 64}
70 65
71unsigned int arch_freq_get_on_cpu(int cpu) 66static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait)
72{ 67{
73 s64 time_delta; 68 s64 time_delta = ktime_ms_delta(now, per_cpu(samples.time, cpu));
74 unsigned int khz; 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}
75 79
80unsigned int aperfmperf_get_khz(int cpu)
81{
76 if (!cpu_khz) 82 if (!cpu_khz)
77 return 0; 83 return 0;
78 84
79 if (!static_cpu_has(X86_FEATURE_APERFMPERF)) 85 if (!static_cpu_has(X86_FEATURE_APERFMPERF))
80 return 0; 86 return 0;
81 87
82 /* Don't bother re-computing within the cache threshold time. */ 88 aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
83 time_delta = ktime_ms_delta(ktime_get(), per_cpu(samples.time, cpu)); 89 return per_cpu(samples.khz, cpu);
84 khz = per_cpu(samples.khz, cpu); 90}
85 if (khz && time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
86 return khz;
87 91
88 smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); 92void arch_freq_prepare_all(void)
89 khz = per_cpu(samples.khz, cpu); 93{
90 if (khz) 94 ktime_t now = ktime_get();
91 return khz; 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
112unsigned 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);
92 122
93 msleep(APERFMPERF_REFRESH_DELAY_MS); 123 msleep(APERFMPERF_REFRESH_DELAY_MS);
94 smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); 124 smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h
index f52a370b6c00..e806b11a99af 100644
--- a/arch/x86/kernel/cpu/cpu.h
+++ b/arch/x86/kernel/cpu/cpu.h
@@ -47,4 +47,7 @@ extern const struct cpu_dev *const __x86_cpu_dev_start[],
47 47
48extern void get_cpu_cap(struct cpuinfo_x86 *c); 48extern void get_cpu_cap(struct cpuinfo_x86 *c);
49extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c); 49extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
50
51unsigned int aperfmperf_get_khz(int cpu);
52
50#endif /* ARCH_X86_CPU_H */ 53#endif /* ARCH_X86_CPU_H */
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 6b7e17bf0b71..e7ecedafa1c8 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -5,6 +5,8 @@
5#include <linux/seq_file.h> 5#include <linux/seq_file.h>
6#include <linux/cpufreq.h> 6#include <linux/cpufreq.h>
7 7
8#include "cpu.h"
9
8/* 10/*
9 * Get CPU information for use by the procfs. 11 * Get CPU information for use by the procfs.
10 */ 12 */
@@ -78,9 +80,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
78 seq_printf(m, "microcode\t: 0x%x\n", c->microcode); 80 seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
79 81
80 if (cpu_has(c, X86_FEATURE_TSC)) { 82 if (cpu_has(c, X86_FEATURE_TSC)) {
81 unsigned int freq = cpufreq_quick_get(cpu); 83 unsigned int freq = aperfmperf_get_khz(cpu);
82 84
83 if (!freq) 85 if (!freq)
86 freq = cpufreq_quick_get(cpu);
87 if (!freq)
84 freq = cpu_khz; 88 freq = cpu_khz;
85 seq_printf(m, "cpu MHz\t\t: %u.%03u\n", 89 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
86 freq / 1000, (freq % 1000)); 90 freq / 1000, (freq % 1000));
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 2362b9e9701e..027d159ac381 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1101,29 +1101,13 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
1101 goto out; 1101 goto out;
1102 } 1102 }
1103 1103
1104 if (dev->power.runtime_status == status) 1104 if (dev->power.runtime_status == status || !parent)
1105 goto out_set; 1105 goto out_set;
1106 1106
1107 if (status == RPM_SUSPENDED) { 1107 if (status == RPM_SUSPENDED) {
1108 /* 1108 atomic_add_unless(&parent->power.child_count, -1, 0);
1109 * It is invalid to suspend a device with an active child, 1109 notify_parent = !parent->power.ignore_children;
1110 * unless it has been set to ignore its children. 1110 } else {
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) {
1127 spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING); 1111 spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
1128 1112
1129 /* 1113 /*
@@ -1307,6 +1291,13 @@ void pm_runtime_enable(struct device *dev)
1307 else 1291 else
1308 dev_warn(dev, "Unbalanced %s!\n", __func__); 1292 dev_warn(dev, "Unbalanced %s!\n", __func__);
1309 1293
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
1310 spin_unlock_irqrestore(&dev->power.lock, flags); 1301 spin_unlock_irqrestore(&dev->power.lock, flags);
1311} 1302}
1312EXPORT_SYMBOL_GPL(pm_runtime_enable); 1303EXPORT_SYMBOL_GPL(pm_runtime_enable);
diff --git a/fs/proc/cpuinfo.c b/fs/proc/cpuinfo.c
index e0f867cd8553..96f1087e372c 100644
--- a/fs/proc/cpuinfo.c
+++ b/fs/proc/cpuinfo.c
@@ -1,12 +1,18 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2#include <linux/cpufreq.h>
2#include <linux/fs.h> 3#include <linux/fs.h>
3#include <linux/init.h> 4#include <linux/init.h>
4#include <linux/proc_fs.h> 5#include <linux/proc_fs.h>
5#include <linux/seq_file.h> 6#include <linux/seq_file.h>
6 7
8__weak void arch_freq_prepare_all(void)
9{
10}
11
7extern const struct seq_operations cpuinfo_op; 12extern const struct seq_operations cpuinfo_op;
8static int cpuinfo_open(struct inode *inode, struct file *file) 13static int cpuinfo_open(struct inode *inode, struct file *file)
9{ 14{
15 arch_freq_prepare_all();
10 return seq_open(file, &cpuinfo_op); 16 return seq_open(file, &cpuinfo_op);
11} 17}
12 18
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 28734ee185a7..065f3a8eb486 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -917,6 +917,7 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
917} 917}
918#endif 918#endif
919 919
920extern void arch_freq_prepare_all(void);
920extern unsigned int arch_freq_get_on_cpu(int cpu); 921extern unsigned int arch_freq_get_on_cpu(int cpu);
921 922
922extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, 923extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,