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