1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2024, Intel Corporation
5 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
7 * Thermal subsystem testing facility.
9 * This facility allows the thermal core functionality to be exercised in a
10 * controlled way in order to verify its behavior.
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.
16 * The currently supported commands are listed in the tt_commands enum below.
18 * The "addtz" command causes a new test thermal zone template to be created,
21 * # echo addtz > /sys/kernel/debug/thermal-testing/command
23 * That template will be represented as a subdirectory in the "thermal-testing"
24 * directory, for example
26 * # ls /sys/kernel/debug/thermal-testing/
29 * The thermal zone template can be populated with trip points with the help of
30 * the "tzaddtrip" command, for example:
32 * # echo tzaddtrip:0 > /sys/kernel/debug/thermal-testing/command
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").
37 * # ls /sys/kernel/debug/thermal-testing/tz0
38 * init_temp temp trip_0_temp trip_0_hyst
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.
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
49 * echo 50000 > /sys/kernel/debug/thermal-testing/tz0/init_temp
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
54 * # echo tzreg:0 > /sys/kernel/debug/thermal-testing/command
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".
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.
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
68 * echo 10000 > /sys/kernel/debug/thermal-testing/tz0/temp
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.
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
77 * # echo deltz:0 > /sys/kernel/debug/thermal-testing/command
79 * which will also unregister the thermal zone based on it, if present.
82 #define pr_fmt(fmt) "thermal-testing: " fmt
84 #include <linux/debugfs.h>
85 #include <linux/module.h>
87 #include "thermal_testing.h"
89 struct dentry
*d_testing
;
91 #define TT_COMMAND_SIZE 16
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",
109 static int tt_command_exec(int index
, const char *arg
)
119 ret
= tt_del_tz(arg
);
122 case TT_CMD_TZADDTRIP
:
123 ret
= tt_zone_add_trip(arg
);
127 ret
= tt_zone_reg(arg
);
131 ret
= tt_zone_unreg(arg
);
142 static ssize_t
tt_command_process(struct dentry
*dentry
, const char __user
*user_buf
,
145 char *buf
__free(kfree
);
149 buf
= kmalloc(count
+ 1, GFP_KERNEL
);
153 if (copy_from_user(buf
, user_buf
, count
))
159 arg
= strstr(buf
, ":");
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
);
173 static ssize_t
tt_command_write(struct file
*file
, const char __user
*user_buf
,
174 size_t count
, loff_t
*ppos
)
176 struct dentry
*dentry
= file
->f_path
.dentry
;
182 if (count
+ 1 > TT_COMMAND_SIZE
)
185 ret
= debugfs_file_get(dentry
);
189 ret
= tt_command_process(dentry
, user_buf
, count
);
196 static const struct file_operations tt_command_fops
= {
197 .write
= tt_command_write
,
199 .llseek
= default_llseek
,
202 static int __init
thermal_testing_init(void)
204 d_testing
= debugfs_create_dir("thermal-testing", NULL
);
205 if (!IS_ERR(d_testing
))
206 debugfs_create_file("command", 0200, d_testing
, NULL
,
211 module_init(thermal_testing_init
);
213 static void __exit
thermal_testing_exit(void)
215 debugfs_remove(d_testing
);
218 module_exit(thermal_testing_exit
);
220 MODULE_DESCRIPTION("Thermal core testing facility");
221 MODULE_LICENSE("GPL v2");