Commit 587b9bfe authored by Dmitry Osipenko's avatar Dmitry Osipenko Committed by Rafael J. Wysocki
Browse files

kernel/reboot: Use static handler for register_platform_power_off()



The register_platform_power_off() fails on m68k platform due to the
memory allocation error that happens at a very early boot time when
memory allocator isn't available yet. Fix it by using a static sys-off
handler for the platform-level power-off handlers.

Fixes: f0f7e526 ("m68k: Switch to new sys-off handler API")
Reported-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarDmitry Osipenko <dmitry.osipenko@collabora.com>
Reviewed-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Tested-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 1ff7bc3b
Loading
Loading
Loading
Loading
+37 −6
Original line number Diff line number Diff line
@@ -315,6 +315,37 @@ 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 *alloc_sys_off_handler(int priority)
{
	struct sys_off_handler *handler;

	/*
	 * 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);
	} else {
		handler = kzalloc(sizeof(*handler), GFP_KERNEL);
		if (!handler)
			return ERR_PTR(-ENOMEM);
	}

	return handler;
}

static void free_sys_off_handler(struct sys_off_handler *handler)
{
	if (handler == &platform_sys_off_handler)
		memset(handler, 0, sizeof(*handler));
	else
		kfree(handler);
}

/**
 *	register_sys_off_handler - Register sys-off handler
 *	@mode: Sys-off mode
@@ -345,9 +376,9 @@ register_sys_off_handler(enum sys_off_mode mode,
	struct sys_off_handler *handler;
	int err;

	handler = kzalloc(sizeof(*handler), GFP_KERNEL);
	if (!handler)
		return ERR_PTR(-ENOMEM);
	handler = alloc_sys_off_handler(priority);
	if (IS_ERR(handler))
		return handler;

	switch (mode) {
	case SYS_OFF_MODE_POWER_OFF_PREPARE:
@@ -364,7 +395,7 @@ register_sys_off_handler(enum sys_off_mode mode,
		break;

	default:
		kfree(handler);
		free_sys_off_handler(handler);
		return ERR_PTR(-EINVAL);
	}

@@ -391,7 +422,7 @@ register_sys_off_handler(enum sys_off_mode mode,
	}

	if (err) {
		kfree(handler);
		free_sys_off_handler(handler);
		return ERR_PTR(err);
	}

@@ -422,7 +453,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
	/* sanity check, shall never happen */
	WARN_ON(err);

	kfree(handler);
	free_sys_off_handler(handler);
}
EXPORT_SYMBOL_GPL(unregister_sys_off_handler);