| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2024, Intel Corporation
- *
- * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * Thermal subsystem testing facility.
- *
- * This facility allows the thermal core functionality to be exercised in a
- * controlled way in order to verify its behavior.
- *
- * It resides in the "thermal-testing" directory under the debugfs root and
- * starts with a single file called "command" which can be written a string
- * representing a thermal testing facility command.
- *
- * The currently supported commands are listed in the tt_commands enum below.
- *
- * The "addtz" command causes a new test thermal zone template to be created,
- * for example:
- *
- * # echo addtz > /sys/kernel/debug/thermal-testing/command
- *
- * That template will be represented as a subdirectory in the "thermal-testing"
- * directory, for example
- *
- * # ls /sys/kernel/debug/thermal-testing/
- * command tz0
- *
- * The thermal zone template can be populated with trip points with the help of
- * the "tzaddtrip" command, for example:
- *
- * # echo tzaddtrip:0 > /sys/kernel/debug/thermal-testing/command
- *
- * which causes a trip point template to be added to the test thermal zone
- * template 0 (represented by the tz0 subdirectory in "thermal-testing").
- *
- * # ls /sys/kernel/debug/thermal-testing/tz0
- * init_temp temp trip_0_temp trip_0_hyst
- *
- * The temperature of a trip point template is initially THERMAL_TEMP_INVALID
- * and its hysteresis is initially 0. They can be adjusted by writing to the
- * "trip_x_temp" and "trip_x_hyst" files correspoinding to that trip point
- * template, respectively.
- *
- * The initial temperature of a thermal zone based on a template can be set by
- * writing to the "init_temp" file in its directory under "thermal-testing", for
- * example:
- *
- * echo 50000 > /sys/kernel/debug/thermal-testing/tz0/init_temp
- *
- * When ready, "tzreg" command can be used for registering and enabling a
- * thermal zone based on a given template with the thermal core, for example
- *
- * # echo tzreg:0 > /sys/kernel/debug/thermal-testing/command
- *
- * In this case, test thermal zone template 0 is used for registering a new
- * thermal zone and the set of trip point templates associated with it is used
- * for populating the new thermal zone's trip points table. The type of the new
- * thermal zone is "test_tz".
- *
- * The temperature and hysteresis of all of the trip points in that new thermal
- * zone are adjustable via sysfs, so they can be updated at any time.
- *
- * The current temperature of the new thermal zone can be set by writing to the
- * "temp" file in the corresponding thermal zone template's directory under
- * "thermal-testing", for example
- *
- * echo 10000 > /sys/kernel/debug/thermal-testing/tz0/temp
- *
- * which will also trigger a temperature update for this zone in the thermal
- * core, including checking its trip points, sending notifications to user space
- * if any of them have been crossed and so on.
- *
- * When it is not needed any more, a test thermal zone template can be deleted
- * with the help of the "deltz" command, for example
- *
- * # echo deltz:0 > /sys/kernel/debug/thermal-testing/command
- *
- * which will also unregister the thermal zone based on it, if present.
- */
- #define pr_fmt(fmt) "thermal-testing: " fmt
- #include <linux/debugfs.h>
- #include <linux/module.h>
- #include "thermal_testing.h"
- struct dentry *d_testing;
- #define TT_COMMAND_SIZE 16
- enum tt_commands {
- TT_CMD_ADDTZ,
- TT_CMD_DELTZ,
- TT_CMD_TZADDTRIP,
- TT_CMD_TZREG,
- TT_CMD_TZUNREG,
- };
- static const char *tt_command_strings[] = {
- [TT_CMD_ADDTZ] = "addtz",
- [TT_CMD_DELTZ] = "deltz",
- [TT_CMD_TZADDTRIP] = "tzaddtrip",
- [TT_CMD_TZREG] = "tzreg",
- [TT_CMD_TZUNREG] = "tzunreg",
- };
- static int tt_command_exec(int index, const char *arg)
- {
- int ret;
- switch (index) {
- case TT_CMD_ADDTZ:
- ret = tt_add_tz();
- break;
- case TT_CMD_DELTZ:
- ret = tt_del_tz(arg);
- break;
- case TT_CMD_TZADDTRIP:
- ret = tt_zone_add_trip(arg);
- break;
- case TT_CMD_TZREG:
- ret = tt_zone_reg(arg);
- break;
- case TT_CMD_TZUNREG:
- ret = tt_zone_unreg(arg);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static ssize_t tt_command_process(struct dentry *dentry, const char __user *user_buf,
- size_t count)
- {
- char *buf __free(kfree);
- char *arg;
- int i;
- buf = kmalloc(count + 1, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- if (copy_from_user(buf, user_buf, count))
- return -EFAULT;
- buf[count] = '\0';
- strim(buf);
- arg = strstr(buf, ":");
- if (arg) {
- *arg = '\0';
- arg++;
- }
- for (i = 0; i < ARRAY_SIZE(tt_command_strings); i++) {
- if (!strcmp(buf, tt_command_strings[i]))
- return tt_command_exec(i, arg);
- }
- return -EINVAL;
- }
- static ssize_t tt_command_write(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
- {
- struct dentry *dentry = file->f_path.dentry;
- ssize_t ret;
- if (*ppos)
- return -EINVAL;
- if (count + 1 > TT_COMMAND_SIZE)
- return -E2BIG;
- ret = debugfs_file_get(dentry);
- if (unlikely(ret))
- return ret;
- ret = tt_command_process(dentry, user_buf, count);
- if (ret)
- return ret;
- return count;
- }
- static const struct file_operations tt_command_fops = {
- .write = tt_command_write,
- .open = simple_open,
- .llseek = default_llseek,
- };
- static int __init thermal_testing_init(void)
- {
- d_testing = debugfs_create_dir("thermal-testing", NULL);
- if (!IS_ERR(d_testing))
- debugfs_create_file("command", 0200, d_testing, NULL,
- &tt_command_fops);
- return 0;
- }
- module_init(thermal_testing_init);
- static void __exit thermal_testing_exit(void)
- {
- debugfs_remove(d_testing);
- tt_zone_cleanup();
- }
- module_exit(thermal_testing_exit);
- MODULE_DESCRIPTION("Thermal core testing facility");
- MODULE_LICENSE("GPL v2");
|