@@ -30,3 +30,11 @@ KernelVersion: 5.11
Contact: Matteo Croce <mcroce@microsoft.com>
Description: Don't wait for any other CPUs on reboot and
avoid anything that could hang.
+
+What: /sys/kernel/reboot/hw_protection
+Date: April 2025
+KernelVersion: 6.15
+Contact: Ahmad Fatoum <a.fatoum@pengutronix.de>
+Description: Hardware protection action taken on critical events like
+ overtemperature or imminent voltage loss.
+ Valid values are: reboot shutdown
@@ -1933,6 +1933,12 @@
which allow the hypervisor to 'idle' the guest
on lock contention.
+ hw_protection= [HW]
+ Format: reboot | shutdown
+
+ Hardware protection action taken on critical events like
+ overtemperature or imminent voltage loss.
+
i2c_bus= [HW] Override the default board specific I2C bus speed
or register an additional I2C bus that is not
registered from board initialization code.
@@ -181,16 +181,36 @@ extern void orderly_reboot(void);
/**
* enum hw_protection_action - Hardware protection action
*
+ * @HWPROT_ACT_DEFAULT:
+ * The default action should be taken. This is HWPROT_ACT_SHUTDOWN
+ * by default, but can be overridden.
* @HWPROT_ACT_SHUTDOWN:
* The system should be shut down (powered off) for HW protection.
* @HWPROT_ACT_REBOOT:
* The system should be rebooted for HW protection.
*/
-enum hw_protection_action { HWPROT_ACT_SHUTDOWN, HWPROT_ACT_REBOOT };
+enum hw_protection_action { HWPROT_ACT_DEFAULT, HWPROT_ACT_SHUTDOWN, HWPROT_ACT_REBOOT };
void __hw_protection_trigger(const char *reason, int ms_until_forced,
enum hw_protection_action action);
+/**
+ * hw_protection_trigger - Trigger default emergency system hardware protection action
+ *
+ * @reason: Reason of emergency shutdown or reboot to be printed.
+ * @ms_until_forced: Time to wait for orderly shutdown or reboot before
+ * triggering it. Negative value disables the forced
+ * shutdown or reboot.
+ *
+ * Initiate an emergency system shutdown or reboot in order to protect
+ * hardware from further damage. The exact action taken is controllable at
+ * runtime and defaults to shutdown.
+ */
+static inline void hw_protection_trigger(const char *reason, int ms_until_forced)
+{
+ __hw_protection_trigger(reason, ms_until_forced, HWPROT_ACT_DEFAULT);
+}
+
static inline void hw_protection_reboot(const char *reason, int ms_until_forced)
{
__hw_protection_trigger(reason, ms_until_forced, HWPROT_ACT_REBOOT);
@@ -275,6 +275,7 @@ struct vfs_ns_cap_data {
/* Allow setting encryption key on loopback filesystem */
/* Allow setting zone reclaim policy */
/* Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility */
+/* Allow setting hardware protection emergency action */
#define CAP_SYS_ADMIN 21
@@ -36,6 +36,8 @@ enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
EXPORT_SYMBOL_GPL(reboot_mode);
enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED;
+static enum hw_protection_action hw_protection_action = HWPROT_ACT_SHUTDOWN;
+
/*
* This variable is used privately to keep track of whether or not
* reboot_type is still set to its default value (i.e., reboot= hasn't
@@ -1027,6 +1029,9 @@ void __hw_protection_trigger(const char *reason, int ms_until_forced,
{
static atomic_t allow_proceed = ATOMIC_INIT(1);
+ if (action == HWPROT_ACT_DEFAULT)
+ action = hw_protection_action;
+
pr_emerg("HARDWARE PROTECTION %s (%s)\n",
hw_protection_action_str(action), reason);
@@ -1046,6 +1051,46 @@ void __hw_protection_trigger(const char *reason, int ms_until_forced,
}
EXPORT_SYMBOL_GPL(__hw_protection_trigger);
+static bool hw_protection_action_parse(const char *str,
+ enum hw_protection_action *action)
+{
+ if (sysfs_streq(str, "shutdown"))
+ *action = HWPROT_ACT_SHUTDOWN;
+ else if (sysfs_streq(str, "reboot"))
+ *action = HWPROT_ACT_REBOOT;
+ else
+ return false;
+
+ return true;
+}
+
+static int __init hw_protection_setup(char *str)
+{
+ hw_protection_action_parse(str, &hw_protection_action);
+ return 1;
+}
+__setup("hw_protection=", hw_protection_setup);
+
+static ssize_t hw_protection_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%s\n",
+ hw_protection_action_str(hw_protection_action));
+}
+static ssize_t hw_protection_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (!hw_protection_action_parse(buf, &hw_protection_action))
+ return -EINVAL;
+
+ return count;
+}
+static struct kobj_attribute hw_protection_attr = __ATTR_RW(hw_protection);
+
static int __init reboot_setup(char *str)
{
for (;;) {
@@ -1305,6 +1350,7 @@ static struct kobj_attribute reboot_cpu_attr = __ATTR_RW(cpu);
#endif
static struct attribute *reboot_attrs[] = {
+ &hw_protection_attr.attr,
&reboot_mode_attr.attr,
#ifdef CONFIG_X86
&reboot_force_attr.attr,