Linux 6.9-rc1
[linux-2.6-microblaze.git] / kernel / reboot.c
index 3c35445..22c16e2 100644 (file)
@@ -55,8 +55,17 @@ struct sys_off_handler {
        enum sys_off_mode mode;
        bool blocking;
        void *list;
+       struct device *dev;
 };
 
+/*
+ * This variable is used to indicate if a halt was initiated instead of a
+ * reboot when the reboot call was invoked with LINUX_REBOOT_CMD_POWER_OFF, but
+ * the system cannot be powered off. This allowes kernel_halt() to notify users
+ * of that.
+ */
+static bool poweroff_fallback_to_halt;
+
 /*
  * Temporary stub that prevents linkage failure while we're in process
  * of removing all uses of legacy pm_power_off() around the kernel.
@@ -74,6 +83,7 @@ void __weak (*pm_power_off)(void);
 void emergency_restart(void)
 {
        kmsg_dump(KMSG_DUMP_EMERG);
+       system_state = SYSTEM_RESTART;
        machine_emergency_restart();
 }
 EXPORT_SYMBOL_GPL(emergency_restart);
@@ -243,6 +253,17 @@ void migrate_to_reboot_cpu(void)
        set_cpus_allowed_ptr(current, cpumask_of(cpu));
 }
 
+/*
+ *     Notifier list for kernel code which wants to be called
+ *     to prepare system for restart.
+ */
+static BLOCKING_NOTIFIER_HEAD(restart_prep_handler_list);
+
+static void do_kernel_restart_prepare(void)
+{
+       blocking_notifier_call_chain(&restart_prep_handler_list, 0, NULL);
+}
+
 /**
  *     kernel_restart - reboot the system
  *     @cmd: pointer to buffer containing command to execute for restart
@@ -254,6 +275,7 @@ void migrate_to_reboot_cpu(void)
 void kernel_restart(char *cmd)
 {
        kernel_restart_prepare(cmd);
+       do_kernel_restart_prepare();
        migrate_to_reboot_cpu();
        syscore_shutdown();
        if (!cmd)
@@ -283,7 +305,10 @@ void kernel_halt(void)
        kernel_shutdown_prepare(SYSTEM_HALT);
        migrate_to_reboot_cpu();
        syscore_shutdown();
-       pr_emerg("System halted\n");
+       if (poweroff_fallback_to_halt)
+               pr_emerg("Power off not available: System halted instead\n");
+       else
+               pr_emerg("System halted\n");
        kmsg_dump(KMSG_DUMP_SHUTDOWN);
        machine_halt();
 }
@@ -311,6 +336,7 @@ static int sys_off_notify(struct notifier_block *nb,
        data.cb_data = handler->cb_data;
        data.mode = mode;
        data.cmd = cmd;
+       data.dev = handler->dev;
 
        return handler->sys_off_cb(&data);
 }
@@ -396,6 +422,11 @@ register_sys_off_handler(enum sys_off_mode mode,
                handler->list = &power_off_handler_list;
                break;
 
+       case SYS_OFF_MODE_RESTART_PREPARE:
+               handler->list = &restart_prep_handler_list;
+               handler->blocking = true;
+               break;
+
        case SYS_OFF_MODE_RESTART:
                handler->list = &restart_handler_list;
                break;
@@ -493,6 +524,7 @@ int devm_register_sys_off_handler(struct device *dev,
        handler = register_sys_off_handler(mode, priority, callback, cb_data);
        if (IS_ERR(handler))
                return PTR_ERR(handler);
+       handler->dev = dev;
 
        return devm_add_action_or_reset(dev, devm_unregister_sys_off_handler,
                                        handler);
@@ -711,8 +743,10 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
        /* Instead of trying to make the power_off code look like
         * halt when pm_power_off is not set do it the easy way.
         */
-       if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !kernel_can_power_off())
+       if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !kernel_can_power_off()) {
+               poweroff_fallback_to_halt = true;
                cmd = LINUX_REBOOT_CMD_HALT;
+       }
 
        mutex_lock(&system_transition_mutex);
        switch (cmd) {
@@ -936,21 +970,24 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
 }
 
 /**
- * hw_protection_shutdown - Trigger an emergency system poweroff
+ * __hw_protection_shutdown - Trigger an emergency system shutdown or reboot
  *
- * @reason:            Reason of emergency shutdown to be printed.
- * @ms_until_forced:   Time to wait for orderly shutdown before tiggering a
- *                     forced shudown. Negative value disables the forced
- *                     shutdown.
+ * @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.
+ * @shutdown:          If true, indicates that a shutdown will happen
+ *                     after the critical tempeature is reached.
+ *                     If false, indicates that a reboot will happen
+ *                     after the critical tempeature is reached.
  *
- * Initiate an emergency system shutdown in order to protect hardware from
- * further damage. Usage examples include a thermal protection or a voltage or
- * current regulator failures.
- * NOTE: The request is ignored if protection shutdown is already pending even
- * if the previous request has given a large timeout for forced shutdown.
- * Can be called from any context.
+ * Initiate an emergency system shutdown or reboot in order to protect
+ * hardware from further damage. Usage examples include a thermal protection.
+ * NOTE: The request is ignored if protection shutdown or reboot is already
+ * pending even if the previous request has given a large timeout for forced
+ * shutdown/reboot.
  */
-void hw_protection_shutdown(const char *reason, int ms_until_forced)
+void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown)
 {
        static atomic_t allow_proceed = ATOMIC_INIT(1);
 
@@ -965,9 +1002,12 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced)
         * orderly_poweroff failure
         */
        hw_failure_emergency_poweroff(ms_until_forced);
-       orderly_poweroff(true);
+       if (shutdown)
+               orderly_poweroff(true);
+       else
+               orderly_reboot();
 }
-EXPORT_SYMBOL_GPL(hw_protection_shutdown);
+EXPORT_SYMBOL_GPL(__hw_protection_shutdown);
 
 static int __init reboot_setup(char *str)
 {