On 4/20/22 21:47, Rafael J. Wysocki wrote:
+ spin_unlock(&platform_power_off_lock);
+
+ if (ret)
+ return ret;
+
+ ret = register_power_off_handler(&priv->power_off_nb);
+ if (ret)
+ priv->platform_power_off_cb = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_platform_power_off);
+
+/**
+ * unregister_platform_power_off - Unregister platform-level power-off callback
+ * @power_off: Power-off callback
+ *
+ * Unregisters previously registered platform power-off callback.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int unregister_platform_power_off(void (*power_off)(void))
+{
+ struct sys_off_handler_private_data *priv;
+ int ret;
+
+ priv = sys_off_handler_private_data(&platform_power_off_handler);
+
+ if (priv->platform_power_off_cb != power_off)
+ return -EINVAL;
+
+ ret = unregister_power_off_handler(&priv->power_off_nb);
+ priv->platform_power_off_cb = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(unregister_platform_power_off);
+
+/**
+ * do_kernel_power_off - Execute kernel power-off handler call chain
+ *
+ * Calls functions registered with register_power_off_handler.
+ *
+ * Expected to be called as last step of the power-off sequence.
+ *
+ * Powers off the system immediately if a power-off handler function has
+ * been registered. Otherwise does nothing.
+ */
+void do_kernel_power_off(void)
+{
+ /* legacy pm_power_off() is unchained and has highest priority */
+ if (pm_power_off && pm_power_off != dummy_pm_power_off)
+ return pm_power_off();
+
+ blocking_notifier_call_chain(&power_off_handler_list, POWEROFF_NORMAL,
+ NULL);
+}
+
+static void do_kernel_power_off_prepare(void)
+{
+ /* legacy pm_power_off_prepare() is unchained and has highest priority */
+ if (pm_power_off_prepare)
+ return pm_power_off_prepare();
+
+ blocking_notifier_call_chain(&power_off_handler_list, POWEROFF_PREPARE,
+ NULL);
+}
+
/**
* kernel_power_off - power_off the system
*
@@ -304,8 +893,7 @@ EXPORT_SYMBOL_GPL(kernel_halt);
void kernel_power_off(void)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
- if (pm_power_off_prepare)
- pm_power_off_prepare();
+ do_kernel_power_off_prepare();
migrate_to_reboot_cpu();
syscore_shutdown();
pr_emerg("Power down\n");
@@ -314,6 +902,16 @@ void kernel_power_off(void)
}
EXPORT_SYMBOL_GPL(kernel_power_off);
+bool kernel_can_power_off(void)
+{
+ if (!pm_power_off &&
+ blocking_notifier_call_chain_is_empty(&power_off_handler_list))
+ return false;
+
+ return true;
return pm_power_off ||
blocking_notifier_call_chain_is_empty(&power_off_handler_list);
Thank you for the thorough review!
You're very welcome!
Thanks again for taking a look at the patches. I don't have strong
preferences about the names and etc, so I'll update it all in v8 like
you suggested.
--
Best regards,
Dmitry