1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
From: Daniel Wagner <wagi@monom.org>
Date: Tue, 17 Feb 2015 09:37:44 +0100
Subject: [PATCH 174/342] thermal: Defer thermal wakups to threads
Origin: https://git.kernel.org/cgit/linux/kernel/git/rt/linux-stable-rt.git/commit?id=80d2debabf144ce9ed2ba4ef7be880809eb9415e
On RT the spin lock in pkg_temp_thermal_platfrom_thermal_notify will
call schedule while we run in irq context.
[<ffffffff816850ac>] dump_stack+0x4e/0x8f
[<ffffffff81680f7d>] __schedule_bug+0xa6/0xb4
[<ffffffff816896b4>] __schedule+0x5b4/0x700
[<ffffffff8168982a>] schedule+0x2a/0x90
[<ffffffff8168a8b5>] rt_spin_lock_slowlock+0xe5/0x2d0
[<ffffffff8168afd5>] rt_spin_lock+0x25/0x30
[<ffffffffa03a7b75>] pkg_temp_thermal_platform_thermal_notify+0x45/0x134 [x86_pkg_temp_thermal]
[<ffffffff8103d4db>] ? therm_throt_process+0x1b/0x160
[<ffffffff8103d831>] intel_thermal_interrupt+0x211/0x250
[<ffffffff8103d8c1>] smp_thermal_interrupt+0x21/0x40
[<ffffffff8169415d>] thermal_interrupt+0x6d/0x80
Let's defer the work to a kthread.
Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
[bigeasy: reoder init/denit position. TODO: flush swork on exit]
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
drivers/thermal/x86_pkg_temp_thermal.c | 52 ++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 3 deletions(-)
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index 1ef937d799e4..a5991cbb408f 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -29,6 +29,7 @@
#include <linux/pm.h>
#include <linux/thermal.h>
#include <linux/debugfs.h>
+#include <linux/swork.h>
#include <asm/cpu_device_id.h>
#include <asm/mce.h>
@@ -329,7 +330,7 @@ static void pkg_thermal_schedule_work(int cpu, struct delayed_work *work)
schedule_delayed_work_on(cpu, work, ms);
}
-static int pkg_thermal_notify(u64 msr_val)
+static void pkg_thermal_notify_work(struct swork_event *event)
{
int cpu = smp_processor_id();
struct pkg_device *pkgdev;
@@ -348,9 +349,47 @@ static int pkg_thermal_notify(u64 msr_val)
}
spin_unlock_irqrestore(&pkg_temp_lock, flags);
+}
+
+#ifdef CONFIG_PREEMPT_RT_FULL
+static struct swork_event notify_work;
+
+static int pkg_thermal_notify_work_init(void)
+{
+ int err;
+
+ err = swork_get();
+ if (err)
+ return err;
+
+ INIT_SWORK(¬ify_work, pkg_thermal_notify_work);
return 0;
}
+static void pkg_thermal_notify_work_cleanup(void)
+{
+ swork_put();
+}
+
+static int pkg_thermal_notify(u64 msr_val)
+{
+ swork_queue(¬ify_work);
+ return 0;
+}
+
+#else /* !CONFIG_PREEMPT_RT_FULL */
+
+static int pkg_thermal_notify_work_init(void) { return 0; }
+
+static void pkg_thermal_notify_work_cleanup(void) { }
+
+static int pkg_thermal_notify(u64 msr_val)
+{
+ pkg_thermal_notify_work(NULL);
+ return 0;
+}
+#endif /* CONFIG_PREEMPT_RT_FULL */
+
static int pkg_temp_thermal_device_add(unsigned int cpu)
{
int pkgid = topology_logical_package_id(cpu);
@@ -515,11 +554,16 @@ static int __init pkg_temp_thermal_init(void)
if (!x86_match_cpu(pkg_temp_thermal_ids))
return -ENODEV;
+ if (!pkg_thermal_notify_work_init())
+ return -ENODEV;
+
max_packages = topology_max_packages();
packages = kcalloc(max_packages, sizeof(struct pkg_device *),
GFP_KERNEL);
- if (!packages)
- return -ENOMEM;
+ if (!packages) {
+ ret = -ENOMEM;
+ goto err;
+ }
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal/x86_pkg:online",
pkg_thermal_cpu_online, pkg_thermal_cpu_offline);
@@ -537,6 +581,7 @@ static int __init pkg_temp_thermal_init(void)
return 0;
err:
+ pkg_thermal_notify_work_cleanup();
kfree(packages);
return ret;
}
@@ -550,6 +595,7 @@ static void __exit pkg_temp_thermal_exit(void)
cpuhp_remove_state(pkg_thermal_hp_state);
debugfs_remove_recursive(debugfs);
kfree(packages);
+ pkg_thermal_notify_work_cleanup();
}
module_exit(pkg_temp_thermal_exit)
|