summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Osipenko <dmitry.osipenko@collabora.com>2022-05-10 02:32:16 +0300
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2022-05-19 19:30:30 +0200
commitfb61375ecfba49e153af561402f49f6fe3bebd39 (patch)
tree369d8119fdc54ba4a3631d001a6681887ae80415
parent0e2110d2e910e44cc7cf23fce14613e232602602 (diff)
downloadlwn-fb61375ecfba49e153af561402f49f6fe3bebd39.tar.gz
lwn-fb61375ecfba49e153af561402f49f6fe3bebd39.zip
kernel/reboot: Add register_platform_power_off()
Add platform-level registration helpers that will ease transition of the arch/platform power-off callbacks to the new sys-off based API, allowing us to remove the global pm_power_off variable in the future. Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--include/linux/reboot.h3
-rw-r--r--kernel/reboot.c55
2 files changed, 58 insertions, 0 deletions
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 5837c6c2fb40..a8fee1d09c65 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -141,6 +141,9 @@ int devm_register_sys_off_handler(struct device *dev,
int (*callback)(struct sys_off_data *data),
void *cb_data);
+int register_platform_power_off(void (*power_off)(void));
+void unregister_platform_power_off(void (*power_off)(void));
+
/*
* Architecture independent implemenations of sys_reboot commands.
*/
diff --git a/kernel/reboot.c b/kernel/reboot.c
index fb3f49350927..673d3f54dcad 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -469,6 +469,61 @@ int devm_register_sys_off_handler(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_register_sys_off_handler);
+static struct sys_off_handler *platform_power_off_handler;
+
+static int platform_power_off_notify(struct sys_off_data *data)
+{
+ void (*platform_power_power_off_cb)(void) = data->cb_data;
+
+ platform_power_power_off_cb();
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * register_platform_power_off - Register platform-level power-off callback
+ * @power_off: Power-off callback
+ *
+ * Registers power-off callback that will be called as last step
+ * of the power-off sequence. This callback is expected to be invoked
+ * for the last resort. Only one platform power-off callback is allowed
+ * to be registered at a time.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int register_platform_power_off(void (*power_off)(void))
+{
+ struct sys_off_handler *handler;
+
+ handler = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_PLATFORM,
+ platform_power_off_notify,
+ power_off);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+
+ platform_power_off_handler = handler;
+
+ return 0;
+}
+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.
+ */
+void unregister_platform_power_off(void (*power_off)(void))
+{
+ if (platform_power_off_handler &&
+ platform_power_off_handler->cb_data == power_off) {
+ unregister_sys_off_handler(platform_power_off_handler);
+ platform_power_off_handler = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(unregister_platform_power_off);
+
static int legacy_pm_power_off_prepare(struct sys_off_data *data)
{
if (pm_power_off_prepare)