[PATCH v1] kernel/reboot: Fix powering off using a non-syscall code paths

2022-06-06 Thread Dmitry Osipenko
There are other methods of powering off machine than the reboot syscall.
Previously we missed to coved those methods and it created power-off
regression for some machines, like the PowerPC e500. Fix this problem
by moving the legacy sys-off handler registration to the latest phase
of power-off process and making the kernel_can_power_off() to check the
legacy pm_power_off presence.

Tested-by: Michael Ellerman  # ppce500
Reported-by: Michael Ellerman  # ppce500
Fixes: da007f171fc9 ("kernel/reboot: Change registration order of legacy 
power-off handler")
Signed-off-by: Dmitry Osipenko 
---
 kernel/reboot.c | 46 ++
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index 3b19b123efec..b5a71d1ff603 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -320,6 +320,7 @@ static struct sys_off_handler platform_sys_off_handler;
 static struct sys_off_handler *alloc_sys_off_handler(int priority)
 {
struct sys_off_handler *handler;
+   gfp_t flags;
 
/*
 * Platforms like m68k can't allocate sys_off handler dynamically
@@ -330,7 +331,12 @@ static struct sys_off_handler *alloc_sys_off_handler(int 
priority)
if (handler->cb_data)
return ERR_PTR(-EBUSY);
} else {
-   handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+   if (system_state > SYSTEM_RUNNING)
+   flags = GFP_ATOMIC;
+   else
+   flags = GFP_KERNEL;
+
+   handler = kzalloc(sizeof(*handler), flags);
if (!handler)
return ERR_PTR(-ENOMEM);
}
@@ -440,7 +446,7 @@ void unregister_sys_off_handler(struct sys_off_handler 
*handler)
 {
int err;
 
-   if (!handler)
+   if (IS_ERR_OR_NULL(handler))
return;
 
if (handler->blocking)
@@ -615,7 +621,23 @@ static void do_kernel_power_off_prepare(void)
  */
 void do_kernel_power_off(void)
 {
+   struct sys_off_handler *sys_off = NULL;
+
+   /*
+* Register sys-off handlers for legacy PM callback. This allows
+* legacy PM callbacks temporary co-exist with the new sys-off API.
+*
+* TODO: Remove legacy handlers once all legacy PM users will be
+*   switched to the sys-off based APIs.
+*/
+   if (pm_power_off)
+   sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+  SYS_OFF_PRIO_DEFAULT,
+  legacy_pm_power_off, NULL);
+
atomic_notifier_call_chain(_off_handler_list, 0, NULL);
+
+   unregister_sys_off_handler(sys_off);
 }
 
 /**
@@ -626,7 +648,8 @@ void do_kernel_power_off(void)
  */
 bool kernel_can_power_off(void)
 {
-   return !atomic_notifier_call_chain_is_empty(_off_handler_list);
+   return !atomic_notifier_call_chain_is_empty(_off_handler_list) ||
+   pm_power_off;
 }
 EXPORT_SYMBOL_GPL(kernel_can_power_off);
 
@@ -661,7 +684,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
void __user *, arg)
 {
struct pid_namespace *pid_ns = task_active_pid_ns(current);
-   struct sys_off_handler *sys_off = NULL;
char buffer[256];
int ret = 0;
 
@@ -686,21 +708,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
if (ret)
return ret;
 
-   /*
-* Register sys-off handlers for legacy PM callback. This allows
-* legacy PM callbacks temporary co-exist with the new sys-off API.
-*
-* TODO: Remove legacy handlers once all legacy PM users will be
-*   switched to the sys-off based APIs.
-*/
-   if (pm_power_off) {
-   sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
-  SYS_OFF_PRIO_DEFAULT,
-  legacy_pm_power_off, NULL);
-   if (IS_ERR(sys_off))
-   return PTR_ERR(sys_off);
-   }
-
/* Instead of trying to make the power_off code look like
 * halt when pm_power_off is not set do it the easy way.
 */
@@ -758,7 +765,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
break;
}
mutex_unlock(_transition_mutex);
-   unregister_sys_off_handler(sys_off);
return ret;
 }
 
-- 
2.35.3



Re: [PATCH v1] kernel/reboot: Change registration order of legacy power-off handler

2022-06-06 Thread Dmitry Osipenko
On 6/6/22 16:06, Michael Ellerman wrote:
> Dmitry Osipenko  writes:
>> Hi Michael,
>>
>> On 6/5/22 05:01, Michael Ellerman wrote:
>>> Dmitry Osipenko  writes:
>>>> We're unconditionally registering sys-off handler for the legacy
>>>> pm_power_off() callback, this causes problem for platforms that don't
>>>> use power-off handlers at all and should be halted. Now reboot syscall
>>>> assumes that there is a power-off handler installed and tries to power
>>>> off system instead of halting it.
>>>>
>>>> To fix the trouble, move the handler's registration to the reboot syscall
>>>> and check the pm_power_off() presence.
>>>
>>> I'm seeing a qemu virtual machine (ppce500) fail to power off using the
>>> gpio-poweroff driver. I bisected it to this commit.
>>>
>>> I think the problem is that the machine is going via kernel_power_off(),
>>> not sys_reboot(), and so legacy_pm_power_off() has not been registered.
>>>
>>> If I just put the core_initcall back then it works as before. Not sure
>>> if that's a safe change in general though.
>>
>> Thank you very much for the testing and reporting the problem! I see now the 
>> two more cases that were missed previously:
>>
>> 1. There is the orderly_poweroff() used by some drivers.
>> 2. PowerPC may invoke do_kernel_power_off() directly from xmon code.
>>
>> Could you please test this change:
> 
> That works, thanks.
> 
> I tested both sysrq-o and the xmon power off path.
> 
> I couldn't come up with an easy way to test the orderly_poweroff()
> path, but it boils down to basically the same code in the end.
> 
> Tested-by: Michael Ellerman 
> 
> cheers

Awesome, thank you!

-- 
Best regards,
Dmitry


Re: [PATCH v1] kernel/reboot: Change registration order of legacy power-off handler

2022-06-05 Thread Dmitry Osipenko


Hi Michael,

On 6/5/22 05:01, Michael Ellerman wrote:
> Dmitry Osipenko  writes:
>> We're unconditionally registering sys-off handler for the legacy
>> pm_power_off() callback, this causes problem for platforms that don't
>> use power-off handlers at all and should be halted. Now reboot syscall
>> assumes that there is a power-off handler installed and tries to power
>> off system instead of halting it.
>>
>> To fix the trouble, move the handler's registration to the reboot syscall
>> and check the pm_power_off() presence.
> 
> I'm seeing a qemu virtual machine (ppce500) fail to power off using the
> gpio-poweroff driver. I bisected it to this commit.
> 
> I think the problem is that the machine is going via kernel_power_off(),
> not sys_reboot(), and so legacy_pm_power_off() has not been registered.
> 
> If I just put the core_initcall back then it works as before. Not sure
> if that's a safe change in general though.

Thank you very much for the testing and reporting the problem! I see now the 
two more cases that were missed previously:

1. There is the orderly_poweroff() used by some drivers.
2. PowerPC may invoke do_kernel_power_off() directly from xmon code.

Could you please test this change:

--- >8 ---

diff --git a/kernel/reboot.c b/kernel/reboot.c
index 3b19b123efec..0e4a3defcd94 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -320,6 +320,7 @@ static struct sys_off_handler platform_sys_off_handler;
 static struct sys_off_handler *alloc_sys_off_handler(int priority)
 {
struct sys_off_handler *handler;
+   gfp_t flags;
 
/*
 * Platforms like m68k can't allocate sys_off handler dynamically
@@ -330,7 +331,12 @@ static struct sys_off_handler *alloc_sys_off_handler(int 
priority)
if (handler->cb_data)
return ERR_PTR(-EBUSY);
} else {
-   handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+   if (system_state > SYSTEM_RUNNING)
+   flags = GFP_ATOMIC;
+   else
+   flags = GFP_KERNEL;
+
+   handler = kzalloc(sizeof(*handler), flags);
if (!handler)
return ERR_PTR(-ENOMEM);
}
@@ -615,7 +621,26 @@ static void do_kernel_power_off_prepare(void)
  */
 void do_kernel_power_off(void)
 {
+   struct sys_off_handler *sys_off = NULL;
+
+   /*
+* Register sys-off handlers for legacy PM callback. This allows
+* legacy PM callbacks temporary co-exist with the new sys-off API.
+*
+* TODO: Remove legacy handlers once all legacy PM users will be
+*   switched to the sys-off based APIs.
+*/
+   if (pm_power_off) {
+   sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+  SYS_OFF_PRIO_DEFAULT,
+  legacy_pm_power_off, NULL);
+   if (IS_ERR(sys_off))
+   return;
+   }
+
atomic_notifier_call_chain(_off_handler_list, 0, NULL);
+
+   unregister_sys_off_handler(sys_off);
 }
 
 /**
@@ -626,7 +651,8 @@ void do_kernel_power_off(void)
  */
 bool kernel_can_power_off(void)
 {
-   return !atomic_notifier_call_chain_is_empty(_off_handler_list);
+   return !atomic_notifier_call_chain_is_empty(_off_handler_list) ||
+   pm_power_off;
 }
 EXPORT_SYMBOL_GPL(kernel_can_power_off);
 
@@ -661,7 +687,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
void __user *, arg)
 {
struct pid_namespace *pid_ns = task_active_pid_ns(current);
-   struct sys_off_handler *sys_off = NULL;
char buffer[256];
int ret = 0;
 
@@ -686,21 +711,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
if (ret)
return ret;
 
-   /*
-* Register sys-off handlers for legacy PM callback. This allows
-* legacy PM callbacks temporary co-exist with the new sys-off API.
-*
-* TODO: Remove legacy handlers once all legacy PM users will be
-*   switched to the sys-off based APIs.
-*/
-   if (pm_power_off) {
-   sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
-  SYS_OFF_PRIO_DEFAULT,
-  legacy_pm_power_off, NULL);
-   if (IS_ERR(sys_off))
-   return PTR_ERR(sys_off);
-   }
-
/* Instead of trying to make the power_off code look like
 * halt when pm_power_off is not set do it the easy way.
 */
@@ -758,7 +768,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned 
int, cmd,
break;
}
mutex_unlock(_transition_mutex);
-   unregister_sys_off_handler(sys_off);
return ret;
 }
 


Re: [PATCH v5 04/21] kernel: Add combined power-off+restart handler call chain API

2022-01-27 Thread Dmitry Osipenko
Hello Michał,

09.01.2022 02:35, Michał Mirosław пишет:
> BTW, I couldn't find a right description of my idea of unifying the
> chains before, so let me sketch it now.
> 
> The idea is to have a single system-off chain in which the callback
> gets a mode ({QUERY_*, PREP_*, DO_*} for each of {*_REBOOT, *_POWEROFF, ...?).
> The QUERY_* calls would be made in can_kernel_reboot/poweroff(): all
> would be called, and if at least one returned true, then the shutdown
> mode would continue. All of PREP_* would be called then. After that
> all DO_* would be tried until one doesn't return (succeeded or broke
> the system hard). Classic for(;;); could be a final fallback for the
> case where arch/machine (lowest priority) call would return instead
> of halting the system in machine-dependent way. The QUERY and PREP
> stages could be combined, but I haven't thought about it enough to
> see what conditions would need to be imposed on the callbacks in
> that case (maybe it's not worth the trouble, since it isn't a fast
> path anyway?). The goal here is to have less (duplicated) code in
> kernel, but otherwise it seems equivalent to your API proposal.

Thank you again for yours proposal! IMO, it's much more important to
keep the core code simple and maintainable, rather than try to optimize
it without a very good reason, given that this isn't a hot code path at
all and saving a couple of bytes won't be noticeable. The poweroff,
restart and reboot were separated before this series and I'm finding
that it's easier to follow the code when it's structured that way. I'm
not convinced that we need to change it.


Re: [PATCH v5 04/21] kernel: Add combined power-off+restart handler call chain API

2022-01-11 Thread Dmitry Osipenko
09.01.2022 02:35, Michał Mirosław пишет:
> On Mon, Dec 13, 2021 at 12:02:52AM +0300, Dmitry Osipenko wrote:
> [...]
>> +/**
>> + * struct power_off_data - Power-off callback argument
>> + *
>> + * @cb_data: Callback data.
>> + */
>> +struct power_off_data {
>> +void *cb_data;
>> +};
>> +
>> +/**
>> + * struct power_off_prep_data - Power-off preparation callback argument
>> + *
>> + * @cb_data: Callback data.
>> + */
>> +struct power_off_prep_data {
>> +void *cb_data;
>> +};
> 
> Why two exactly same structures? Why only a single pointer instead? If
> it just to enable type-checking callbacks, then thouse could be opaque
> or zero-sized structs that would be embedded or casted away in
> respective callbacks.

Preparation and final execution are two different operations, it's much
cleaner from a user's perspective to have same separated, IMO. In the
future we may would want to extend one of the structs, and not the
other. Type-checking is another benefit, of course.

The single callback pointer is what is utilized by all current kernel
users. This may change in the future and then it won't be a problem to
extend the power-off API without disrupting whole kernel.

>> +
>> +/**
>> + * struct restart_data - Restart callback argument
>> + *
>> + * @cb_data: Callback data.
>> + * @cmd: Restart command string.
>> + * @stop_chain: Further lower priority callbacks won't be executed if set to
>> + *  true. Can be changed within callback. Default is false.
>> + * @mode: Reboot mode ID.
>> + */
>> +struct restart_data {
>> +void *cb_data;
>> +const char *cmd;
>> +bool stop_chain;
>> +enum reboot_mode mode;
>> +};
>> +
>> +/**
>> + * struct reboot_prep_data - Reboot and shutdown preparation callback 
>> argument
>> + *
>> + * @cb_data: Callback data.
>> + * @cmd: Restart command string.
>> + * @stop_chain: Further lower priority callbacks won't be executed if set to
>> + *  true. Can be changed within callback. Default is false.
> 
> Why would we want to stop power-off or erboot chain? If the callback
> succeded, then further calls won't be made. If it doesn't succeed, but
> possibly breaks the system somehow, it shouldn't return. Then the only
> case left would be to just try the next method of shutting down.

This is what some of the API users were doing for years. I don't know
for sure why they want to stop the chain, it indeed looks like an
incorrect behaviour, but that's up to developers to decide. I only
retained the old behaviour for those users.

>> + * @mode: Preparation mode ID.
>> + */
>> +struct reboot_prep_data {
>> +void *cb_data;
>> +const char *cmd;
>> +bool stop_chain;
>> +enum reboot_prepare_mode mode;
>> +};
>> +
>> +struct sys_off_handler_private_data {
>> +struct notifier_block power_off_nb;
>> +struct notifier_block restart_nb;
>> +struct notifier_block reboot_nb;
> 
> What's the difference between restart and reboot?

Reboot is always executed before restart and power-off callbacks. This
is explained in the doc-comment of the struct sys_off_handler.

+ * @reboot_prepare_cb: Reboot/shutdown preparation callback. All reboot
+ * preparation callbacks are invoked before @restart_cb or @power_off_cb,
+ * depending on the mode. It's registered with register_reboot_notifier().
+ * The point is to remove boilerplate code from drivers which use this
+ * callback in conjunction with the restart/power-off callbacks.
+ *

This reboot callback usually performs early preparations that are need
to be done before machine is placed into reset state, please see [1] for
the examples.

[1] https://elixir.bootlin.com/linux/v5.16/A/ident/register_reboot_notifier

I agree that "reboot" sounds like a misnomer. This name was coined long
time ago, perhaps not worth to rename it at this point. I'm also not
sure what could be a better name.

>> +void (*platform_power_off_cb)(void);
>> +void (*simple_power_off_cb)(void *data);
>> +void *simple_power_off_cb_data;
>> +bool registered;
>> +};
> 
> BTW, I couldn't find a right description of my idea of unifying the
> chains before, so let me sketch it now.
> 
> The idea is to have a single system-off chain in which the callback
> gets a mode ({QUERY_*, PREP_*, DO_*} for each of {*_REBOOT, *_POWEROFF, ...?).
> The QUERY_* calls would be made in can_kernel_reboot/poweroff(): all
> would be called, and if at least one returned true, then the shutdown
> mode would continue. All of PREP_* would be called then. After that
> all DO_* would be tried until one doesn't

[PATCH v5 21/21] reboot: Remove pm_power_off_prepare()

2021-12-12 Thread Dmitry Osipenko
All pm_power_off_prepare() users were converted to sys-off handler API.
Remove the obsolete callback.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/pm.h |  1 -
 kernel/reboot.c| 11 ---
 2 files changed, 12 deletions(-)

diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1d8209c09686..d9bf1426f81e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -20,7 +20,6 @@
  * Callbacks for platform drivers to implement.
  */
 extern void (*pm_power_off)(void);
-extern void (*pm_power_off_prepare)(void);
 
 struct device; /* we have a circular dep with device.h */
 #ifdef CONFIG_VT_CONSOLE_SLEEP
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 3085873a876f..2f79d4f7cfaa 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -48,13 +48,6 @@ int reboot_cpu;
 enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
-/*
- * If set, this is used for preparing the system to power off.
- */
-
-void (*pm_power_off_prepare)(void);
-EXPORT_SYMBOL_GPL(pm_power_off_prepare);
-
 /**
  * emergency_restart - reboot the system
  *
@@ -829,10 +822,6 @@ void do_kernel_power_off(void)
 
 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(_off_handler_list, POWEROFF_PREPARE,
 NULL);
 }
-- 
2.33.1



[PATCH v5 20/21] regulator: pfuze100: Use devm_register_sys_off_handler()

2021-12-12 Thread Dmitry Osipenko
Use devm_register_sys_off_handler() that replaces global
pm_power_off_prepare variable and allows to register multiple
power-off handlers.

Acked-by: Mark Brown 
Signed-off-by: Dmitry Osipenko 
---
 drivers/regulator/pfuze100-regulator.c | 38 ++
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/drivers/regulator/pfuze100-regulator.c 
b/drivers/regulator/pfuze100-regulator.c
index d60d7d1b7fa2..2eca8d43a097 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -76,6 +77,7 @@ struct pfuze_chip {
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
struct pfuze_regulator *pfuze_regulators;
+   struct sys_off_handler sys_off;
 };
 
 static const int pfuze100_swbst[] = {
@@ -569,10 +571,10 @@ static inline struct device_node *match_of_node(int index)
return pfuze_matches[index].of_node;
 }
 
-static struct pfuze_chip *syspm_pfuze_chip;
-
-static void pfuze_power_off_prepare(void)
+static void pfuze_power_off_prepare(struct power_off_prep_data *data)
 {
+   struct pfuze_chip *syspm_pfuze_chip = data->cb_data;
+
dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
 
/* Switch from default mode: APS/APS to APS/Off */
@@ -611,24 +613,23 @@ static void pfuze_power_off_prepare(void)
 
 static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
 {
+   int err;
+
if (pfuze_chip->chip_id != PFUZE100) {
dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare 
handler for not supported chip\n");
return -ENODEV;
}
 
-   if (pm_power_off_prepare) {
-   dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already 
registered.\n");
-   return -EBUSY;
-   }
+   pfuze_chip->sys_off.power_off_prepare_cb = pfuze_power_off_prepare;
+   pfuze_chip->sys_off.cb_data = pfuze_chip;
 
-   if (syspm_pfuze_chip) {
-   dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
-   return -EBUSY;
+   err = devm_register_sys_off_handler(pfuze_chip->dev, 
_chip->sys_off);
+   if (err) {
+   dev_err(pfuze_chip->dev,
+   "failed to register sys-off handler: %d\n", err);
+   return err;
}
 
-   syspm_pfuze_chip = pfuze_chip;
-   pm_power_off_prepare = pfuze_power_off_prepare;
-
return 0;
 }
 
@@ -837,23 +838,12 @@ static int pfuze100_regulator_probe(struct i2c_client 
*client,
return 0;
 }
 
-static int pfuze100_regulator_remove(struct i2c_client *client)
-{
-   if (syspm_pfuze_chip) {
-   syspm_pfuze_chip = NULL;
-   pm_power_off_prepare = NULL;
-   }
-
-   return 0;
-}
-
 static struct i2c_driver pfuze_driver = {
.driver = {
.name = "pfuze100-regulator",
.of_match_table = pfuze_dt_ids,
},
.probe = pfuze100_regulator_probe,
-   .remove = pfuze100_regulator_remove,
 };
 module_i2c_driver(pfuze_driver);
 
-- 
2.33.1



[PATCH v5 19/21] ACPI: power: Switch to sys-off handler API

2021-12-12 Thread Dmitry Osipenko
Switch to sys-off API that replaces legacy pm_power_off callbacks.

Signed-off-by: Dmitry Osipenko 
---
 drivers/acpi/sleep.c | 25 +++--
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eaa47753b758..2e613fddd614 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -47,19 +47,11 @@ static void acpi_sleep_tts_switch(u32 acpi_state)
}
 }
 
