Commit 59b6d859 authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by Greg Kroah-Hartman
Browse files

firmware: fix capturing errors on fw_cache_init() on early init



register_pm_notifier() can technically fail, caputure this.
Note that register_syscore_ops() cannot fail given it just
adds an element to a linked list. This has been broken since
v3.7. Chances of this failing however are slim.

To improve code readability move the code folded under CONFIG_PM_SLEEP
into a helper.

Fixes: 07646d9c ("firmware loader: cache devices firmware during suspend/resume cycle")
Signed-off-by: default avatarLuis R. Rodriguez <mcgrof@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a67e503b
Loading
Loading
Loading
Loading
+32 −13
Original line number Diff line number Diff line
@@ -1768,6 +1768,26 @@ static struct syscore_ops fw_syscore_ops = {
	.suspend = fw_suspend,
};

static int __init register_fw_pm_ops(void)
{
	int ret;

	spin_lock_init(&fw_cache.name_lock);
	INIT_LIST_HEAD(&fw_cache.fw_names);

	INIT_DELAYED_WORK(&fw_cache.work,
			  device_uncache_fw_images_work);

	fw_cache.pm_notify.notifier_call = fw_pm_notify;
	ret = register_pm_notifier(&fw_cache.pm_notify);
	if (ret)
		return ret;

	register_syscore_ops(&fw_syscore_ops);

	return ret;
}

static inline void unregister_fw_pm_ops(void)
{
	unregister_syscore_ops(&fw_syscore_ops);
@@ -1778,6 +1798,10 @@ static int fw_cache_piggyback_on_request(const char *name)
{
	return 0;
}
static inline int register_fw_pm_ops(void)
{
	return 0;
}
static inline void unregister_fw_pm_ops(void)
{
}
@@ -1788,19 +1812,6 @@ static void __init fw_cache_init(void)
	spin_lock_init(&fw_cache.lock);
	INIT_LIST_HEAD(&fw_cache.head);
	fw_cache.state = FW_LOADER_NO_CACHE;

#ifdef CONFIG_PM_SLEEP
	spin_lock_init(&fw_cache.name_lock);
	INIT_LIST_HEAD(&fw_cache.fw_names);

	INIT_DELAYED_WORK(&fw_cache.work,
			  device_uncache_fw_images_work);

	fw_cache.pm_notify.notifier_call = fw_pm_notify;
	register_pm_notifier(&fw_cache.pm_notify);

	register_syscore_ops(&fw_syscore_ops);
#endif
}

static int fw_shutdown_notify(struct notifier_block *unused1,
@@ -1821,7 +1832,15 @@ static struct notifier_block fw_shutdown_nb = {

static int __init firmware_class_init(void)
{
	int ret;

	/* No need to unfold these on exit */
	fw_cache_init();

	ret = register_fw_pm_ops();
	if (ret)
		return ret;

	register_reboot_notifier(&fw_shutdown_nb);
#ifdef CONFIG_FW_LOADER_USER_HELPER
	return class_register(&firmware_class);