I am interested in converting the axp20x PMIC driver to use the sys-off
API for its poweroff handler, so it can be used as a fallback for the
SBI poweroff handler on RISC-V. But the PSCI poweroff handler still uses
pm_power_off, so done alone, this would cause the axp20x callback to be
called first, before the PSCI poweroff handler.
In order to prevent this change in behavior, the PSCI poweroff handler
needs to be converted to the sys-off API first, at a higher priority.
This series performs the conversion, after accounting for the fact that
the PSCI poweroff handler is registered quite early during boot.
Samuel Holland (2):
kernel/reboot: Use the static sys-off handler for any priority
firmware/psci: Switch to the sys-off handler API
drivers/firmware/psci/psci.c | 9 ++++++---
kernel/reboot.c | 10 ++++------
2 files changed, 10 insertions(+), 9 deletions(-)
--
2.37.3
commit 587b9bfe0668 ("kernel/reboot: Use static handler for
register_platform_power_off()") addded a statically-allocated handler
so register_sys_off_handler() could be called before the slab allocator
is available.
That behavior was limited to the SYS_OFF_PRIO_PLATFORM priority.
However, it is also required for handlers such as PSCI on ARM, which
needs to be registered at SYS_OFF_PRIO_FIRMWARE. Currently, this call
stack crashes:
start_kernel()
setup_arch()
psci_dt_init()
psci_0_2_init()
register_sys_off_handler()
kmem_cache_alloc()
Generalize the code to use the statically-allocated handler for the
first registration, regardless of priority. Check .sys_off_cb for
conflicts instead of .cb_data; some callbacks (e.g. firmware) do not
need any per-instance data, so .cb_data could be NULL.
Signed-off-by: Samuel Holland <[email protected]>
---
kernel/reboot.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 3bba88c7ffc6..38c18d4f0a36 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -327,7 +327,7 @@ static int sys_off_notify(struct notifier_block *nb,
return handler->sys_off_cb(&data);
}
-static struct sys_off_handler platform_sys_off_handler;
+static struct sys_off_handler early_sys_off_handler;
static struct sys_off_handler *alloc_sys_off_handler(int priority)
{
@@ -338,10 +338,8 @@ static struct sys_off_handler *alloc_sys_off_handler(int priority)
* Platforms like m68k can't allocate sys_off handler dynamically
* at the early boot time because memory allocator isn't available yet.
*/
- if (priority == SYS_OFF_PRIO_PLATFORM) {
- handler = &platform_sys_off_handler;
- if (handler->cb_data)
- return ERR_PTR(-EBUSY);
+ if (!early_sys_off_handler.sys_off_cb) {
+ handler = &early_sys_off_handler;
} else {
if (system_state > SYSTEM_RUNNING)
flags = GFP_ATOMIC;
@@ -358,7 +356,7 @@ static struct sys_off_handler *alloc_sys_off_handler(int priority)
static void free_sys_off_handler(struct sys_off_handler *handler)
{
- if (handler == &platform_sys_off_handler)
+ if (handler == &early_sys_off_handler)
memset(handler, 0, sizeof(*handler));
else
kfree(handler);
--
2.37.3
On 11/6/22 00:48, Samuel Holland wrote:
> commit 587b9bfe0668 ("kernel/reboot: Use static handler for
> register_platform_power_off()") addded a statically-allocated handler
> so register_sys_off_handler() could be called before the slab allocator
> is available.
>
> That behavior was limited to the SYS_OFF_PRIO_PLATFORM priority.
> However, it is also required for handlers such as PSCI on ARM, which
> needs to be registered at SYS_OFF_PRIO_FIRMWARE. Currently, this call
> stack crashes:
>
> start_kernel()
> setup_arch()
> psci_dt_init()
> psci_0_2_init()
> register_sys_off_handler()
> kmem_cache_alloc()
>
> Generalize the code to use the statically-allocated handler for the
> first registration, regardless of priority. Check .sys_off_cb for
> conflicts instead of .cb_data; some callbacks (e.g. firmware) do not
> need any per-instance data, so .cb_data could be NULL.
>
> Signed-off-by: Samuel Holland <[email protected]>
> ---
>
> kernel/reboot.c | 10 ++++------
> 1 file changed, 4 insertions(+), 6 deletions(-)
>
> diff --git a/kernel/reboot.c b/kernel/reboot.c
> index 3bba88c7ffc6..38c18d4f0a36 100644
> --- a/kernel/reboot.c
> +++ b/kernel/reboot.c
> @@ -327,7 +327,7 @@ static int sys_off_notify(struct notifier_block *nb,
> return handler->sys_off_cb(&data);
> }
>
> -static struct sys_off_handler platform_sys_off_handler;
> +static struct sys_off_handler early_sys_off_handler;
>
> static struct sys_off_handler *alloc_sys_off_handler(int priority)
> {
> @@ -338,10 +338,8 @@ static struct sys_off_handler *alloc_sys_off_handler(int priority)
> * Platforms like m68k can't allocate sys_off handler dynamically
> * at the early boot time because memory allocator isn't available yet.
> */
> - if (priority == SYS_OFF_PRIO_PLATFORM) {
> - handler = &platform_sys_off_handler;
> - if (handler->cb_data)
> - return ERR_PTR(-EBUSY);
> + if (!early_sys_off_handler.sys_off_cb) {
> + handler = &early_sys_off_handler;
> } else {
> if (system_state > SYSTEM_RUNNING)
> flags = GFP_ATOMIC;
> @@ -358,7 +356,7 @@ static struct sys_off_handler *alloc_sys_off_handler(int priority)
>
> static void free_sys_off_handler(struct sys_off_handler *handler)
> {
> - if (handler == &platform_sys_off_handler)
> + if (handler == &early_sys_off_handler)
> memset(handler, 0, sizeof(*handler));
> else
> kfree(handler);
Reviewed-by: Dmitry Osipenko <[email protected]>
--
Best regards,
Dmitry