Skip to content

Commit f6a034f

Browse files
committed
thermal: Introduce a debugfs-based testing facility
Introduce a facility allowing the thermal core functionality to be exercised in a controlled way in order to verify its behavior, without affecting its regular users noticeably. It is based on the idea of preparing thermal zone templates along with their trip points by writing to files in debugfs. When ready, those templates can be used for registering test thermal zones with the thermal core. The temperature of a test thermal zone created this way can be adjusted via debugfs, which also triggers a __thermal_zone_device_update() call for it. By manipulating the temperature of a test thermal zone, one can check if the thermal core reacts to the changes of it as expected. Signed-off-by: Rafael J. Wysocki <[email protected]> Link: https://patch.msgid.link/[email protected] [ rjw: Fixed ordering of kcalloc() arguments ] [ rjw: Fixed debugfs_create_dir() return value checks ] [ rjw: Fixed two kerneldoc comments ] Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent f9ba1e0 commit f6a034f

File tree

6 files changed

+717
-0
lines changed

6 files changed

+717
-0
lines changed

drivers/thermal/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ config THERMAL_DEBUGFS
4040
Say Y to allow the thermal subsystem to collect diagnostic
4141
information that can be accessed via debugfs.
4242

43+
config THERMAL_CORE_TESTING
44+
tristate "Thermal core testing facility"
45+
depends on DEBUG_FS
46+
help
47+
Say Y to add a debugfs-based thermal core testing facility.
48+
It allows test thermal zones to be created and populated
49+
with trip points in order to exercise the thermal core
50+
functionality in a controlled way.
51+
4352
config THERMAL_EMERGENCY_POWEROFF_DELAY_MS
4453
int "Emergency poweroff delay in milli-seconds"
4554
default 0

drivers/thermal/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
6363
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
6464
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
6565
obj-$(CONFIG_LOONGSON2_THERMAL) += loongson2_thermal.o
66+
obj-$(CONFIG_THERMAL_CORE_TESTING) += testing/

drivers/thermal/testing/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# Thermal core testing facility.
4+
5+
obj-$(CONFIG_THERMAL_CORE_TESTING) += thermal-testing.o
6+
7+
thermal-testing-y := command.o zone.o

