diff mbox series

[v5,2/3] reboot: Introduce hw_protection_reboot()

Message ID 20230829194200.1901988-2-festevam@gmail.com (mailing list archive)
State Changes Requested, archived
Headers show
Series [v5,1/3] dt-bindings: thermal-zones: Document critical-action | expand

Commit Message

Fabio Estevam Aug. 29, 2023, 7:41 p.m. UTC
From: Fabio Estevam <festevam@denx.de>

Introduce hw_protection_reboot() to trigger an emergency reboot.

It is a counterpart of hw_protection_shutdown() with the difference
that it will force a reboot instead of shutdown.

The motivation for doing this is to allow the thermal subystem
to trigger a reboot when the temperature reaches the critical
temperature.

Signed-off-by: Fabio Estevam <festevam@denx.de>
---
Changes since v4:
- None

 include/linux/reboot.h |  1 +
 kernel/reboot.c        | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

Comments

Rafael J. Wysocki Aug. 30, 2023, 11:33 a.m. UTC | #1
On Tue, Aug 29, 2023 at 9:42 PM Fabio Estevam <festevam@gmail.com> wrote:
>
> From: Fabio Estevam <festevam@denx.de>
>
> Introduce hw_protection_reboot() to trigger an emergency reboot.
>
> It is a counterpart of hw_protection_shutdown() with the difference
> that it will force a reboot instead of shutdown.
>
> The motivation for doing this is to allow the thermal subystem
> to trigger a reboot when the temperature reaches the critical
> temperature.
>
> Signed-off-by: Fabio Estevam <festevam@denx.de>
> ---
> Changes since v4:
> - None
>
>  include/linux/reboot.h |  1 +
>  kernel/reboot.c        | 34 ++++++++++++++++++++++++++++++++++
>  2 files changed, 35 insertions(+)
>
> diff --git a/include/linux/reboot.h b/include/linux/reboot.h
> index 2b6bb593be5b..4a319bc24f6a 100644
> --- a/include/linux/reboot.h
> +++ b/include/linux/reboot.h
> @@ -174,6 +174,7 @@ void ctrl_alt_del(void);
>
>  extern void orderly_poweroff(bool force);
>  extern void orderly_reboot(void);
> +void hw_protection_reboot(const char *reason, int ms_until_forced);
>  void hw_protection_shutdown(const char *reason, int ms_until_forced);
>
>  /*
> diff --git a/kernel/reboot.c b/kernel/reboot.c
> index 3bba88c7ffc6..05333ae8bc6b 100644
> --- a/kernel/reboot.c
> +++ b/kernel/reboot.c
> @@ -952,6 +952,40 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
>                               msecs_to_jiffies(poweroff_delay_ms));
>  }
>
> +/**
> + * hw_protection_reboot - Trigger an emergency system reboot
> + *
> + * @reason:            Reason of emergency reboot to be printed.
> + * @ms_until_forced:   Time to wait for orderly reboot before tiggering a
> + *                     forced reboot. Negative value disables the forced
> + *                     reboot.
> + *
> + * Initiate an emergency system reboot in order to protect hardware from
> + * further damage. Usage examples include a thermal protection.
> + *
> + * NOTE: The request is ignored if protection reboot is already pending even
> + * if the previous request has given a large timeout for forced reboot.
> + * Can be called from any context.
> + */
> +void hw_protection_reboot(const char *reason, int ms_until_forced)

Some code and kerneldoc comment duplication could be avoided by
changing hw_protection_shutdown() definition to take an additional
argument specifying the final action to carry out, so there would be

void __hw_protection_shutdown(const char *reason, int ms_until_forced,
bool reboot)
{
...
   if (reboot)
       orderly_reboot();
   else
      orderly_poweroff(true);
}

and both hw_protection_shutdown() and hw_protection_reboot() can be
defined as static inline wrappers around this.

> +{
> +       static atomic_t allow_proceed = ATOMIC_INIT(1);
> +
> +       pr_emerg("HARDWARE PROTECTION reboot (%s)\n", reason);
> +
> +       /* Reboot should be initiated only once. */
> +       if (!atomic_dec_and_test(&allow_proceed))
> +               return;
> +
> +       /*
> +        * Queue a backup emergency reboot in the event of
> +        * orderly_reboot failure
> +        */
> +       hw_failure_emergency_poweroff(ms_until_forced);
> +       orderly_reboot();
> +}
> +EXPORT_SYMBOL_GPL(hw_protection_reboot);
> +
>  /**
>   * hw_protection_shutdown - Trigger an emergency system poweroff
>   *
> --
> 2.34.1
>
diff mbox series

Patch

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 2b6bb593be5b..4a319bc24f6a 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -174,6 +174,7 @@  void ctrl_alt_del(void);
 
 extern void orderly_poweroff(bool force);
 extern void orderly_reboot(void);
+void hw_protection_reboot(const char *reason, int ms_until_forced);
 void hw_protection_shutdown(const char *reason, int ms_until_forced);
 
 /*
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 3bba88c7ffc6..05333ae8bc6b 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -952,6 +952,40 @@  static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
 			      msecs_to_jiffies(poweroff_delay_ms));
 }
 
+/**
+ * hw_protection_reboot - Trigger an emergency system reboot
+ *
+ * @reason:		Reason of emergency reboot to be printed.
+ * @ms_until_forced:	Time to wait for orderly reboot before tiggering a
+ *			forced reboot. Negative value disables the forced
+ *			reboot.
+ *
+ * Initiate an emergency system reboot in order to protect hardware from
+ * further damage. Usage examples include a thermal protection.
+ *
+ * NOTE: The request is ignored if protection reboot is already pending even
+ * if the previous request has given a large timeout for forced reboot.
+ * Can be called from any context.
+ */
+void hw_protection_reboot(const char *reason, int ms_until_forced)
+{
+	static atomic_t allow_proceed = ATOMIC_INIT(1);
+
+	pr_emerg("HARDWARE PROTECTION reboot (%s)\n", reason);
+
+	/* Reboot should be initiated only once. */
+	if (!atomic_dec_and_test(&allow_proceed))
+		return;
+
+	/*
+	 * Queue a backup emergency reboot in the event of
+	 * orderly_reboot failure
+	 */
+	hw_failure_emergency_poweroff(ms_until_forced);
+	orderly_reboot();
+}
+EXPORT_SYMBOL_GPL(hw_protection_reboot);
+
 /**
  * hw_protection_shutdown - Trigger an emergency system poweroff
  *