-static int tts_notify_reboot(struct notifier_block *this,
-   unsigned long code, void *x)
+static void tts_reboot_prepare(struct reboot_prep_data *data)
 {
acpi_sleep_tts_switch(ACPI_STATE_S5);
-   return NOTIFY_DONE;
 }
 
-static struct notifier_block tts_notifier = {
-   .notifier_call  = tts_notify_reboot,
-   .next   = NULL,
-   .priority   = 0,
-};
-
 static int acpi_sleep_prepare(u32 acpi_state)
 {
 #ifdef CONFIG_ACPI_SLEEP
@@ -1020,7 +1012,7 @@ static void acpi_sleep_hibernate_setup(void)
 static inline void acpi_sleep_hibernate_setup(void) {}
 #endif /* !CONFIG_HIBERNATION */
 
-static void acpi_power_off_prepare(void)
+static void acpi_power_off_prepare(struct power_off_prep_data *data)
 {
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
@@ -1028,7 +1020,7 @@ static void acpi_power_off_prepare(void)
acpi_os_wait_events_complete();
 }
 
-static void acpi_power_off(void)
+static void acpi_power_off(struct power_off_data *data)
 {
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
pr_debug("%s called\n", __func__);
@@ -1036,6 +1028,11 @@ static void acpi_power_off(void)
acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
+static struct sys_off_handler acpi_sys_off_handler = {
+   .power_off_priority = POWEROFF_PRIO_FIRMWARE,
+   .reboot_prepare_cb = tts_reboot_prepare,
+};
+
 int __init acpi_sleep_init(void)
 {
char supported[ACPI_S_STATE_COUNT * 3 + 1];
@@ -1052,8 +1049,8 @@ int __init acpi_sleep_init(void)
 
if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
sleep_states[ACPI_STATE_S5] = 1;
-   pm_power_off_prepare = acpi_power_off_prepare;
-   pm_power_off = acpi_power_off;
+   acpi_sys_off_handler.power_off_cb = acpi_power_off;
+   acpi_sys_off_handler.power_off_prepare_cb = 
acpi_power_off_prepare;
} else {
acpi_no_s5 = true;
}
@@ -1069,6 +1066,6 @@ int __init acpi_sleep_init(void)
 * Register the tts_notifier to reboot notifier list so that the _TTS
 * object can also be evaluated when the system enters S5.
 */
-   register_reboot_notifier(_notifier);
+   register_sys_off_handler(_sys_off_handler);
return 0;
 }
-- 
2.33.1



[PATCH v5 18/21] memory: emif: Use kernel_can_power_off()

2021-12-12 Thread Dmitry Osipenko
Replace legacy pm_power_off with kernel_can_power_off() helper that
is aware about chained power-off handlers.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/emif.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 762d0c0f0716..cab10d5274a0 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -630,7 +630,7 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
dev_emerg(emif->dev, "SDRAM temperature exceeds operating 
limit.. Needs shut down!!!\n");
 
/* If we have Power OFF ability, use it, else try restarting */
-   if (pm_power_off) {
+   if (kernel_can_power_off()) {
kernel_power_off();
} else {
WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
-- 
2.33.1



[PATCH v5 17/21] nds32: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/nds32/kernel/process.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c
index 49fab9e39cbf..0936dcd7db1b 100644
--- a/arch/nds32/kernel/process.c
+++ b/arch/nds32/kernel/process.c
@@ -54,8 +54,7 @@ EXPORT_SYMBOL(machine_halt);
 
 void machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 EXPORT_SYMBOL(machine_power_off);
-- 
2.33.1



[PATCH v5 16/21] mips: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/mips/kernel/reset.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c
index 6288780b779e..e7ce07b3e79b 100644
--- a/arch/mips/kernel/reset.c
+++ b/arch/mips/kernel/reset.c
@@ -114,8 +114,7 @@ void machine_halt(void)
 
 void machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 
 #ifdef CONFIG_SMP
preempt_disable();
-- 
2.33.1



[PATCH v5 15/21] ia64: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/ia64/kernel/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 834df24a88f1..cee4d7db2143 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -599,8 +600,7 @@ machine_halt (void)
 void
 machine_power_off (void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
machine_halt();
 }
 
-- 
2.33.1



[PATCH v5 14/21] x86: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/x86/kernel/reboot.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index fa700b46588e..c3636ea4aa71 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -739,10 +739,10 @@ static void native_machine_halt(void)
 
 static void native_machine_power_off(void)
 {
-   if (pm_power_off) {
+   if (kernel_can_power_off()) {
if (!reboot_force)
machine_shutdown();
-   pm_power_off();
+   do_kernel_power_off();
}
/* A fallback in case there is no PM info available */
tboot_shutdown(TB_SHUTDOWN_HALT);
-- 
2.33.1



[PATCH v5 13/21] sh: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/sh/kernel/reboot.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
index 5c33f036418b..e8eeedc9b182 100644
--- a/arch/sh/kernel/reboot.c
+++ b/arch/sh/kernel/reboot.c
@@ -46,8 +46,7 @@ static void native_machine_shutdown(void)
 
 static void native_machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 static void native_machine_halt(void)
-- 
2.33.1



[PATCH v5 12/21] m68k: Switch to new sys-off handler API

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use
register_power_off_handler() that registers power-off handlers and
do_kernel_power_off() that invokes chained power-off handlers. Legacy
pm_power_off() will be removed once all drivers will be converted to
the new power-off API.

Normally arch code should adopt only the do_kernel_power_off() at first,
but m68k is a special case because it uses pm_power_off() "inside out",
i.e. pm_power_off() invokes machine_power_off() [in fact it does nothing],
while it's machine_power_off() that should invoke the pm_power_off(), and
thus, we can't convert platforms to the new API separately. There are only
two platforms changed here, so it's not a big deal.

Acked-by: Geert Uytterhoeven 
Signed-off-by: Dmitry Osipenko 
---
 arch/m68k/emu/natfeat.c | 3 ++-
 arch/m68k/include/asm/machdep.h | 1 -
 arch/m68k/kernel/process.c  | 5 ++---
 arch/m68k/kernel/setup_mm.c | 1 -
 arch/m68k/kernel/setup_no.c | 1 -
 arch/m68k/mac/config.c  | 4 +++-
 6 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/m68k/emu/natfeat.c b/arch/m68k/emu/natfeat.c
index 71b78ecee75c..b19dc00026d9 100644
--- a/arch/m68k/emu/natfeat.c
+++ b/arch/m68k/emu/natfeat.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -90,5 +91,5 @@ void __init nf_init(void)
pr_info("NatFeats found (%s, %lu.%lu)\n", buf, version >> 16,
version & 0x);
 
-   mach_power_off = nf_poweroff;
+   register_platform_power_off(nf_poweroff);
 }
diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h
index 8fd80ef1b77e..8d8c3ee2069f 100644
--- a/arch/m68k/include/asm/machdep.h
+++ b/arch/m68k/include/asm/machdep.h
@@ -24,7 +24,6 @@ extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
-extern void (*mach_power_off)( void );
 extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
 extern void (*mach_hd_setup)(char *, int *);
 extern void (*mach_heartbeat) (int);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index a6030dbaa089..e160a7c57bd3 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -67,12 +67,11 @@ void machine_halt(void)
 
 void machine_power_off(void)
 {
-   if (mach_power_off)
-   mach_power_off();
+   do_kernel_power_off();
for (;;);
 }
 
-void (*pm_power_off)(void) = machine_power_off;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 void show_regs(struct pt_regs * regs)
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index 49e573b94326..a3ff1342ced7 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -98,7 +98,6 @@ EXPORT_SYMBOL(mach_get_rtc_pll);
 EXPORT_SYMBOL(mach_set_rtc_pll);
 void (*mach_reset)( void );
 void (*mach_halt)( void );
-void (*mach_power_off)( void );
 #ifdef CONFIG_HEARTBEAT
 void (*mach_heartbeat) (int);
 EXPORT_SYMBOL(mach_heartbeat);
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 5e4104f07a44..00bf82258233 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -55,7 +55,6 @@ int (*mach_hwclk) (int, struct rtc_time*);
 /* machine dependent reboot functions */
 void (*mach_reset)(void);
 void (*mach_halt)(void);
-void (*mach_power_off)(void);
 
 #ifdef CONFIG_M68000
 #if defined(CONFIG_M68328)
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 5d16f9b47aa9..727320dedf08 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -12,6 +12,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -139,7 +140,6 @@ void __init config_mac(void)
mach_hwclk = mac_hwclk;
mach_reset = mac_reset;
mach_halt = mac_poweroff;
-   mach_power_off = mac_poweroff;
 #if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
mach_beep = mac_mksound;
 #endif
@@ -159,6 +159,8 @@ void __init config_mac(void)
 
if (macintosh_config->ident == MAC_MODEL_IICI)
mach_l2_flush = via_l2_flush;
+
+   register_platform_power_off(mac_poweroff);
 }
 
 
-- 
2.33.1



[PATCH v5 11/21] powerpc: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Michael Ellerman 
Signed-off-by: Dmitry Osipenko 
---
 arch/powerpc/kernel/setup-common.c | 4 +---
 arch/powerpc/xmon/xmon.c   | 3 +--
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/kernel/setup-common.c 
b/arch/powerpc/kernel/setup-common.c
index f8da937df918..8158e940db81 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -161,9 +161,7 @@ void machine_restart(char *cmd)
 void machine_power_off(void)
 {
machine_shutdown();
-   if (pm_power_off)
-   pm_power_off();
-
+   do_kernel_power_off();
smp_send_stop();
machine_hang();
 }
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 83100c6524cc..759e167704e6 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1243,8 +1243,7 @@ static void bootcmds(void)
} else if (cmd == 'h') {
ppc_md.halt();
} else if (cmd == 'p') {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
}
 }
 
-- 
2.33.1



[PATCH v5 10/21] xen/x86: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Juergen Gross 
Signed-off-by: Dmitry Osipenko 
---
 arch/x86/xen/enlighten_pv.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 5004feb16783..527fa545eb1f 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -1068,8 +1069,7 @@ static void xen_machine_halt(void)
 
 static void xen_machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
xen_reboot(SHUTDOWN_poweroff);
 }
 
-- 
2.33.1



[PATCH v5 09/21] parisc: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Helge Deller  # parisc
Signed-off-by: Dmitry Osipenko 
---
 arch/parisc/kernel/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index ea3d83b6fb62..928201b1f58f 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -114,8 +115,7 @@ void machine_power_off(void)
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
 
/* ipmi_poweroff may have been installed. */
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();

/* It seems we have no way to power the system off via
 * software. The user has to press the button himself. */
-- 
2.33.1



[PATCH v5 08/21] arm64: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Catalin Marinas 
Signed-off-by: Dmitry Osipenko 
---
 arch/arm64/kernel/process.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index aacf2f5559a8..f8db031afa7d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -110,8 +110,7 @@ void machine_power_off(void)
 {
local_irq_disable();
smp_send_stop();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 /*
-- 
2.33.1



[PATCH v5 07/21] riscv: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Palmer Dabbelt 
Signed-off-by: Dmitry Osipenko 
---
 arch/riscv/kernel/reset.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c
index 9c842c41684a..912288572226 100644
--- a/arch/riscv/kernel/reset.c
+++ b/arch/riscv/kernel/reset.c
@@ -23,16 +23,12 @@ void machine_restart(char *cmd)
 
 void machine_halt(void)
 {
-   if (pm_power_off != NULL)
-   pm_power_off();
-   else
-   default_power_off();
+   do_kernel_power_off();
+   default_power_off();
 }
 
 void machine_power_off(void)
 {
-   if (pm_power_off != NULL)
-   pm_power_off();
-   else
-   default_power_off();
+   do_kernel_power_off();
+   default_power_off();
 }
-- 
2.33.1



[PATCH v5 06/21] csky: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Guo Ren 
Signed-off-by: Dmitry Osipenko 
---
 arch/csky/kernel/power.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/csky/kernel/power.c b/arch/csky/kernel/power.c
index 923ee4e381b8..86ee202906f8 100644
--- a/arch/csky/kernel/power.c
+++ b/arch/csky/kernel/power.c
@@ -9,16 +9,14 @@ EXPORT_SYMBOL(pm_power_off);
 void machine_power_off(void)
 {
local_irq_disable();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
asm volatile ("bkpt");
 }
 
 void machine_halt(void)
 {
local_irq_disable();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
asm volatile ("bkpt");
 }
 
-- 
2.33.1



[PATCH v5 05/21] ARM: Use do_kernel_power_off()

2021-12-12 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Reviewed-by: Russell King (Oracle) 
Signed-off-by: Dmitry Osipenko 
---
 arch/arm/kernel/reboot.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
index 3044fcb8d073..2cb943422554 100644
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -116,9 +116,7 @@ void machine_power_off(void)
 {
local_irq_disable();
smp_send_stop();
-
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 /*
-- 
2.33.1



[PATCH v5 04/21] kernel: Add combined power-off+restart handler call chain API

2021-12-12 Thread Dmitry Osipenko
SoC platforms often have multiple ways of how to perform system's
power-off and restart operations. Meanwhile today's kernel is limited to
a single option. Add combined power-off+restart handler call chain API,
which is inspired by the restart API. The new API provides both power-off
and restart functionality.

The old pm_power_off method will be kept around till all users are
converted to the new API.

Current restart API will be replaced by the new unified API since
new API is its superset. The restart functionality of the sys-off handler
API is built upon the existing restart-notifier APIs.

In order to ease conversion to the new API, convenient helpers are added
for the common use-cases. They will reduce amount of boilerplate code and
remove global variables. These helpers preserve old behaviour for cases
where only one power-off handler is expected, this is what all existing
drivers want, and thus, they could be easily converted to the new API.
Users of the new API should explicitly enable power-off chaining by
setting corresponding flag of the power_handler structure.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h   | 265 ++-
 kernel/power/hibernate.c |   2 +-
 kernel/reboot.c  | 556 ++-
 3 files changed, 815 insertions(+), 8 deletions(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index af907a3d68d1..c2fa8d63c129 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -8,10 +8,35 @@
 
 struct device;
 
-#define SYS_DOWN   0x0001  /* Notify of system down */
-#define SYS_RESTARTSYS_DOWN
-#define SYS_HALT   0x0002  /* Notify of system halt */
-#define SYS_POWER_OFF  0x0003  /* Notify of system power off */
+enum reboot_prepare_mode {
+   SYS_DOWN = 1,   /* Notify of system down */
+   SYS_RESTART = SYS_DOWN,
+   SYS_HALT,   /* Notify of system halt */
+   SYS_POWER_OFF,  /* Notify of system power off */
+};
+
+/*
+ * Standard restart priority levels. Intended to be set in the
+ * sys_off_handler.restart_priority field.
+ *
+ * Use `RESTART_PRIO_ABC +- prio` style for additional levels.
+ *
+ * RESTART_PRIO_RESERVED:  Falls back to RESTART_PRIO_DEFAULT.
+ * Drivers may leave priority initialized
+ * to zero, to auto-set it to the default level.
+ *
+ * RESTART_PRIO_LOW:   Use this for handler of last resort.
+ *
+ * RESTART_PRIO_DEFAULT:   Use this for default/generic handler.
+ *
+ * RESTART_PRIO_HIGH:  Use this if you have multiple handlers and
+ * this handler has higher priority than the
+ * default handler.
+ */
+#define RESTART_PRIO_RESERVED  0
+#define RESTART_PRIO_LOW   8
+#define RESTART_PRIO_DEFAULT   128
+#define RESTART_PRIO_HIGH  192
 
 enum reboot_mode {
REBOOT_UNDEFINED = -1,
@@ -49,6 +74,237 @@ extern int register_restart_handler(struct notifier_block 
*);
 extern int unregister_restart_handler(struct notifier_block *);
 extern void do_kernel_restart(char *cmd);
 
+/*
+ * System power-off and restart API.
+ */
+
+/*
+ * Standard power-off priority levels. Intended to be set in the
+ * sys_off_handler.power_off_priority field.
+ *
+ * Use `POWEROFF_PRIO_ABC +- prio` style for additional levels.
+ *
+ * POWEROFF_PRIO_RESERVED: Falls back to POWEROFF_PRIO_DEFAULT.
+ * Drivers may leave priority initialized
+ * to zero, to auto-set it to the default level.
+ *
+ * POWEROFF_PRIO_PLATFORM: Intended to be used by platform-level handler.
+ * Has lowest priority since device drivers are
+ * expected to take over platform handler which
+ * doesn't allow further callback chaining.
+ *
+ * POWEROFF_PRIO_DEFAULT:  Use this for default/generic handler.
+ *
+ * POWEROFF_PRIO_FIRMWARE: Use this if handler uses firmware call.
+ * Has highest priority since firmware is expected
+ * to know best how to power-off hardware properly.
+ */
+#define POWEROFF_PRIO_RESERVED 0
+#define POWEROFF_PRIO_PLATFORM 1
+#define POWEROFF_PRIO_DEFAULT  128
+#define POWEROFF_PRIO_HIGH 192
+#define POWEROFF_PRIO_FIRMWARE 224
+
+enum poweroff_mode {
+   POWEROFF_NORMAL = 0,
+   POWEROFF_PREPARE,
+};
+
+/**
+ * struct power_off_data - Power-off callback argument
+ *
+ * @cb_data: Callback data.
+ */
+struct power_off_data {
+   void *cb_data;
+};
+
+/**
+ * struct power_off_prep_data - Power-off preparation callback argument
+ *
+ * @cb_data: Callback data.
+ */
+struct power_off_prep_data {
+   void *cb_data;
+};
+
+/**
+ * struct restart_data - Restart callback argument
+ *
+ * @cb_data: Callback data.
+ * @cmd: Restart

[PATCH v5 03/21] reboot: Print error message if restart handler has duplicated priority

2021-12-12 Thread Dmitry Osipenko
Add sanity check which ensures that there are no two restart handlers
registered using the same priority. This requirement will become mandatory
once all drivers will be converted to the new API and such errors will be
fixed.

Signed-off-by: Dmitry Osipenko 
---
 kernel/reboot.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index 6bcc5d6a6572..35f0cde641c1 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -182,6 +182,21 @@ static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
  */
 int register_restart_handler(struct notifier_block *nb)
 {
+   int ret;
+
+   ret = atomic_notifier_chain_register_unique_prio(_handler_list, 
nb);
+   if (ret != -EBUSY)
+   return ret;
+
+   /*
+* Handler must have unique priority. Otherwise call order is
+* determined by registration order, which is unreliable.
+*
+* This requirement will become mandatory once all drivers
+* will be converted to use new sys-off API.
+*/
+   pr_err("failed to register restart handler using unique priority\n");
+
return atomic_notifier_chain_register(_handler_list, nb);
 }
 EXPORT_SYMBOL(register_restart_handler);
-- 
2.33.1



[PATCH v5 02/21] notifier: Add atomic/blocking_notifier_chain_register_unique_prio()

2021-12-12 Thread Dmitry Osipenko
Add variant of atomic/blocking_notifier_chain_register() functions that
doesn't allow to register notifier using a duplicated priority. The -EBUSY
error code is returned in this case by the new API functions.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h |  5 +++
 kernel/notifier.c| 87 +++-
 2 files changed, 73 insertions(+), 19 deletions(-)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index d4717bc0ab85..ccce26197dd2 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -150,6 +150,11 @@ extern int raw_notifier_chain_register(struct 
raw_notifier_head *nh,
 extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *nb);
 
+extern int atomic_notifier_chain_register_unique_prio(
+   struct atomic_notifier_head *nh, struct notifier_block *nb);
+extern int blocking_notifier_chain_register_unique_prio(
+   struct blocking_notifier_head *nh, struct notifier_block *nb);
+
 extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
struct notifier_block *nb);
 extern int blocking_notifier_chain_unregister(struct blocking_notifier_head 
*nh,
diff --git a/kernel/notifier.c b/kernel/notifier.c
index e30d24ee88e9..77e5112ff05b 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -20,7 +20,7 @@ BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
  */
 
 static int notifier_chain_register(struct notifier_block **nl,
-   struct notifier_block *n)
+   struct notifier_block *n, bool unique_priority)
 {
while ((*nl) != NULL) {
if (unlikely((*nl) == n)) {
@@ -29,6 +29,8 @@ static int notifier_chain_register(struct notifier_block **nl,
}
if (n->priority > (*nl)->priority)
break;
+   if (n->priority == (*nl)->priority && unique_priority)
+   return -EBUSY;
nl = &((*nl)->next);
}
n->next = *nl;
@@ -143,12 +145,35 @@ int atomic_notifier_chain_register(struct 
atomic_notifier_head *nh,
int ret;
 
spin_lock_irqsave(>lock, flags);
-   ret = notifier_chain_register(>head, n);
+   ret = notifier_chain_register(>head, n, false);
spin_unlock_irqrestore(>lock, flags);
return ret;
 }
 EXPORT_SYMBOL_GPL(atomic_notifier_chain_register);
 
+/**
+ * atomic_notifier_chain_register_unique_prio - Add notifier to an atomic 
notifier chain
+ * @nh: Pointer to head of the atomic notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to an atomic notifier chain if there is no other
+ * notifier registered using the same priority.
+ *
+ * Returns zero on success, -EBUSY otherwise.
+ */
+int atomic_notifier_chain_register_unique_prio(struct atomic_notifier_head *nh,
+  struct notifier_block *n)
+{
+   unsigned long flags;
+   int ret;
+
+   spin_lock_irqsave(>lock, flags);
+   ret = notifier_chain_register(>head, n, true);
+   spin_unlock_irqrestore(>lock, flags);
+   return ret;
+}
+EXPORT_SYMBOL_GPL(atomic_notifier_chain_register_unique_prio);
+
 /**
  * atomic_notifier_chain_unregister - Remove notifier from an atomic 
notifier chain
  * @nh: Pointer to head of the atomic notifier chain
@@ -208,18 +233,9 @@ NOKPROBE_SYMBOL(atomic_notifier_call_chain);
  * synchronized by an rwsem.
  */
 
-/**
- * blocking_notifier_chain_register - Add notifier to a blocking notifier 
chain
- * @nh: Pointer to head of the blocking notifier chain
- * @n: New entry in notifier chain
- *
- * Adds a notifier to a blocking notifier chain.
- * Must be called in process context.
- *
- * Currently always returns zero.
- */
-int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
-   struct notifier_block *n)
+static int __blocking_notifier_chain_register(struct blocking_notifier_head 
*nh,
+ struct notifier_block *n,
+ bool unique_priority)
 {
int ret;
 
@@ -229,15 +245,48 @@ int blocking_notifier_chain_register(struct 
blocking_notifier_head *nh,
 * such times we must not call down_write().
 */
if (unlikely(system_state == SYSTEM_BOOTING))
-   return notifier_chain_register(>head, n);
+   return notifier_chain_register(>head, n, unique_priority);
 
down_write(>rwsem);
-   ret = notifier_chain_register(>head, n);
+   ret = notifier_chain_register(>head, n, unique_priority);
up_write(>rwsem);
return ret;
 }
+
+/**
+ * blocking_notifier_chain_register - Add notifier to a blocking notifier 
chain
+ * @nh: Pointer to head of the blocking

[PATCH v5 01/21] notifier: Add blocking_notifier_call_chain_is_empty()

2021-12-12 Thread Dmitry Osipenko
Add blocking_notifier_call_chain_is_empty() that returns true if call
chain is empty.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h |  2 ++
 kernel/notifier.c| 13 +
 2 files changed, 15 insertions(+)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 87069b8459af..d4717bc0ab85 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -173,6 +173,8 @@ extern int blocking_notifier_call_chain_robust(struct 
blocking_notifier_head *nh
 extern int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
 
+extern bool blocking_notifier_call_chain_is_empty(struct 
blocking_notifier_head *nh);
+
 #define NOTIFY_DONE0x  /* Don't care */
 #define NOTIFY_OK  0x0001  /* Suits me */
 #define NOTIFY_STOP_MASK   0x8000  /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index b8251dc0bc0f..e30d24ee88e9 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -322,6 +322,19 @@ int blocking_notifier_call_chain(struct 
blocking_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
+/**
+ * blocking_notifier_call_chain_is_empty - Check whether notifier chain is 
empty
+ * @nh: Pointer to head of the blocking notifier chain
+ *
+ * Checks whether notifier chain is empty.
+ *
+ * Returns true is notifier chain is empty, false otherwise.
+ */
+bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh)
+{
+   return !rcu_access_pointer(nh->head);
+}
+
 /*
  * Raw notifier chain routines.  There is no protection;
  * the caller must provide it.  Use at your own risk!
-- 
2.33.1



[PATCH v5 00/21] Introduce power-off+restart call chain API

2021-12-12 Thread Dmitry Osipenko
 v2.

v2: - Replaced standalone power-off call chain demo-API with the combined
  power-off+restart API because this is what drivers want. It's a more
  comprehensive solution.

- Converted multiple drivers and arch code to the new API. Suggested by
  Andy Shevchenko. I skimmed through the rest of drivers, verifying that
  new API suits them. The rest of the drivers will be converted once we
  will settle on the new API, otherwise will be too many patches here.

- v2 API doesn't expose notifier to users and require handlers to
  have unique priority. Suggested by Guenter Roeck.

- v2 API has power-off chaining disabled by default and require
  drivers to explicitly opt-in to the chaining. This preserves old
  behaviour for existing drivers once they are converted to the new
  API.

Dmitry Osipenko (21):
  notifier: Add blocking_notifier_call_chain_is_empty()
  notifier: Add atomic/blocking_notifier_chain_register_unique_prio()
  reboot: Print error message if restart handler has duplicated priority
  kernel: Add combined power-off+restart handler call chain API
  ARM: Use do_kernel_power_off()
  csky: Use do_kernel_power_off()
  riscv: Use do_kernel_power_off()
  arm64: Use do_kernel_power_off()
  parisc: Use do_kernel_power_off()
  xen/x86: Use do_kernel_power_off()
  powerpc: Use do_kernel_power_off()
  m68k: Switch to new sys-off handler API
  sh: Use do_kernel_power_off()
  x86: Use do_kernel_power_off()
  ia64: Use do_kernel_power_off()
  mips: Use do_kernel_power_off()
  nds32: Use do_kernel_power_off()
  memory: emif: Use kernel_can_power_off()
  ACPI: power: Switch to sys-off handler API
  regulator: pfuze100: Use devm_register_sys_off_handler()
  reboot: Remove pm_power_off_prepare()

 arch/arm/kernel/reboot.c   |   4 +-
 arch/arm64/kernel/process.c|   3 +-
 arch/csky/kernel/power.c   |   6 +-
 arch/ia64/kernel/process.c |   4 +-
 arch/m68k/emu/natfeat.c|   3 +-
 arch/m68k/include/asm/machdep.h|   1 -
 arch/m68k/kernel/process.c |   5 +-
 arch/m68k/kernel/setup_mm.c|   1 -
 arch/m68k/kernel/setup_no.c|   1 -
 arch/m68k/mac/config.c |   4 +-
 arch/mips/kernel/reset.c   |   3 +-
 arch/nds32/kernel/process.c|   3 +-
 arch/parisc/kernel/process.c   |   4 +-
 arch/powerpc/kernel/setup-common.c |   4 +-
 arch/powerpc/xmon/xmon.c   |   3 +-
 arch/riscv/kernel/reset.c  |  12 +-
 arch/sh/kernel/reboot.c|   3 +-
 arch/x86/kernel/reboot.c   |   4 +-
 arch/x86/xen/enlighten_pv.c|   4 +-
 drivers/acpi/sleep.c   |  25 +-
 drivers/memory/emif.c  |   2 +-
 drivers/regulator/pfuze100-regulator.c |  38 +-
 include/linux/notifier.h   |   7 +
 include/linux/pm.h |   1 -
 include/linux/reboot.h | 265 +++-
 kernel/notifier.c  | 100 -
 kernel/power/hibernate.c   |   2 +-
 kernel/reboot.c| 574 -
 28 files changed, 968 insertions(+), 118 deletions(-)

-- 
2.33.1



Re: [PATCH v4 03/25] notifier: Add atomic/blocking_notifier_has_unique_priority()

2021-12-12 Thread Dmitry Osipenko
10.12.2021 22:33, Dmitry Osipenko пишет:
>> Not really, they only prevent the race from occurring while
>> notifier_has_unique_priority() is running.
>>
>> If anyone depends on this check for correctness, they need to lock the
>> rwsem, do the check, do the thing depending on the check while holding
>> the rwsem and then release the rwsem.  Otherwise it is racy.
>>
> It's fine that it's a bit "racy" since in the context of this series. We
> always do the check after adding new entry, so it's not a problem.
> 
> There are two options:
> 
> 1. Use blocking_notifier_has_unique_priority() like it's done in this
> patchset. Remove it after all drivers are converted to the new API and
> add blocking_notifier_chain_register_unique().
> 
> 2. Add blocking_notifier_chain_register_unique(), but don't let it fail
> the registration of non-unique entries until all drivers are converted
> to the new API.

There is third, perhaps the best option:

3. Add blocking_notifier_chain_register_unique() and fall back to
blocking_notifier_chain_register() if unique fails, do it until all
drivers are converted to the new API.


Re: [PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-12-12 Thread Dmitry Osipenko
10.12.2021 22:44, Dmitry Osipenko пишет:
> 10.12.2021 22:42, Dmitry Osipenko пишет:
> ...
>>>> There is no strong requirement for priorities to be unique, the reboot.c
>>>> code will work properly.
>>>
>>> In which case adding the WARN() is not appropriate IMV.
>>>
>>> Also I've looked at the existing code and at least in some cases the
>>> order in which the notifiers run doesn't matter.  I'm not sure what
>>> the purpose of this patch is TBH.
>>
>> The purpose is to let developer know that driver needs to be corrected.
>>
>>>> The potential problem is on the user's side and the warning is intended
>>>> to aid the user.
>>>
>>> Unless somebody has the panic_on_warn mentioned previously set and
>>> really the user need not understand what the WARN() is about.  IOW,
>>> WARN() helps developers, not users.
>>>
>>>> We can make it a strong requirement, but only after converting and
>>>> testing all kernel drivers.
>>>
>>> Right.
>>>
>>>> I'll consider to add patches for that.
>>>
>>> But can you avoid adding more patches to this series?
>>
>> I won't add more patches since such patches can be added only after
>> completion of transition to the new API of the whole kernel.
>>
> 
> Thank you for the review.
> 

I meant you, Rafael, and Michał, just in case :)


Re: [PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-12-12 Thread Dmitry Osipenko
10.12.2021 22:42, Dmitry Osipenko пишет:
...
>>> There is no strong requirement for priorities to be unique, the reboot.c
>>> code will work properly.
>>
>> In which case adding the WARN() is not appropriate IMV.
>>
>> Also I've looked at the existing code and at least in some cases the
>> order in which the notifiers run doesn't matter.  I'm not sure what
>> the purpose of this patch is TBH.
> 
> The purpose is to let developer know that driver needs to be corrected.
> 
>>> The potential problem is on the user's side and the warning is intended
>>> to aid the user.
>>
>> Unless somebody has the panic_on_warn mentioned previously set and
>> really the user need not understand what the WARN() is about.  IOW,
>> WARN() helps developers, not users.
>>
>>> We can make it a strong requirement, but only after converting and
>>> testing all kernel drivers.
>>
>> Right.
>>
>>> I'll consider to add patches for that.
>>
>> But can you avoid adding more patches to this series?
> 
> I won't add more patches since such patches can be added only after
> completion of transition to the new API of the whole kernel.
> 

Thank you for the review.


Re: [PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-12-12 Thread Dmitry Osipenko
10.12.2021 22:14, Rafael J. Wysocki пишет:
> On Fri, Dec 10, 2021 at 8:04 PM Dmitry Osipenko  wrote:
>>
>> 10.12.2021 21:27, Rafael J. Wysocki пишет:
>>> On Mon, Nov 29, 2021 at 12:34 PM Dmitry Osipenko  wrote:
>>>>
>>>> 29.11.2021 03:26, Michał Mirosław пишет:
>>>>> On Mon, Nov 29, 2021 at 12:06:19AM +0300, Dmitry Osipenko wrote:
>>>>>> 28.11.2021 03:28, Michał Mirosław пишет:
>>>>>>> On Fri, Nov 26, 2021 at 09:00:41PM +0300, Dmitry Osipenko wrote:
>>>>>>>> Add sanity check which ensures that there are no two restart handlers
>>>>>>>> registered with the same priority. Normally it's a direct sign of a
>>>>>>>> problem if two handlers use the same priority.
>>>>>>>
>>>>>>> The patch doesn't ensure the property that there are no 
>>>>>>> duplicated-priority
>>>>>>> entries on the chain.
>>>>>>
>>>>>> It's not the exact point of this patch.
>>>>>>
>>>>>>> I'd rather see a atomic_notifier_chain_register_unique() that returns
>>>>>>> -EBUSY or something istead of adding an entry with duplicate priority.
>>>>>>> That way it would need only one list traversal unless you want to
>>>>>>> register the duplicate anyway (then you would call the older
>>>>>>> atomic_notifier_chain_register() after reporting the error).
>>>>>>
>>>>>> The point of this patch is to warn developers about the problem that
>>>>>> needs to be fixed. We already have such troubling drivers in mainline.
>>>>>>
>>>>>> It's not critical to register different handlers with a duplicated
>>>>>> priorities, but such cases really need to be corrected. We shouldn't
>>>>>> break users' machines during transition to the new API, meanwhile
>>>>>> developers should take action of fixing theirs drivers.
>>>>>>
>>>>>>> (Or you could return > 0 when a duplicate is registered in
>>>>>>> atomic_notifier_chain_register() if the callers are prepared
>>>>>>> for that. I don't really like this way, though.)
>>>>>>
>>>>>> I had a similar thought at some point before and decided that I'm not in
>>>>>> favor of this approach. It's nicer to have a dedicated function that
>>>>>> verifies the uniqueness, IMO.
>>>>>
>>>>> I don't like the part that it traverses the list second time to check
>>>>> the uniqueness. But actually you could avoid that if
>>>>> notifier_chain_register() would always add equal-priority entries in
>>>>> reverse order:
>>>>>
>>>>>  static int notifier_chain_register(struct notifier_block **nl,
>>>>>   struct notifier_block *n)
>>>>>  {
>>>>>   while ((*nl) != NULL) {
>>>>>   if (unlikely((*nl) == n)) {
>>>>>   WARN(1, "double register detected");
>>>>>   return 0;
>>>>>   }
>>>>> - if (n->priority > (*nl)->priority)
>>>>> + if (n->priority >= (*nl)->priority)
>>>>>   break;
>>>>>   nl = &((*nl)->next);
>>>>>   }
>>>>>   n->next = *nl;
>>>>>   rcu_assign_pointer(*nl, n);
>>>>>   return 0;
>>>>>  }
>>>>>
>>>>> Then the check for uniqueness after adding would be:
>>>>>
>>>>>  WARN(nb->next && nb->priority == nb->next->priority);
>>>>
>>>> We can't just change the registration order because invocation order of
>>>> the call chain depends on the registration order
>>>
>>> It doesn't if unique priorities are required and isn't that what you want?
>>>
>>>> and some of current
>>>> users may rely on that order. I'm pretty sure that changing the order
>>>> will have unfortunate consequences.
>>>
>>> Well, the WARN() doesn't help much then.
>>>
>>> Either you can make all of the users register with unique priorities,
>>> and then you can make the registration reject non-unique ones, or you
>>> cannot assume them to be unique.
>>
>> There is no strong requirement for priorities to be unique, the reboot.c
>> code will work properly.
> 
> In which case adding the WARN() is not appropriate IMV.
> 
> Also I've looked at the existing code and at least in some cases the
> order in which the notifiers run doesn't matter.  I'm not sure what
> the purpose of this patch is TBH.

The purpose is to let developer know that driver needs to be corrected.

>> The potential problem is on the user's side and the warning is intended
>> to aid the user.
> 
> Unless somebody has the panic_on_warn mentioned previously set and
> really the user need not understand what the WARN() is about.  IOW,
> WARN() helps developers, not users.
> 
>> We can make it a strong requirement, but only after converting and
>> testing all kernel drivers.
> 
> Right.
> 
>> I'll consider to add patches for that.
> 
> But can you avoid adding more patches to this series?

I won't add more patches since such patches can be added only after
completion of transition to the new API of the whole kernel.


Re: [PATCH v4 06/25] reboot: Warn if unregister_restart_handler() fails

2021-12-12 Thread Dmitry Osipenko
10.12.2021 22:08, Rafael J. Wysocki пишет:
> On Fri, Dec 10, 2021 at 7:54 PM Dmitry Osipenko  wrote:
>>
>> 10.12.2021 21:32, Rafael J. Wysocki пишет:
>>> On Fri, Nov 26, 2021 at 7:02 PM Dmitry Osipenko  wrote:
>>>>
>>>> Emit warning if unregister_restart_handler() fails since it never should
>>>> fail. This will ease further API development by catching mistakes early.
>>>>
>>>> Signed-off-by: Dmitry Osipenko 
>>>> ---
>>>>  kernel/reboot.c | 2 +-
>>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/kernel/reboot.c b/kernel/reboot.c
>>>> index e6659ae329f1..f0e7b9c13f6b 100644
>>>> --- a/kernel/reboot.c
>>>> +++ b/kernel/reboot.c
>>>> @@ -210,7 +210,7 @@ EXPORT_SYMBOL(register_restart_handler);
>>>>   */
>>>>  int unregister_restart_handler(struct notifier_block *nb)
>>>>  {
>>>> -   return atomic_notifier_chain_unregister(_handler_list, nb);
>>>> +   return 
>>>> WARN_ON(atomic_notifier_chain_unregister(_handler_list, nb));
>>>
>>> The only reason why it can fail is if the object pointed to by nb is
>>> not in the chain.
>>
>> I had exactly this case where object wasn't in the chain due to a bug
>> and this warning was very helpful.
> 
> During the development.  In production it would be rather annoying.
> 
>>>  Why WARN() about this?  And what about systems with
>>> panic_on_warn set?
>>
>> That warning condition will never happen normally, only when something
>> is seriously wrong.
>>
>> Those systems with panic_on_warn will get what was they asked for.
> 
> They may not be asking for panicking on bugs in the reboot notifier
> code, though.  That's what your change is making them panic on.
> 

Alright, I'll drop the warnings and turn the warning about uniqueness
into error or warning message.


Re: [PATCH v4 03/25] notifier: Add atomic/blocking_notifier_has_unique_priority()

2021-12-12 Thread Dmitry Osipenko
10.12.2021 22:05, Rafael J. Wysocki пишет:
> On Fri, Dec 10, 2021 at 7:52 PM Dmitry Osipenko  wrote:
>>
>> 10.12.2021 21:19, Rafael J. Wysocki пишет:
>> ...
>>>> +bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
>>>> +   struct notifier_block *n)
>>>> +{
>>>> +   unsigned long flags;
>>>> +   bool ret;
>>>> +
>>>> +   spin_lock_irqsave(>lock, flags);
>>>> +   ret = notifier_has_unique_priority(>head, n);
>>>> +   spin_unlock_irqrestore(>lock, flags);
>>>
>>> This only works if the caller can prevent new entries from being added
>>> to the list at this point or if the caller knows that they cannot be
>>> added for some reason, but the kerneldoc doesn't mention this
>>> limitation.
>>
>> I'll update the comment.
>>
>> ..
>>>> +bool blocking_notifier_has_unique_priority(struct blocking_notifier_head 
>>>> *nh,
>>>> +   struct notifier_block *n)
>>>> +{
>>>> +   bool ret;
>>>> +
>>>> +   /*
>>>> +* This code gets used during boot-up, when task switching is
>>>> +* not yet working and interrupts must remain disabled. At such
>>>> +* times we must not call down_read().
>>>> +*/
>>>> +   if (system_state != SYSTEM_BOOTING)
>>>
>>> No, please don't do this, it makes the whole thing error-prone.
>>
>> What should I do then?
> 
> First of all, do you know of any users who may want to call this
> during early initialization?  If so, then why may they want to do
> that?

I'll need to carefully review all those dozens of platform restart
handlers to answer this question.

> Depending on the above, I would consider adding a special mechanism for them.

Please notice that every blocking_notifier_*() function has this
SYSTEM_BOOTING check, it's not my invention. Notifier API needs to be
generic.

>>>> +   down_read(>rwsem);
>>>> +
>>>> +   ret = notifier_has_unique_priority(>head, n);
>>>> +
>>>> +   if (system_state != SYSTEM_BOOTING)
>>>> +   up_read(>rwsem);
>>>
>>> And still what if a new entry with a non-unique priority is added to
>>> the chain at this point?
>>
>> If entry with a non-unique priority is added after the check, then
>> obviously it won't be detected.
> 
> Why isn't this a problem?>> I don't understand the question. These
>> down/up_read() are the locks that prevent the race, if that's the question.
> 
> Not really, they only prevent the race from occurring while
> notifier_has_unique_priority() is running.
> 
> If anyone depends on this check for correctness, they need to lock the
> rwsem, do the check, do the thing depending on the check while holding
> the rwsem and then release the rwsem.  Otherwise it is racy.
> 

It's fine that it's a bit "racy" since in the context of this series. We
always do the check after adding new entry, so it's not a problem.

There are two options:

1. Use blocking_notifier_has_unique_priority() like it's done in this
patchset. Remove it after all drivers are converted to the new API and
add blocking_notifier_chain_register_unique().

2. Add blocking_notifier_chain_register_unique(), but don't let it fail
the registration of non-unique entries until all drivers are converted
to the new API.


Re: [PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-12-12 Thread Dmitry Osipenko
10.12.2021 21:27, Rafael J. Wysocki пишет:
> On Mon, Nov 29, 2021 at 12:34 PM Dmitry Osipenko  wrote:
>>
>> 29.11.2021 03:26, Michał Mirosław пишет:
>>> On Mon, Nov 29, 2021 at 12:06:19AM +0300, Dmitry Osipenko wrote:
>>>> 28.11.2021 03:28, Michał Mirosław пишет:
>>>>> On Fri, Nov 26, 2021 at 09:00:41PM +0300, Dmitry Osipenko wrote:
>>>>>> Add sanity check which ensures that there are no two restart handlers
>>>>>> registered with the same priority. Normally it's a direct sign of a
>>>>>> problem if two handlers use the same priority.
>>>>>
>>>>> The patch doesn't ensure the property that there are no 
>>>>> duplicated-priority
>>>>> entries on the chain.
>>>>
>>>> It's not the exact point of this patch.
>>>>
>>>>> I'd rather see a atomic_notifier_chain_register_unique() that returns
>>>>> -EBUSY or something istead of adding an entry with duplicate priority.
>>>>> That way it would need only one list traversal unless you want to
>>>>> register the duplicate anyway (then you would call the older
>>>>> atomic_notifier_chain_register() after reporting the error).
>>>>
>>>> The point of this patch is to warn developers about the problem that
>>>> needs to be fixed. We already have such troubling drivers in mainline.
>>>>
>>>> It's not critical to register different handlers with a duplicated
>>>> priorities, but such cases really need to be corrected. We shouldn't
>>>> break users' machines during transition to the new API, meanwhile
>>>> developers should take action of fixing theirs drivers.
>>>>
>>>>> (Or you could return > 0 when a duplicate is registered in
>>>>> atomic_notifier_chain_register() if the callers are prepared
>>>>> for that. I don't really like this way, though.)
>>>>
>>>> I had a similar thought at some point before and decided that I'm not in
>>>> favor of this approach. It's nicer to have a dedicated function that
>>>> verifies the uniqueness, IMO.
>>>
>>> I don't like the part that it traverses the list second time to check
>>> the uniqueness. But actually you could avoid that if
>>> notifier_chain_register() would always add equal-priority entries in
>>> reverse order:
>>>
>>>  static int notifier_chain_register(struct notifier_block **nl,
>>>   struct notifier_block *n)
>>>  {
>>>   while ((*nl) != NULL) {
>>>   if (unlikely((*nl) == n)) {
>>>   WARN(1, "double register detected");
>>>   return 0;
>>>   }
>>> - if (n->priority > (*nl)->priority)
>>> + if (n->priority >= (*nl)->priority)
>>>   break;
>>>   nl = &((*nl)->next);
>>>   }
>>>   n->next = *nl;
>>>   rcu_assign_pointer(*nl, n);
>>>   return 0;
>>>  }
>>>
>>> Then the check for uniqueness after adding would be:
>>>
>>>  WARN(nb->next && nb->priority == nb->next->priority);
>>
>> We can't just change the registration order because invocation order of
>> the call chain depends on the registration order
> 
> It doesn't if unique priorities are required and isn't that what you want?
> 
>> and some of current
>> users may rely on that order. I'm pretty sure that changing the order
>> will have unfortunate consequences.
> 
> Well, the WARN() doesn't help much then.
> 
> Either you can make all of the users register with unique priorities,
> and then you can make the registration reject non-unique ones, or you
> cannot assume them to be unique.

There is no strong requirement for priorities to be unique, the reboot.c
code will work properly.

The potential problem is on the user's side and the warning is intended
to aid the user.

We can make it a strong requirement, but only after converting and
testing all kernel drivers. I'll consider to add patches for that.


Re: [PATCH v4 07/25] reboot: Remove extern annotation from function prototypes

2021-12-12 Thread Dmitry Osipenko
10.12.2021 21:35, Rafael J. Wysocki пишет:
> On Fri, Dec 10, 2021 at 7:16 PM Dmitry Osipenko  wrote:
>>
>> 10.12.2021 21:09, Rafael J. Wysocki пишет:
>>> On Fri, Nov 26, 2021 at 7:02 PM Dmitry Osipenko  wrote:
>>>>
>>>> There is no need to annotate function prototypes with 'extern', it makes
>>>> code less readable. Remove unnecessary annotations from .
>>>>
>>>> Signed-off-by: Dmitry Osipenko 
>>>
>>> I'm not sure that this is really useful.
>>>
>>> Personally, I tend to respect the existing conventions like this.
>>>
>>> Surely, this change is not required for the rest of the series to work.
>>
>> Problem that such things start to spread all over the kernel with a
>> copy-paste approach if there is nobody to clean up the code.
>>
>> This is not a common convention and sometimes it's getting corrected [1].
>>
>> [1] https://git.kernel.org/linus/6d7434931
> 
> In separate patches outside of series adding new features, if one is
> so inclined.
> 

Alright, I'll drop this patch then because it can't be done in parallel
without creating the merge conflict. I'll try not to forget to come back
to this later on.


Re: [PATCH v4 06/25] reboot: Warn if unregister_restart_handler() fails

2021-12-12 Thread Dmitry Osipenko
10.12.2021 21:32, Rafael J. Wysocki пишет:
> On Fri, Nov 26, 2021 at 7:02 PM Dmitry Osipenko  wrote:
>>
>> Emit warning if unregister_restart_handler() fails since it never should
>> fail. This will ease further API development by catching mistakes early.
>>
>> Signed-off-by: Dmitry Osipenko 
>> ---
>>  kernel/reboot.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/kernel/reboot.c b/kernel/reboot.c
>> index e6659ae329f1..f0e7b9c13f6b 100644
>> --- a/kernel/reboot.c
>> +++ b/kernel/reboot.c
>> @@ -210,7 +210,7 @@ EXPORT_SYMBOL(register_restart_handler);
>>   */
>>  int unregister_restart_handler(struct notifier_block *nb)
>>  {
>> -   return atomic_notifier_chain_unregister(_handler_list, nb);
>> +   return 
>> WARN_ON(atomic_notifier_chain_unregister(_handler_list, nb));
> 
> The only reason why it can fail is if the object pointed to by nb is
> not in the chain.

I had exactly this case where object wasn't in the chain due to a bug
and this warning was very helpful.

>  Why WARN() about this?  And what about systems with
> panic_on_warn set?

That warning condition will never happen normally, only when something
is seriously wrong.

Those systems with panic_on_warn will get what was they asked for.


Re: [PATCH v4 03/25] notifier: Add atomic/blocking_notifier_has_unique_priority()

2021-12-12 Thread Dmitry Osipenko
10.12.2021 21:19, Rafael J. Wysocki пишет:
...
>> +bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
>> +   struct notifier_block *n)
>> +{
>> +   unsigned long flags;
>> +   bool ret;
>> +
>> +   spin_lock_irqsave(>lock, flags);
>> +   ret = notifier_has_unique_priority(>head, n);
>> +   spin_unlock_irqrestore(>lock, flags);
> 
> This only works if the caller can prevent new entries from being added
> to the list at this point or if the caller knows that they cannot be
> added for some reason, but the kerneldoc doesn't mention this
> limitation.

I'll update the comment.

..
>> +bool blocking_notifier_has_unique_priority(struct blocking_notifier_head 
>> *nh,
>> +   struct notifier_block *n)
>> +{
>> +   bool ret;
>> +
>> +   /*
>> +* This code gets used during boot-up, when task switching is
>> +* not yet working and interrupts must remain disabled. At such
>> +* times we must not call down_read().
>> +*/
>> +   if (system_state != SYSTEM_BOOTING)
> 
> No, please don't do this, it makes the whole thing error-prone.

What should I do then?

>> +   down_read(>rwsem);
>> +
>> +   ret = notifier_has_unique_priority(>head, n);
>> +
>> +   if (system_state != SYSTEM_BOOTING)
>> +   up_read(>rwsem);
> 
> And still what if a new entry with a non-unique priority is added to
> the chain at this point?

If entry with a non-unique priority is added after the check, then
obviously it won't be detected. I don't understand the question. These
down/up_read() are the locks that prevent the race, if that's the question.



Re: [PATCH v4 02/25] notifier: Add blocking_notifier_call_chain_is_empty()

2021-12-12 Thread Dmitry Osipenko
10.12.2021 21:14, Rafael J. Wysocki пишет:
> On Fri, Nov 26, 2021 at 7:01 PM Dmitry Osipenko  wrote:
>>
>> Add blocking_notifier_call_chain_is_empty() that returns true if call
>> chain is empty.
>>
>> Signed-off-by: Dmitry Osipenko 
>> ---
>>  include/linux/notifier.h |  2 ++
>>  kernel/notifier.c| 14 ++
>>  2 files changed, 16 insertions(+)
>>
>> diff --git a/include/linux/notifier.h b/include/linux/notifier.h
>> index 4b80a815b666..924c9d7c8e73 100644
>> --- a/include/linux/notifier.h
>> +++ b/include/linux/notifier.h
>> @@ -173,6 +173,8 @@ int blocking_notifier_call_chain_robust(struct 
>> blocking_notifier_head *nh,
>>  int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
>> unsigned long val_up, unsigned long val_down, void *v);
>>
>> +bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head 
>> *nh);
>> +
>>  #define NOTIFY_DONE0x  /* Don't care */
>>  #define NOTIFY_OK  0x0001  /* Suits me */
>>  #define NOTIFY_STOP_MASK   0x8000  /* Don't call further */
>> diff --git a/kernel/notifier.c b/kernel/notifier.c
>> index b8251dc0bc0f..b20cb7b9b1f0 100644
>> --- a/kernel/notifier.c
>> +++ b/kernel/notifier.c
>> @@ -322,6 +322,20 @@ int blocking_notifier_call_chain(struct 
>> blocking_notifier_head *nh,
>>  }
>>  EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
>>
>> +/**
>> + * blocking_notifier_call_chain_is_empty - Check whether notifier chain 
>> is empty
>> + * @nh: Pointer to head of the blocking notifier chain
>> + *
>> + * Checks whether notifier chain is empty.
>> + *
>> + * Returns true is notifier chain is empty, false otherwise.
>> + */
>> +bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head 
>> *nh)
>> +{
>> +   return !rcu_access_pointer(nh->head);
>> +}
>> +EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_is_empty);
> 
> The check is not reliable (racy) without locking, so I wouldn't export
> anything like this to modules.
> 
> At least IMO it should be added along with a user.
> 

I'll remove the export since it's indeed not obvious how other users may
want to use this function.


Re: [PATCH v4 07/25] reboot: Remove extern annotation from function prototypes

2021-12-12 Thread Dmitry Osipenko
10.12.2021 21:09, Rafael J. Wysocki пишет:
> On Fri, Nov 26, 2021 at 7:02 PM Dmitry Osipenko  wrote:
>>
>> There is no need to annotate function prototypes with 'extern', it makes
>> code less readable. Remove unnecessary annotations from .
>>
>> Signed-off-by: Dmitry Osipenko 
> 
> I'm not sure that this is really useful.
> 
> Personally, I tend to respect the existing conventions like this.
> 
> Surely, this change is not required for the rest of the series to work.

Problem that such things start to spread all over the kernel with a
copy-paste approach if there is nobody to clean up the code.

This is not a common convention and sometimes it's getting corrected [1].

[1] https://git.kernel.org/linus/6d7434931


Re: [PATCH v2 28/45] mfd: rn5t618: Use devm_register_power_handler()

2021-11-29 Thread Dmitry Osipenko
29.11.2021 14:55, Lee Jones пишет:
> On Thu, 28 Oct 2021, Dmitry Osipenko wrote:
> 
>> Use devm_register_power_handler() that replaces global pm_power_off
>> variable and allows to register multiple power-off handlers. It also
>> provides restart-handler support, i.e. all in one API.
>>
>> Signed-off-by: Dmitry Osipenko 
>> ---
>>  drivers/mfd/rn5t618.c | 56 ---
>>  1 file changed, 21 insertions(+), 35 deletions(-)
> 
> For my own reference (apply this as-is to your sign-off block):
> 
>   Acked-for-MFD-by: Lee Jones 
> 

Thanks you. This and other driver patches will be slightly changed
because the power-handler was renamed to sys-off handler starting with
the v3 of this series, but yours ack still will be valid here.


Re: [PATCH v4 08/25] kernel: Add combined power-off+restart handler call chain API

2021-11-29 Thread Dmitry Osipenko
29.11.2021 03:36, Michał Mirosław пишет:
> On Mon, Nov 29, 2021 at 12:53:51AM +0300, Dmitry Osipenko wrote:
>> 29.11.2021 00:17, Michał Mirosław пишет:
>>>> I'm having trouble with parsing this comment. Could you please try to
>>>> rephrase it? I don't see how you could check whether power-off handler
>>>> is available if you'll mix all handlers together.
>>> If notify_call_chain() would be fixed to return NOTIFY_OK if any call
>>> returned NOTIFY_OK, then this would be a clear way to gather the
>>> answer if any of the handlers will attempt the final action (reboot or
>>> power off).
>> Could you please show a code snippet that implements your suggestion?
> 
> A rough idea is this:
> 
>  static int notifier_call_chain(struct notifier_block **nl,
>  unsigned long val, void *v,
>  int nr_to_call, int *nr_calls)
>  {
> - int ret = NOTIFY_DONE;
> + int ret, result = NOTIFY_DONE;
>   struct notifier_block *nb, *next_nb;
>  
>   nb = rcu_dereference_raw(*nl);
>  
>   while (nb && nr_to_call) {
> ...
>   ret = nb->notifier_call(nb, val, v);
> +
> + /* Assuming NOTIFY_STOP-carrying return is always greater than 
> non-stopping one. */
> + if (result < ret)
> + result = ret;
> ... 
>   }
> - return ret;
> + return result;
>  }
> 
> Then:
> 
> bool prepare_reboot()
> {
>   int ret = xx_notifier_call_chain(_notifier, PREPARE_REBOOT, 
> ...);
>   return ret == NOTIFY_OK;
> }
> 
> And the return value would signify whether the reboot will be attempted
> when calling the chain for the REBOOT action. (Analogously for powering off.)

If you started to execute call chain, then you began the power-off /
restart sequence, this is a point of no return. Sorry, I still don't
understand what you're trying to achieve.

The approach of having separate call chains is simple and intuitive, I
don't see reasons to change it.


Re: [PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-11-29 Thread Dmitry Osipenko
29.11.2021 03:26, Michał Mirosław пишет:
> On Mon, Nov 29, 2021 at 12:06:19AM +0300, Dmitry Osipenko wrote:
>> 28.11.2021 03:28, Michał Mirosław пишет:
>>> On Fri, Nov 26, 2021 at 09:00:41PM +0300, Dmitry Osipenko wrote:
>>>> Add sanity check which ensures that there are no two restart handlers
>>>> registered with the same priority. Normally it's a direct sign of a
>>>> problem if two handlers use the same priority.
>>>
>>> The patch doesn't ensure the property that there are no duplicated-priority
>>> entries on the chain.
>>
>> It's not the exact point of this patch.
>>
>>> I'd rather see a atomic_notifier_chain_register_unique() that returns
>>> -EBUSY or something istead of adding an entry with duplicate priority.
>>> That way it would need only one list traversal unless you want to
>>> register the duplicate anyway (then you would call the older
>>> atomic_notifier_chain_register() after reporting the error).
>>
>> The point of this patch is to warn developers about the problem that
>> needs to be fixed. We already have such troubling drivers in mainline.
>>
>> It's not critical to register different handlers with a duplicated
>> priorities, but such cases really need to be corrected. We shouldn't
>> break users' machines during transition to the new API, meanwhile
>> developers should take action of fixing theirs drivers.
>>
>>> (Or you could return > 0 when a duplicate is registered in
>>> atomic_notifier_chain_register() if the callers are prepared
>>> for that. I don't really like this way, though.)
>>
>> I had a similar thought at some point before and decided that I'm not in
>> favor of this approach. It's nicer to have a dedicated function that
>> verifies the uniqueness, IMO.
> 
> I don't like the part that it traverses the list second time to check
> the uniqueness. But actually you could avoid that if
> notifier_chain_register() would always add equal-priority entries in
> reverse order:
> 
>  static int notifier_chain_register(struct notifier_block **nl,
>   struct notifier_block *n)
>  {
>   while ((*nl) != NULL) {
>   if (unlikely((*nl) == n)) {
>   WARN(1, "double register detected");
>   return 0;
>   }
> - if (n->priority > (*nl)->priority)
> + if (n->priority >= (*nl)->priority)
>   break;
>   nl = &((*nl)->next);
>   }
>   n->next = *nl;
>   rcu_assign_pointer(*nl, n);
>   return 0;
>  }
> 
> Then the check for uniqueness after adding would be:
> 
>  WARN(nb->next && nb->priority == nb->next->priority);

We can't just change the registration order because invocation order of
the call chain depends on the registration order and some of current
users may rely on that order. I'm pretty sure that changing the order
will have unfortunate consequences.


Re: [PATCH v4 08/25] kernel: Add combined power-off+restart handler call chain API

2021-11-28 Thread Dmitry Osipenko
29.11.2021 00:17, Michał Mirosław пишет:
>> I'm having trouble with parsing this comment. Could you please try to
>> rephrase it? I don't see how you could check whether power-off handler
>> is available if you'll mix all handlers together.
> If notify_call_chain() would be fixed to return NOTIFY_OK if any call
> returned NOTIFY_OK, then this would be a clear way to gather the
> answer if any of the handlers will attempt the final action (reboot or
> power off).
> 

Could you please show a code snippet that implements your suggestion?


Re: [PATCH v4 18/25] x86: Use do_kernel_power_off()

2021-11-28 Thread Dmitry Osipenko
28.11.2021 04:15, Michał Mirosław пишет:
> On Fri, Nov 26, 2021 at 09:00:54PM +0300, Dmitry Osipenko wrote:
>> Kernel now supports chained power-off handlers. Use do_kernel_power_off()
>> that invokes chained power-off handlers. It also invokes legacy
>> pm_power_off() for now, which will be removed once all drivers will
>> be converted to the new power-off API.
>>
>> Signed-off-by: Dmitry Osipenko 
>> ---
>>  arch/x86/kernel/reboot.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
>> index 0a40df66a40d..cd7d9416d81a 100644
>> --- a/arch/x86/kernel/reboot.c
>> +++ b/arch/x86/kernel/reboot.c
>> @@ -747,10 +747,10 @@ static void native_machine_halt(void)
>>  
>>  static void native_machine_power_off(void)
>>  {
>> -if (pm_power_off) {
>> +if (kernel_can_power_off()) {
>>  if (!reboot_force)
>>  machine_shutdown();
>> -pm_power_off();
>> +do_kernel_power_off();
>>  }
> 
> Judging from an old commit from 2006 [1], this can be rewritten as:
> 
> if (!reboot_force && kernel_can_power_off())
>   machine_shutdown();
> do_kernel_power_off();
> 
> And maybe later reworked so it doesn't need kernel_can_power_off().
> 
> [1] http://lkml.iu.edu/hypermail//linux/kernel/0511.3/0681.html

It could be rewritten like you're suggesting, but I'd prefer to keep the
old variant, for clarity.


Re: [PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-11-28 Thread Dmitry Osipenko
28.11.2021 03:28, Michał Mirosław пишет:
> On Fri, Nov 26, 2021 at 09:00:41PM +0300, Dmitry Osipenko wrote:
>> Add sanity check which ensures that there are no two restart handlers
>> registered with the same priority. Normally it's a direct sign of a
>> problem if two handlers use the same priority.
> 
> The patch doesn't ensure the property that there are no duplicated-priority
> entries on the chain.

It's not the exact point of this patch.

> I'd rather see a atomic_notifier_chain_register_unique() that returns
> -EBUSY or something istead of adding an entry with duplicate priority.
> That way it would need only one list traversal unless you want to
> register the duplicate anyway (then you would call the older
> atomic_notifier_chain_register() after reporting the error).

The point of this patch is to warn developers about the problem that
needs to be fixed. We already have such troubling drivers in mainline.

It's not critical to register different handlers with a duplicated
priorities, but such cases really need to be corrected. We shouldn't
break users' machines during transition to the new API, meanwhile
developers should take action of fixing theirs drivers.

> (Or you could return > 0 when a duplicate is registered in
> atomic_notifier_chain_register() if the callers are prepared
> for that. I don't really like this way, though.)

I had a similar thought at some point before and decided that I'm not in
favor of this approach. It's nicer to have a dedicated function that
verifies the uniqueness, IMO.


Re: [PATCH v4 22/25] memory: emif: Use kernel_can_power_off()

2021-11-28 Thread Dmitry Osipenko
28.11.2021 04:23, Michał Mirosław пишет:
> On Fri, Nov 26, 2021 at 09:00:58PM +0300, Dmitry Osipenko wrote:
>> Replace legacy pm_power_off with kernel_can_power_off() helper that
>> is aware about chained power-off handlers.
>>
>> Signed-off-by: Dmitry Osipenko 
>> ---
>>  drivers/memory/emif.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
>> index 762d0c0f0716..cab10d5274a0 100644
>> --- a/drivers/memory/emif.c
>> +++ b/drivers/memory/emif.c
>> @@ -630,7 +630,7 @@ static irqreturn_t emif_threaded_isr(int irq, void 
>> *dev_id)
>>  dev_emerg(emif->dev, "SDRAM temperature exceeds operating 
>> limit.. Needs shut down!!!\n");
>>  
>>  /* If we have Power OFF ability, use it, else try restarting */
>> -if (pm_power_off) {
>> +if (kernel_can_power_off()) {
>>  kernel_power_off();
>>  } else {
>>  WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
> 
> BTW, this part of the code seems to be better moved to generic code that
> could replace POWER_OFF request with REBOOT like it is done for reboot()
> syscall.

Not sure that it can be done. Somebody will have to verify that it won't
break all those platform power-off handlers. Better to keep this code
as-is in the context of this patchset.


Re: [PATCH v4 08/25] kernel: Add combined power-off+restart handler call chain API

2021-11-28 Thread Dmitry Osipenko
28.11.2021 03:43, Michał Mirosław пишет:
> On Fri, Nov 26, 2021 at 09:00:44PM +0300, Dmitry Osipenko wrote:
>> SoC platforms often have multiple ways of how to perform system's
>> power-off and restart operations. Meanwhile today's kernel is limited to
>> a single option. Add combined power-off+restart handler call chain API,
>> which is inspired by the restart API. The new API provides both power-off
>> and restart functionality.
>>
>> The old pm_power_off method will be kept around till all users are
>> converted to the new API.
>>
>> Current restart API will be replaced by the new unified API since
>> new API is its superset. The restart functionality of the sys-off handler
>> API is built upon the existing restart-notifier APIs.
>>
>> In order to ease conversion to the new API, convenient helpers are added
>> for the common use-cases. They will reduce amount of boilerplate code and
>> remove global variables. These helpers preserve old behaviour for cases
>> where only one power-off handler is expected, this is what all existing
>> drivers want, and thus, they could be easily converted to the new API.
>> Users of the new API should explicitly enable power-off chaining by
>> setting corresponding flag of the power_handler structure.
> [...]
> 
> Hi,
> 
> A general question: do we really need three distinct chains for this?

Hello Michał,

At minimum this makes code easier to follow.

> Can't there be only one that chain of callbacks that get a stage
> (RESTART_PREPARE, RESTART, POWER_OFF_PREPARE, POWER_OFF) and can ignore
> them at will? Calling through POWER_OFF_PREPARE would also return
> whether that POWER_OFF is possible (for kernel_can_power_off()).

I'm having trouble with parsing this comment. Could you please try to
rephrase it? I don't see how you could check whether power-off handler
is available if you'll mix all handlers together.

> I would also split this patch into preparation cleanups (like wrapping
> pm_power_off call with a function) and adding the notifier-based
> implementation.

What's the benefit of this split up will be? Are you suggesting that it
will ease reviewing of this patch or something else?


[PATCH v4 25/25] reboot: Remove pm_power_off_prepare()

2021-11-26 Thread Dmitry Osipenko
All pm_power_off_prepare() users were converted to sys-off handler API.
Remove the obsolete callback.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/pm.h |  1 -
 kernel/reboot.c| 11 ---
 2 files changed, 12 deletions(-)

diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1d8209c09686..d9bf1426f81e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -20,7 +20,6 @@
  * Callbacks for platform drivers to implement.
  */
 extern void (*pm_power_off)(void);
-extern void (*pm_power_off_prepare)(void);
 
 struct device; /* we have a circular dep with device.h */
 #ifdef CONFIG_VT_CONSOLE_SLEEP
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 4884204f9a31..a832bb660040 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -48,13 +48,6 @@ int reboot_cpu;
 enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
-/*
- * If set, this is used for preparing the system to power off.
- */
-
-void (*pm_power_off_prepare)(void);
-EXPORT_SYMBOL_GPL(pm_power_off_prepare);
-
 /**
  * emergency_restart - reboot the system
  *
@@ -807,10 +800,6 @@ void do_kernel_power_off(void)
 
 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(_off_handler_list, POWEROFF_PREPARE,
 NULL);
 }
-- 
2.33.1



[PATCH v4 24/25] regulator: pfuze100: Use devm_register_sys_off_handler()

2021-11-26 Thread Dmitry Osipenko
Use devm_register_sys_off_handler() that replaces global
pm_power_off_prepare variable and allows to register multiple
power-off handlers.

Acked-by: Mark Brown 
Signed-off-by: Dmitry Osipenko 
---
 drivers/regulator/pfuze100-regulator.c | 38 ++
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/drivers/regulator/pfuze100-regulator.c 
b/drivers/regulator/pfuze100-regulator.c
index d60d7d1b7fa2..2eca8d43a097 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -76,6 +77,7 @@ struct pfuze_chip {
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
struct pfuze_regulator *pfuze_regulators;
+   struct sys_off_handler sys_off;
 };
 
 static const int pfuze100_swbst[] = {
@@ -569,10 +571,10 @@ static inline struct device_node *match_of_node(int index)
return pfuze_matches[index].of_node;
 }
 
-static struct pfuze_chip *syspm_pfuze_chip;
-
-static void pfuze_power_off_prepare(void)
+static void pfuze_power_off_prepare(struct power_off_prep_data *data)
 {
+   struct pfuze_chip *syspm_pfuze_chip = data->cb_data;
+
dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
 
/* Switch from default mode: APS/APS to APS/Off */
@@ -611,24 +613,23 @@ static void pfuze_power_off_prepare(void)
 
 static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
 {
+   int err;
+
if (pfuze_chip->chip_id != PFUZE100) {
dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare 
handler for not supported chip\n");
return -ENODEV;
}
 
-   if (pm_power_off_prepare) {
-   dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already 
registered.\n");
-   return -EBUSY;
-   }
+   pfuze_chip->sys_off.power_off_prepare_cb = pfuze_power_off_prepare;
+   pfuze_chip->sys_off.cb_data = pfuze_chip;
 
-   if (syspm_pfuze_chip) {
-   dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
-   return -EBUSY;
+   err = devm_register_sys_off_handler(pfuze_chip->dev, 
_chip->sys_off);
+   if (err) {
+   dev_err(pfuze_chip->dev,
+   "failed to register sys-off handler: %d\n", err);
+   return err;
}
 
-   syspm_pfuze_chip = pfuze_chip;
-   pm_power_off_prepare = pfuze_power_off_prepare;
-
return 0;
 }
 
@@ -837,23 +838,12 @@ static int pfuze100_regulator_probe(struct i2c_client 
*client,
return 0;
 }
 
-static int pfuze100_regulator_remove(struct i2c_client *client)
-{
-   if (syspm_pfuze_chip) {
-   syspm_pfuze_chip = NULL;
-   pm_power_off_prepare = NULL;
-   }
-
-   return 0;
-}
-
 static struct i2c_driver pfuze_driver = {
.driver = {
.name = "pfuze100-regulator",
.of_match_table = pfuze_dt_ids,
},
.probe = pfuze100_regulator_probe,
-   .remove = pfuze100_regulator_remove,
 };
 module_i2c_driver(pfuze_driver);
 
-- 
2.33.1



[PATCH v4 23/25] ACPI: power: Switch to sys-off handler API

2021-11-26 Thread Dmitry Osipenko
Switch to sys-off API that replaces legacy pm_power_off callbacks.

Signed-off-by: Dmitry Osipenko 
---
 drivers/acpi/sleep.c | 25 +++--
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eaa47753b758..2e613fddd614 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -47,19 +47,11 @@ static void acpi_sleep_tts_switch(u32 acpi_state)
}
 }
 
-static int tts_notify_reboot(struct notifier_block *this,
-   unsigned long code, void *x)
+static void tts_reboot_prepare(struct reboot_prep_data *data)
 {
acpi_sleep_tts_switch(ACPI_STATE_S5);
-   return NOTIFY_DONE;
 }
 
-static struct notifier_block tts_notifier = {
-   .notifier_call  = tts_notify_reboot,
-   .next   = NULL,
-   .priority   = 0,
-};
-
 static int acpi_sleep_prepare(u32 acpi_state)
 {
 #ifdef CONFIG_ACPI_SLEEP
@@ -1020,7 +1012,7 @@ static void acpi_sleep_hibernate_setup(void)
 static inline void acpi_sleep_hibernate_setup(void) {}
 #endif /* !CONFIG_HIBERNATION */
 
-static void acpi_power_off_prepare(void)
+static void acpi_power_off_prepare(struct power_off_prep_data *data)
 {
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
@@ -1028,7 +1020,7 @@ static void acpi_power_off_prepare(void)
acpi_os_wait_events_complete();
 }
 
-static void acpi_power_off(void)
+static void acpi_power_off(struct power_off_data *data)
 {
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
pr_debug("%s called\n", __func__);
@@ -1036,6 +1028,11 @@ static void acpi_power_off(void)
acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
+static struct sys_off_handler acpi_sys_off_handler = {
+   .power_off_priority = POWEROFF_PRIO_FIRMWARE,
+   .reboot_prepare_cb = tts_reboot_prepare,
+};
+
 int __init acpi_sleep_init(void)
 {
char supported[ACPI_S_STATE_COUNT * 3 + 1];
@@ -1052,8 +1049,8 @@ int __init acpi_sleep_init(void)
 
if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
sleep_states[ACPI_STATE_S5] = 1;
-   pm_power_off_prepare = acpi_power_off_prepare;
-   pm_power_off = acpi_power_off;
+   acpi_sys_off_handler.power_off_cb = acpi_power_off;
+   acpi_sys_off_handler.power_off_prepare_cb = 
acpi_power_off_prepare;
} else {
acpi_no_s5 = true;
}
@@ -1069,6 +1066,6 @@ int __init acpi_sleep_init(void)
 * Register the tts_notifier to reboot notifier list so that the _TTS
 * object can also be evaluated when the system enters S5.
 */
-   register_reboot_notifier(_notifier);
+   register_sys_off_handler(_sys_off_handler);
return 0;
 }
-- 
2.33.1



[PATCH v4 22/25] memory: emif: Use kernel_can_power_off()

2021-11-26 Thread Dmitry Osipenko
Replace legacy pm_power_off with kernel_can_power_off() helper that
is aware about chained power-off handlers.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/emif.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 762d0c0f0716..cab10d5274a0 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -630,7 +630,7 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
dev_emerg(emif->dev, "SDRAM temperature exceeds operating 
limit.. Needs shut down!!!\n");
 
/* If we have Power OFF ability, use it, else try restarting */
-   if (pm_power_off) {
+   if (kernel_can_power_off()) {
kernel_power_off();
} else {
WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
-- 
2.33.1



[PATCH v4 21/25] nds32: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/nds32/kernel/process.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c
index 49fab9e39cbf..0936dcd7db1b 100644
--- a/arch/nds32/kernel/process.c
+++ b/arch/nds32/kernel/process.c
@@ -54,8 +54,7 @@ EXPORT_SYMBOL(machine_halt);
 
 void machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 EXPORT_SYMBOL(machine_power_off);
-- 
2.33.1



[PATCH v4 20/25] mips: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/mips/kernel/reset.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c
index 6288780b779e..e7ce07b3e79b 100644
--- a/arch/mips/kernel/reset.c
+++ b/arch/mips/kernel/reset.c
@@ -114,8 +114,7 @@ void machine_halt(void)
 
 void machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 
 #ifdef CONFIG_SMP
preempt_disable();
-- 
2.33.1



[PATCH v4 19/25] ia64: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/ia64/kernel/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 834df24a88f1..cee4d7db2143 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -599,8 +600,7 @@ machine_halt (void)
 void
 machine_power_off (void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
machine_halt();
 }
 
-- 
2.33.1



[PATCH v4 18/25] x86: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/x86/kernel/reboot.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 0a40df66a40d..cd7d9416d81a 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -747,10 +747,10 @@ static void native_machine_halt(void)
 
 static void native_machine_power_off(void)
 {
-   if (pm_power_off) {
+   if (kernel_can_power_off()) {
if (!reboot_force)
machine_shutdown();
-   pm_power_off();
+   do_kernel_power_off();
}
/* A fallback in case there is no PM info available */
tboot_shutdown(TB_SHUTDOWN_HALT);
-- 
2.33.1



[PATCH v4 17/25] sh: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/sh/kernel/reboot.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
index 5c33f036418b..e8eeedc9b182 100644
--- a/arch/sh/kernel/reboot.c
+++ b/arch/sh/kernel/reboot.c
@@ -46,8 +46,7 @@ static void native_machine_shutdown(void)
 
 static void native_machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 static void native_machine_halt(void)
-- 
2.33.1



[PATCH v4 16/25] m68k: Switch to new sys-off handler API

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use
register_power_off_handler() that registers power-off handlers and
do_kernel_power_off() that invokes chained power-off handlers. Legacy
pm_power_off() will be removed once all drivers will be converted to
the new power-off API.

Normally arch code should adopt only the do_kernel_power_off() at first,
but m68k is a special case because it uses pm_power_off() "inside out",
i.e. pm_power_off() invokes machine_power_off() [in fact it does nothing],
while it's machine_power_off() that should invoke the pm_power_off(), and
thus, we can't convert platforms to the new API separately. There are only
two platforms changed here, so it's not a big deal.

Acked-by: Geert Uytterhoeven 
Signed-off-by: Dmitry Osipenko 
---
 arch/m68k/emu/natfeat.c | 3 ++-
 arch/m68k/include/asm/machdep.h | 1 -
 arch/m68k/kernel/process.c  | 5 ++---
 arch/m68k/kernel/setup_mm.c | 1 -
 arch/m68k/kernel/setup_no.c | 1 -
 arch/m68k/mac/config.c  | 4 +++-
 6 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/m68k/emu/natfeat.c b/arch/m68k/emu/natfeat.c
index 71b78ecee75c..b19dc00026d9 100644
--- a/arch/m68k/emu/natfeat.c
+++ b/arch/m68k/emu/natfeat.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -90,5 +91,5 @@ void __init nf_init(void)
pr_info("NatFeats found (%s, %lu.%lu)\n", buf, version >> 16,
version & 0x);
 
-   mach_power_off = nf_poweroff;
+   register_platform_power_off(nf_poweroff);
 }
diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h
index 8fd80ef1b77e..8d8c3ee2069f 100644
--- a/arch/m68k/include/asm/machdep.h
+++ b/arch/m68k/include/asm/machdep.h
@@ -24,7 +24,6 @@ extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
-extern void (*mach_power_off)( void );
 extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
 extern void (*mach_hd_setup)(char *, int *);
 extern void (*mach_heartbeat) (int);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index a6030dbaa089..e160a7c57bd3 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -67,12 +67,11 @@ void machine_halt(void)
 
 void machine_power_off(void)
 {
-   if (mach_power_off)
-   mach_power_off();
+   do_kernel_power_off();
for (;;);
 }
 
-void (*pm_power_off)(void) = machine_power_off;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 void show_regs(struct pt_regs * regs)
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index 4b51bfd38e5f..50f4f120a4ff 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -98,7 +98,6 @@ EXPORT_SYMBOL(mach_get_rtc_pll);
 EXPORT_SYMBOL(mach_set_rtc_pll);
 void (*mach_reset)( void );
 void (*mach_halt)( void );
-void (*mach_power_off)( void );
 #ifdef CONFIG_HEARTBEAT
 void (*mach_heartbeat) (int);
 EXPORT_SYMBOL(mach_heartbeat);
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 5e4104f07a44..00bf82258233 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -55,7 +55,6 @@ int (*mach_hwclk) (int, struct rtc_time*);
 /* machine dependent reboot functions */
 void (*mach_reset)(void);
 void (*mach_halt)(void);
-void (*mach_power_off)(void);
 
 #ifdef CONFIG_M68000
 #if defined(CONFIG_M68328)
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 5d16f9b47aa9..727320dedf08 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -12,6 +12,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -139,7 +140,6 @@ void __init config_mac(void)
mach_hwclk = mac_hwclk;
mach_reset = mac_reset;
mach_halt = mac_poweroff;
-   mach_power_off = mac_poweroff;
 #if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
mach_beep = mac_mksound;
 #endif
@@ -159,6 +159,8 @@ void __init config_mac(void)
 
if (macintosh_config->ident == MAC_MODEL_IICI)
mach_l2_flush = via_l2_flush;
+
+   register_platform_power_off(mac_poweroff);
 }
 
 
-- 
2.33.1



[PATCH v4 15/25] powerpc: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Michael Ellerman 
Signed-off-by: Dmitry Osipenko 
---
 arch/powerpc/kernel/setup-common.c | 4 +---
 arch/powerpc/xmon/xmon.c   | 3 +--
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/kernel/setup-common.c 
b/arch/powerpc/kernel/setup-common.c
index 4f1322b65760..71c4ccd9bbb1 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -161,9 +161,7 @@ void machine_restart(char *cmd)
 void machine_power_off(void)
 {
machine_shutdown();
-   if (pm_power_off)
-   pm_power_off();
-
+   do_kernel_power_off();
smp_send_stop();
machine_hang();
 }
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 83100c6524cc..759e167704e6 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1243,8 +1243,7 @@ static void bootcmds(void)
} else if (cmd == 'h') {
ppc_md.halt();
} else if (cmd == 'p') {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
}
 }
 
-- 
2.33.1



[PATCH v4 14/25] xen/x86: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Juergen Gross 
Signed-off-by: Dmitry Osipenko 
---
 arch/x86/xen/enlighten_pv.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 5004feb16783..527fa545eb1f 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -1068,8 +1069,7 @@ static void xen_machine_halt(void)
 
 static void xen_machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
xen_reboot(SHUTDOWN_poweroff);
 }
 
-- 
2.33.1



[PATCH v4 13/25] parisc: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Helge Deller  # parisc
Signed-off-by: Dmitry Osipenko 
---
 arch/parisc/kernel/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index ea3d83b6fb62..928201b1f58f 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -114,8 +115,7 @@ void machine_power_off(void)
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
 
/* ipmi_poweroff may have been installed. */
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();

/* It seems we have no way to power the system off via
 * software. The user has to press the button himself. */
-- 
2.33.1



[PATCH v4 12/25] arm64: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Catalin Marinas 
Signed-off-by: Dmitry Osipenko 
---
 arch/arm64/kernel/process.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index aacf2f5559a8..f8db031afa7d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -110,8 +110,7 @@ void machine_power_off(void)
 {
local_irq_disable();
smp_send_stop();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 /*
-- 
2.33.1



[PATCH v4 11/25] riscv: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Palmer Dabbelt 
Signed-off-by: Dmitry Osipenko 
---
 arch/riscv/kernel/reset.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c
index 9c842c41684a..912288572226 100644
--- a/arch/riscv/kernel/reset.c
+++ b/arch/riscv/kernel/reset.c
@@ -23,16 +23,12 @@ void machine_restart(char *cmd)
 
 void machine_halt(void)
 {
-   if (pm_power_off != NULL)
-   pm_power_off();
-   else
-   default_power_off();
+   do_kernel_power_off();
+   default_power_off();
 }
 
 void machine_power_off(void)
 {
-   if (pm_power_off != NULL)
-   pm_power_off();
-   else
-   default_power_off();
+   do_kernel_power_off();
+   default_power_off();
 }
-- 
2.33.1



[PATCH v4 10/25] csky: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Guo Ren 
Signed-off-by: Dmitry Osipenko 
---
 arch/csky/kernel/power.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/csky/kernel/power.c b/arch/csky/kernel/power.c
index 923ee4e381b8..86ee202906f8 100644
--- a/arch/csky/kernel/power.c
+++ b/arch/csky/kernel/power.c
@@ -9,16 +9,14 @@ EXPORT_SYMBOL(pm_power_off);
 void machine_power_off(void)
 {
local_irq_disable();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
asm volatile ("bkpt");
 }
 
 void machine_halt(void)
 {
local_irq_disable();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
asm volatile ("bkpt");
 }
 
-- 
2.33.1



[PATCH v4 09/25] ARM: Use do_kernel_power_off()

2021-11-26 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Reviewed-by: Russell King (Oracle) 
Signed-off-by: Dmitry Osipenko 
---
 arch/arm/kernel/reboot.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
index 3044fcb8d073..2cb943422554 100644
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -116,9 +116,7 @@ void machine_power_off(void)
 {
local_irq_disable();
smp_send_stop();
-
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 /*
-- 
2.33.1



[PATCH v4 08/25] kernel: Add combined power-off+restart handler call chain API

2021-11-26 Thread Dmitry Osipenko
SoC platforms often have multiple ways of how to perform system's
power-off and restart operations. Meanwhile today's kernel is limited to
a single option. Add combined power-off+restart handler call chain API,
which is inspired by the restart API. The new API provides both power-off
and restart functionality.

The old pm_power_off method will be kept around till all users are
converted to the new API.

Current restart API will be replaced by the new unified API since
new API is its superset. The restart functionality of the sys-off handler
API is built upon the existing restart-notifier APIs.

In order to ease conversion to the new API, convenient helpers are added
for the common use-cases. They will reduce amount of boilerplate code and
remove global variables. These helpers preserve old behaviour for cases
where only one power-off handler is expected, this is what all existing
drivers want, and thus, they could be easily converted to the new API.
Users of the new API should explicitly enable power-off chaining by
setting corresponding flag of the power_handler structure.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h   | 265 ++-
 kernel/power/hibernate.c |   2 +-
 kernel/reboot.c  | 536 ++-
 3 files changed, 795 insertions(+), 8 deletions(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index b7fa25726323..76799bb3a560 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -8,10 +8,35 @@
 
 struct device;
 
-#define SYS_DOWN   0x0001  /* Notify of system down */
-#define SYS_RESTARTSYS_DOWN
-#define SYS_HALT   0x0002  /* Notify of system halt */
-#define SYS_POWER_OFF  0x0003  /* Notify of system power off */
+enum reboot_prepare_mode {
+   SYS_DOWN = 1,   /* Notify of system down */
+   SYS_RESTART = SYS_DOWN,
+   SYS_HALT,   /* Notify of system halt */
+   SYS_POWER_OFF,  /* Notify of system power off */
+};
+
+/*
+ * Standard restart priority levels. Intended to be set in the
+ * sys_off_handler.restart_priority field.
+ *
+ * Use `RESTART_PRIO_ABC +- prio` style for additional levels.
+ *
+ * RESTART_PRIO_RESERVED:  Falls back to RESTART_PRIO_DEFAULT.
+ * Drivers may leave priority initialized
+ * to zero, to auto-set it to the default level.
+ *
+ * RESTART_PRIO_LOW:   Use this for handler of last resort.
+ *
+ * RESTART_PRIO_DEFAULT:   Use this for default/generic handler.
+ *
+ * RESTART_PRIO_HIGH:  Use this if you have multiple handlers and
+ * this handler has higher priority than the
+ * default handler.
+ */
+#define RESTART_PRIO_RESERVED  0
+#define RESTART_PRIO_LOW   8
+#define RESTART_PRIO_DEFAULT   128
+#define RESTART_PRIO_HIGH  192
 
 enum reboot_mode {
REBOOT_UNDEFINED = -1,
@@ -49,6 +74,237 @@ int register_restart_handler(struct notifier_block *);
 int unregister_restart_handler(struct notifier_block *);
 void do_kernel_restart(char *cmd);
 
+/*
+ * System power-off and restart API.
+ */
+
+/*
+ * Standard power-off priority levels. Intended to be set in the
+ * sys_off_handler.power_off_priority field.
+ *
+ * Use `POWEROFF_PRIO_ABC +- prio` style for additional levels.
+ *
+ * POWEROFF_PRIO_RESERVED: Falls back to POWEROFF_PRIO_DEFAULT.
+ * Drivers may leave priority initialized
+ * to zero, to auto-set it to the default level.
+ *
+ * POWEROFF_PRIO_PLATFORM: Intended to be used by platform-level handler.
+ * Has lowest priority since device drivers are
+ * expected to take over platform handler which
+ * doesn't allow further callback chaining.
+ *
+ * POWEROFF_PRIO_DEFAULT:  Use this for default/generic handler.
+ *
+ * POWEROFF_PRIO_FIRMWARE: Use this if handler uses firmware call.
+ * Has highest priority since firmware is expected
+ * to know best how to power-off hardware properly.
+ */
+#define POWEROFF_PRIO_RESERVED 0
+#define POWEROFF_PRIO_PLATFORM 1
+#define POWEROFF_PRIO_DEFAULT  128
+#define POWEROFF_PRIO_HIGH 192
+#define POWEROFF_PRIO_FIRMWARE 224
+
+enum poweroff_mode {
+   POWEROFF_NORMAL = 0,
+   POWEROFF_PREPARE,
+};
+
+/**
+ * struct power_off_data - Power-off callback argument
+ *
+ * @cb_data: Callback data.
+ */
+struct power_off_data {
+   void *cb_data;
+};
+
+/**
+ * struct power_off_prep_data - Power-off preparation callback argument
+ *
+ * @cb_data: Callback data.
+ */
+struct power_off_prep_data {
+   void *cb_data;
+};
+
+/**
+ * struct restart_data - Restart callback argument
+ *
+ * @cb_data: Callback data.
+ * @cmd: Restart command string

[PATCH v4 07/25] reboot: Remove extern annotation from function prototypes

2021-11-26 Thread Dmitry Osipenko
There is no need to annotate function prototypes with 'extern', it makes
code less readable. Remove unnecessary annotations from .

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h | 38 +++---
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 7c288013a3ca..b7fa25726323 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -40,36 +40,36 @@ extern int reboot_cpu;
 extern int reboot_force;
 
 
-extern int register_reboot_notifier(struct notifier_block *);
-extern int unregister_reboot_notifier(struct notifier_block *);
+int register_reboot_notifier(struct notifier_block *);
+int unregister_reboot_notifier(struct notifier_block *);
 
-extern int devm_register_reboot_notifier(struct device *, struct 
notifier_block *);
+int devm_register_reboot_notifier(struct device *, struct notifier_block *);
 
-extern int register_restart_handler(struct notifier_block *);
-extern int unregister_restart_handler(struct notifier_block *);
-extern void do_kernel_restart(char *cmd);
+int register_restart_handler(struct notifier_block *);
+int unregister_restart_handler(struct notifier_block *);
+void do_kernel_restart(char *cmd);
 
 /*
  * Architecture-specific implementations of sys_reboot commands.
  */
 
-extern void migrate_to_reboot_cpu(void);
-extern void machine_restart(char *cmd);
-extern void machine_halt(void);
-extern void machine_power_off(void);
+void migrate_to_reboot_cpu(void);
+void machine_restart(char *cmd);
+void machine_halt(void);
+void machine_power_off(void);
 
-extern void machine_shutdown(void);
+void machine_shutdown(void);
 struct pt_regs;
-extern void machine_crash_shutdown(struct pt_regs *);
+void machine_crash_shutdown(struct pt_regs *);
 
 /*
  * Architecture independent implementations of sys_reboot commands.
  */
 
-extern void kernel_restart_prepare(char *cmd);
-extern void kernel_restart(char *cmd);
-extern void kernel_halt(void);
-extern void kernel_power_off(void);
+void kernel_restart_prepare(char *cmd);
+void kernel_restart(char *cmd);
+void kernel_halt(void);
+void kernel_power_off(void);
 
 extern int C_A_D; /* for sysctl */
 void ctrl_alt_del(void);
@@ -77,15 +77,15 @@ void ctrl_alt_del(void);
 #define POWEROFF_CMD_PATH_LEN  256
 extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
 
-extern void orderly_poweroff(bool force);
-extern void orderly_reboot(void);
+void orderly_poweroff(bool force);
+void orderly_reboot(void);
 void hw_protection_shutdown(const char *reason, int ms_until_forced);
 
 /*
  * Emergency restart, callable from an interrupt handler.
  */
 
-extern void emergency_restart(void);
+void emergency_restart(void);
 #include 
 
 #endif /* _LINUX_REBOOT_H */
-- 
2.33.1



[PATCH v4 06/25] reboot: Warn if unregister_restart_handler() fails

2021-11-26 Thread Dmitry Osipenko
Emit warning if unregister_restart_handler() fails since it never should
fail. This will ease further API development by catching mistakes early.

Signed-off-by: Dmitry Osipenko 
---
 kernel/reboot.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index e6659ae329f1..f0e7b9c13f6b 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -210,7 +210,7 @@ EXPORT_SYMBOL(register_restart_handler);
  */
 int unregister_restart_handler(struct notifier_block *nb)
 {
-   return atomic_notifier_chain_unregister(_handler_list, nb);
+   return WARN_ON(atomic_notifier_chain_unregister(_handler_list, 
nb));
 }
 EXPORT_SYMBOL(unregister_restart_handler);
 
-- 
2.33.1



[PATCH v4 05/25] reboot: Warn if restart handler has duplicated priority

2021-11-26 Thread Dmitry Osipenko
Add sanity check which ensures that there are no two restart handlers
registered with the same priority. Normally it's a direct sign of a
problem if two handlers use the same priority.

Signed-off-by: Dmitry Osipenko 
---
 kernel/reboot.c | 15 ++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index 6bcc5d6a6572..e6659ae329f1 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -182,7 +182,20 @@ static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
  */
 int register_restart_handler(struct notifier_block *nb)
 {
-   return atomic_notifier_chain_register(_handler_list, nb);
+   int ret;
+
+   ret = atomic_notifier_chain_register(_handler_list, nb);
+   if (ret)
+   return ret;
+
+   /*
+* Handler must have unique priority. Otherwise call order is
+* determined by registration order, which is unreliable.
+*/
+   WARN(!atomic_notifier_has_unique_priority(_handler_list, nb),
+"restart handler must have unique priority\n");
+
+   return 0;
 }
 EXPORT_SYMBOL(register_restart_handler);
 
-- 
2.33.1



[PATCH v4 04/25] reboot: Correct typo in a comment

2021-11-26 Thread Dmitry Osipenko
Correct s/implemenations/implementations/ in .

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index af907a3d68d1..7c288013a3ca 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -63,7 +63,7 @@ struct pt_regs;
 extern void machine_crash_shutdown(struct pt_regs *);
 
 /*
- * Architecture independent implemenations of sys_reboot commands.
+ * Architecture independent implementations of sys_reboot commands.
  */
 
 extern void kernel_restart_prepare(char *cmd);
-- 
2.33.1



[PATCH v4 03/25] notifier: Add atomic/blocking_notifier_has_unique_priority()

2021-11-26 Thread Dmitry Osipenko
Add atomic/blocking_notifier_has_unique_priority() helpers which return
true if given handler has unique priority.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h |  5 +++
 kernel/notifier.c| 69 
 2 files changed, 74 insertions(+)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 924c9d7c8e73..2c4036f225e1 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -175,6 +175,11 @@ int raw_notifier_call_chain_robust(struct 
raw_notifier_head *nh,
 
 bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh);
 
+bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
+   struct notifier_block *nb);
+bool blocking_notifier_has_unique_priority(struct blocking_notifier_head *nh,
+   struct notifier_block *nb);
+
 #define NOTIFY_DONE0x  /* Don't care */
 #define NOTIFY_OK  0x0001  /* Suits me */
 #define NOTIFY_STOP_MASK   0x8000  /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index b20cb7b9b1f0..7a325b742104 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -122,6 +122,19 @@ static int notifier_call_chain_robust(struct 
notifier_block **nl,
return ret;
 }
 
+static int notifier_has_unique_priority(struct notifier_block **nl,
+   struct notifier_block *n)
+{
+   while (*nl && (*nl)->priority >= n->priority) {
+   if ((*nl)->priority == n->priority && *nl != n)
+   return false;
+
+   nl = &((*nl)->next);
+   }
+
+   return true;
+}
+
 /*
  * Atomic notifier chain routines.  Registration and unregistration
  * use a spinlock, and call_chain is synchronized by RCU (no locks).
@@ -203,6 +216,30 @@ int atomic_notifier_call_chain(struct atomic_notifier_head 
*nh,
 EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 NOKPROBE_SYMBOL(atomic_notifier_call_chain);
 
+/**
+ * atomic_notifier_has_unique_priority - Checks whether notifier's 
priority is unique
+ * @nh: Pointer to head of the atomic notifier chain
+ * @n: Entry in notifier chain to check
+ *
+ * Checks whether there is another notifier in the chain with the same 
priority.
+ * Must be called in process context.
+ *
+ * Returns true if priority is unique, false otherwise.
+ */
+bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
+   struct notifier_block *n)
+{
+   unsigned long flags;
+   bool ret;
+
+   spin_lock_irqsave(>lock, flags);
+   ret = notifier_has_unique_priority(>head, n);
+   spin_unlock_irqrestore(>lock, flags);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(atomic_notifier_has_unique_priority);
+
 /*
  * Blocking notifier chain routines.  All access to the chain is
  * synchronized by an rwsem.
@@ -336,6 +373,38 @@ bool blocking_notifier_call_chain_is_empty(struct 
blocking_notifier_head *nh)
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_is_empty);
 
+/**
+ * blocking_notifier_has_unique_priority - Checks whether notifier's 
priority is unique
+ * @nh: Pointer to head of the blocking notifier chain
+ * @n: Entry in notifier chain to check
+ *
+ * Checks whether there is another notifier in the chain with the same 
priority.
+ * Must be called in process context.
+ *
+ * Returns true if priority is unique, false otherwise.
+ */
+bool blocking_notifier_has_unique_priority(struct blocking_notifier_head *nh,
+   struct notifier_block *n)
+{
+   bool ret;
+
+   /*
+* This code gets used during boot-up, when task switching is
+* not yet working and interrupts must remain disabled. At such
+* times we must not call down_read().
+*/
+   if (system_state != SYSTEM_BOOTING)
+   down_read(>rwsem);
+
+   ret = notifier_has_unique_priority(>head, n);
+
+   if (system_state != SYSTEM_BOOTING)
+   up_read(>rwsem);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_has_unique_priority);
+
 /*
  * Raw notifier chain routines.  There is no protection;
  * the caller must provide it.  Use at your own risk!
-- 
2.33.1



[PATCH v4 02/25] notifier: Add blocking_notifier_call_chain_is_empty()

2021-11-26 Thread Dmitry Osipenko
Add blocking_notifier_call_chain_is_empty() that returns true if call
chain is empty.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h |  2 ++
 kernel/notifier.c| 14 ++
 2 files changed, 16 insertions(+)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 4b80a815b666..924c9d7c8e73 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -173,6 +173,8 @@ int blocking_notifier_call_chain_robust(struct 
blocking_notifier_head *nh,
 int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
 
+bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh);
+
 #define NOTIFY_DONE0x  /* Don't care */
 #define NOTIFY_OK  0x0001  /* Suits me */
 #define NOTIFY_STOP_MASK   0x8000  /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index b8251dc0bc0f..b20cb7b9b1f0 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -322,6 +322,20 @@ int blocking_notifier_call_chain(struct 
blocking_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
+/**
+ * blocking_notifier_call_chain_is_empty - Check whether notifier chain is 
empty
+ * @nh: Pointer to head of the blocking notifier chain
+ *
+ * Checks whether notifier chain is empty.
+ *
+ * Returns true is notifier chain is empty, false otherwise.
+ */
+bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh)
+{
+   return !rcu_access_pointer(nh->head);
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_is_empty);
+
 /*
  * Raw notifier chain routines.  There is no protection;
  * the caller must provide it.  Use at your own risk!
-- 
2.33.1



[PATCH v4 01/25] notifier: Remove extern annotation from function prototypes

2021-11-26 Thread Dmitry Osipenko
There is no need to annotate function prototypes with 'extern', it makes
code less readable. Remove unnecessary annotations from .

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h | 30 +++---
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 87069b8459af..4b80a815b666 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -90,7 +90,7 @@ struct srcu_notifier_head {
} while (0)
 
 /* srcu_notifier_heads must be cleaned up dynamically */
-extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
+void srcu_init_notifier_head(struct srcu_notifier_head *nh);
 #define srcu_cleanup_notifier_head(name)   \
cleanup_srcu_struct(&(name)->srcu);
 
@@ -141,36 +141,36 @@ extern void srcu_init_notifier_head(struct 
srcu_notifier_head *nh);
 
 #ifdef __KERNEL__
 
-extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *nb);
-extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);
-extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
+int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *nb);
-extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *nb);
 
-extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
struct notifier_block *nb);
-extern int blocking_notifier_chain_unregister(struct blocking_notifier_head 
*nh,
+int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *nb);
-extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
struct notifier_block *nb);
-extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
struct notifier_block *nb);
 
-extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v);
-extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v);
-extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
+int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v);
-extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
unsigned long val, void *v);
 
-extern int blocking_notifier_call_chain_robust(struct blocking_notifier_head 
*nh,
+int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
-extern int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
+int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
 
 #define NOTIFY_DONE0x  /* Don't care */
-- 
2.33.1



[PATCH v4 00/25] Introduce power-off+restart call chain API

2021-11-26 Thread Dmitry Osipenko
Problem
---

SoC devices require power-off call chaining functionality from kernel.
We have a widely used restart chaining provided by restart notifier API,
but nothing for power-off.

Solution


Introduce new API that provides both restart and power-off call chains.

Why combine restart with power-off? Because drivers often do both.
More practical to have API that provides both under the same roof.

The new API is designed with simplicity and extensibility in mind.
It's built upon the existing restart and reboot APIs. The simplicity
is in new helper functions that are convenient for drivers. The
extensibility is in the design that doesn't hardcode callback
arguments, making easy to add new parameters and remove old.

This is a third attempt to introduce the new API. First was made by
Guenter Roeck back in 2014, second was made by Thierry Reding in 2017.
In fact the work didn't stop and recently arm_pm_restart() was removed
from v5.14 kernel, which was a part of preparatory work started by
Guenter Roeck. I took into account experience and ideas from the
previous attempts, extended and polished them.

Adoption plan
-

This patchset introduces the new API. It also converts multiple drivers
and arch code to the new API to demonstrate how it all looks in practice.

The plan is:

1. Merge new API (patches 1-8). This API will co-exist with the old APIs.

2. Convert arch code to do_kernel_power_off() (patches 9-21).

3. Convert drivers and platform code to the new API.

4. Remove obsolete pm_power_off and pm_power_off_prepare variables.

5. Make restart-notifier API private to kernel/reboot.c once no users left.

It's fully implemented here:

[1] https://github.com/grate-driver/linux/commits/sys-off-handler

For now I'm sending only the first 25 base patches out of ~180. It's
preferable to squash 1-2, partially 3 and 4 points of the plan into a
single patchset to ease and speed up applying of the rest of the patches.
Majority of drivers and platform patches depend on the base, hence they
will come later (and per subsystem), once base will land.

All [1] patches are compile-tested. Tegra and x86 ACPI patches are tested
on hardware. The remaining should be covered by unit tests (unpublished).

Results
---

1. Devices can be powered off properly.

2. Global variables are removed from drivers.

3. Global pm_power_off and pm_power_off_prepare callback variables are
removed once all users are converted to the new API. The latter callback
is removed by patch #25 of this series.

4. Ambiguous call chain ordering is prohibited. See patch #5 which adds
verification of restart handlers priorities, ensuring that they are unique.

Changelog:

v4: - Made a very minor improvement to doc comments, clarifying couple
  default values.

- Corrected list of emails recipient by adding Linus, Sebastian,
  Philipp and more NDS people. Removed bouncing emails.

- Added acks that were given to v3.

v3: - Renamed power_handler to sys_off_handler as was suggested by
  Rafael Wysocki.

- Improved doc-comments as was suggested by Rafael Wysocki. Added more
  doc-comments.

- Implemented full set of 180 patches which convert whole kernel in
  accordance to the plan, see link [1] above. Slightly adjusted API to
  better suit for the remaining converted drivers.

  * Added unregister_sys_off_handler() that is handy for a couple old
platform drivers.

  * Dropped devm_register_trivial_restart_handler(), 'simple' variant
is enough to have.

- Improved "Add atomic/blocking_notifier_has_unique_priority()" patch,
  as was suggested by Andy Shevchenko. Also replaced down_write() with
  down_read() and factored out common notifier_has_unique_priority().

- Added stop_chain field to struct restart_data and reboot_prep_data
  after discovering couple drivers wanting that feature.

- Added acks that were given to v2.

v2: - Replaced standalone power-off call chain demo-API with the combined
  power-off+restart API because this is what drivers want. It's a more
  comprehensive solution.

- Converted multiple drivers and arch code to the new API. Suggested by
  Andy Shevchenko. I skimmed through the rest of drivers, verifying that
  new API suits them. The rest of the drivers will be converted once we
  will settle on the new API, otherwise will be too many patches here.

- v2 API doesn't expose notifier to users and require handlers to
  have unique priority. Suggested by Guenter Roeck.

- v2 API has power-off chaining disabled by default and require
  drivers to explicitly opt-in to the chaining. This preserves old
  behaviour for existing drivers once they are converted to the new
  API.

Dmitry Osipenko (25):
  notifier: Remove extern annotation from function prototypes
  notifier: Add blocking_notifier_call_chain_is_empty()
  notifier: Add atomic/blocking_notifier_has_uniqu

Re: [PATCH v2 27/45] mfd: ntxec: Use devm_register_power_handler()

2021-11-10 Thread Dmitry Osipenko
10.11.2021 13:43, Jonathan Neuschäfer пишет:
> On Mon, Nov 08, 2021 at 02:36:42PM +0300, Dmitry Osipenko wrote:
>> 08.11.2021 14:22, Jonathan Neuschäfer пишет:
>>> On Sun, Nov 07, 2021 at 08:42:33PM +0300, Dmitry Osipenko wrote:
>>> [...]
>>>> EC drivers tend to use higher priority in general. Jonathan, could you
>>>> please confirm that NTXEC driver is a more preferable restart method
>>>> than the watchdog?
>>>
>>> Yes. The original firmware uses the NTXEC to restart, and it works well,
>>> so I do think it's preferable.
>>
>> Thank you, then I'll update the NTXEC patch like this:
>>
>> https://github.com/grate-driver/linux/commit/22da3d91f1734d9a0ed036220ad4ea28465af988
> 
> I tested again, but sys_off_handler_reboot called a bogus pointer
> (probably reboot_prepare_cb). I think it was left uninitialized in
> ntxec_probe, which uses devm_kmalloc. I guess we could switch it to
> devm_kzalloc:
> 
> diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
> index 1f55dfce14308..30364beb4b1d0 100644
> --- a/drivers/mfd/ntxec.c
> +++ b/drivers/mfd/ntxec.c
> @@ -144,7 +144,7 @@ static int ntxec_probe(struct i2c_client *client)
>   const struct mfd_cell *subdevs;
>   size_t n_subdevs;
>  
> - ec = devm_kmalloc(>dev, sizeof(*ec), GFP_KERNEL);
> + ec = devm_kzalloc(>dev, sizeof(*ec), GFP_KERNEL);
>   if (!ec)
>   return -ENOMEM;
>  
> 
> 
> With that done, it works flawlessly.

Good catch, thank you! I'll correct this patch and add yours t-b.



Re: [PATCH v2 27/45] mfd: ntxec: Use devm_register_power_handler()

2021-11-08 Thread Dmitry Osipenko
08.11.2021 14:22, Jonathan Neuschäfer пишет:
> On Sun, Nov 07, 2021 at 08:42:33PM +0300, Dmitry Osipenko wrote:
> [...]
>> EC drivers tend to use higher priority in general. Jonathan, could you
>> please confirm that NTXEC driver is a more preferable restart method
>> than the watchdog?
> 
> Yes. The original firmware uses the NTXEC to restart, and it works well,
> so I do think it's preferable.

Thank you, then I'll update the NTXEC patch like this:

https://github.com/grate-driver/linux/commit/22da3d91f1734d9a0ed036220ad4ea28465af988



Re: [PATCH v3 00/25] Introduce power-off+restart call chain API

2021-11-07 Thread Dmitry Osipenko
08.11.2021 03:44, Dmitry Osipenko пишет:
> Problem
> ---
> 
> SoC devices require power-off call chaining functionality from kernel.
> We have a widely used restart chaining provided by restart notifier API,
> but nothing for power-off.
> 
> Solution
> 
> 
> Introduce new API that provides both restart and power-off call chains.
> 
> Why combine restart with power-off? Because drivers often do both.
> More practical to have API that provides both under the same roof.
> 
> The new API is designed with simplicity and extensibility in mind.
> It's built upon the existing restart and reboot APIs. The simplicity
> is in new helper functions that are convenient for drivers. The
> extensibility is in the design that doesn't hardcode callback
> arguments, making easy to add new parameters and remove old.
> 
> This is a third attempt to introduce the new API. First was made by
> Guenter Roeck back in 2014, second was made by Thierry Reding in 2017.
> In fact the work didn't stop and recently arm_pm_restart() was removed
> from v5.14 kernel, which was a part of preparatory work started by
> Guenter Roeck. I took into account experience and ideas from the
> previous attempts, extended and polished them.
> 
> Adoption plan
> -
> 
> This patchset introduces the new API. It also converts multiple drivers
> and arch code to the new API to demonstrate how it all looks in practice.
> 
> The plan is:
> 
> 1. Merge new API (patches 1-8). This API will co-exist with the old APIs.
> 
> 2. Convert arch code to do_kernel_power_off() (patches 9-21).
> 
> 3. Convert drivers and platform code to the new API.
> 
> 4. Remove obsolete pm_power_off and pm_power_off_prepare variables.
> 
> 5. Make restart-notifier API private to kernel/reboot.c once no users left.
> 
> It's fully implemented here:
> 
> [1] https://github.com/grate-driver/linux/commits/sys-off-handler
> 
> For now I'm sending only the first 25 base patches out of ~180. It's
> preferable to squash 1-2, partially 3 and 4 points of the plan into a
> single patchset to ease and speed up applying of the rest of the patches.
> Majority of drivers and platform patches depend on the base, hence they
> will come later (and per subsystem), once base will land.
> 
> All [1] patches are compile-tested. Tegra and x86 ACPI patches are tested
> on hardware. The remaining should be covered by unit tests (unpublished).
> 
> Results
> ---
> 
> 1. Devices can be powered off properly.
> 
> 2. Global variables are removed from drivers.
> 
> 3. Global pm_power_off and pm_power_off_prepare callback variables are
> removed once all users are converted to the new API. The latter callback
> is removed by patch #25 of this series.
> 
> 4. Ambiguous call chain ordering is prohibited. See patch #5 which adds
> verification of restart handlers priorities, ensuring that they are unique.
> 
> Changelog:
> 
> v3: - Renamed power_handler to sys_off_handler as was suggested by
>   Rafael Wysocki.
> 
> - Improved doc-comments as was suggested by Rafael Wysocki. Added more
>   doc-comments.
> 
> - Implemented full set of 180 patches which convert whole kernel in
>   accordance to the plan, see link [1] above. Slightly adjusted API to
>   better suit for the remaining converted drivers.
> 
>   * Added unregister_sys_off_handler() that is handy for a couple old
> platform drivers.
> 
>   * Dropped devm_register_trivial_restart_handler(), 'simple' variant
> is enough to have.
> 
> - Improved "Add atomic/blocking_notifier_has_unique_priority()" patch,
>   as was suggested by Andy Shevchenko. Also replaced down_write() with
>   down_read() and factored out common notifier_has_unique_priority().
> 
> - Added stop_chain field to struct restart_data and reboot_prep_data
>   after discovering couple drivers wanting that feature.
> 
> - Added acks that were given to v2.
> 
> v2: - Replaced standalone power-off call chain demo-API with the combined
>   power-off+restart API because this is what drivers want. It's a more
>   comprehensive solution.
> 
> - Converted multiple drivers and arch code to the new API. Suggested by
>   Andy Shevchenko. I skimmed through the rest of drivers, verifying that
>   new API suits them. The rest of the drivers will be converted once we
>   will settle on the new API, otherwise will be too many patches here.
> 
> - v2 API doesn't expose notifier to users and require handlers to
>   have unique priority. Suggested by Guenter Roeck.
> 
> - v2 API has power-off chaining disabled by defa

[PATCH v3 25/25] reboot: Remove pm_power_off_prepare()

2021-11-07 Thread Dmitry Osipenko
All pm_power_off_prepare() users were converted to sys-off handler API.
Remove the obsolete callback.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/pm.h |  1 -
 kernel/reboot.c| 11 ---
 2 files changed, 12 deletions(-)

diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1d8209c09686..d9bf1426f81e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -20,7 +20,6 @@
  * Callbacks for platform drivers to implement.
  */
 extern void (*pm_power_off)(void);
-extern void (*pm_power_off_prepare)(void);
 
 struct device; /* we have a circular dep with device.h */
 #ifdef CONFIG_VT_CONSOLE_SLEEP
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 4884204f9a31..a832bb660040 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -48,13 +48,6 @@ int reboot_cpu;
 enum reboot_type reboot_type = BOOT_ACPI;
 int reboot_force;
 
-/*
- * If set, this is used for preparing the system to power off.
- */
-
-void (*pm_power_off_prepare)(void);
-EXPORT_SYMBOL_GPL(pm_power_off_prepare);
-
 /**
  * emergency_restart - reboot the system
  *
@@ -807,10 +800,6 @@ void do_kernel_power_off(void)
 
 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(_off_handler_list, POWEROFF_PREPARE,
 NULL);
 }
-- 
2.33.1



[PATCH v3 24/25] regulator: pfuze100: Use devm_register_sys_off_handler()

2021-11-07 Thread Dmitry Osipenko
Use devm_register_sys_off_handler() that replaces global
pm_power_off_prepare variable and allows to register multiple
power-off handlers.

Acked-by: Mark Brown 
Signed-off-by: Dmitry Osipenko 
---
 drivers/regulator/pfuze100-regulator.c | 38 ++
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/drivers/regulator/pfuze100-regulator.c 
b/drivers/regulator/pfuze100-regulator.c
index d60d7d1b7fa2..2eca8d43a097 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -76,6 +77,7 @@ struct pfuze_chip {
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
struct pfuze_regulator *pfuze_regulators;
+   struct sys_off_handler sys_off;
 };
 
 static const int pfuze100_swbst[] = {
@@ -569,10 +571,10 @@ static inline struct device_node *match_of_node(int index)
return pfuze_matches[index].of_node;
 }
 
-static struct pfuze_chip *syspm_pfuze_chip;
-
-static void pfuze_power_off_prepare(void)
+static void pfuze_power_off_prepare(struct power_off_prep_data *data)
 {
+   struct pfuze_chip *syspm_pfuze_chip = data->cb_data;
+
dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
 
/* Switch from default mode: APS/APS to APS/Off */
@@ -611,24 +613,23 @@ static void pfuze_power_off_prepare(void)
 
 static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
 {
+   int err;
+
if (pfuze_chip->chip_id != PFUZE100) {
dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare 
handler for not supported chip\n");
return -ENODEV;
}
 
-   if (pm_power_off_prepare) {
-   dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already 
registered.\n");
-   return -EBUSY;
-   }
+   pfuze_chip->sys_off.power_off_prepare_cb = pfuze_power_off_prepare;
+   pfuze_chip->sys_off.cb_data = pfuze_chip;
 
-   if (syspm_pfuze_chip) {
-   dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
-   return -EBUSY;
+   err = devm_register_sys_off_handler(pfuze_chip->dev, 
_chip->sys_off);
+   if (err) {
+   dev_err(pfuze_chip->dev,
+   "failed to register sys-off handler: %d\n", err);
+   return err;
}
 
-   syspm_pfuze_chip = pfuze_chip;
-   pm_power_off_prepare = pfuze_power_off_prepare;
-
return 0;
 }
 
@@ -837,23 +838,12 @@ static int pfuze100_regulator_probe(struct i2c_client 
*client,
return 0;
 }
 
-static int pfuze100_regulator_remove(struct i2c_client *client)
-{
-   if (syspm_pfuze_chip) {
-   syspm_pfuze_chip = NULL;
-   pm_power_off_prepare = NULL;
-   }
-
-   return 0;
-}
-
 static struct i2c_driver pfuze_driver = {
.driver = {
.name = "pfuze100-regulator",
.of_match_table = pfuze_dt_ids,
},
.probe = pfuze100_regulator_probe,
-   .remove = pfuze100_regulator_remove,
 };
 module_i2c_driver(pfuze_driver);
 
-- 
2.33.1



[PATCH v3 23/25] ACPI: power: Switch to sys-off handler API

2021-11-07 Thread Dmitry Osipenko
Switch to sys-off API that replaces legacy pm_power_off callbacks.

Signed-off-by: Dmitry Osipenko 
---
 drivers/acpi/sleep.c | 25 +++--
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eaa47753b758..2e613fddd614 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -47,19 +47,11 @@ static void acpi_sleep_tts_switch(u32 acpi_state)
}
 }
 
-static int tts_notify_reboot(struct notifier_block *this,
-   unsigned long code, void *x)
+static void tts_reboot_prepare(struct reboot_prep_data *data)
 {
acpi_sleep_tts_switch(ACPI_STATE_S5);
-   return NOTIFY_DONE;
 }
 
-static struct notifier_block tts_notifier = {
-   .notifier_call  = tts_notify_reboot,
-   .next   = NULL,
-   .priority   = 0,
-};
-
 static int acpi_sleep_prepare(u32 acpi_state)
 {
 #ifdef CONFIG_ACPI_SLEEP
@@ -1020,7 +1012,7 @@ static void acpi_sleep_hibernate_setup(void)
 static inline void acpi_sleep_hibernate_setup(void) {}
 #endif /* !CONFIG_HIBERNATION */
 
-static void acpi_power_off_prepare(void)
+static void acpi_power_off_prepare(struct power_off_prep_data *data)
 {
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
@@ -1028,7 +1020,7 @@ static void acpi_power_off_prepare(void)
acpi_os_wait_events_complete();
 }
 
-static void acpi_power_off(void)
+static void acpi_power_off(struct power_off_data *data)
 {
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
pr_debug("%s called\n", __func__);
@@ -1036,6 +1028,11 @@ static void acpi_power_off(void)
acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
+static struct sys_off_handler acpi_sys_off_handler = {
+   .power_off_priority = POWEROFF_PRIO_FIRMWARE,
+   .reboot_prepare_cb = tts_reboot_prepare,
+};
+
 int __init acpi_sleep_init(void)
 {
char supported[ACPI_S_STATE_COUNT * 3 + 1];
@@ -1052,8 +1049,8 @@ int __init acpi_sleep_init(void)
 
if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
sleep_states[ACPI_STATE_S5] = 1;
-   pm_power_off_prepare = acpi_power_off_prepare;
-   pm_power_off = acpi_power_off;
+   acpi_sys_off_handler.power_off_cb = acpi_power_off;
+   acpi_sys_off_handler.power_off_prepare_cb = 
acpi_power_off_prepare;
} else {
acpi_no_s5 = true;
}
@@ -1069,6 +1066,6 @@ int __init acpi_sleep_init(void)
 * Register the tts_notifier to reboot notifier list so that the _TTS
 * object can also be evaluated when the system enters S5.
 */
-   register_reboot_notifier(_notifier);
+   register_sys_off_handler(_sys_off_handler);
return 0;
 }
-- 
2.33.1



[PATCH v3 22/25] memory: emif: Use kernel_can_power_off()

2021-11-07 Thread Dmitry Osipenko
Replace legacy pm_power_off with kernel_can_power_off() helper that
is aware about chained power-off handlers.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/emif.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 762d0c0f0716..cab10d5274a0 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -630,7 +630,7 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
dev_emerg(emif->dev, "SDRAM temperature exceeds operating 
limit.. Needs shut down!!!\n");
 
/* If we have Power OFF ability, use it, else try restarting */
-   if (pm_power_off) {
+   if (kernel_can_power_off()) {
kernel_power_off();
} else {
WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
-- 
2.33.1



[PATCH v3 21/25] m68k: Switch to new sys-off handler API

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use
register_power_off_handler() that registers power-off handlers and
do_kernel_power_off() that invokes chained power-off handlers. Legacy
pm_power_off() will be removed once all drivers will be converted to
the new power-off API.

Normally arch code should adopt only the do_kernel_power_off() at first,
but m68k is a special case because it uses pm_power_off() "inside out",
i.e. pm_power_off() invokes machine_power_off() [in fact it does nothing],
while it's machine_power_off() that should invoke the pm_power_off(), and
thus, we can't convert platforms to the new API separately. There are only
two platforms changed here, so it's not a big deal.

Signed-off-by: Dmitry Osipenko 
---
 arch/m68k/emu/natfeat.c | 3 ++-
 arch/m68k/include/asm/machdep.h | 1 -
 arch/m68k/kernel/process.c  | 5 ++---
 arch/m68k/kernel/setup_mm.c | 1 -
 arch/m68k/kernel/setup_no.c | 1 -
 arch/m68k/mac/config.c  | 4 +++-
 6 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/m68k/emu/natfeat.c b/arch/m68k/emu/natfeat.c
index 71b78ecee75c..b19dc00026d9 100644
--- a/arch/m68k/emu/natfeat.c
+++ b/arch/m68k/emu/natfeat.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -90,5 +91,5 @@ void __init nf_init(void)
pr_info("NatFeats found (%s, %lu.%lu)\n", buf, version >> 16,
version & 0x);
 
-   mach_power_off = nf_poweroff;
+   register_platform_power_off(nf_poweroff);
 }
diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h
index 8fd80ef1b77e..8d8c3ee2069f 100644
--- a/arch/m68k/include/asm/machdep.h
+++ b/arch/m68k/include/asm/machdep.h
@@ -24,7 +24,6 @@ extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
-extern void (*mach_power_off)( void );
 extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
 extern void (*mach_hd_setup)(char *, int *);
 extern void (*mach_heartbeat) (int);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index a6030dbaa089..e160a7c57bd3 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -67,12 +67,11 @@ void machine_halt(void)
 
 void machine_power_off(void)
 {
-   if (mach_power_off)
-   mach_power_off();
+   do_kernel_power_off();
for (;;);
 }
 
-void (*pm_power_off)(void) = machine_power_off;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 void show_regs(struct pt_regs * regs)
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index 4b51bfd38e5f..50f4f120a4ff 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -98,7 +98,6 @@ EXPORT_SYMBOL(mach_get_rtc_pll);
 EXPORT_SYMBOL(mach_set_rtc_pll);
 void (*mach_reset)( void );
 void (*mach_halt)( void );
-void (*mach_power_off)( void );
 #ifdef CONFIG_HEARTBEAT
 void (*mach_heartbeat) (int);
 EXPORT_SYMBOL(mach_heartbeat);
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 5e4104f07a44..00bf82258233 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -55,7 +55,6 @@ int (*mach_hwclk) (int, struct rtc_time*);
 /* machine dependent reboot functions */
 void (*mach_reset)(void);
 void (*mach_halt)(void);
-void (*mach_power_off)(void);
 
 #ifdef CONFIG_M68000
 #if defined(CONFIG_M68328)
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 5d16f9b47aa9..727320dedf08 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -12,6 +12,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -139,7 +140,6 @@ void __init config_mac(void)
mach_hwclk = mac_hwclk;
mach_reset = mac_reset;
mach_halt = mac_poweroff;
-   mach_power_off = mac_poweroff;
 #if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
mach_beep = mac_mksound;
 #endif
@@ -159,6 +159,8 @@ void __init config_mac(void)
 
if (macintosh_config->ident == MAC_MODEL_IICI)
mach_l2_flush = via_l2_flush;
+
+   register_platform_power_off(mac_poweroff);
 }
 
 
-- 
2.33.1



[PATCH v3 20/25] powerpc: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/powerpc/kernel/setup-common.c | 4 +---
 arch/powerpc/xmon/xmon.c   | 3 +--
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/kernel/setup-common.c 
b/arch/powerpc/kernel/setup-common.c
index 4f1322b65760..71c4ccd9bbb1 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -161,9 +161,7 @@ void machine_restart(char *cmd)
 void machine_power_off(void)
 {
machine_shutdown();
-   if (pm_power_off)
-   pm_power_off();
-
+   do_kernel_power_off();
smp_send_stop();
machine_hang();
 }
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 8b28ff9d98d1..8b9c9ff4834b 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1243,8 +1243,7 @@ static void bootcmds(void)
} else if (cmd == 'h') {
ppc_md.halt();
} else if (cmd == 'p') {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
}
 }
 
-- 
2.33.1



[PATCH v3 19/25] nds32: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/nds32/kernel/process.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c
index 49fab9e39cbf..0936dcd7db1b 100644
--- a/arch/nds32/kernel/process.c
+++ b/arch/nds32/kernel/process.c
@@ -54,8 +54,7 @@ EXPORT_SYMBOL(machine_halt);
 
 void machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 EXPORT_SYMBOL(machine_power_off);
-- 
2.33.1



[PATCH v3 18/25] mips: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/mips/kernel/reset.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/mips/kernel/reset.c b/arch/mips/kernel/reset.c
index 6288780b779e..e7ce07b3e79b 100644
--- a/arch/mips/kernel/reset.c
+++ b/arch/mips/kernel/reset.c
@@ -114,8 +114,7 @@ void machine_halt(void)
 
 void machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 
 #ifdef CONFIG_SMP
preempt_disable();
-- 
2.33.1



[PATCH v3 17/25] ia64: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/ia64/kernel/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 834df24a88f1..cee4d7db2143 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -599,8 +600,7 @@ machine_halt (void)
 void
 machine_power_off (void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
machine_halt();
 }
 
-- 
2.33.1



[PATCH v3 16/25] x86: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/x86/kernel/reboot.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 0a40df66a40d..cd7d9416d81a 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -747,10 +747,10 @@ static void native_machine_halt(void)
 
 static void native_machine_power_off(void)
 {
-   if (pm_power_off) {
+   if (kernel_can_power_off()) {
if (!reboot_force)
machine_shutdown();
-   pm_power_off();
+   do_kernel_power_off();
}
/* A fallback in case there is no PM info available */
tboot_shutdown(TB_SHUTDOWN_HALT);
-- 
2.33.1



[PATCH v3 15/25] sh: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Signed-off-by: Dmitry Osipenko 
---
 arch/sh/kernel/reboot.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
index 5c33f036418b..e8eeedc9b182 100644
--- a/arch/sh/kernel/reboot.c
+++ b/arch/sh/kernel/reboot.c
@@ -46,8 +46,7 @@ static void native_machine_shutdown(void)
 
 static void native_machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 static void native_machine_halt(void)
-- 
2.33.1



[PATCH v3 14/25] xen/x86: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Juergen Gross 
Signed-off-by: Dmitry Osipenko 
---
 arch/x86/xen/enlighten_pv.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 5004feb16783..527fa545eb1f 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -1068,8 +1069,7 @@ static void xen_machine_halt(void)
 
 static void xen_machine_power_off(void)
 {
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
xen_reboot(SHUTDOWN_poweroff);
 }
 
-- 
2.33.1



[PATCH v3 13/25] parisc: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Helge Deller  # parisc
Signed-off-by: Dmitry Osipenko 
---
 arch/parisc/kernel/process.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index ea3d83b6fb62..928201b1f58f 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -114,8 +115,7 @@ void machine_power_off(void)
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
 
/* ipmi_poweroff may have been installed. */
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();

/* It seems we have no way to power the system off via
 * software. The user has to press the button himself. */
-- 
2.33.1



[PATCH v3 12/25] arm64: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Catalin Marinas 
Signed-off-by: Dmitry Osipenko 
---
 arch/arm64/kernel/process.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index aacf2f5559a8..f8db031afa7d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -110,8 +110,7 @@ void machine_power_off(void)
 {
local_irq_disable();
smp_send_stop();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 /*
-- 
2.33.1



[PATCH v3 11/25] riscv: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Palmer Dabbelt 
Signed-off-by: Dmitry Osipenko 
---
 arch/riscv/kernel/reset.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c
index 9c842c41684a..912288572226 100644
--- a/arch/riscv/kernel/reset.c
+++ b/arch/riscv/kernel/reset.c
@@ -23,16 +23,12 @@ void machine_restart(char *cmd)
 
 void machine_halt(void)
 {
-   if (pm_power_off != NULL)
-   pm_power_off();
-   else
-   default_power_off();
+   do_kernel_power_off();
+   default_power_off();
 }
 
 void machine_power_off(void)
 {
-   if (pm_power_off != NULL)
-   pm_power_off();
-   else
-   default_power_off();
+   do_kernel_power_off();
+   default_power_off();
 }
-- 
2.33.1



[PATCH v3 10/25] csky: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Acked-by: Guo Ren 
Signed-off-by: Dmitry Osipenko 
---
 arch/csky/kernel/power.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/csky/kernel/power.c b/arch/csky/kernel/power.c
index 923ee4e381b8..86ee202906f8 100644
--- a/arch/csky/kernel/power.c
+++ b/arch/csky/kernel/power.c
@@ -9,16 +9,14 @@ EXPORT_SYMBOL(pm_power_off);
 void machine_power_off(void)
 {
local_irq_disable();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
asm volatile ("bkpt");
 }
 
 void machine_halt(void)
 {
local_irq_disable();
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
asm volatile ("bkpt");
 }
 
-- 
2.33.1



[PATCH v3 09/25] ARM: Use do_kernel_power_off()

2021-11-07 Thread Dmitry Osipenko
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.

Reviewed-by: Russell King (Oracle) 
Signed-off-by: Dmitry Osipenko 
---
 arch/arm/kernel/reboot.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
index 3044fcb8d073..2cb943422554 100644
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -116,9 +116,7 @@ void machine_power_off(void)
 {
local_irq_disable();
smp_send_stop();
-
-   if (pm_power_off)
-   pm_power_off();
+   do_kernel_power_off();
 }
 
 /*
-- 
2.33.1



[PATCH v3 08/25] kernel: Add combined power-off+restart handler call chain API

2021-11-07 Thread Dmitry Osipenko
SoC platforms often have multiple ways of how to perform system's
power-off and restart operations. Meanwhile today's kernel is limited to
a single option. Add combined power-off+restart handler call chain API,
which is inspired by the restart API. The new API provides both power-off
and restart functionality.

The old pm_power_off method will be kept around till all users are
converted to the new API.

Current restart API will be replaced by the new unified API since
new API is its superset. The restart functionality of the sys-off handler
API is built upon the existing restart-notifier APIs.

In order to ease conversion to the new API, convenient helpers are added
for the common use-cases. They will reduce amount of boilerplate code and
remove global variables. These helpers preserve old behaviour for cases
where only one power-off handler is expected, this is what all existing
drivers want, and thus, they could be easily converted to the new API.
Users of the new API should explicitly enable power-off chaining by
setting corresponding flag of the power_handler structure.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h   | 265 ++-
 kernel/power/hibernate.c |   2 +-
 kernel/reboot.c  | 536 ++-
 3 files changed, 795 insertions(+), 8 deletions(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index b7fa25726323..261d86ef71df 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -8,10 +8,35 @@
 
 struct device;
 
-#define SYS_DOWN   0x0001  /* Notify of system down */
-#define SYS_RESTARTSYS_DOWN
-#define SYS_HALT   0x0002  /* Notify of system halt */
-#define SYS_POWER_OFF  0x0003  /* Notify of system power off */
+enum reboot_prepare_mode {
+   SYS_DOWN = 1,   /* Notify of system down */
+   SYS_RESTART = SYS_DOWN,
+   SYS_HALT,   /* Notify of system halt */
+   SYS_POWER_OFF,  /* Notify of system power off */
+};
+
+/*
+ * Standard restart priority levels. Intended to be set in the
+ * sys_off_handler.restart_priority field.
+ *
+ * Use `RESTART_PRIO_ABC +- prio` style for additional levels.
+ *
+ * RESTART_PRIO_RESERVED:  Falls back to RESTART_PRIO_DEFAULT.
+ * Drivers may leave priority initialized
+ * to zero, to auto-set it to the default level.
+ *
+ * RESTART_PRIO_LOW:   Use this for handler of last resort.
+ *
+ * RESTART_PRIO_DEFAULT:   Use this for default/generic handler.
+ *
+ * RESTART_PRIO_HIGH:  Use this if you have multiple handlers and
+ * this handler has higher priority than the
+ * default handler.
+ */
+#define RESTART_PRIO_RESERVED  0
+#define RESTART_PRIO_LOW   8
+#define RESTART_PRIO_DEFAULT   128
+#define RESTART_PRIO_HIGH  192
 
 enum reboot_mode {
REBOOT_UNDEFINED = -1,
@@ -49,6 +74,237 @@ int register_restart_handler(struct notifier_block *);
 int unregister_restart_handler(struct notifier_block *);
 void do_kernel_restart(char *cmd);
 
+/*
+ * System power-off and restart API.
+ */
+
+/*
+ * Standard power-off priority levels. Intended to be set in the
+ * sys_off_handler.power_off_priority field.
+ *
+ * Use `POWEROFF_PRIO_ABC +- prio` style for additional levels.
+ *
+ * POWEROFF_PRIO_RESERVED: Falls back to POWEROFF_PRIO_DEFAULT.
+ * Drivers may leave priority initialized
+ * to zero, to auto-set it to the default level.
+ *
+ * POWEROFF_PRIO_PLATFORM: Intended to be used by platform-level handler.
+ * Has lowest priority since device drivers are
+ * expected to take over platform handler which
+ * doesn't allow further callback chaining.
+ *
+ * POWEROFF_PRIO_DEFAULT:  Use this for default/generic handler.
+ *
+ * POWEROFF_PRIO_FIRMWARE: Use this if handler uses firmware call.
+ * Has highest priority since firmware is expected
+ * to know best how to power-off hardware properly.
+ */
+#define POWEROFF_PRIO_RESERVED 0
+#define POWEROFF_PRIO_PLATFORM 1
+#define POWEROFF_PRIO_DEFAULT  128
+#define POWEROFF_PRIO_HIGH 192
+#define POWEROFF_PRIO_FIRMWARE 224
+
+enum poweroff_mode {
+   POWEROFF_NORMAL = 0,
+   POWEROFF_PREPARE,
+};
+
+/**
+ * struct power_off_data - Power-off callback argument
+ *
+ * @cb_data: Callback data.
+ */
+struct power_off_data {
+   void *cb_data;
+};
+
+/**
+ * struct power_off_prep_data - Power-off preparation callback argument
+ *
+ * @cb_data: Callback data.
+ */
+struct power_off_prep_data {
+   void *cb_data;
+};
+
+/**
+ * struct restart_data - Restart callback argument
+ *
+ * @cb_data: Callback data.
+ * @cmd: Restart command string

[PATCH v3 07/25] reboot: Remove extern annotation from function prototypes

2021-11-07 Thread Dmitry Osipenko
There is no need to annotate function prototypes with 'extern', it makes
code less readable. Remove unnecessary annotations from .

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h | 38 +++---
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 7c288013a3ca..b7fa25726323 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -40,36 +40,36 @@ extern int reboot_cpu;
 extern int reboot_force;
 
 
-extern int register_reboot_notifier(struct notifier_block *);
-extern int unregister_reboot_notifier(struct notifier_block *);
+int register_reboot_notifier(struct notifier_block *);
+int unregister_reboot_notifier(struct notifier_block *);
 
-extern int devm_register_reboot_notifier(struct device *, struct 
notifier_block *);
+int devm_register_reboot_notifier(struct device *, struct notifier_block *);
 
-extern int register_restart_handler(struct notifier_block *);
-extern int unregister_restart_handler(struct notifier_block *);
-extern void do_kernel_restart(char *cmd);
+int register_restart_handler(struct notifier_block *);
+int unregister_restart_handler(struct notifier_block *);
+void do_kernel_restart(char *cmd);
 
 /*
  * Architecture-specific implementations of sys_reboot commands.
  */
 
-extern void migrate_to_reboot_cpu(void);
-extern void machine_restart(char *cmd);
-extern void machine_halt(void);
-extern void machine_power_off(void);
+void migrate_to_reboot_cpu(void);
+void machine_restart(char *cmd);
+void machine_halt(void);
+void machine_power_off(void);
 
-extern void machine_shutdown(void);
+void machine_shutdown(void);
 struct pt_regs;
-extern void machine_crash_shutdown(struct pt_regs *);
+void machine_crash_shutdown(struct pt_regs *);
 
 /*
  * Architecture independent implementations of sys_reboot commands.
  */
 
-extern void kernel_restart_prepare(char *cmd);
-extern void kernel_restart(char *cmd);
-extern void kernel_halt(void);
-extern void kernel_power_off(void);
+void kernel_restart_prepare(char *cmd);
+void kernel_restart(char *cmd);
+void kernel_halt(void);
+void kernel_power_off(void);
 
 extern int C_A_D; /* for sysctl */
 void ctrl_alt_del(void);
@@ -77,15 +77,15 @@ void ctrl_alt_del(void);
 #define POWEROFF_CMD_PATH_LEN  256
 extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
 
-extern void orderly_poweroff(bool force);
-extern void orderly_reboot(void);
+void orderly_poweroff(bool force);
+void orderly_reboot(void);
 void hw_protection_shutdown(const char *reason, int ms_until_forced);
 
 /*
  * Emergency restart, callable from an interrupt handler.
  */
 
-extern void emergency_restart(void);
+void emergency_restart(void);
 #include 
 
 #endif /* _LINUX_REBOOT_H */
-- 
2.33.1



[PATCH v3 06/25] reboot: Warn if unregister_restart_handler() fails

2021-11-07 Thread Dmitry Osipenko
Emit warning if unregister_restart_handler() fails since it never should
fail. This will ease further API development by catching mistakes early.

Signed-off-by: Dmitry Osipenko 
---
 kernel/reboot.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index e6659ae329f1..f0e7b9c13f6b 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -210,7 +210,7 @@ EXPORT_SYMBOL(register_restart_handler);
  */
 int unregister_restart_handler(struct notifier_block *nb)
 {
-   return atomic_notifier_chain_unregister(_handler_list, nb);
+   return WARN_ON(atomic_notifier_chain_unregister(_handler_list, 
nb));
 }
 EXPORT_SYMBOL(unregister_restart_handler);
 
-- 
2.33.1



[PATCH v3 05/25] reboot: Warn if restart handler has duplicated priority

2021-11-07 Thread Dmitry Osipenko
Add sanity check which ensures that there are no two restart handlers
registered with the same priority. Normally it's a direct sign of a
problem if two handlers use the same priority.

Signed-off-by: Dmitry Osipenko 
---
 kernel/reboot.c | 15 ++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index 6bcc5d6a6572..e6659ae329f1 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -182,7 +182,20 @@ static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
  */
 int register_restart_handler(struct notifier_block *nb)
 {
-   return atomic_notifier_chain_register(_handler_list, nb);
+   int ret;
+
+   ret = atomic_notifier_chain_register(_handler_list, nb);
+   if (ret)
+   return ret;
+
+   /*
+* Handler must have unique priority. Otherwise call order is
+* determined by registration order, which is unreliable.
+*/
+   WARN(!atomic_notifier_has_unique_priority(_handler_list, nb),
+"restart handler must have unique priority\n");
+
+   return 0;
 }
 EXPORT_SYMBOL(register_restart_handler);
 
-- 
2.33.1



[PATCH v3 04/25] reboot: Correct typo in a comment

2021-11-07 Thread Dmitry Osipenko
Correct s/implemenations/implementations/ in .

Signed-off-by: Dmitry Osipenko 
---
 include/linux/reboot.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index af907a3d68d1..7c288013a3ca 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -63,7 +63,7 @@ struct pt_regs;
 extern void machine_crash_shutdown(struct pt_regs *);
 
 /*
- * Architecture independent implemenations of sys_reboot commands.
+ * Architecture independent implementations of sys_reboot commands.
  */
 
 extern void kernel_restart_prepare(char *cmd);
-- 
2.33.1



[PATCH v3 03/25] notifier: Add atomic/blocking_notifier_has_unique_priority()

2021-11-07 Thread Dmitry Osipenko
Add atomic/blocking_notifier_has_unique_priority() helpers which return
true if given handler has unique priority.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h |  5 +++
 kernel/notifier.c| 69 
 2 files changed, 74 insertions(+)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 924c9d7c8e73..2c4036f225e1 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -175,6 +175,11 @@ int raw_notifier_call_chain_robust(struct 
raw_notifier_head *nh,
 
 bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh);
 
+bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
+   struct notifier_block *nb);
+bool blocking_notifier_has_unique_priority(struct blocking_notifier_head *nh,
+   struct notifier_block *nb);
+
 #define NOTIFY_DONE0x  /* Don't care */
 #define NOTIFY_OK  0x0001  /* Suits me */
 #define NOTIFY_STOP_MASK   0x8000  /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index b20cb7b9b1f0..7a325b742104 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -122,6 +122,19 @@ static int notifier_call_chain_robust(struct 
notifier_block **nl,
return ret;
 }
 
+static int notifier_has_unique_priority(struct notifier_block **nl,
+   struct notifier_block *n)
+{
+   while (*nl && (*nl)->priority >= n->priority) {
+   if ((*nl)->priority == n->priority && *nl != n)
+   return false;
+
+   nl = &((*nl)->next);
+   }
+
+   return true;
+}
+
 /*
  * Atomic notifier chain routines.  Registration and unregistration
  * use a spinlock, and call_chain is synchronized by RCU (no locks).
@@ -203,6 +216,30 @@ int atomic_notifier_call_chain(struct atomic_notifier_head 
*nh,
 EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 NOKPROBE_SYMBOL(atomic_notifier_call_chain);
 
+/**
+ * atomic_notifier_has_unique_priority - Checks whether notifier's 
priority is unique
+ * @nh: Pointer to head of the atomic notifier chain
+ * @n: Entry in notifier chain to check
+ *
+ * Checks whether there is another notifier in the chain with the same 
priority.
+ * Must be called in process context.
+ *
+ * Returns true if priority is unique, false otherwise.
+ */
+bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
+   struct notifier_block *n)
+{
+   unsigned long flags;
+   bool ret;
+
+   spin_lock_irqsave(>lock, flags);
+   ret = notifier_has_unique_priority(>head, n);
+   spin_unlock_irqrestore(>lock, flags);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(atomic_notifier_has_unique_priority);
+
 /*
  * Blocking notifier chain routines.  All access to the chain is
  * synchronized by an rwsem.
@@ -336,6 +373,38 @@ bool blocking_notifier_call_chain_is_empty(struct 
blocking_notifier_head *nh)
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_is_empty);
 
+/**
+ * blocking_notifier_has_unique_priority - Checks whether notifier's 
priority is unique
+ * @nh: Pointer to head of the blocking notifier chain
+ * @n: Entry in notifier chain to check
+ *
+ * Checks whether there is another notifier in the chain with the same 
priority.
+ * Must be called in process context.
+ *
+ * Returns true if priority is unique, false otherwise.
+ */
+bool blocking_notifier_has_unique_priority(struct blocking_notifier_head *nh,
+   struct notifier_block *n)
+{
+   bool ret;
+
+   /*
+* This code gets used during boot-up, when task switching is
+* not yet working and interrupts must remain disabled. At such
+* times we must not call down_read().
+*/
+   if (system_state != SYSTEM_BOOTING)
+   down_read(>rwsem);
+
+   ret = notifier_has_unique_priority(>head, n);
+
+   if (system_state != SYSTEM_BOOTING)
+   up_read(>rwsem);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_has_unique_priority);
+
 /*
  * Raw notifier chain routines.  There is no protection;
  * the caller must provide it.  Use at your own risk!
-- 
2.33.1



[PATCH v3 02/25] notifier: Add blocking_notifier_call_chain_is_empty()

2021-11-07 Thread Dmitry Osipenko
Add blocking_notifier_call_chain_is_empty() that returns true if call
chain is empty.

Signed-off-by: Dmitry Osipenko 
---
 include/linux/notifier.h |  2 ++
 kernel/notifier.c| 14 ++
 2 files changed, 16 insertions(+)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 4b80a815b666..924c9d7c8e73 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -173,6 +173,8 @@ int blocking_notifier_call_chain_robust(struct 
blocking_notifier_head *nh,
 int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
 
+bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh);
+
 #define NOTIFY_DONE0x  /* Don't care */
 #define NOTIFY_OK  0x0001  /* Suits me */
 #define NOTIFY_STOP_MASK   0x8000  /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index b8251dc0bc0f..b20cb7b9b1f0 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -322,6 +322,20 @@ int blocking_notifier_call_chain(struct 
blocking_notifier_head *nh,
 }
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
+/**
+ * blocking_notifier_call_chain_is_empty - Check whether notifier chain is 
empty
+ * @nh: Pointer to head of the blocking notifier chain
+ *
+ * Checks whether notifier chain is empty.
+ *
+ * Returns true is notifier chain is empty, false otherwise.
+ */
+bool blocking_notifier_call_chain_is_empty(struct blocking_notifier_head *nh)
+{
+   return !rcu_access_pointer(nh->head);
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_is_empty);
+
 /*
  * Raw notifier chain routines.  There is no protection;
  * the caller must provide it.  Use at your own risk!
-- 
2.33.1



  1   2   >