drivers/thermal/testing/command.c

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright 2024, Intel Corporation
4+
*
5+
* Author: Rafael J. Wysocki <[email protected]>
6+
*
7+
* Thermal subsystem testing facility.
8+
*
9+
* This facility allows the thermal core functionality to be exercised in a
10+
* controlled way in order to verify its behavior.
11+
*
12+
* It resides in the "thermal-testing" directory under the debugfs root and
13+
* starts with a single file called "command" which can be written a string
14+
* representing a thermal testing facility command.
15+
*
16+
* The currently supported commands are listed in the tt_commands enum below.
17+
*
18+
* The "addtz" command causes a new test thermal zone template to be created,
19+
* for example:
20+
*
21+
* # echo addtz > /sys/kernel/debug/thermal-testing/command
22+
*
23+
* That template will be represented as a subdirectory in the "thermal-testing"
24+
* directory, for example
25+
*
26+
* # ls /sys/kernel/debug/thermal-testing/
27+
* command tz0
28+
*
29+
* The thermal zone template can be populated with trip points with the help of
30+
* the "tzaddtrip" command, for example:
31+
*
32+
* # echo tzaddtrip:0 > /sys/kernel/debug/thermal-testing/command
33+
*
34+
* which causes a trip point template to be added to the test thermal zone
35+
* template 0 (represented by the tz0 subdirectory in "thermal-testing").
36+
*
37+
* # ls /sys/kernel/debug/thermal-testing/tz0
38+
* init_temp temp trip_0_temp trip_0_hyst
39+
*
40+
* The temperature of a trip point template is initially THERMAL_TEMP_INVALID
41+
* and its hysteresis is initially 0. They can be adjusted by writing to the
42+
* "trip_x_temp" and "trip_x_hyst" files correspoinding to that trip point
43+
* template, respectively.
44+
*
45+
* The initial temperature of a thermal zone based on a template can be set by
46+
* writing to the "init_temp" file in its directory under "thermal-testing", for
47+
* example:
48+
*
49+
* echo 50000 > /sys/kernel/debug/thermal-testing/tz0/init_temp
50+
*
51+
* When ready, "tzreg" command can be used for registering and enabling a
52+
* thermal zone based on a given template with the thermal core, for example
53+
*
54+
* # echo tzreg:0 > /sys/kernel/debug/thermal-testing/command
55+
*
56+
* In this case, test thermal zone template 0 is used for registering a new
57+
* thermal zone and the set of trip point templates associated with it is used
58+
* for populating the new thermal zone's trip points table. The type of the new
59+
* thermal zone is "test_tz".
60+
*
61+
* The temperature and hysteresis of all of the trip points in that new thermal
62+
* zone are adjustable via sysfs, so they can be updated at any time.
63+
*
64+
* The current temperature of the new thermal zone can be set by writing to the
65+
* "temp" file in the corresponding thermal zone template's directory under
66+
* "thermal-testing", for example
67+
*
68+
* echo 10000 > /sys/kernel/debug/thermal-testing/tz0/temp
69+
*
70+
* which will also trigger a temperature update for this zone in the thermal
71+
* core, including checking its trip points, sending notifications to user space
72+
* if any of them have been crossed and so on.
73+
*
74+
* When it is not needed any more, a test thermal zone template can be deleted
75+
* with the help of the "deltz" command, for example
76+
*
77+
* # echo deltz:0 > /sys/kernel/debug/thermal-testing/command
78+
*
79+
* which will also unregister the thermal zone based on it, if present.
80+
*/
81+
82+
#define pr_fmt(fmt) "thermal-testing: " fmt
83+
84+
#include <linux/debugfs.h>
85+
#include <linux/module.h>
86+
87+
#include "thermal_testing.h"
88+
89+
struct dentry *d_testing;
90+
91+
#define TT_COMMAND_SIZE 16
92+
93+
enum tt_commands {
94+
TT_CMD_ADDTZ,
95+
TT_CMD_DELTZ,
96+
TT_CMD_TZADDTRIP,
97+
TT_CMD_TZREG,
98+
TT_CMD_TZUNREG,
99+
};
100+
101+
static const char *tt_command_strings[] = {
102+
[TT_CMD_ADDTZ] = "addtz",
103+
[TT_CMD_DELTZ] = "deltz",
104+
[TT_CMD_TZADDTRIP] = "tzaddtrip",
105+
[TT_CMD_TZREG] = "tzreg",
106+
[TT_CMD_TZUNREG] = "tzunreg",
107+
};
108+
109+
static int tt_command_exec(int index, const char *arg)
110+
{
111+
int ret;
112+
113+
switch (index) {
114+
case TT_CMD_ADDTZ:
115+
ret = tt_add_tz();
116+
break;
117+
118+
case TT_CMD_DELTZ:
119+
ret = tt_del_tz(arg);
120+
break;
121+
122+
case TT_CMD_TZADDTRIP:
123+
ret = tt_zone_add_trip(arg);
124+
break;
125+
126+
case TT_CMD_TZREG:
127+
ret = tt_zone_reg(arg);
128+
break;
129+
130+
case TT_CMD_TZUNREG:
131+
ret = tt_zone_unreg(arg);
132+
break;
133+
134+
default:
135+
ret = -EINVAL;
136+
break;
137+
}
138+
139+
return ret;
140+
}
141+
142+
static ssize_t tt_command_process(struct dentry *dentry, const char __user *user_buf,
143+
size_t count)
144+
{
145+
char *buf __free(kfree);
146+
char *arg;
147+
int i;
148+
149+
buf = kmalloc(count + 1, GFP_KERNEL);
150+
if (!buf)
151+
return -ENOMEM;
152+
153+
if (copy_from_user(buf, user_buf, count))
154+
return -EFAULT;
155+
156+
buf[count] = '\0';
157+
strim(buf);
158+
159+
arg = strstr(buf, ":");
160+
if (arg) {
161+
*arg = '\0';
162+
arg++;
163+
}
164+
165+
for (i = 0; i < ARRAY_SIZE(tt_command_strings); i++) {
166+
if (!strcmp(buf, tt_command_strings[i]))
167+
return tt_command_exec(i, arg);
168+
}
169+
170+
return -EINVAL;
171+
}
172+
173+
static ssize_t tt_command_write(struct file *file, const char __user *user_buf,
174+
size_t count, loff_t *ppos)
175+
{
176+
struct dentry *dentry = file->f_path.dentry;
177+
ssize_t ret;
178+
179+
if (*ppos)
180+
return -EINVAL;
181+
182+
if (count + 1 > TT_COMMAND_SIZE)
183+
return -E2BIG;
184+
185+
ret = debugfs_file_get(dentry);
186+
if (unlikely(ret))
187+
return ret;
188+
189+
ret = tt_command_process(dentry, user_buf, count);
190+
if (ret)
191+
return ret;
192+
193+
return count;
194+
}
195+
196+
static const struct file_operations tt_command_fops = {
197+
.write = tt_command_write,
198+
.open = simple_open,
199+
.llseek = default_llseek,
200+
};
201+
202+
static int __init thermal_testing_init(void)
203+
{
204+
d_testing = debugfs_create_dir("thermal-testing", NULL);
205+
if (!IS_ERR(d_testing))
206+
debugfs_create_file("command", 0200, d_testing, NULL,
207+
&tt_command_fops);
208+
209+
return 0;
210+
}
211+
module_init(thermal_testing_init);
212+
213+
static void __exit thermal_testing_exit(void)
214+
{
215+
debugfs_remove(d_testing);
216+
tt_zone_cleanup();
217+
}
218+
module_exit(thermal_testing_exit);
219+
220+
MODULE_DESCRIPTION("Thermal core testing facility");
221+
MODULE_LICENSE("GPL v2");
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
extern struct dentry *d_testing;
4+
5+
int tt_add_tz(void);
6+
int tt_del_tz(const char *arg);
7+
int tt_zone_add_trip(const char *arg);
8+
int tt_zone_reg(const char *arg);
9+
int tt_zone_unreg(const char *arg);
10+
11+
void tt_zone_cleanup(void);

0 commit comments

Comments
 (0)