xref: /linux/drivers/base/firmware_loader/main.c (revision 1fe6e4f0)
15d6d1dddSLuis R. Rodriguez // SPDX-License-Identifier: GPL-2.0
25d6d1dddSLuis R. Rodriguez /*
35d6d1dddSLuis R. Rodriguez  * main.c - Multi purpose firmware loading support
45d6d1dddSLuis R. Rodriguez  *
55d6d1dddSLuis R. Rodriguez  * Copyright (c) 2003 Manuel Estrada Sainz
65d6d1dddSLuis R. Rodriguez  *
70c580d83SArkadiusz Drabczyk  * Please see Documentation/driver-api/firmware/ for more information.
85d6d1dddSLuis R. Rodriguez  *
95d6d1dddSLuis R. Rodriguez  */
105d6d1dddSLuis R. Rodriguez 
115d6d1dddSLuis R. Rodriguez #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
125d6d1dddSLuis R. Rodriguez 
135d6d1dddSLuis R. Rodriguez #include <linux/capability.h>
145d6d1dddSLuis R. Rodriguez #include <linux/device.h>
15b89999d0SScott Branden #include <linux/kernel_read_file.h>
165d6d1dddSLuis R. Rodriguez #include <linux/module.h>
175d6d1dddSLuis R. Rodriguez #include <linux/init.h>
18e7cb072eSRasmus Villemoes #include <linux/initrd.h>
195d6d1dddSLuis R. Rodriguez #include <linux/timer.h>
205d6d1dddSLuis R. Rodriguez #include <linux/vmalloc.h>
215d6d1dddSLuis R. Rodriguez #include <linux/interrupt.h>
225d6d1dddSLuis R. Rodriguez #include <linux/bitops.h>
235d6d1dddSLuis R. Rodriguez #include <linux/mutex.h>
245d6d1dddSLuis R. Rodriguez #include <linux/workqueue.h>
255d6d1dddSLuis R. Rodriguez #include <linux/highmem.h>
265d6d1dddSLuis R. Rodriguez #include <linux/firmware.h>
275d6d1dddSLuis R. Rodriguez #include <linux/slab.h>
285d6d1dddSLuis R. Rodriguez #include <linux/sched.h>
295d6d1dddSLuis R. Rodriguez #include <linux/file.h>
305d6d1dddSLuis R. Rodriguez #include <linux/list.h>
315d6d1dddSLuis R. Rodriguez #include <linux/fs.h>
325d6d1dddSLuis R. Rodriguez #include <linux/async.h>
335d6d1dddSLuis R. Rodriguez #include <linux/pm.h>
345d6d1dddSLuis R. Rodriguez #include <linux/suspend.h>
355d6d1dddSLuis R. Rodriguez #include <linux/syscore_ops.h>
365d6d1dddSLuis R. Rodriguez #include <linux/reboot.h>
375d6d1dddSLuis R. Rodriguez #include <linux/security.h>
3823cfbc6eSTakashi Iwai #include <linux/zstd.h>
3982fd7a81STakashi Iwai #include <linux/xz.h>
405d6d1dddSLuis R. Rodriguez 
415d6d1dddSLuis R. Rodriguez #include <generated/utsrelease.h>
425d6d1dddSLuis R. Rodriguez 
435d6d1dddSLuis R. Rodriguez #include "../base.h"
445d6d1dddSLuis R. Rodriguez #include "firmware.h"
455d6d1dddSLuis R. Rodriguez #include "fallback.h"
465d6d1dddSLuis R. Rodriguez 
475d6d1dddSLuis R. Rodriguez MODULE_AUTHOR("Manuel Estrada Sainz");
485d6d1dddSLuis R. Rodriguez MODULE_DESCRIPTION("Multi purpose firmware loading support");
495d6d1dddSLuis R. Rodriguez MODULE_LICENSE("GPL");
505d6d1dddSLuis R. Rodriguez 
515d6d1dddSLuis R. Rodriguez struct firmware_cache {
525d6d1dddSLuis R. Rodriguez 	/* firmware_buf instance will be added into the below list */
535d6d1dddSLuis R. Rodriguez 	spinlock_t lock;
545d6d1dddSLuis R. Rodriguez 	struct list_head head;
555d6d1dddSLuis R. Rodriguez 	int state;
565d6d1dddSLuis R. Rodriguez 
57030cc787SMark Salyzyn #ifdef CONFIG_FW_CACHE
585d6d1dddSLuis R. Rodriguez 	/*
595d6d1dddSLuis R. Rodriguez 	 * Names of firmware images which have been cached successfully
605d6d1dddSLuis R. Rodriguez 	 * will be added into the below list so that device uncache
615d6d1dddSLuis R. Rodriguez 	 * helper can trace which firmware images have been cached
625d6d1dddSLuis R. Rodriguez 	 * before.
635d6d1dddSLuis R. Rodriguez 	 */
645d6d1dddSLuis R. Rodriguez 	spinlock_t name_lock;
655d6d1dddSLuis R. Rodriguez 	struct list_head fw_names;
665d6d1dddSLuis R. Rodriguez 
675d6d1dddSLuis R. Rodriguez 	struct delayed_work work;
685d6d1dddSLuis R. Rodriguez 
695d6d1dddSLuis R. Rodriguez 	struct notifier_block   pm_notify;
705d6d1dddSLuis R. Rodriguez #endif
715d6d1dddSLuis R. Rodriguez };
725d6d1dddSLuis R. Rodriguez 
735d6d1dddSLuis R. Rodriguez struct fw_cache_entry {
745d6d1dddSLuis R. Rodriguez 	struct list_head list;
755d6d1dddSLuis R. Rodriguez 	const char *name;
765d6d1dddSLuis R. Rodriguez };
775d6d1dddSLuis R. Rodriguez 
785d6d1dddSLuis R. Rodriguez struct fw_name_devm {
795d6d1dddSLuis R. Rodriguez 	unsigned long magic;
805d6d1dddSLuis R. Rodriguez 	const char *name;
815d6d1dddSLuis R. Rodriguez };
825d6d1dddSLuis R. Rodriguez 
to_fw_priv(struct kref * ref)835d6d1dddSLuis R. Rodriguez static inline struct fw_priv *to_fw_priv(struct kref *ref)
845d6d1dddSLuis R. Rodriguez {
855d6d1dddSLuis R. Rodriguez 	return container_of(ref, struct fw_priv, ref);
865d6d1dddSLuis R. Rodriguez }
875d6d1dddSLuis R. Rodriguez 
885d6d1dddSLuis R. Rodriguez #define	FW_LOADER_NO_CACHE	0
895d6d1dddSLuis R. Rodriguez #define	FW_LOADER_START_CACHE	1
905d6d1dddSLuis R. Rodriguez 
915d6d1dddSLuis R. Rodriguez /* fw_lock could be moved to 'struct fw_sysfs' but since it is just
925d6d1dddSLuis R. Rodriguez  * guarding for corner cases a global lock should be OK */
935d6d1dddSLuis R. Rodriguez DEFINE_MUTEX(fw_lock);
945d6d1dddSLuis R. Rodriguez 
9597730bbbSRuss Weight struct firmware_cache fw_cache;
96effd7c70SMukesh Ojha bool fw_load_abort_all;
975d6d1dddSLuis R. Rodriguez 
fw_state_init(struct fw_priv * fw_priv)9897730bbbSRuss Weight void fw_state_init(struct fw_priv *fw_priv)
995d6d1dddSLuis R. Rodriguez {
1005d6d1dddSLuis R. Rodriguez 	struct fw_state *fw_st = &fw_priv->fw_st;
1015d6d1dddSLuis R. Rodriguez 
1025d6d1dddSLuis R. Rodriguez 	init_completion(&fw_st->completion);
1035d6d1dddSLuis R. Rodriguez 	fw_st->status = FW_STATUS_UNKNOWN;
1045d6d1dddSLuis R. Rodriguez }
1055d6d1dddSLuis R. Rodriguez 
fw_state_wait(struct fw_priv * fw_priv)1065d6d1dddSLuis R. Rodriguez static inline int fw_state_wait(struct fw_priv *fw_priv)
1075d6d1dddSLuis R. Rodriguez {
1085d6d1dddSLuis R. Rodriguez 	return __fw_state_wait_common(fw_priv, MAX_SCHEDULE_TIMEOUT);
1095d6d1dddSLuis R. Rodriguez }
1105d6d1dddSLuis R. Rodriguez 
1113ecc8cb7SZhen Lei static void fw_cache_piggyback_on_request(struct fw_priv *fw_priv);
1125d6d1dddSLuis R. Rodriguez 
__allocate_fw_priv(const char * fw_name,struct firmware_cache * fwc,void * dbuf,size_t size,size_t offset,u32 opt_flags)1135d6d1dddSLuis R. Rodriguez static struct fw_priv *__allocate_fw_priv(const char *fw_name,
1145d6d1dddSLuis R. Rodriguez 					  struct firmware_cache *fwc,
11589287c16SKees Cook 					  void *dbuf,
11689287c16SKees Cook 					  size_t size,
11759cdb23cSScott Branden 					  size_t offset,
11889287c16SKees Cook 					  u32 opt_flags)
1195d6d1dddSLuis R. Rodriguez {
1205d6d1dddSLuis R. Rodriguez 	struct fw_priv *fw_priv;
1215d6d1dddSLuis R. Rodriguez 
12259cdb23cSScott Branden 	/* For a partial read, the buffer must be preallocated. */
12359cdb23cSScott Branden 	if ((opt_flags & FW_OPT_PARTIAL) && !dbuf)
12459cdb23cSScott Branden 		return NULL;
12559cdb23cSScott Branden 
12659cdb23cSScott Branden 	/* Only partial reads are allowed to use an offset. */
12759cdb23cSScott Branden 	if (offset != 0 && !(opt_flags & FW_OPT_PARTIAL))
12859cdb23cSScott Branden 		return NULL;
12959cdb23cSScott Branden 
1305d6d1dddSLuis R. Rodriguez 	fw_priv = kzalloc(sizeof(*fw_priv), GFP_ATOMIC);
1315d6d1dddSLuis R. Rodriguez 	if (!fw_priv)
1325d6d1dddSLuis R. Rodriguez 		return NULL;
1335d6d1dddSLuis R. Rodriguez 
1345d6d1dddSLuis R. Rodriguez 	fw_priv->fw_name = kstrdup_const(fw_name, GFP_ATOMIC);
1355d6d1dddSLuis R. Rodriguez 	if (!fw_priv->fw_name) {
1365d6d1dddSLuis R. Rodriguez 		kfree(fw_priv);
1375d6d1dddSLuis R. Rodriguez 		return NULL;
1385d6d1dddSLuis R. Rodriguez 	}
1395d6d1dddSLuis R. Rodriguez 
1405d6d1dddSLuis R. Rodriguez 	kref_init(&fw_priv->ref);
1415d6d1dddSLuis R. Rodriguez 	fw_priv->fwc = fwc;
1425d6d1dddSLuis R. Rodriguez 	fw_priv->data = dbuf;
1435d6d1dddSLuis R. Rodriguez 	fw_priv->allocated_size = size;
14459cdb23cSScott Branden 	fw_priv->offset = offset;
14589287c16SKees Cook 	fw_priv->opt_flags = opt_flags;
1465d6d1dddSLuis R. Rodriguez 	fw_state_init(fw_priv);
1475d6d1dddSLuis R. Rodriguez #ifdef CONFIG_FW_LOADER_USER_HELPER
1485d6d1dddSLuis R. Rodriguez 	INIT_LIST_HEAD(&fw_priv->pending_list);
1495d6d1dddSLuis R. Rodriguez #endif
1505d6d1dddSLuis R. Rodriguez 
1515d6d1dddSLuis R. Rodriguez 	pr_debug("%s: fw-%s fw_priv=%p\n", __func__, fw_name, fw_priv);
1525d6d1dddSLuis R. Rodriguez 
1535d6d1dddSLuis R. Rodriguez 	return fw_priv;
1545d6d1dddSLuis R. Rodriguez }
1555d6d1dddSLuis R. Rodriguez 
__lookup_fw_priv(const char * fw_name)1565d6d1dddSLuis R. Rodriguez static struct fw_priv *__lookup_fw_priv(const char *fw_name)
1575d6d1dddSLuis R. Rodriguez {
1585d6d1dddSLuis R. Rodriguez 	struct fw_priv *tmp;
1595d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
1605d6d1dddSLuis R. Rodriguez 
1615d6d1dddSLuis R. Rodriguez 	list_for_each_entry(tmp, &fwc->head, list)
1625d6d1dddSLuis R. Rodriguez 		if (!strcmp(tmp->fw_name, fw_name))
1635d6d1dddSLuis R. Rodriguez 			return tmp;
1645d6d1dddSLuis R. Rodriguez 	return NULL;
1655d6d1dddSLuis R. Rodriguez }
1665d6d1dddSLuis R. Rodriguez 
1675d6d1dddSLuis R. Rodriguez /* Returns 1 for batching firmware requests with the same name */
alloc_lookup_fw_priv(const char * fw_name,struct firmware_cache * fwc,struct fw_priv ** fw_priv,void * dbuf,size_t size,size_t offset,u32 opt_flags)16897730bbbSRuss Weight int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc,
16997730bbbSRuss Weight 			 struct fw_priv **fw_priv, void *dbuf, size_t size,
17097730bbbSRuss Weight 			 size_t offset, u32 opt_flags)
1715d6d1dddSLuis R. Rodriguez {
1725d6d1dddSLuis R. Rodriguez 	struct fw_priv *tmp;
1735d6d1dddSLuis R. Rodriguez 
1745d6d1dddSLuis R. Rodriguez 	spin_lock(&fwc->lock);
17559cdb23cSScott Branden 	/*
17659cdb23cSScott Branden 	 * Do not merge requests that are marked to be non-cached or
17759cdb23cSScott Branden 	 * are performing partial reads.
17859cdb23cSScott Branden 	 */
17959cdb23cSScott Branden 	if (!(opt_flags & (FW_OPT_NOCACHE | FW_OPT_PARTIAL))) {
1805d6d1dddSLuis R. Rodriguez 		tmp = __lookup_fw_priv(fw_name);
1815d6d1dddSLuis R. Rodriguez 		if (tmp) {
1825d6d1dddSLuis R. Rodriguez 			kref_get(&tmp->ref);
1835d6d1dddSLuis R. Rodriguez 			spin_unlock(&fwc->lock);
1845d6d1dddSLuis R. Rodriguez 			*fw_priv = tmp;
1855d6d1dddSLuis R. Rodriguez 			pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n");
1865d6d1dddSLuis R. Rodriguez 			return 1;
1875d6d1dddSLuis R. Rodriguez 		}
188422b3db2SRishabh Bhatnagar 	}
189422b3db2SRishabh Bhatnagar 
19059cdb23cSScott Branden 	tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, offset, opt_flags);
19170120405SBjorn Andersson 	if (tmp) {
19270120405SBjorn Andersson 		INIT_LIST_HEAD(&tmp->list);
19370120405SBjorn Andersson 		if (!(opt_flags & FW_OPT_NOCACHE))
1945d6d1dddSLuis R. Rodriguez 			list_add(&tmp->list, &fwc->head);
19570120405SBjorn Andersson 	}
1965d6d1dddSLuis R. Rodriguez 	spin_unlock(&fwc->lock);
1975d6d1dddSLuis R. Rodriguez 
1985d6d1dddSLuis R. Rodriguez 	*fw_priv = tmp;
1995d6d1dddSLuis R. Rodriguez 
2005d6d1dddSLuis R. Rodriguez 	return tmp ? 0 : -ENOMEM;
2015d6d1dddSLuis R. Rodriguez }
2025d6d1dddSLuis R. Rodriguez 
__free_fw_priv(struct kref * ref)2035d6d1dddSLuis R. Rodriguez static void __free_fw_priv(struct kref *ref)
2045d6d1dddSLuis R. Rodriguez 	__releases(&fwc->lock)
2055d6d1dddSLuis R. Rodriguez {
2065d6d1dddSLuis R. Rodriguez 	struct fw_priv *fw_priv = to_fw_priv(ref);
2075d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = fw_priv->fwc;
2085d6d1dddSLuis R. Rodriguez 
2095d6d1dddSLuis R. Rodriguez 	pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n",
2105d6d1dddSLuis R. Rodriguez 		 __func__, fw_priv->fw_name, fw_priv, fw_priv->data,
2115d6d1dddSLuis R. Rodriguez 		 (unsigned int)fw_priv->size);
2125d6d1dddSLuis R. Rodriguez 
2135d6d1dddSLuis R. Rodriguez 	list_del(&fw_priv->list);
2145d6d1dddSLuis R. Rodriguez 	spin_unlock(&fwc->lock);
2155d6d1dddSLuis R. Rodriguez 
2164965b8cdSPrateek Sood 	if (fw_is_paged_buf(fw_priv))
2174965b8cdSPrateek Sood 		fw_free_paged_buf(fw_priv);
2184965b8cdSPrateek Sood 	else if (!fw_priv->allocated_size)
2195d6d1dddSLuis R. Rodriguez 		vfree(fw_priv->data);
2204965b8cdSPrateek Sood 
2215d6d1dddSLuis R. Rodriguez 	kfree_const(fw_priv->fw_name);
2225d6d1dddSLuis R. Rodriguez 	kfree(fw_priv);
2235d6d1dddSLuis R. Rodriguez }
2245d6d1dddSLuis R. Rodriguez 
free_fw_priv(struct fw_priv * fw_priv)22597730bbbSRuss Weight void free_fw_priv(struct fw_priv *fw_priv)
2265d6d1dddSLuis R. Rodriguez {
2275d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = fw_priv->fwc;
2285d6d1dddSLuis R. Rodriguez 	spin_lock(&fwc->lock);
2295d6d1dddSLuis R. Rodriguez 	if (!kref_put(&fw_priv->ref, __free_fw_priv))
2305d6d1dddSLuis R. Rodriguez 		spin_unlock(&fwc->lock);
2315d6d1dddSLuis R. Rodriguez }
2325d6d1dddSLuis R. Rodriguez 
23382fd7a81STakashi Iwai #ifdef CONFIG_FW_LOADER_PAGED_BUF
fw_is_paged_buf(struct fw_priv * fw_priv)2344965b8cdSPrateek Sood bool fw_is_paged_buf(struct fw_priv *fw_priv)
2354965b8cdSPrateek Sood {
2364965b8cdSPrateek Sood 	return fw_priv->is_paged_buf;
2374965b8cdSPrateek Sood }
2384965b8cdSPrateek Sood 
fw_free_paged_buf(struct fw_priv * fw_priv)2398f58570bSTakashi Iwai void fw_free_paged_buf(struct fw_priv *fw_priv)
2408f58570bSTakashi Iwai {
2418f58570bSTakashi Iwai 	int i;
2428f58570bSTakashi Iwai 
2438f58570bSTakashi Iwai 	if (!fw_priv->pages)
2448f58570bSTakashi Iwai 		return;
2458f58570bSTakashi Iwai 
2464965b8cdSPrateek Sood 	vunmap(fw_priv->data);
2474965b8cdSPrateek Sood 
2488f58570bSTakashi Iwai 	for (i = 0; i < fw_priv->nr_pages; i++)
2498f58570bSTakashi Iwai 		__free_page(fw_priv->pages[i]);
250993f5d11STakashi Iwai 	kvfree(fw_priv->pages);
2518f58570bSTakashi Iwai 	fw_priv->pages = NULL;
2528f58570bSTakashi Iwai 	fw_priv->page_array_size = 0;
2538f58570bSTakashi Iwai 	fw_priv->nr_pages = 0;
2544ac4a90dSRuss Weight 	fw_priv->data = NULL;
2554ac4a90dSRuss Weight 	fw_priv->size = 0;
2568f58570bSTakashi Iwai }
2575342e709STakashi Iwai 
fw_grow_paged_buf(struct fw_priv * fw_priv,int pages_needed)2585342e709STakashi Iwai int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed)
2595342e709STakashi Iwai {
2605342e709STakashi Iwai 	/* If the array of pages is too small, grow it */
2615342e709STakashi Iwai 	if (fw_priv->page_array_size < pages_needed) {
2625342e709STakashi Iwai 		int new_array_size = max(pages_needed,
2635342e709STakashi Iwai 					 fw_priv->page_array_size * 2);
2645342e709STakashi Iwai 		struct page **new_pages;
2655342e709STakashi Iwai 
2665342e709STakashi Iwai 		new_pages = kvmalloc_array(new_array_size, sizeof(void *),
2675342e709STakashi Iwai 					   GFP_KERNEL);
2685342e709STakashi Iwai 		if (!new_pages)
2695342e709STakashi Iwai 			return -ENOMEM;
2705342e709STakashi Iwai 		memcpy(new_pages, fw_priv->pages,
2715342e709STakashi Iwai 		       fw_priv->page_array_size * sizeof(void *));
2725342e709STakashi Iwai 		memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
2735342e709STakashi Iwai 		       (new_array_size - fw_priv->page_array_size));
2745342e709STakashi Iwai 		kvfree(fw_priv->pages);
2755342e709STakashi Iwai 		fw_priv->pages = new_pages;
2765342e709STakashi Iwai 		fw_priv->page_array_size = new_array_size;
2775342e709STakashi Iwai 	}
2785342e709STakashi Iwai 
2795342e709STakashi Iwai 	while (fw_priv->nr_pages < pages_needed) {
2805342e709STakashi Iwai 		fw_priv->pages[fw_priv->nr_pages] =
2815342e709STakashi Iwai 			alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
2825342e709STakashi Iwai 
2835342e709STakashi Iwai 		if (!fw_priv->pages[fw_priv->nr_pages])
2845342e709STakashi Iwai 			return -ENOMEM;
2855342e709STakashi Iwai 		fw_priv->nr_pages++;
2865342e709STakashi Iwai 	}
2875342e709STakashi Iwai 
2885342e709STakashi Iwai 	return 0;
2895342e709STakashi Iwai }
2905342e709STakashi Iwai 
fw_map_paged_buf(struct fw_priv * fw_priv)2915342e709STakashi Iwai int fw_map_paged_buf(struct fw_priv *fw_priv)
2925342e709STakashi Iwai {
2935342e709STakashi Iwai 	/* one pages buffer should be mapped/unmapped only once */
2945342e709STakashi Iwai 	if (!fw_priv->pages)
2955342e709STakashi Iwai 		return 0;
2965342e709STakashi Iwai 
2975342e709STakashi Iwai 	vunmap(fw_priv->data);
2985342e709STakashi Iwai 	fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
2995342e709STakashi Iwai 			     PAGE_KERNEL_RO);
3005342e709STakashi Iwai 	if (!fw_priv->data)
3015342e709STakashi Iwai 		return -ENOMEM;
3025342e709STakashi Iwai 
3035342e709STakashi Iwai 	return 0;
3045342e709STakashi Iwai }
3058f58570bSTakashi Iwai #endif
3068f58570bSTakashi Iwai 
30782fd7a81STakashi Iwai /*
30823cfbc6eSTakashi Iwai  * ZSTD-compressed firmware support
30923cfbc6eSTakashi Iwai  */
31023cfbc6eSTakashi Iwai #ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD
fw_decompress_zstd(struct device * dev,struct fw_priv * fw_priv,size_t in_size,const void * in_buffer)31123cfbc6eSTakashi Iwai static int fw_decompress_zstd(struct device *dev, struct fw_priv *fw_priv,
31223cfbc6eSTakashi Iwai 			      size_t in_size, const void *in_buffer)
31323cfbc6eSTakashi Iwai {
31423cfbc6eSTakashi Iwai 	size_t len, out_size, workspace_size;
31523cfbc6eSTakashi Iwai 	void *workspace, *out_buf;
31623cfbc6eSTakashi Iwai 	zstd_dctx *ctx;
31723cfbc6eSTakashi Iwai 	int err;
31823cfbc6eSTakashi Iwai 
31923cfbc6eSTakashi Iwai 	if (fw_priv->allocated_size) {
32023cfbc6eSTakashi Iwai 		out_size = fw_priv->allocated_size;
32123cfbc6eSTakashi Iwai 		out_buf = fw_priv->data;
32223cfbc6eSTakashi Iwai 	} else {
32323cfbc6eSTakashi Iwai 		zstd_frame_header params;
32423cfbc6eSTakashi Iwai 
32523cfbc6eSTakashi Iwai 		if (zstd_get_frame_header(&params, in_buffer, in_size) ||
32623cfbc6eSTakashi Iwai 		    params.frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN) {
32723cfbc6eSTakashi Iwai 			dev_dbg(dev, "%s: invalid zstd header\n", __func__);
32823cfbc6eSTakashi Iwai 			return -EINVAL;
32923cfbc6eSTakashi Iwai 		}
33023cfbc6eSTakashi Iwai 		out_size = params.frameContentSize;
33123cfbc6eSTakashi Iwai 		out_buf = vzalloc(out_size);
33223cfbc6eSTakashi Iwai 		if (!out_buf)
33323cfbc6eSTakashi Iwai 			return -ENOMEM;
33423cfbc6eSTakashi Iwai 	}
33523cfbc6eSTakashi Iwai 
33623cfbc6eSTakashi Iwai 	workspace_size = zstd_dctx_workspace_bound();
33723cfbc6eSTakashi Iwai 	workspace = kvzalloc(workspace_size, GFP_KERNEL);
33823cfbc6eSTakashi Iwai 	if (!workspace) {
33923cfbc6eSTakashi Iwai 		err = -ENOMEM;
34023cfbc6eSTakashi Iwai 		goto error;
34123cfbc6eSTakashi Iwai 	}
34223cfbc6eSTakashi Iwai 
34323cfbc6eSTakashi Iwai 	ctx = zstd_init_dctx(workspace, workspace_size);
34423cfbc6eSTakashi Iwai 	if (!ctx) {
34523cfbc6eSTakashi Iwai 		dev_dbg(dev, "%s: failed to initialize context\n", __func__);
34623cfbc6eSTakashi Iwai 		err = -EINVAL;
34723cfbc6eSTakashi Iwai 		goto error;
34823cfbc6eSTakashi Iwai 	}
34923cfbc6eSTakashi Iwai 
35023cfbc6eSTakashi Iwai 	len = zstd_decompress_dctx(ctx, out_buf, out_size, in_buffer, in_size);
35123cfbc6eSTakashi Iwai 	if (zstd_is_error(len)) {
35223cfbc6eSTakashi Iwai 		dev_dbg(dev, "%s: failed to decompress: %d\n", __func__,
35323cfbc6eSTakashi Iwai 			zstd_get_error_code(len));
35423cfbc6eSTakashi Iwai 		err = -EINVAL;
35523cfbc6eSTakashi Iwai 		goto error;
35623cfbc6eSTakashi Iwai 	}
35723cfbc6eSTakashi Iwai 
35823cfbc6eSTakashi Iwai 	if (!fw_priv->allocated_size)
35923cfbc6eSTakashi Iwai 		fw_priv->data = out_buf;
36023cfbc6eSTakashi Iwai 	fw_priv->size = len;
36123cfbc6eSTakashi Iwai 	err = 0;
36223cfbc6eSTakashi Iwai 
36323cfbc6eSTakashi Iwai  error:
36423cfbc6eSTakashi Iwai 	kvfree(workspace);
36523cfbc6eSTakashi Iwai 	if (err && !fw_priv->allocated_size)
36623cfbc6eSTakashi Iwai 		vfree(out_buf);
36723cfbc6eSTakashi Iwai 	return err;
36823cfbc6eSTakashi Iwai }
36923cfbc6eSTakashi Iwai #endif /* CONFIG_FW_LOADER_COMPRESS_ZSTD */
37023cfbc6eSTakashi Iwai 
37123cfbc6eSTakashi Iwai /*
37282fd7a81STakashi Iwai  * XZ-compressed firmware support
37382fd7a81STakashi Iwai  */
37423cfbc6eSTakashi Iwai #ifdef CONFIG_FW_LOADER_COMPRESS_XZ
37582fd7a81STakashi Iwai /* show an error and return the standard error code */
fw_decompress_xz_error(struct device * dev,enum xz_ret xz_ret)37682fd7a81STakashi Iwai static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret)
37782fd7a81STakashi Iwai {
37882fd7a81STakashi Iwai 	if (xz_ret != XZ_STREAM_END) {
37982fd7a81STakashi Iwai 		dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret);
38082fd7a81STakashi Iwai 		return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL;
38182fd7a81STakashi Iwai 	}
38282fd7a81STakashi Iwai 	return 0;
38382fd7a81STakashi Iwai }
38482fd7a81STakashi Iwai 
38582fd7a81STakashi Iwai /* single-shot decompression onto the pre-allocated buffer */
fw_decompress_xz_single(struct device * dev,struct fw_priv * fw_priv,size_t in_size,const void * in_buffer)38682fd7a81STakashi Iwai static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv,
38782fd7a81STakashi Iwai 				   size_t in_size, const void *in_buffer)
38882fd7a81STakashi Iwai {
38982fd7a81STakashi Iwai 	struct xz_dec *xz_dec;
39082fd7a81STakashi Iwai 	struct xz_buf xz_buf;
39182fd7a81STakashi Iwai 	enum xz_ret xz_ret;
39282fd7a81STakashi Iwai 
39382fd7a81STakashi Iwai 	xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1);
39482fd7a81STakashi Iwai 	if (!xz_dec)
39582fd7a81STakashi Iwai 		return -ENOMEM;
39682fd7a81STakashi Iwai 
39782fd7a81STakashi Iwai 	xz_buf.in_size = in_size;
39882fd7a81STakashi Iwai 	xz_buf.in = in_buffer;
39982fd7a81STakashi Iwai 	xz_buf.in_pos = 0;
40082fd7a81STakashi Iwai 	xz_buf.out_size = fw_priv->allocated_size;
40182fd7a81STakashi Iwai 	xz_buf.out = fw_priv->data;
40282fd7a81STakashi Iwai 	xz_buf.out_pos = 0;
40382fd7a81STakashi Iwai 
40482fd7a81STakashi Iwai 	xz_ret = xz_dec_run(xz_dec, &xz_buf);
40582fd7a81STakashi Iwai 	xz_dec_end(xz_dec);
40682fd7a81STakashi Iwai 
40782fd7a81STakashi Iwai 	fw_priv->size = xz_buf.out_pos;
40882fd7a81STakashi Iwai 	return fw_decompress_xz_error(dev, xz_ret);
40982fd7a81STakashi Iwai }
41082fd7a81STakashi Iwai 
41182fd7a81STakashi Iwai /* decompression on paged buffer and map it */
fw_decompress_xz_pages(struct device * dev,struct fw_priv * fw_priv,size_t in_size,const void * in_buffer)41282fd7a81STakashi Iwai static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv,
41382fd7a81STakashi Iwai 				  size_t in_size, const void *in_buffer)
41482fd7a81STakashi Iwai {
41582fd7a81STakashi Iwai 	struct xz_dec *xz_dec;
41682fd7a81STakashi Iwai 	struct xz_buf xz_buf;
41782fd7a81STakashi Iwai 	enum xz_ret xz_ret;
41882fd7a81STakashi Iwai 	struct page *page;
41982fd7a81STakashi Iwai 	int err = 0;
42082fd7a81STakashi Iwai 
42182fd7a81STakashi Iwai 	xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1);
42282fd7a81STakashi Iwai 	if (!xz_dec)
42382fd7a81STakashi Iwai 		return -ENOMEM;
42482fd7a81STakashi Iwai 
42582fd7a81STakashi Iwai 	xz_buf.in_size = in_size;
42682fd7a81STakashi Iwai 	xz_buf.in = in_buffer;
42782fd7a81STakashi Iwai 	xz_buf.in_pos = 0;
42882fd7a81STakashi Iwai 
42982fd7a81STakashi Iwai 	fw_priv->is_paged_buf = true;
43082fd7a81STakashi Iwai 	fw_priv->size = 0;
43182fd7a81STakashi Iwai 	do {
43282fd7a81STakashi Iwai 		if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) {
43382fd7a81STakashi Iwai 			err = -ENOMEM;
43482fd7a81STakashi Iwai 			goto out;
43582fd7a81STakashi Iwai 		}
43682fd7a81STakashi Iwai 
43782fd7a81STakashi Iwai 		/* decompress onto the new allocated page */
43882fd7a81STakashi Iwai 		page = fw_priv->pages[fw_priv->nr_pages - 1];
439f2d57765SFabio M. De Francesco 		xz_buf.out = kmap_local_page(page);
44082fd7a81STakashi Iwai 		xz_buf.out_pos = 0;
44182fd7a81STakashi Iwai 		xz_buf.out_size = PAGE_SIZE;
44282fd7a81STakashi Iwai 		xz_ret = xz_dec_run(xz_dec, &xz_buf);
443f2d57765SFabio M. De Francesco 		kunmap_local(xz_buf.out);
44482fd7a81STakashi Iwai 		fw_priv->size += xz_buf.out_pos;
44582fd7a81STakashi Iwai 		/* partial decompression means either end or error */
44682fd7a81STakashi Iwai 		if (xz_buf.out_pos != PAGE_SIZE)
44782fd7a81STakashi Iwai 			break;
44882fd7a81STakashi Iwai 	} while (xz_ret == XZ_OK);
44982fd7a81STakashi Iwai 
45082fd7a81STakashi Iwai 	err = fw_decompress_xz_error(dev, xz_ret);
45182fd7a81STakashi Iwai 	if (!err)
45282fd7a81STakashi Iwai 		err = fw_map_paged_buf(fw_priv);
45382fd7a81STakashi Iwai 
45482fd7a81STakashi Iwai  out:
45582fd7a81STakashi Iwai 	xz_dec_end(xz_dec);
45682fd7a81STakashi Iwai 	return err;
45782fd7a81STakashi Iwai }
45882fd7a81STakashi Iwai 
fw_decompress_xz(struct device * dev,struct fw_priv * fw_priv,size_t in_size,const void * in_buffer)45982fd7a81STakashi Iwai static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv,
46082fd7a81STakashi Iwai 			    size_t in_size, const void *in_buffer)
46182fd7a81STakashi Iwai {
46282fd7a81STakashi Iwai 	/* if the buffer is pre-allocated, we can perform in single-shot mode */
46382fd7a81STakashi Iwai 	if (fw_priv->data)
46482fd7a81STakashi Iwai 		return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer);
46582fd7a81STakashi Iwai 	else
46682fd7a81STakashi Iwai 		return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer);
46782fd7a81STakashi Iwai }
46823cfbc6eSTakashi Iwai #endif /* CONFIG_FW_LOADER_COMPRESS_XZ */
46982fd7a81STakashi Iwai 
4705d6d1dddSLuis R. Rodriguez /* direct firmware loading support */
4715d6d1dddSLuis R. Rodriguez static char fw_path_para[256];
4725d6d1dddSLuis R. Rodriguez static const char * const fw_path[] = {
4735d6d1dddSLuis R. Rodriguez 	fw_path_para,
4745d6d1dddSLuis R. Rodriguez 	"/lib/firmware/updates/" UTS_RELEASE,
4755d6d1dddSLuis R. Rodriguez 	"/lib/firmware/updates",
4765d6d1dddSLuis R. Rodriguez 	"/lib/firmware/" UTS_RELEASE,
4775d6d1dddSLuis R. Rodriguez 	"/lib/firmware"
4785d6d1dddSLuis R. Rodriguez };
4795d6d1dddSLuis R. Rodriguez 
4805d6d1dddSLuis R. Rodriguez /*
4815d6d1dddSLuis R. Rodriguez  * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH'
4825d6d1dddSLuis R. Rodriguez  * from kernel command line because firmware_class is generally built in
4835d6d1dddSLuis R. Rodriguez  * kernel instead of module.
4845d6d1dddSLuis R. Rodriguez  */
4855d6d1dddSLuis R. Rodriguez module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
4865d6d1dddSLuis R. Rodriguez MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
4875d6d1dddSLuis R. Rodriguez 
4885d6d1dddSLuis R. Rodriguez static int
fw_get_filesystem_firmware(struct device * device,struct fw_priv * fw_priv,const char * suffix,int (* decompress)(struct device * dev,struct fw_priv * fw_priv,size_t in_size,const void * in_buffer))48982fd7a81STakashi Iwai fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
49082fd7a81STakashi Iwai 			   const char *suffix,
49182fd7a81STakashi Iwai 			   int (*decompress)(struct device *dev,
49282fd7a81STakashi Iwai 					     struct fw_priv *fw_priv,
49382fd7a81STakashi Iwai 					     size_t in_size,
49482fd7a81STakashi Iwai 					     const void *in_buffer))
4955d6d1dddSLuis R. Rodriguez {
496f7a4f689SKees Cook 	size_t size;
497495ff363SFlorian Fainelli 	int i, len, maxlen = 0;
4985d6d1dddSLuis R. Rodriguez 	int rc = -ENOENT;
499495ff363SFlorian Fainelli 	char *path, *nt = NULL;
5005d6d1dddSLuis R. Rodriguez 	size_t msize = INT_MAX;
50182fd7a81STakashi Iwai 	void *buffer = NULL;
5025d6d1dddSLuis R. Rodriguez 
5035d6d1dddSLuis R. Rodriguez 	/* Already populated data member means we're loading into a buffer */
50482fd7a81STakashi Iwai 	if (!decompress && fw_priv->data) {
50582fd7a81STakashi Iwai 		buffer = fw_priv->data;
5065d6d1dddSLuis R. Rodriguez 		msize = fw_priv->allocated_size;
5075d6d1dddSLuis R. Rodriguez 	}
5085d6d1dddSLuis R. Rodriguez 
5095d6d1dddSLuis R. Rodriguez 	path = __getname();
5105d6d1dddSLuis R. Rodriguez 	if (!path)
5115d6d1dddSLuis R. Rodriguez 		return -ENOMEM;
5125d6d1dddSLuis R. Rodriguez 
513e7cb072eSRasmus Villemoes 	wait_for_initramfs();
5145d6d1dddSLuis R. Rodriguez 	for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
51559cdb23cSScott Branden 		size_t file_size = 0;
51659cdb23cSScott Branden 		size_t *file_size_ptr = NULL;
51759cdb23cSScott Branden 
5185d6d1dddSLuis R. Rodriguez 		/* skip the unset customized path */
5195d6d1dddSLuis R. Rodriguez 		if (!fw_path[i][0])
5205d6d1dddSLuis R. Rodriguez 			continue;
5215d6d1dddSLuis R. Rodriguez 
522495ff363SFlorian Fainelli 		/* strip off \n from customized path */
523495ff363SFlorian Fainelli 		maxlen = strlen(fw_path[i]);
524495ff363SFlorian Fainelli 		if (i == 0) {
525495ff363SFlorian Fainelli 			nt = strchr(fw_path[i], '\n');
526495ff363SFlorian Fainelli 			if (nt)
527495ff363SFlorian Fainelli 				maxlen = nt - fw_path[i];
528495ff363SFlorian Fainelli 		}
529495ff363SFlorian Fainelli 
530495ff363SFlorian Fainelli 		len = snprintf(path, PATH_MAX, "%.*s/%s%s",
531495ff363SFlorian Fainelli 			       maxlen, fw_path[i],
532495ff363SFlorian Fainelli 			       fw_priv->fw_name, suffix);
5335d6d1dddSLuis R. Rodriguez 		if (len >= PATH_MAX) {
5345d6d1dddSLuis R. Rodriguez 			rc = -ENAMETOOLONG;
5355d6d1dddSLuis R. Rodriguez 			break;
5365d6d1dddSLuis R. Rodriguez 		}
5375d6d1dddSLuis R. Rodriguez 
5385d6d1dddSLuis R. Rodriguez 		fw_priv->size = 0;
539901cff7cSTopi Miettinen 
54059cdb23cSScott Branden 		/*
54159cdb23cSScott Branden 		 * The total file size is only examined when doing a partial
54259cdb23cSScott Branden 		 * read; the "full read" case needs to fail if the whole
54359cdb23cSScott Branden 		 * firmware was not completely loaded.
54459cdb23cSScott Branden 		 */
54559cdb23cSScott Branden 		if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && buffer)
54659cdb23cSScott Branden 			file_size_ptr = &file_size;
54759cdb23cSScott Branden 
548901cff7cSTopi Miettinen 		/* load firmware files from the mount namespace of init */
54959cdb23cSScott Branden 		rc = kernel_read_file_from_path_initns(path, fw_priv->offset,
55059cdb23cSScott Branden 						       &buffer, msize,
55159cdb23cSScott Branden 						       file_size_ptr,
552c307459bSKees Cook 						       READING_FIRMWARE);
553f7a4f689SKees Cook 		if (rc < 0) {
554*1fe6e4f0SMukesh Ojha 			if (!(fw_priv->opt_flags & FW_OPT_NO_WARN)) {
555eac473bcSJohn Zhao 				if (rc != -ENOENT)
556*1fe6e4f0SMukesh Ojha 					dev_warn(device,
557*1fe6e4f0SMukesh Ojha 						 "loading %s failed with error %d\n",
5585d6d1dddSLuis R. Rodriguez 						 path, rc);
559eac473bcSJohn Zhao 				else
560*1fe6e4f0SMukesh Ojha 					dev_dbg(device,
561*1fe6e4f0SMukesh Ojha 						"loading %s failed for no such file or directory.\n",
562eac473bcSJohn Zhao 						path);
563*1fe6e4f0SMukesh Ojha 			}
5645d6d1dddSLuis R. Rodriguez 			continue;
5655d6d1dddSLuis R. Rodriguez 		}
566f7a4f689SKees Cook 		size = rc;
567f7a4f689SKees Cook 		rc = 0;
568f7a4f689SKees Cook 
569b889b3b0SDrew DeVault 		dev_dbg(device, "Loading firmware from %s\n", path);
57082fd7a81STakashi Iwai 		if (decompress) {
57182fd7a81STakashi Iwai 			dev_dbg(device, "f/w decompressing %s\n",
57282fd7a81STakashi Iwai 				fw_priv->fw_name);
57382fd7a81STakashi Iwai 			rc = decompress(device, fw_priv, size, buffer);
57482fd7a81STakashi Iwai 			/* discard the superfluous original content */
57582fd7a81STakashi Iwai 			vfree(buffer);
57682fd7a81STakashi Iwai 			buffer = NULL;
57782fd7a81STakashi Iwai 			if (rc) {
57882fd7a81STakashi Iwai 				fw_free_paged_buf(fw_priv);
57982fd7a81STakashi Iwai 				continue;
58082fd7a81STakashi Iwai 			}
58182fd7a81STakashi Iwai 		} else {
58282fd7a81STakashi Iwai 			dev_dbg(device, "direct-loading %s\n",
58382fd7a81STakashi Iwai 				fw_priv->fw_name);
58482fd7a81STakashi Iwai 			if (!fw_priv->data)
58582fd7a81STakashi Iwai 				fw_priv->data = buffer;
5865d6d1dddSLuis R. Rodriguez 			fw_priv->size = size;
58782fd7a81STakashi Iwai 		}
5885d6d1dddSLuis R. Rodriguez 		fw_state_done(fw_priv);
5895d6d1dddSLuis R. Rodriguez 		break;
5905d6d1dddSLuis R. Rodriguez 	}
5915d6d1dddSLuis R. Rodriguez 	__putname(path);
5925d6d1dddSLuis R. Rodriguez 
5935d6d1dddSLuis R. Rodriguez 	return rc;
5945d6d1dddSLuis R. Rodriguez }
5955d6d1dddSLuis R. Rodriguez 
5965d6d1dddSLuis R. Rodriguez /* firmware holds the ownership of pages */
firmware_free_data(const struct firmware * fw)5975d6d1dddSLuis R. Rodriguez static void firmware_free_data(const struct firmware *fw)
5985d6d1dddSLuis R. Rodriguez {
5995d6d1dddSLuis R. Rodriguez 	/* Loaded directly? */
6005d6d1dddSLuis R. Rodriguez 	if (!fw->priv) {
6015d6d1dddSLuis R. Rodriguez 		vfree(fw->data);
6025d6d1dddSLuis R. Rodriguez 		return;
6035d6d1dddSLuis R. Rodriguez 	}
6045d6d1dddSLuis R. Rodriguez 	free_fw_priv(fw->priv);
6055d6d1dddSLuis R. Rodriguez }
6065d6d1dddSLuis R. Rodriguez 
6075d6d1dddSLuis R. Rodriguez /* store the pages buffer info firmware from buf */
fw_set_page_data(struct fw_priv * fw_priv,struct firmware * fw)6085d6d1dddSLuis R. Rodriguez static void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw)
6095d6d1dddSLuis R. Rodriguez {
6105d6d1dddSLuis R. Rodriguez 	fw->priv = fw_priv;
6115d6d1dddSLuis R. Rodriguez 	fw->size = fw_priv->size;
6125d6d1dddSLuis R. Rodriguez 	fw->data = fw_priv->data;
6135d6d1dddSLuis R. Rodriguez 
6145d6d1dddSLuis R. Rodriguez 	pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n",
6155d6d1dddSLuis R. Rodriguez 		 __func__, fw_priv->fw_name, fw_priv, fw_priv->data,
6165d6d1dddSLuis R. Rodriguez 		 (unsigned int)fw_priv->size);
6175d6d1dddSLuis R. Rodriguez }
6185d6d1dddSLuis R. Rodriguez 
619030cc787SMark Salyzyn #ifdef CONFIG_FW_CACHE
fw_name_devm_release(struct device * dev,void * res)6205d6d1dddSLuis R. Rodriguez static void fw_name_devm_release(struct device *dev, void *res)
6215d6d1dddSLuis R. Rodriguez {
6225d6d1dddSLuis R. Rodriguez 	struct fw_name_devm *fwn = res;
6235d6d1dddSLuis R. Rodriguez 
6245d6d1dddSLuis R. Rodriguez 	if (fwn->magic == (unsigned long)&fw_cache)
6255d6d1dddSLuis R. Rodriguez 		pr_debug("%s: fw_name-%s devm-%p released\n",
6265d6d1dddSLuis R. Rodriguez 				__func__, fwn->name, res);
6275d6d1dddSLuis R. Rodriguez 	kfree_const(fwn->name);
6285d6d1dddSLuis R. Rodriguez }
6295d6d1dddSLuis R. Rodriguez 
fw_devm_match(struct device * dev,void * res,void * match_data)6305d6d1dddSLuis R. Rodriguez static int fw_devm_match(struct device *dev, void *res,
6315d6d1dddSLuis R. Rodriguez 		void *match_data)
6325d6d1dddSLuis R. Rodriguez {
6335d6d1dddSLuis R. Rodriguez 	struct fw_name_devm *fwn = res;
6345d6d1dddSLuis R. Rodriguez 
6355d6d1dddSLuis R. Rodriguez 	return (fwn->magic == (unsigned long)&fw_cache) &&
6365d6d1dddSLuis R. Rodriguez 		!strcmp(fwn->name, match_data);
6375d6d1dddSLuis R. Rodriguez }
6385d6d1dddSLuis R. Rodriguez 
fw_find_devm_name(struct device * dev,const char * name)6395d6d1dddSLuis R. Rodriguez static struct fw_name_devm *fw_find_devm_name(struct device *dev,
6405d6d1dddSLuis R. Rodriguez 		const char *name)
6415d6d1dddSLuis R. Rodriguez {
6425d6d1dddSLuis R. Rodriguez 	struct fw_name_devm *fwn;
6435d6d1dddSLuis R. Rodriguez 
6445d6d1dddSLuis R. Rodriguez 	fwn = devres_find(dev, fw_name_devm_release,
6455d6d1dddSLuis R. Rodriguez 			  fw_devm_match, (void *)name);
6465d6d1dddSLuis R. Rodriguez 	return fwn;
6475d6d1dddSLuis R. Rodriguez }
6485d6d1dddSLuis R. Rodriguez 
fw_cache_is_setup(struct device * dev,const char * name)6493194d06aSLuis R. Rodriguez static bool fw_cache_is_setup(struct device *dev, const char *name)
6505d6d1dddSLuis R. Rodriguez {
6515d6d1dddSLuis R. Rodriguez 	struct fw_name_devm *fwn;
6525d6d1dddSLuis R. Rodriguez 
6535d6d1dddSLuis R. Rodriguez 	fwn = fw_find_devm_name(dev, name);
6545d6d1dddSLuis R. Rodriguez 	if (fwn)
6553194d06aSLuis R. Rodriguez 		return true;
6563194d06aSLuis R. Rodriguez 
6573194d06aSLuis R. Rodriguez 	return false;
6583194d06aSLuis R. Rodriguez }
6593194d06aSLuis R. Rodriguez 
6603194d06aSLuis R. Rodriguez /* add firmware name into devres list */
fw_add_devm_name(struct device * dev,const char * name)6613194d06aSLuis R. Rodriguez static int fw_add_devm_name(struct device *dev, const char *name)
6623194d06aSLuis R. Rodriguez {
6633194d06aSLuis R. Rodriguez 	struct fw_name_devm *fwn;
6643194d06aSLuis R. Rodriguez 
6653194d06aSLuis R. Rodriguez 	if (fw_cache_is_setup(dev, name))
666d15d7311SLuis R. Rodriguez 		return 0;
6675d6d1dddSLuis R. Rodriguez 
6685d6d1dddSLuis R. Rodriguez 	fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
6695d6d1dddSLuis R. Rodriguez 			   GFP_KERNEL);
6705d6d1dddSLuis R. Rodriguez 	if (!fwn)
6715d6d1dddSLuis R. Rodriguez 		return -ENOMEM;
6725d6d1dddSLuis R. Rodriguez 	fwn->name = kstrdup_const(name, GFP_KERNEL);
6735d6d1dddSLuis R. Rodriguez 	if (!fwn->name) {
6745d6d1dddSLuis R. Rodriguez 		devres_free(fwn);
6755d6d1dddSLuis R. Rodriguez 		return -ENOMEM;
6765d6d1dddSLuis R. Rodriguez 	}
6775d6d1dddSLuis R. Rodriguez 
6785d6d1dddSLuis R. Rodriguez 	fwn->magic = (unsigned long)&fw_cache;
6795d6d1dddSLuis R. Rodriguez 	devres_add(dev, fwn);
6805d6d1dddSLuis R. Rodriguez 
6815d6d1dddSLuis R. Rodriguez 	return 0;
6825d6d1dddSLuis R. Rodriguez }
6835d6d1dddSLuis R. Rodriguez #else
fw_cache_is_setup(struct device * dev,const char * name)684995e8695SLuis R. Rodriguez static bool fw_cache_is_setup(struct device *dev, const char *name)
685995e8695SLuis R. Rodriguez {
686995e8695SLuis R. Rodriguez 	return false;
687995e8695SLuis R. Rodriguez }
688995e8695SLuis R. Rodriguez 
fw_add_devm_name(struct device * dev,const char * name)6895d6d1dddSLuis R. Rodriguez static int fw_add_devm_name(struct device *dev, const char *name)
6905d6d1dddSLuis R. Rodriguez {
6915d6d1dddSLuis R. Rodriguez 	return 0;
6925d6d1dddSLuis R. Rodriguez }
6935d6d1dddSLuis R. Rodriguez #endif
6945d6d1dddSLuis R. Rodriguez 
assign_fw(struct firmware * fw,struct device * device)69589287c16SKees Cook int assign_fw(struct firmware *fw, struct device *device)
6965d6d1dddSLuis R. Rodriguez {
6975d6d1dddSLuis R. Rodriguez 	struct fw_priv *fw_priv = fw->priv;
698d15d7311SLuis R. Rodriguez 	int ret;
6995d6d1dddSLuis R. Rodriguez 
7005d6d1dddSLuis R. Rodriguez 	mutex_lock(&fw_lock);
7015d6d1dddSLuis R. Rodriguez 	if (!fw_priv->size || fw_state_is_aborted(fw_priv)) {
7025d6d1dddSLuis R. Rodriguez 		mutex_unlock(&fw_lock);
7035d6d1dddSLuis R. Rodriguez 		return -ENOENT;
7045d6d1dddSLuis R. Rodriguez 	}
7055d6d1dddSLuis R. Rodriguez 
7065d6d1dddSLuis R. Rodriguez 	/*
7075d6d1dddSLuis R. Rodriguez 	 * add firmware name into devres list so that we can auto cache
7085d6d1dddSLuis R. Rodriguez 	 * and uncache firmware for device.
7095d6d1dddSLuis R. Rodriguez 	 *
7105d6d1dddSLuis R. Rodriguez 	 * device may has been deleted already, but the problem
7115d6d1dddSLuis R. Rodriguez 	 * should be fixed in devres or driver core.
7125d6d1dddSLuis R. Rodriguez 	 */
7135d6d1dddSLuis R. Rodriguez 	/* don't cache firmware handled without uevent */
71489287c16SKees Cook 	if (device && (fw_priv->opt_flags & FW_OPT_UEVENT) &&
71589287c16SKees Cook 	    !(fw_priv->opt_flags & FW_OPT_NOCACHE)) {
716d15d7311SLuis R. Rodriguez 		ret = fw_add_devm_name(device, fw_priv->fw_name);
717d15d7311SLuis R. Rodriguez 		if (ret) {
718d15d7311SLuis R. Rodriguez 			mutex_unlock(&fw_lock);
719d15d7311SLuis R. Rodriguez 			return ret;
720d15d7311SLuis R. Rodriguez 		}
721d15d7311SLuis R. Rodriguez 	}
7225d6d1dddSLuis R. Rodriguez 
7235d6d1dddSLuis R. Rodriguez 	/*
7245d6d1dddSLuis R. Rodriguez 	 * After caching firmware image is started, let it piggyback
7255d6d1dddSLuis R. Rodriguez 	 * on request firmware.
7265d6d1dddSLuis R. Rodriguez 	 */
72789287c16SKees Cook 	if (!(fw_priv->opt_flags & FW_OPT_NOCACHE) &&
7283ecc8cb7SZhen Lei 	    fw_priv->fwc->state == FW_LOADER_START_CACHE)
7293ecc8cb7SZhen Lei 		fw_cache_piggyback_on_request(fw_priv);
7305d6d1dddSLuis R. Rodriguez 
7315d6d1dddSLuis R. Rodriguez 	/* pass the pages buffer to driver at the last minute */
7325d6d1dddSLuis R. Rodriguez 	fw_set_page_data(fw_priv, fw);
7335d6d1dddSLuis R. Rodriguez 	mutex_unlock(&fw_lock);
7345d6d1dddSLuis R. Rodriguez 	return 0;
7355d6d1dddSLuis R. Rodriguez }
7365d6d1dddSLuis R. Rodriguez 
7375d6d1dddSLuis R. Rodriguez /* prepare firmware and firmware_buf structs;
7385d6d1dddSLuis R. Rodriguez  * return 0 if a firmware is already assigned, 1 if need to load one,
7395d6d1dddSLuis R. Rodriguez  * or a negative error code
7405d6d1dddSLuis R. Rodriguez  */
7415d6d1dddSLuis R. Rodriguez static int
_request_firmware_prepare(struct firmware ** firmware_p,const char * name,struct device * device,void * dbuf,size_t size,size_t offset,u32 opt_flags)7425d6d1dddSLuis R. Rodriguez _request_firmware_prepare(struct firmware **firmware_p, const char *name,
743422b3db2SRishabh Bhatnagar 			  struct device *device, void *dbuf, size_t size,
74459cdb23cSScott Branden 			  size_t offset, u32 opt_flags)
7455d6d1dddSLuis R. Rodriguez {
7465d6d1dddSLuis R. Rodriguez 	struct firmware *firmware;
7475d6d1dddSLuis R. Rodriguez 	struct fw_priv *fw_priv;
7485d6d1dddSLuis R. Rodriguez 	int ret;
7495d6d1dddSLuis R. Rodriguez 
7505d6d1dddSLuis R. Rodriguez 	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
7515d6d1dddSLuis R. Rodriguez 	if (!firmware) {
7525d6d1dddSLuis R. Rodriguez 		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
7535d6d1dddSLuis R. Rodriguez 			__func__);
7545d6d1dddSLuis R. Rodriguez 		return -ENOMEM;
7555d6d1dddSLuis R. Rodriguez 	}
7565d6d1dddSLuis R. Rodriguez 
7577c4fd907SLuis Chamberlain 	if (firmware_request_builtin_buf(firmware, name, dbuf, size)) {
7585d6d1dddSLuis R. Rodriguez 		dev_dbg(device, "using built-in %s\n", name);
7595d6d1dddSLuis R. Rodriguez 		return 0; /* assigned */
7605d6d1dddSLuis R. Rodriguez 	}
7615d6d1dddSLuis R. Rodriguez 
762422b3db2SRishabh Bhatnagar 	ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size,
76359cdb23cSScott Branden 				   offset, opt_flags);
7645d6d1dddSLuis R. Rodriguez 
7655d6d1dddSLuis R. Rodriguez 	/*
7665d6d1dddSLuis R. Rodriguez 	 * bind with 'priv' now to avoid warning in failure path
7675d6d1dddSLuis R. Rodriguez 	 * of requesting firmware.
7685d6d1dddSLuis R. Rodriguez 	 */
7695d6d1dddSLuis R. Rodriguez 	firmware->priv = fw_priv;
7705d6d1dddSLuis R. Rodriguez 
7715d6d1dddSLuis R. Rodriguez 	if (ret > 0) {
7725d6d1dddSLuis R. Rodriguez 		ret = fw_state_wait(fw_priv);
7735d6d1dddSLuis R. Rodriguez 		if (!ret) {
7745d6d1dddSLuis R. Rodriguez 			fw_set_page_data(fw_priv, firmware);
7755d6d1dddSLuis R. Rodriguez 			return 0; /* assigned */
7765d6d1dddSLuis R. Rodriguez 		}
7775d6d1dddSLuis R. Rodriguez 	}
7785d6d1dddSLuis R. Rodriguez 
7795d6d1dddSLuis R. Rodriguez 	if (ret < 0)
7805d6d1dddSLuis R. Rodriguez 		return ret;
7815d6d1dddSLuis R. Rodriguez 	return 1; /* need to load */
7825d6d1dddSLuis R. Rodriguez }
7835d6d1dddSLuis R. Rodriguez 
7845d6d1dddSLuis R. Rodriguez /*
7855d6d1dddSLuis R. Rodriguez  * Batched requests need only one wake, we need to do this step last due to the
7865d6d1dddSLuis R. Rodriguez  * fallback mechanism. The buf is protected with kref_get(), and it won't be
7875d6d1dddSLuis R. Rodriguez  * released until the last user calls release_firmware().
7885d6d1dddSLuis R. Rodriguez  *
7895d6d1dddSLuis R. Rodriguez  * Failed batched requests are possible as well, in such cases we just share
7905d6d1dddSLuis R. Rodriguez  * the struct fw_priv and won't release it until all requests are woken
7915d6d1dddSLuis R. Rodriguez  * and have gone through this same path.
7925d6d1dddSLuis R. Rodriguez  */
fw_abort_batch_reqs(struct firmware * fw)7935d6d1dddSLuis R. Rodriguez static void fw_abort_batch_reqs(struct firmware *fw)
7945d6d1dddSLuis R. Rodriguez {
7955d6d1dddSLuis R. Rodriguez 	struct fw_priv *fw_priv;
7965d6d1dddSLuis R. Rodriguez 
7975d6d1dddSLuis R. Rodriguez 	/* Loaded directly? */
7985d6d1dddSLuis R. Rodriguez 	if (!fw || !fw->priv)
7995d6d1dddSLuis R. Rodriguez 		return;
8005d6d1dddSLuis R. Rodriguez 
8015d6d1dddSLuis R. Rodriguez 	fw_priv = fw->priv;
80275d95e2eSAnirudh Rayabharam 	mutex_lock(&fw_lock);
8035d6d1dddSLuis R. Rodriguez 	if (!fw_state_is_aborted(fw_priv))
8045d6d1dddSLuis R. Rodriguez 		fw_state_aborted(fw_priv);
80575d95e2eSAnirudh Rayabharam 	mutex_unlock(&fw_lock);
8065d6d1dddSLuis R. Rodriguez }
8075d6d1dddSLuis R. Rodriguez 
80802fe26f2SAmadeusz Sławiński #if defined(CONFIG_FW_LOADER_DEBUG)
80902fe26f2SAmadeusz Sławiński #include <crypto/hash.h>
81002fe26f2SAmadeusz Sławiński #include <crypto/sha2.h>
81102fe26f2SAmadeusz Sławiński 
fw_log_firmware_info(const struct firmware * fw,const char * name,struct device * device)81202fe26f2SAmadeusz Sławiński static void fw_log_firmware_info(const struct firmware *fw, const char *name, struct device *device)
81302fe26f2SAmadeusz Sławiński {
81402fe26f2SAmadeusz Sławiński 	struct shash_desc *shash;
81502fe26f2SAmadeusz Sławiński 	struct crypto_shash *alg;
81602fe26f2SAmadeusz Sławiński 	u8 *sha256buf;
81702fe26f2SAmadeusz Sławiński 	char *outbuf;
81802fe26f2SAmadeusz Sławiński 
81902fe26f2SAmadeusz Sławiński 	alg = crypto_alloc_shash("sha256", 0, 0);
820ffa28312SDan Carpenter 	if (IS_ERR(alg))
82102fe26f2SAmadeusz Sławiński 		return;
82202fe26f2SAmadeusz Sławiński 
82302fe26f2SAmadeusz Sławiński 	sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
82402fe26f2SAmadeusz Sławiński 	outbuf = kmalloc(SHA256_BLOCK_SIZE + 1, GFP_KERNEL);
82502fe26f2SAmadeusz Sławiński 	shash = kmalloc(sizeof(*shash) + crypto_shash_descsize(alg), GFP_KERNEL);
82602fe26f2SAmadeusz Sławiński 	if (!sha256buf || !outbuf || !shash)
82702fe26f2SAmadeusz Sławiński 		goto out_free;
82802fe26f2SAmadeusz Sławiński 
82902fe26f2SAmadeusz Sławiński 	shash->tfm = alg;
83002fe26f2SAmadeusz Sławiński 
83102fe26f2SAmadeusz Sławiński 	if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0)
83202fe26f2SAmadeusz Sławiński 		goto out_shash;
83302fe26f2SAmadeusz Sławiński 
83402fe26f2SAmadeusz Sławiński 	for (int i = 0; i < SHA256_DIGEST_SIZE; i++)
83502fe26f2SAmadeusz Sławiński 		sprintf(&outbuf[i * 2], "%02x", sha256buf[i]);
83602fe26f2SAmadeusz Sławiński 	outbuf[SHA256_BLOCK_SIZE] = 0;
83702fe26f2SAmadeusz Sławiński 	dev_dbg(device, "Loaded FW: %s, sha256: %s\n", name, outbuf);
83802fe26f2SAmadeusz Sławiński 
83902fe26f2SAmadeusz Sławiński out_shash:
84002fe26f2SAmadeusz Sławiński 	crypto_free_shash(alg);
84102fe26f2SAmadeusz Sławiński out_free:
84202fe26f2SAmadeusz Sławiński 	kfree(shash);
84302fe26f2SAmadeusz Sławiński 	kfree(outbuf);
84402fe26f2SAmadeusz Sławiński 	kfree(sha256buf);
84502fe26f2SAmadeusz Sławiński }
84602fe26f2SAmadeusz Sławiński #else
fw_log_firmware_info(const struct firmware * fw,const char * name,struct device * device)84702fe26f2SAmadeusz Sławiński static void fw_log_firmware_info(const struct firmware *fw, const char *name,
84802fe26f2SAmadeusz Sławiński 				 struct device *device)
84902fe26f2SAmadeusz Sławiński {}
85002fe26f2SAmadeusz Sławiński #endif
85102fe26f2SAmadeusz Sławiński 
8525d6d1dddSLuis R. Rodriguez /* called from request_firmware() and request_firmware_work_func() */
8535d6d1dddSLuis R. Rodriguez static int
_request_firmware(const struct firmware ** firmware_p,const char * name,struct device * device,void * buf,size_t size,size_t offset,u32 opt_flags)8545d6d1dddSLuis R. Rodriguez _request_firmware(const struct firmware **firmware_p, const char *name,
8555d6d1dddSLuis R. Rodriguez 		  struct device *device, void *buf, size_t size,
85659cdb23cSScott Branden 		  size_t offset, u32 opt_flags)
8575d6d1dddSLuis R. Rodriguez {
8585d6d1dddSLuis R. Rodriguez 	struct firmware *fw = NULL;
859581dd698SThiébaud Weksteen 	struct cred *kern_cred = NULL;
860581dd698SThiébaud Weksteen 	const struct cred *old_cred;
86159cdb23cSScott Branden 	bool nondirect = false;
8625d6d1dddSLuis R. Rodriguez 	int ret;
8635d6d1dddSLuis R. Rodriguez 
8645d6d1dddSLuis R. Rodriguez 	if (!firmware_p)
8655d6d1dddSLuis R. Rodriguez 		return -EINVAL;
8665d6d1dddSLuis R. Rodriguez 
8675d6d1dddSLuis R. Rodriguez 	if (!name || name[0] == '\0') {
8685d6d1dddSLuis R. Rodriguez 		ret = -EINVAL;
8695d6d1dddSLuis R. Rodriguez 		goto out;
8705d6d1dddSLuis R. Rodriguez 	}
8715d6d1dddSLuis R. Rodriguez 
872422b3db2SRishabh Bhatnagar 	ret = _request_firmware_prepare(&fw, name, device, buf, size,
87359cdb23cSScott Branden 					offset, opt_flags);
8745d6d1dddSLuis R. Rodriguez 	if (ret <= 0) /* error or already assigned */
8755d6d1dddSLuis R. Rodriguez 		goto out;
8765d6d1dddSLuis R. Rodriguez 
877581dd698SThiébaud Weksteen 	/*
878581dd698SThiébaud Weksteen 	 * We are about to try to access the firmware file. Because we may have been
879581dd698SThiébaud Weksteen 	 * called by a driver when serving an unrelated request from userland, we use
880581dd698SThiébaud Weksteen 	 * the kernel credentials to read the file.
881581dd698SThiébaud Weksteen 	 */
8825a17f040SKees Cook 	kern_cred = prepare_kernel_cred(&init_task);
883581dd698SThiébaud Weksteen 	if (!kern_cred) {
884581dd698SThiébaud Weksteen 		ret = -ENOMEM;
885581dd698SThiébaud Weksteen 		goto out;
886581dd698SThiébaud Weksteen 	}
887581dd698SThiébaud Weksteen 	old_cred = override_creds(kern_cred);
888581dd698SThiébaud Weksteen 
88982fd7a81STakashi Iwai 	ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
89059cdb23cSScott Branden 
89159cdb23cSScott Branden 	/* Only full reads can support decompression, platform, and sysfs. */
89259cdb23cSScott Branden 	if (!(opt_flags & FW_OPT_PARTIAL))
89359cdb23cSScott Branden 		nondirect = true;
89459cdb23cSScott Branden 
89523cfbc6eSTakashi Iwai #ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD
89623cfbc6eSTakashi Iwai 	if (ret == -ENOENT && nondirect)
89723cfbc6eSTakashi Iwai 		ret = fw_get_filesystem_firmware(device, fw->priv, ".zst",
89823cfbc6eSTakashi Iwai 						 fw_decompress_zstd);
89923cfbc6eSTakashi Iwai #endif
90023cfbc6eSTakashi Iwai #ifdef CONFIG_FW_LOADER_COMPRESS_XZ
90159cdb23cSScott Branden 	if (ret == -ENOENT && nondirect)
90282fd7a81STakashi Iwai 		ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
90382fd7a81STakashi Iwai 						 fw_decompress_xz);
90482fd7a81STakashi Iwai #endif
90559cdb23cSScott Branden 	if (ret == -ENOENT && nondirect)
90689287c16SKees Cook 		ret = firmware_fallback_platform(fw->priv);
907e4c2c0ffSHans de Goede 
9085d6d1dddSLuis R. Rodriguez 	if (ret) {
9095d6d1dddSLuis R. Rodriguez 		if (!(opt_flags & FW_OPT_NO_WARN))
9105d6d1dddSLuis R. Rodriguez 			dev_warn(device,
9115d6d1dddSLuis R. Rodriguez 				 "Direct firmware load for %s failed with error %d\n",
9125d6d1dddSLuis R. Rodriguez 				 name, ret);
91359cdb23cSScott Branden 		if (nondirect)
91459cdb23cSScott Branden 			ret = firmware_fallback_sysfs(fw, name, device,
91559cdb23cSScott Branden 						      opt_flags, ret);
9165d6d1dddSLuis R. Rodriguez 	} else
91789287c16SKees Cook 		ret = assign_fw(fw, device);
9185d6d1dddSLuis R. Rodriguez 
919581dd698SThiébaud Weksteen 	revert_creds(old_cred);
920581dd698SThiébaud Weksteen 	put_cred(kern_cred);
921581dd698SThiébaud Weksteen 
9225d6d1dddSLuis R. Rodriguez out:
9235d6d1dddSLuis R. Rodriguez 	if (ret < 0) {
9245d6d1dddSLuis R. Rodriguez 		fw_abort_batch_reqs(fw);
9255d6d1dddSLuis R. Rodriguez 		release_firmware(fw);
9265d6d1dddSLuis R. Rodriguez 		fw = NULL;
92702fe26f2SAmadeusz Sławiński 	} else {
92802fe26f2SAmadeusz Sławiński 		fw_log_firmware_info(fw, name, device);
9295d6d1dddSLuis R. Rodriguez 	}
9305d6d1dddSLuis R. Rodriguez 
9315d6d1dddSLuis R. Rodriguez 	*firmware_p = fw;
9325d6d1dddSLuis R. Rodriguez 	return ret;
9335d6d1dddSLuis R. Rodriguez }
9345d6d1dddSLuis R. Rodriguez 
9355d6d1dddSLuis R. Rodriguez /**
936c35f9cbbSAndres Rodriguez  * request_firmware() - send firmware request and wait for it
9375d6d1dddSLuis R. Rodriguez  * @firmware_p: pointer to firmware image
9385d6d1dddSLuis R. Rodriguez  * @name: name of firmware file
9395d6d1dddSLuis R. Rodriguez  * @device: device for which firmware is being loaded
9405d6d1dddSLuis R. Rodriguez  *
9415d6d1dddSLuis R. Rodriguez  *      @firmware_p will be used to return a firmware image by the name
9425d6d1dddSLuis R. Rodriguez  *      of @name for device @device.
9435d6d1dddSLuis R. Rodriguez  *
9445d6d1dddSLuis R. Rodriguez  *      Should be called from user context where sleeping is allowed.
9455d6d1dddSLuis R. Rodriguez  *
9465d6d1dddSLuis R. Rodriguez  *      @name will be used as $FIRMWARE in the uevent environment and
9475d6d1dddSLuis R. Rodriguez  *      should be distinctive enough not to be confused with any other
9485d6d1dddSLuis R. Rodriguez  *      firmware image for this or any other device.
9495d6d1dddSLuis R. Rodriguez  *
9505d6d1dddSLuis R. Rodriguez  *	Caller must hold the reference count of @device.
9515d6d1dddSLuis R. Rodriguez  *
9525d6d1dddSLuis R. Rodriguez  *	The function can be called safely inside device's suspend and
9535d6d1dddSLuis R. Rodriguez  *	resume callback.
9545d6d1dddSLuis R. Rodriguez  **/
9555d6d1dddSLuis R. Rodriguez int
request_firmware(const struct firmware ** firmware_p,const char * name,struct device * device)9565d6d1dddSLuis R. Rodriguez request_firmware(const struct firmware **firmware_p, const char *name,
9575d6d1dddSLuis R. Rodriguez 		 struct device *device)
9585d6d1dddSLuis R. Rodriguez {
9595d6d1dddSLuis R. Rodriguez 	int ret;
9605d6d1dddSLuis R. Rodriguez 
9615d6d1dddSLuis R. Rodriguez 	/* Need to pin this module until return */
9625d6d1dddSLuis R. Rodriguez 	__module_get(THIS_MODULE);
96359cdb23cSScott Branden 	ret = _request_firmware(firmware_p, name, device, NULL, 0, 0,
9645d6d1dddSLuis R. Rodriguez 				FW_OPT_UEVENT);
9655d6d1dddSLuis R. Rodriguez 	module_put(THIS_MODULE);
9665d6d1dddSLuis R. Rodriguez 	return ret;
9675d6d1dddSLuis R. Rodriguez }
9685d6d1dddSLuis R. Rodriguez EXPORT_SYMBOL(request_firmware);
9695d6d1dddSLuis R. Rodriguez 
9705d6d1dddSLuis R. Rodriguez /**
9717dcc0134SAndres Rodriguez  * firmware_request_nowarn() - request for an optional fw module
9727dcc0134SAndres Rodriguez  * @firmware: pointer to firmware image
9737dcc0134SAndres Rodriguez  * @name: name of firmware file
9747dcc0134SAndres Rodriguez  * @device: device for which firmware is being loaded
9757dcc0134SAndres Rodriguez  *
9762fce60beSWolfram Sang  * This function is similar in behaviour to request_firmware(), except it
9772fce60beSWolfram Sang  * doesn't produce warning messages when the file is not found. The sysfs
9782fce60beSWolfram Sang  * fallback mechanism is enabled if direct filesystem lookup fails. However,
9792fce60beSWolfram Sang  * failures to find the firmware file with it are still suppressed. It is
9802fce60beSWolfram Sang  * therefore up to the driver to check for the return value of this call and to
9812fce60beSWolfram Sang  * decide when to inform the users of errors.
9827dcc0134SAndres Rodriguez  **/
firmware_request_nowarn(const struct firmware ** firmware,const char * name,struct device * device)9837dcc0134SAndres Rodriguez int firmware_request_nowarn(const struct firmware **firmware, const char *name,
9847dcc0134SAndres Rodriguez 			    struct device *device)
9857dcc0134SAndres Rodriguez {
9867dcc0134SAndres Rodriguez 	int ret;
9877dcc0134SAndres Rodriguez 
9887dcc0134SAndres Rodriguez 	/* Need to pin this module until return */
9897dcc0134SAndres Rodriguez 	__module_get(THIS_MODULE);
99059cdb23cSScott Branden 	ret = _request_firmware(firmware, name, device, NULL, 0, 0,
9917dcc0134SAndres Rodriguez 				FW_OPT_UEVENT | FW_OPT_NO_WARN);
9927dcc0134SAndres Rodriguez 	module_put(THIS_MODULE);
9937dcc0134SAndres Rodriguez 	return ret;
9947dcc0134SAndres Rodriguez }
9957dcc0134SAndres Rodriguez EXPORT_SYMBOL_GPL(firmware_request_nowarn);
9967dcc0134SAndres Rodriguez 
9977dcc0134SAndres Rodriguez /**
998c35f9cbbSAndres Rodriguez  * request_firmware_direct() - load firmware directly without usermode helper
9995d6d1dddSLuis R. Rodriguez  * @firmware_p: pointer to firmware image
10005d6d1dddSLuis R. Rodriguez  * @name: name of firmware file
10015d6d1dddSLuis R. Rodriguez  * @device: device for which firmware is being loaded
10025d6d1dddSLuis R. Rodriguez  *
10035d6d1dddSLuis R. Rodriguez  * This function works pretty much like request_firmware(), but this doesn't
10045d6d1dddSLuis R. Rodriguez  * fall back to usermode helper even if the firmware couldn't be loaded
10055d6d1dddSLuis R. Rodriguez  * directly from fs.  Hence it's useful for loading optional firmwares, which
10065d6d1dddSLuis R. Rodriguez  * aren't always present, without extra long timeouts of udev.
10075d6d1dddSLuis R. Rodriguez  **/
request_firmware_direct(const struct firmware ** firmware_p,const char * name,struct device * device)10085d6d1dddSLuis R. Rodriguez int request_firmware_direct(const struct firmware **firmware_p,
10095d6d1dddSLuis R. Rodriguez 			    const char *name, struct device *device)
10105d6d1dddSLuis R. Rodriguez {
10115d6d1dddSLuis R. Rodriguez 	int ret;
10125d6d1dddSLuis R. Rodriguez 
10135d6d1dddSLuis R. Rodriguez 	__module_get(THIS_MODULE);
101459cdb23cSScott Branden 	ret = _request_firmware(firmware_p, name, device, NULL, 0, 0,
10155d6d1dddSLuis R. Rodriguez 				FW_OPT_UEVENT | FW_OPT_NO_WARN |
101685db1cdeSHans de Goede 				FW_OPT_NOFALLBACK_SYSFS);
10175d6d1dddSLuis R. Rodriguez 	module_put(THIS_MODULE);
10185d6d1dddSLuis R. Rodriguez 	return ret;
10195d6d1dddSLuis R. Rodriguez }
10205d6d1dddSLuis R. Rodriguez EXPORT_SYMBOL_GPL(request_firmware_direct);
10215d6d1dddSLuis R. Rodriguez 
10225d6d1dddSLuis R. Rodriguez /**
1023e4c2c0ffSHans de Goede  * firmware_request_platform() - request firmware with platform-fw fallback
1024e4c2c0ffSHans de Goede  * @firmware: pointer to firmware image
1025e4c2c0ffSHans de Goede  * @name: name of firmware file
1026e4c2c0ffSHans de Goede  * @device: device for which firmware is being loaded
1027e4c2c0ffSHans de Goede  *
1028e4c2c0ffSHans de Goede  * This function is similar in behaviour to request_firmware, except that if
1029e4c2c0ffSHans de Goede  * direct filesystem lookup fails, it will fallback to looking for a copy of the
1030e4c2c0ffSHans de Goede  * requested firmware embedded in the platform's main (e.g. UEFI) firmware.
1031e4c2c0ffSHans de Goede  **/
firmware_request_platform(const struct firmware ** firmware,const char * name,struct device * device)1032e4c2c0ffSHans de Goede int firmware_request_platform(const struct firmware **firmware,
1033e4c2c0ffSHans de Goede 			      const char *name, struct device *device)
1034e4c2c0ffSHans de Goede {
1035e4c2c0ffSHans de Goede 	int ret;
1036e4c2c0ffSHans de Goede 
1037e4c2c0ffSHans de Goede 	/* Need to pin this module until return */
1038e4c2c0ffSHans de Goede 	__module_get(THIS_MODULE);
103959cdb23cSScott Branden 	ret = _request_firmware(firmware, name, device, NULL, 0, 0,
1040e4c2c0ffSHans de Goede 				FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM);
1041e4c2c0ffSHans de Goede 	module_put(THIS_MODULE);
1042e4c2c0ffSHans de Goede 	return ret;
1043e4c2c0ffSHans de Goede }
1044e4c2c0ffSHans de Goede EXPORT_SYMBOL_GPL(firmware_request_platform);
1045e4c2c0ffSHans de Goede 
1046e4c2c0ffSHans de Goede /**
1047c35f9cbbSAndres Rodriguez  * firmware_request_cache() - cache firmware for suspend so resume can use it
10485d42c96eSLuis R. Rodriguez  * @name: name of firmware file
10495d42c96eSLuis R. Rodriguez  * @device: device for which firmware should be cached for
10505d42c96eSLuis R. Rodriguez  *
10515d42c96eSLuis R. Rodriguez  * There are some devices with an optimization that enables the device to not
10525d42c96eSLuis R. Rodriguez  * require loading firmware on system reboot. This optimization may still
10535d42c96eSLuis R. Rodriguez  * require the firmware present on resume from suspend. This routine can be
10545d42c96eSLuis R. Rodriguez  * used to ensure the firmware is present on resume from suspend in these
10555d42c96eSLuis R. Rodriguez  * situations. This helper is not compatible with drivers which use
10565d42c96eSLuis R. Rodriguez  * request_firmware_into_buf() or request_firmware_nowait() with no uevent set.
10575d42c96eSLuis R. Rodriguez  **/
firmware_request_cache(struct device * device,const char * name)10585d42c96eSLuis R. Rodriguez int firmware_request_cache(struct device *device, const char *name)
10595d42c96eSLuis R. Rodriguez {
10605d42c96eSLuis R. Rodriguez 	int ret;
10615d42c96eSLuis R. Rodriguez 
10625d42c96eSLuis R. Rodriguez 	mutex_lock(&fw_lock);
10635d42c96eSLuis R. Rodriguez 	ret = fw_add_devm_name(device, name);
10645d42c96eSLuis R. Rodriguez 	mutex_unlock(&fw_lock);
10655d42c96eSLuis R. Rodriguez 
10665d42c96eSLuis R. Rodriguez 	return ret;
10675d42c96eSLuis R. Rodriguez }
10685d42c96eSLuis R. Rodriguez EXPORT_SYMBOL_GPL(firmware_request_cache);
10695d42c96eSLuis R. Rodriguez 
10705d42c96eSLuis R. Rodriguez /**
1071c35f9cbbSAndres Rodriguez  * request_firmware_into_buf() - load firmware into a previously allocated buffer
10725d6d1dddSLuis R. Rodriguez  * @firmware_p: pointer to firmware image
10735d6d1dddSLuis R. Rodriguez  * @name: name of firmware file
10745d6d1dddSLuis R. Rodriguez  * @device: device for which firmware is being loaded and DMA region allocated
10755d6d1dddSLuis R. Rodriguez  * @buf: address of buffer to load firmware into
10765d6d1dddSLuis R. Rodriguez  * @size: size of buffer
10775d6d1dddSLuis R. Rodriguez  *
10785d6d1dddSLuis R. Rodriguez  * This function works pretty much like request_firmware(), but it doesn't
10795d6d1dddSLuis R. Rodriguez  * allocate a buffer to hold the firmware data. Instead, the firmware
10805d6d1dddSLuis R. Rodriguez  * is loaded directly into the buffer pointed to by @buf and the @firmware_p
10815d6d1dddSLuis R. Rodriguez  * data member is pointed at @buf.
10825d6d1dddSLuis R. Rodriguez  *
10835d6d1dddSLuis R. Rodriguez  * This function doesn't cache firmware either.
10845d6d1dddSLuis R. Rodriguez  */
10855d6d1dddSLuis R. Rodriguez int
request_firmware_into_buf(const struct firmware ** firmware_p,const char * name,struct device * device,void * buf,size_t size)10865d6d1dddSLuis R. Rodriguez request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
10875d6d1dddSLuis R. Rodriguez 			  struct device *device, void *buf, size_t size)
10885d6d1dddSLuis R. Rodriguez {
10895d6d1dddSLuis R. Rodriguez 	int ret;
10905d6d1dddSLuis R. Rodriguez 
1091995e8695SLuis R. Rodriguez 	if (fw_cache_is_setup(device, name))
1092995e8695SLuis R. Rodriguez 		return -EOPNOTSUPP;
1093995e8695SLuis R. Rodriguez 
10945d6d1dddSLuis R. Rodriguez 	__module_get(THIS_MODULE);
109559cdb23cSScott Branden 	ret = _request_firmware(firmware_p, name, device, buf, size, 0,
10965d6d1dddSLuis R. Rodriguez 				FW_OPT_UEVENT | FW_OPT_NOCACHE);
10975d6d1dddSLuis R. Rodriguez 	module_put(THIS_MODULE);
10985d6d1dddSLuis R. Rodriguez 	return ret;
10995d6d1dddSLuis R. Rodriguez }
11005d6d1dddSLuis R. Rodriguez EXPORT_SYMBOL(request_firmware_into_buf);
11015d6d1dddSLuis R. Rodriguez 
11025d6d1dddSLuis R. Rodriguez /**
110359cdb23cSScott Branden  * request_partial_firmware_into_buf() - load partial firmware into a previously allocated buffer
110459cdb23cSScott Branden  * @firmware_p: pointer to firmware image
110559cdb23cSScott Branden  * @name: name of firmware file
110659cdb23cSScott Branden  * @device: device for which firmware is being loaded and DMA region allocated
110759cdb23cSScott Branden  * @buf: address of buffer to load firmware into
110859cdb23cSScott Branden  * @size: size of buffer
110959cdb23cSScott Branden  * @offset: offset into file to read
111059cdb23cSScott Branden  *
111159cdb23cSScott Branden  * This function works pretty much like request_firmware_into_buf except
111259cdb23cSScott Branden  * it allows a partial read of the file.
111359cdb23cSScott Branden  */
111459cdb23cSScott Branden int
request_partial_firmware_into_buf(const struct firmware ** firmware_p,const char * name,struct device * device,void * buf,size_t size,size_t offset)111559cdb23cSScott Branden request_partial_firmware_into_buf(const struct firmware **firmware_p,
111659cdb23cSScott Branden 				  const char *name, struct device *device,
111759cdb23cSScott Branden 				  void *buf, size_t size, size_t offset)
111859cdb23cSScott Branden {
111959cdb23cSScott Branden 	int ret;
112059cdb23cSScott Branden 
112159cdb23cSScott Branden 	if (fw_cache_is_setup(device, name))
112259cdb23cSScott Branden 		return -EOPNOTSUPP;
112359cdb23cSScott Branden 
112459cdb23cSScott Branden 	__module_get(THIS_MODULE);
112559cdb23cSScott Branden 	ret = _request_firmware(firmware_p, name, device, buf, size, offset,
112659cdb23cSScott Branden 				FW_OPT_UEVENT | FW_OPT_NOCACHE |
112759cdb23cSScott Branden 				FW_OPT_PARTIAL);
112859cdb23cSScott Branden 	module_put(THIS_MODULE);
112959cdb23cSScott Branden 	return ret;
113059cdb23cSScott Branden }
113159cdb23cSScott Branden EXPORT_SYMBOL(request_partial_firmware_into_buf);
113259cdb23cSScott Branden 
113359cdb23cSScott Branden /**
1134c35f9cbbSAndres Rodriguez  * release_firmware() - release the resource associated with a firmware image
11355d6d1dddSLuis R. Rodriguez  * @fw: firmware resource to release
11365d6d1dddSLuis R. Rodriguez  **/
release_firmware(const struct firmware * fw)11375d6d1dddSLuis R. Rodriguez void release_firmware(const struct firmware *fw)
11385d6d1dddSLuis R. Rodriguez {
11395d6d1dddSLuis R. Rodriguez 	if (fw) {
114048d09e97SLuis Chamberlain 		if (!firmware_is_builtin(fw))
11415d6d1dddSLuis R. Rodriguez 			firmware_free_data(fw);
11425d6d1dddSLuis R. Rodriguez 		kfree(fw);
11435d6d1dddSLuis R. Rodriguez 	}
11445d6d1dddSLuis R. Rodriguez }
11455d6d1dddSLuis R. Rodriguez EXPORT_SYMBOL(release_firmware);
11465d6d1dddSLuis R. Rodriguez 
11475d6d1dddSLuis R. Rodriguez /* Async support */
11485d6d1dddSLuis R. Rodriguez struct firmware_work {
11495d6d1dddSLuis R. Rodriguez 	struct work_struct work;
11505d6d1dddSLuis R. Rodriguez 	struct module *module;
11515d6d1dddSLuis R. Rodriguez 	const char *name;
11525d6d1dddSLuis R. Rodriguez 	struct device *device;
11535d6d1dddSLuis R. Rodriguez 	void *context;
11545d6d1dddSLuis R. Rodriguez 	void (*cont)(const struct firmware *fw, void *context);
1155c2c07616SScott Branden 	u32 opt_flags;
11565d6d1dddSLuis R. Rodriguez };
11575d6d1dddSLuis R. Rodriguez 
request_firmware_work_func(struct work_struct * work)11585d6d1dddSLuis R. Rodriguez static void request_firmware_work_func(struct work_struct *work)
11595d6d1dddSLuis R. Rodriguez {
11605d6d1dddSLuis R. Rodriguez 	struct firmware_work *fw_work;
11615d6d1dddSLuis R. Rodriguez 	const struct firmware *fw;
11625d6d1dddSLuis R. Rodriguez 
11635d6d1dddSLuis R. Rodriguez 	fw_work = container_of(work, struct firmware_work, work);
11645d6d1dddSLuis R. Rodriguez 
116559cdb23cSScott Branden 	_request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0,
11665d6d1dddSLuis R. Rodriguez 			  fw_work->opt_flags);
11675d6d1dddSLuis R. Rodriguez 	fw_work->cont(fw, fw_work->context);
11685d6d1dddSLuis R. Rodriguez 	put_device(fw_work->device); /* taken in request_firmware_nowait() */
11695d6d1dddSLuis R. Rodriguez 
11705d6d1dddSLuis R. Rodriguez 	module_put(fw_work->module);
11715d6d1dddSLuis R. Rodriguez 	kfree_const(fw_work->name);
11725d6d1dddSLuis R. Rodriguez 	kfree(fw_work);
11735d6d1dddSLuis R. Rodriguez }
11745d6d1dddSLuis R. Rodriguez 
11755d6d1dddSLuis R. Rodriguez /**
1176c35f9cbbSAndres Rodriguez  * request_firmware_nowait() - asynchronous version of request_firmware
11775d6d1dddSLuis R. Rodriguez  * @module: module requesting the firmware
11785d6d1dddSLuis R. Rodriguez  * @uevent: sends uevent to copy the firmware image if this flag
11795d6d1dddSLuis R. Rodriguez  *	is non-zero else the firmware copy must be done manually.
11805d6d1dddSLuis R. Rodriguez  * @name: name of firmware file
11815d6d1dddSLuis R. Rodriguez  * @device: device for which firmware is being loaded
11825d6d1dddSLuis R. Rodriguez  * @gfp: allocation flags
11835d6d1dddSLuis R. Rodriguez  * @context: will be passed over to @cont, and
11845d6d1dddSLuis R. Rodriguez  *	@fw may be %NULL if firmware request fails.
11855d6d1dddSLuis R. Rodriguez  * @cont: function will be called asynchronously when the firmware
11865d6d1dddSLuis R. Rodriguez  *	request is over.
11875d6d1dddSLuis R. Rodriguez  *
11885d6d1dddSLuis R. Rodriguez  *	Caller must hold the reference count of @device.
11895d6d1dddSLuis R. Rodriguez  *
11905d6d1dddSLuis R. Rodriguez  *	Asynchronous variant of request_firmware() for user contexts:
11915d6d1dddSLuis R. Rodriguez  *		- sleep for as small periods as possible since it may
11925d6d1dddSLuis R. Rodriguez  *		  increase kernel boot time of built-in device drivers
11935d6d1dddSLuis R. Rodriguez  *		  requesting firmware in their ->probe() methods, if
11945d6d1dddSLuis R. Rodriguez  *		  @gfp is GFP_KERNEL.
11955d6d1dddSLuis R. Rodriguez  *
11965d6d1dddSLuis R. Rodriguez  *		- can't sleep at all if @gfp is GFP_ATOMIC.
11975d6d1dddSLuis R. Rodriguez  **/
11985d6d1dddSLuis R. Rodriguez int
request_firmware_nowait(struct module * module,bool uevent,const char * name,struct device * device,gfp_t gfp,void * context,void (* cont)(const struct firmware * fw,void * context))11995d6d1dddSLuis R. Rodriguez request_firmware_nowait(
12005d6d1dddSLuis R. Rodriguez 	struct module *module, bool uevent,
12015d6d1dddSLuis R. Rodriguez 	const char *name, struct device *device, gfp_t gfp, void *context,
12025d6d1dddSLuis R. Rodriguez 	void (*cont)(const struct firmware *fw, void *context))
12035d6d1dddSLuis R. Rodriguez {
12045d6d1dddSLuis R. Rodriguez 	struct firmware_work *fw_work;
12055d6d1dddSLuis R. Rodriguez 
12065d6d1dddSLuis R. Rodriguez 	fw_work = kzalloc(sizeof(struct firmware_work), gfp);
12075d6d1dddSLuis R. Rodriguez 	if (!fw_work)
12085d6d1dddSLuis R. Rodriguez 		return -ENOMEM;
12095d6d1dddSLuis R. Rodriguez 
12105d6d1dddSLuis R. Rodriguez 	fw_work->module = module;
12115d6d1dddSLuis R. Rodriguez 	fw_work->name = kstrdup_const(name, gfp);
12125d6d1dddSLuis R. Rodriguez 	if (!fw_work->name) {
12135d6d1dddSLuis R. Rodriguez 		kfree(fw_work);
12145d6d1dddSLuis R. Rodriguez 		return -ENOMEM;
12155d6d1dddSLuis R. Rodriguez 	}
12165d6d1dddSLuis R. Rodriguez 	fw_work->device = device;
12175d6d1dddSLuis R. Rodriguez 	fw_work->context = context;
12185d6d1dddSLuis R. Rodriguez 	fw_work->cont = cont;
12195d6d1dddSLuis R. Rodriguez 	fw_work->opt_flags = FW_OPT_NOWAIT |
12205d6d1dddSLuis R. Rodriguez 		(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
12215d6d1dddSLuis R. Rodriguez 
1222995e8695SLuis R. Rodriguez 	if (!uevent && fw_cache_is_setup(device, name)) {
1223995e8695SLuis R. Rodriguez 		kfree_const(fw_work->name);
1224995e8695SLuis R. Rodriguez 		kfree(fw_work);
1225995e8695SLuis R. Rodriguez 		return -EOPNOTSUPP;
1226995e8695SLuis R. Rodriguez 	}
1227995e8695SLuis R. Rodriguez 
12285d6d1dddSLuis R. Rodriguez 	if (!try_module_get(module)) {
12295d6d1dddSLuis R. Rodriguez 		kfree_const(fw_work->name);
12305d6d1dddSLuis R. Rodriguez 		kfree(fw_work);
12315d6d1dddSLuis R. Rodriguez 		return -EFAULT;
12325d6d1dddSLuis R. Rodriguez 	}
12335d6d1dddSLuis R. Rodriguez 
12345d6d1dddSLuis R. Rodriguez 	get_device(fw_work->device);
12355d6d1dddSLuis R. Rodriguez 	INIT_WORK(&fw_work->work, request_firmware_work_func);
12365d6d1dddSLuis R. Rodriguez 	schedule_work(&fw_work->work);
12375d6d1dddSLuis R. Rodriguez 	return 0;
12385d6d1dddSLuis R. Rodriguez }
12395d6d1dddSLuis R. Rodriguez EXPORT_SYMBOL(request_firmware_nowait);
12405d6d1dddSLuis R. Rodriguez 
1241030cc787SMark Salyzyn #ifdef CONFIG_FW_CACHE
12425d6d1dddSLuis R. Rodriguez static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
12435d6d1dddSLuis R. Rodriguez 
12445d6d1dddSLuis R. Rodriguez /**
1245c35f9cbbSAndres Rodriguez  * cache_firmware() - cache one firmware image in kernel memory space
12465d6d1dddSLuis R. Rodriguez  * @fw_name: the firmware image name
12475d6d1dddSLuis R. Rodriguez  *
12485d6d1dddSLuis R. Rodriguez  * Cache firmware in kernel memory so that drivers can use it when
12495d6d1dddSLuis R. Rodriguez  * system isn't ready for them to request firmware image from userspace.
12505d6d1dddSLuis R. Rodriguez  * Once it returns successfully, driver can use request_firmware or its
12515d6d1dddSLuis R. Rodriguez  * nowait version to get the cached firmware without any interacting
12525d6d1dddSLuis R. Rodriguez  * with userspace
12535d6d1dddSLuis R. Rodriguez  *
12545d6d1dddSLuis R. Rodriguez  * Return 0 if the firmware image has been cached successfully
12555d6d1dddSLuis R. Rodriguez  * Return !0 otherwise
12565d6d1dddSLuis R. Rodriguez  *
12575d6d1dddSLuis R. Rodriguez  */
cache_firmware(const char * fw_name)12585d6d1dddSLuis R. Rodriguez static int cache_firmware(const char *fw_name)
12595d6d1dddSLuis R. Rodriguez {
12605d6d1dddSLuis R. Rodriguez 	int ret;
12615d6d1dddSLuis R. Rodriguez 	const struct firmware *fw;
12625d6d1dddSLuis R. Rodriguez 
12635d6d1dddSLuis R. Rodriguez 	pr_debug("%s: %s\n", __func__, fw_name);
12645d6d1dddSLuis R. Rodriguez 
12655d6d1dddSLuis R. Rodriguez 	ret = request_firmware(&fw, fw_name, NULL);
12665d6d1dddSLuis R. Rodriguez 	if (!ret)
12675d6d1dddSLuis R. Rodriguez 		kfree(fw);
12685d6d1dddSLuis R. Rodriguez 
12695d6d1dddSLuis R. Rodriguez 	pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret);
12705d6d1dddSLuis R. Rodriguez 
12715d6d1dddSLuis R. Rodriguez 	return ret;
12725d6d1dddSLuis R. Rodriguez }
12735d6d1dddSLuis R. Rodriguez 
lookup_fw_priv(const char * fw_name)12745d6d1dddSLuis R. Rodriguez static struct fw_priv *lookup_fw_priv(const char *fw_name)
12755d6d1dddSLuis R. Rodriguez {
12765d6d1dddSLuis R. Rodriguez 	struct fw_priv *tmp;
12775d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
12785d6d1dddSLuis R. Rodriguez 
12795d6d1dddSLuis R. Rodriguez 	spin_lock(&fwc->lock);
12805d6d1dddSLuis R. Rodriguez 	tmp = __lookup_fw_priv(fw_name);
12815d6d1dddSLuis R. Rodriguez 	spin_unlock(&fwc->lock);
12825d6d1dddSLuis R. Rodriguez 
12835d6d1dddSLuis R. Rodriguez 	return tmp;
12845d6d1dddSLuis R. Rodriguez }
12855d6d1dddSLuis R. Rodriguez 
12865d6d1dddSLuis R. Rodriguez /**
1287c35f9cbbSAndres Rodriguez  * uncache_firmware() - remove one cached firmware image
12885d6d1dddSLuis R. Rodriguez  * @fw_name: the firmware image name
12895d6d1dddSLuis R. Rodriguez  *
12905d6d1dddSLuis R. Rodriguez  * Uncache one firmware image which has been cached successfully
12915d6d1dddSLuis R. Rodriguez  * before.
12925d6d1dddSLuis R. Rodriguez  *
12935d6d1dddSLuis R. Rodriguez  * Return 0 if the firmware cache has been removed successfully
12945d6d1dddSLuis R. Rodriguez  * Return !0 otherwise
12955d6d1dddSLuis R. Rodriguez  *
12965d6d1dddSLuis R. Rodriguez  */
uncache_firmware(const char * fw_name)12975d6d1dddSLuis R. Rodriguez static int uncache_firmware(const char *fw_name)
12985d6d1dddSLuis R. Rodriguez {
12995d6d1dddSLuis R. Rodriguez 	struct fw_priv *fw_priv;
13005d6d1dddSLuis R. Rodriguez 	struct firmware fw;
13015d6d1dddSLuis R. Rodriguez 
13025d6d1dddSLuis R. Rodriguez 	pr_debug("%s: %s\n", __func__, fw_name);
13035d6d1dddSLuis R. Rodriguez 
13047c4fd907SLuis Chamberlain 	if (firmware_request_builtin(&fw, fw_name))
13055d6d1dddSLuis R. Rodriguez 		return 0;
13065d6d1dddSLuis R. Rodriguez 
13075d6d1dddSLuis R. Rodriguez 	fw_priv = lookup_fw_priv(fw_name);
13085d6d1dddSLuis R. Rodriguez 	if (fw_priv) {
13095d6d1dddSLuis R. Rodriguez 		free_fw_priv(fw_priv);
13105d6d1dddSLuis R. Rodriguez 		return 0;
13115d6d1dddSLuis R. Rodriguez 	}
13125d6d1dddSLuis R. Rodriguez 
13135d6d1dddSLuis R. Rodriguez 	return -EINVAL;
13145d6d1dddSLuis R. Rodriguez }
13155d6d1dddSLuis R. Rodriguez 
alloc_fw_cache_entry(const char * name)13165d6d1dddSLuis R. Rodriguez static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
13175d6d1dddSLuis R. Rodriguez {
13185d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce;
13195d6d1dddSLuis R. Rodriguez 
13205d6d1dddSLuis R. Rodriguez 	fce = kzalloc(sizeof(*fce), GFP_ATOMIC);
13215d6d1dddSLuis R. Rodriguez 	if (!fce)
13225d6d1dddSLuis R. Rodriguez 		goto exit;
13235d6d1dddSLuis R. Rodriguez 
13245d6d1dddSLuis R. Rodriguez 	fce->name = kstrdup_const(name, GFP_ATOMIC);
13255d6d1dddSLuis R. Rodriguez 	if (!fce->name) {
13265d6d1dddSLuis R. Rodriguez 		kfree(fce);
13275d6d1dddSLuis R. Rodriguez 		fce = NULL;
13285d6d1dddSLuis R. Rodriguez 		goto exit;
13295d6d1dddSLuis R. Rodriguez 	}
13305d6d1dddSLuis R. Rodriguez exit:
13315d6d1dddSLuis R. Rodriguez 	return fce;
13325d6d1dddSLuis R. Rodriguez }
13335d6d1dddSLuis R. Rodriguez 
__fw_entry_found(const char * name)13345d6d1dddSLuis R. Rodriguez static int __fw_entry_found(const char *name)
13355d6d1dddSLuis R. Rodriguez {
13365d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
13375d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce;
13385d6d1dddSLuis R. Rodriguez 
13395d6d1dddSLuis R. Rodriguez 	list_for_each_entry(fce, &fwc->fw_names, list) {
13405d6d1dddSLuis R. Rodriguez 		if (!strcmp(fce->name, name))
13415d6d1dddSLuis R. Rodriguez 			return 1;
13425d6d1dddSLuis R. Rodriguez 	}
13435d6d1dddSLuis R. Rodriguez 	return 0;
13445d6d1dddSLuis R. Rodriguez }
13455d6d1dddSLuis R. Rodriguez 
fw_cache_piggyback_on_request(struct fw_priv * fw_priv)13463ecc8cb7SZhen Lei static void fw_cache_piggyback_on_request(struct fw_priv *fw_priv)
13475d6d1dddSLuis R. Rodriguez {
13483ecc8cb7SZhen Lei 	const char *name = fw_priv->fw_name;
13493ecc8cb7SZhen Lei 	struct firmware_cache *fwc = fw_priv->fwc;
13505d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce;
13515d6d1dddSLuis R. Rodriguez 
13525d6d1dddSLuis R. Rodriguez 	spin_lock(&fwc->name_lock);
13535d6d1dddSLuis R. Rodriguez 	if (__fw_entry_found(name))
13545d6d1dddSLuis R. Rodriguez 		goto found;
13555d6d1dddSLuis R. Rodriguez 
13565d6d1dddSLuis R. Rodriguez 	fce = alloc_fw_cache_entry(name);
13575d6d1dddSLuis R. Rodriguez 	if (fce) {
13585d6d1dddSLuis R. Rodriguez 		list_add(&fce->list, &fwc->fw_names);
13593ecc8cb7SZhen Lei 		kref_get(&fw_priv->ref);
13605d6d1dddSLuis R. Rodriguez 		pr_debug("%s: fw: %s\n", __func__, name);
13615d6d1dddSLuis R. Rodriguez 	}
13625d6d1dddSLuis R. Rodriguez found:
13635d6d1dddSLuis R. Rodriguez 	spin_unlock(&fwc->name_lock);
13645d6d1dddSLuis R. Rodriguez }
13655d6d1dddSLuis R. Rodriguez 
free_fw_cache_entry(struct fw_cache_entry * fce)13665d6d1dddSLuis R. Rodriguez static void free_fw_cache_entry(struct fw_cache_entry *fce)
13675d6d1dddSLuis R. Rodriguez {
13685d6d1dddSLuis R. Rodriguez 	kfree_const(fce->name);
13695d6d1dddSLuis R. Rodriguez 	kfree(fce);
13705d6d1dddSLuis R. Rodriguez }
13715d6d1dddSLuis R. Rodriguez 
__async_dev_cache_fw_image(void * fw_entry,async_cookie_t cookie)13725d6d1dddSLuis R. Rodriguez static void __async_dev_cache_fw_image(void *fw_entry,
13735d6d1dddSLuis R. Rodriguez 				       async_cookie_t cookie)
13745d6d1dddSLuis R. Rodriguez {
13755d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce = fw_entry;
13765d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
13775d6d1dddSLuis R. Rodriguez 	int ret;
13785d6d1dddSLuis R. Rodriguez 
13795d6d1dddSLuis R. Rodriguez 	ret = cache_firmware(fce->name);
13805d6d1dddSLuis R. Rodriguez 	if (ret) {
13815d6d1dddSLuis R. Rodriguez 		spin_lock(&fwc->name_lock);
13825d6d1dddSLuis R. Rodriguez 		list_del(&fce->list);
13835d6d1dddSLuis R. Rodriguez 		spin_unlock(&fwc->name_lock);
13845d6d1dddSLuis R. Rodriguez 
13855d6d1dddSLuis R. Rodriguez 		free_fw_cache_entry(fce);
13865d6d1dddSLuis R. Rodriguez 	}
13875d6d1dddSLuis R. Rodriguez }
13885d6d1dddSLuis R. Rodriguez 
13895d6d1dddSLuis R. Rodriguez /* called with dev->devres_lock held */
dev_create_fw_entry(struct device * dev,void * res,void * data)13905d6d1dddSLuis R. Rodriguez static void dev_create_fw_entry(struct device *dev, void *res,
13915d6d1dddSLuis R. Rodriguez 				void *data)
13925d6d1dddSLuis R. Rodriguez {
13935d6d1dddSLuis R. Rodriguez 	struct fw_name_devm *fwn = res;
13945d6d1dddSLuis R. Rodriguez 	const char *fw_name = fwn->name;
13955d6d1dddSLuis R. Rodriguez 	struct list_head *head = data;
13965d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce;
13975d6d1dddSLuis R. Rodriguez 
13985d6d1dddSLuis R. Rodriguez 	fce = alloc_fw_cache_entry(fw_name);
13995d6d1dddSLuis R. Rodriguez 	if (fce)
14005d6d1dddSLuis R. Rodriguez 		list_add(&fce->list, head);
14015d6d1dddSLuis R. Rodriguez }
14025d6d1dddSLuis R. Rodriguez 
devm_name_match(struct device * dev,void * res,void * match_data)14035d6d1dddSLuis R. Rodriguez static int devm_name_match(struct device *dev, void *res,
14045d6d1dddSLuis R. Rodriguez 			   void *match_data)
14055d6d1dddSLuis R. Rodriguez {
14065d6d1dddSLuis R. Rodriguez 	struct fw_name_devm *fwn = res;
14075d6d1dddSLuis R. Rodriguez 	return (fwn->magic == (unsigned long)match_data);
14085d6d1dddSLuis R. Rodriguez }
14095d6d1dddSLuis R. Rodriguez 
dev_cache_fw_image(struct device * dev,void * data)14105d6d1dddSLuis R. Rodriguez static void dev_cache_fw_image(struct device *dev, void *data)
14115d6d1dddSLuis R. Rodriguez {
14125d6d1dddSLuis R. Rodriguez 	LIST_HEAD(todo);
14135d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce;
14145d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce_next;
14155d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
14165d6d1dddSLuis R. Rodriguez 
14175d6d1dddSLuis R. Rodriguez 	devres_for_each_res(dev, fw_name_devm_release,
14185d6d1dddSLuis R. Rodriguez 			    devm_name_match, &fw_cache,
14195d6d1dddSLuis R. Rodriguez 			    dev_create_fw_entry, &todo);
14205d6d1dddSLuis R. Rodriguez 
14215d6d1dddSLuis R. Rodriguez 	list_for_each_entry_safe(fce, fce_next, &todo, list) {
14225d6d1dddSLuis R. Rodriguez 		list_del(&fce->list);
14235d6d1dddSLuis R. Rodriguez 
14245d6d1dddSLuis R. Rodriguez 		spin_lock(&fwc->name_lock);
14255d6d1dddSLuis R. Rodriguez 		/* only one cache entry for one firmware */
14265d6d1dddSLuis R. Rodriguez 		if (!__fw_entry_found(fce->name)) {
14275d6d1dddSLuis R. Rodriguez 			list_add(&fce->list, &fwc->fw_names);
14285d6d1dddSLuis R. Rodriguez 		} else {
14295d6d1dddSLuis R. Rodriguez 			free_fw_cache_entry(fce);
14305d6d1dddSLuis R. Rodriguez 			fce = NULL;
14315d6d1dddSLuis R. Rodriguez 		}
14325d6d1dddSLuis R. Rodriguez 		spin_unlock(&fwc->name_lock);
14335d6d1dddSLuis R. Rodriguez 
14345d6d1dddSLuis R. Rodriguez 		if (fce)
14355d6d1dddSLuis R. Rodriguez 			async_schedule_domain(__async_dev_cache_fw_image,
14365d6d1dddSLuis R. Rodriguez 					      (void *)fce,
14375d6d1dddSLuis R. Rodriguez 					      &fw_cache_domain);
14385d6d1dddSLuis R. Rodriguez 	}
14395d6d1dddSLuis R. Rodriguez }
14405d6d1dddSLuis R. Rodriguez 
__device_uncache_fw_images(void)14415d6d1dddSLuis R. Rodriguez static void __device_uncache_fw_images(void)
14425d6d1dddSLuis R. Rodriguez {
14435d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
14445d6d1dddSLuis R. Rodriguez 	struct fw_cache_entry *fce;
14455d6d1dddSLuis R. Rodriguez 
14465d6d1dddSLuis R. Rodriguez 	spin_lock(&fwc->name_lock);
14475d6d1dddSLuis R. Rodriguez 	while (!list_empty(&fwc->fw_names)) {
14485d6d1dddSLuis R. Rodriguez 		fce = list_entry(fwc->fw_names.next,
14495d6d1dddSLuis R. Rodriguez 				struct fw_cache_entry, list);
14505d6d1dddSLuis R. Rodriguez 		list_del(&fce->list);
14515d6d1dddSLuis R. Rodriguez 		spin_unlock(&fwc->name_lock);
14525d6d1dddSLuis R. Rodriguez 
14535d6d1dddSLuis R. Rodriguez 		uncache_firmware(fce->name);
14545d6d1dddSLuis R. Rodriguez 		free_fw_cache_entry(fce);
14555d6d1dddSLuis R. Rodriguez 
14565d6d1dddSLuis R. Rodriguez 		spin_lock(&fwc->name_lock);
14575d6d1dddSLuis R. Rodriguez 	}
14585d6d1dddSLuis R. Rodriguez 	spin_unlock(&fwc->name_lock);
14595d6d1dddSLuis R. Rodriguez }
14605d6d1dddSLuis R. Rodriguez 
14615d6d1dddSLuis R. Rodriguez /**
1462c35f9cbbSAndres Rodriguez  * device_cache_fw_images() - cache devices' firmware
14635d6d1dddSLuis R. Rodriguez  *
14645d6d1dddSLuis R. Rodriguez  * If one device called request_firmware or its nowait version
14655d6d1dddSLuis R. Rodriguez  * successfully before, the firmware names are recored into the
14665d6d1dddSLuis R. Rodriguez  * device's devres link list, so device_cache_fw_images can call
14675d6d1dddSLuis R. Rodriguez  * cache_firmware() to cache these firmwares for the device,
14685d6d1dddSLuis R. Rodriguez  * then the device driver can load its firmwares easily at
14695d6d1dddSLuis R. Rodriguez  * time when system is not ready to complete loading firmware.
14705d6d1dddSLuis R. Rodriguez  */
device_cache_fw_images(void)14715d6d1dddSLuis R. Rodriguez static void device_cache_fw_images(void)
14725d6d1dddSLuis R. Rodriguez {
14735d6d1dddSLuis R. Rodriguez 	struct firmware_cache *fwc = &fw_cache;
14745d6d1dddSLuis R. Rodriguez 	DEFINE_WAIT(wait);
14755d6d1dddSLuis R. Rodriguez 
14765d6d1dddSLuis R. Rodriguez 	pr_debug("%s\n", __func__);
14775d6d1dddSLuis R. Rodriguez 
14785d6d1dddSLuis R. Rodriguez 	/* cancel uncache work */
14795d6d1dddSLuis R. Rodriguez 	cancel_delayed_work_sync(&fwc->work);
14805d6d1dddSLuis R. Rodriguez 
14815d6d1dddSLuis R. Rodriguez 	fw_fallback_set_cache_timeout();
14825d6d1dddSLuis R. Rodriguez 
14835d6d1dddSLuis R. Rodriguez 	mutex_lock(&fw_lock);
14845d6d1dddSLuis R. Rodriguez 	fwc->state = FW_LOADER_START_CACHE;
14855d6d1dddSLuis R. Rodriguez 	dpm_for_each_dev(NULL, dev_cache_fw_image);
14865d6d1dddSLuis R. Rodriguez 	mutex_unlock(&fw_lock);
14875d6d1dddSLuis R. Rodriguez 
14885d6d1dddSLuis R. Rodriguez 	/* wait for completion of caching firmware for all devices */
14895d6d1dddSLuis R. Rodriguez 	async_synchronize_full_domain(&fw_cache_domain);
14905d6d1dddSLuis R. Rodriguez 
14915d6d1dddSLuis R. Rodriguez 	fw_fallback_set_default_timeout();
14925d6d1dddSLuis R. Rodriguez }
14935d6d1dddSLuis R. Rodriguez 
14945d6d1dddSLuis R. Rodriguez /**
1495c35f9cbbSAndres Rodriguez  * device_uncache_fw_images() - uncache devices' firmware
14965d6d1dddSLuis R. Rodriguez  *
14975d6d1dddSLuis R. Rodriguez  * uncache all firmwares which have been cached successfully
14985d6d1dddSLuis R. Rodriguez  * by device_uncache_fw_images earlier
14995d6d1dddSLuis R. Rodriguez  */
device_uncache_fw_images(void)15005d6d1dddSLuis R. Rodriguez static void device_uncache_fw_images(void)
15015d6d1dddSLuis R. Rodriguez {
15025d6d1dddSLuis R. Rodriguez 	pr_debug("%s\n", __func__);
15035d6d1dddSLuis R. Rodriguez 	__device_uncache_fw_images();
15045d6d1dddSLuis R. Rodriguez }
15055d6d1dddSLuis R. Rodriguez 
device_uncache_fw_images_work(struct work_struct * work)15065d6d1dddSLuis R. Rodriguez static void device_uncache_fw_images_work(struct work_struct *work)
15075d6d1dddSLuis R. Rodriguez {
15085d6d1dddSLuis R. Rodriguez 	device_uncache_fw_images();
15095d6d1dddSLuis R. Rodriguez }
15105d6d1dddSLuis R. Rodriguez 
15115d6d1dddSLuis R. Rodriguez /**
1512c35f9cbbSAndres Rodriguez  * device_uncache_fw_images_delay() - uncache devices firmwares
15135d6d1dddSLuis R. Rodriguez  * @delay: number of milliseconds to delay uncache device firmwares
15145d6d1dddSLuis R. Rodriguez  *
15155d6d1dddSLuis R. Rodriguez  * uncache all devices's firmwares which has been cached successfully
15165d6d1dddSLuis R. Rodriguez  * by device_cache_fw_images after @delay milliseconds.
15175d6d1dddSLuis R. Rodriguez  */
device_uncache_fw_images_delay(unsigned long delay)15185d6d1dddSLuis R. Rodriguez static void device_uncache_fw_images_delay(unsigned long delay)
15195d6d1dddSLuis R. Rodriguez {
15205d6d1dddSLuis R. Rodriguez 	queue_delayed_work(system_power_efficient_wq, &fw_cache.work,
15215d6d1dddSLuis R. Rodriguez 			   msecs_to_jiffies(delay));
15225d6d1dddSLuis R. Rodriguez }
15235d6d1dddSLuis R. Rodriguez 
fw_pm_notify(struct notifier_block * notify_block,unsigned long mode,void * unused)15245d6d1dddSLuis R. Rodriguez static int fw_pm_notify(struct notifier_block *notify_block,
15255d6d1dddSLuis R. Rodriguez 			unsigned long mode, void *unused)
15265d6d1dddSLuis R. Rodriguez {
15275d6d1dddSLuis R. Rodriguez 	switch (mode) {
15285d6d1dddSLuis R. Rodriguez 	case PM_HIBERNATION_PREPARE:
15295d6d1dddSLuis R. Rodriguez 	case PM_SUSPEND_PREPARE:
15305d6d1dddSLuis R. Rodriguez 	case PM_RESTORE_PREPARE:
15315d6d1dddSLuis R. Rodriguez 		/*
153287ffa98eSMukesh Ojha 		 * Here, kill pending fallback requests will only kill
153387ffa98eSMukesh Ojha 		 * non-uevent firmware request to avoid stalling suspend.
15345d6d1dddSLuis R. Rodriguez 		 */
153587ffa98eSMukesh Ojha 		kill_pending_fw_fallback_reqs(false);
15365d6d1dddSLuis R. Rodriguez 		device_cache_fw_images();
15375d6d1dddSLuis R. Rodriguez 		break;
15385d6d1dddSLuis R. Rodriguez 
15395d6d1dddSLuis R. Rodriguez 	case PM_POST_SUSPEND:
15405d6d1dddSLuis R. Rodriguez 	case PM_POST_HIBERNATION:
15415d6d1dddSLuis R. Rodriguez 	case PM_POST_RESTORE:
15425d6d1dddSLuis R. Rodriguez 		/*
15435d6d1dddSLuis R. Rodriguez 		 * In case that system sleep failed and syscore_suspend is
15445d6d1dddSLuis R. Rodriguez 		 * not called.
15455d6d1dddSLuis R. Rodriguez 		 */
15465d6d1dddSLuis R. Rodriguez 		mutex_lock(&fw_lock);
15475d6d1dddSLuis R. Rodriguez 		fw_cache.state = FW_LOADER_NO_CACHE;
15485d6d1dddSLuis R. Rodriguez 		mutex_unlock(&fw_lock);
15495d6d1dddSLuis R. Rodriguez 
15505d6d1dddSLuis R. Rodriguez 		device_uncache_fw_images_delay(10 * MSEC_PER_SEC);
15515d6d1dddSLuis R. Rodriguez 		break;
15525d6d1dddSLuis R. Rodriguez 	}
15535d6d1dddSLuis R. Rodriguez 
15545d6d1dddSLuis R. Rodriguez 	return 0;
15555d6d1dddSLuis R. Rodriguez }
15565d6d1dddSLuis R. Rodriguez 
15575d6d1dddSLuis R. Rodriguez /* stop caching firmware once syscore_suspend is reached */
fw_suspend(void)15585d6d1dddSLuis R. Rodriguez static int fw_suspend(void)
15595d6d1dddSLuis R. Rodriguez {
15605d6d1dddSLuis R. Rodriguez 	fw_cache.state = FW_LOADER_NO_CACHE;
15615d6d1dddSLuis R. Rodriguez 	return 0;
15625d6d1dddSLuis R. Rodriguez }
15635d6d1dddSLuis R. Rodriguez 
15645d6d1dddSLuis R. Rodriguez static struct syscore_ops fw_syscore_ops = {
15655d6d1dddSLuis R. Rodriguez 	.suspend = fw_suspend,
15665d6d1dddSLuis R. Rodriguez };
15675d6d1dddSLuis R. Rodriguez 
register_fw_pm_ops(void)15685d6d1dddSLuis R. Rodriguez static int __init register_fw_pm_ops(void)
15695d6d1dddSLuis R. Rodriguez {
15705d6d1dddSLuis R. Rodriguez 	int ret;
15715d6d1dddSLuis R. Rodriguez 
15725d6d1dddSLuis R. Rodriguez 	spin_lock_init(&fw_cache.name_lock);
15735d6d1dddSLuis R. Rodriguez 	INIT_LIST_HEAD(&fw_cache.fw_names);
15745d6d1dddSLuis R. Rodriguez 
15755d6d1dddSLuis R. Rodriguez 	INIT_DELAYED_WORK(&fw_cache.work,
15765d6d1dddSLuis R. Rodriguez 			  device_uncache_fw_images_work);
15775d6d1dddSLuis R. Rodriguez 
15785d6d1dddSLuis R. Rodriguez 	fw_cache.pm_notify.notifier_call = fw_pm_notify;
15795d6d1dddSLuis R. Rodriguez 	ret = register_pm_notifier(&fw_cache.pm_notify);
15805d6d1dddSLuis R. Rodriguez 	if (ret)
15815d6d1dddSLuis R. Rodriguez 		return ret;
15825d6d1dddSLuis R. Rodriguez 
15835d6d1dddSLuis R. Rodriguez 	register_syscore_ops(&fw_syscore_ops);
15845d6d1dddSLuis R. Rodriguez 
15855d6d1dddSLuis R. Rodriguez 	return ret;
15865d6d1dddSLuis R. Rodriguez }
15875d6d1dddSLuis R. Rodriguez 
unregister_fw_pm_ops(void)15885d6d1dddSLuis R. Rodriguez static inline void unregister_fw_pm_ops(void)
15895d6d1dddSLuis R. Rodriguez {
15905d6d1dddSLuis R. Rodriguez 	unregister_syscore_ops(&fw_syscore_ops);
15915d6d1dddSLuis R. Rodriguez 	unregister_pm_notifier(&fw_cache.pm_notify);
15925d6d1dddSLuis R. Rodriguez }
15935d6d1dddSLuis R. Rodriguez #else
fw_cache_piggyback_on_request(struct fw_priv * fw_priv)15943ecc8cb7SZhen Lei static void fw_cache_piggyback_on_request(struct fw_priv *fw_priv)
15955d6d1dddSLuis R. Rodriguez {
15965d6d1dddSLuis R. Rodriguez }
register_fw_pm_ops(void)15975d6d1dddSLuis R. Rodriguez static inline int register_fw_pm_ops(void)
15985d6d1dddSLuis R. Rodriguez {
15995d6d1dddSLuis R. Rodriguez 	return 0;
16005d6d1dddSLuis R. Rodriguez }
unregister_fw_pm_ops(void)16015d6d1dddSLuis R. Rodriguez static inline void unregister_fw_pm_ops(void)
16025d6d1dddSLuis R. Rodriguez {
16035d6d1dddSLuis R. Rodriguez }
16045d6d1dddSLuis R. Rodriguez #endif
16055d6d1dddSLuis R. Rodriguez 
fw_cache_init(void)16065d6d1dddSLuis R. Rodriguez static void __init fw_cache_init(void)
16075d6d1dddSLuis R. Rodriguez {
16085d6d1dddSLuis R. Rodriguez 	spin_lock_init(&fw_cache.lock);
16095d6d1dddSLuis R. Rodriguez 	INIT_LIST_HEAD(&fw_cache.head);
16105d6d1dddSLuis R. Rodriguez 	fw_cache.state = FW_LOADER_NO_CACHE;
16115d6d1dddSLuis R. Rodriguez }
16125d6d1dddSLuis R. Rodriguez 
fw_shutdown_notify(struct notifier_block * unused1,unsigned long unused2,void * unused3)16135d6d1dddSLuis R. Rodriguez static int fw_shutdown_notify(struct notifier_block *unused1,
16145d6d1dddSLuis R. Rodriguez 			      unsigned long unused2, void *unused3)
16155d6d1dddSLuis R. Rodriguez {
16165d6d1dddSLuis R. Rodriguez 	/*
16175d6d1dddSLuis R. Rodriguez 	 * Kill all pending fallback requests to avoid both stalling shutdown,
16185d6d1dddSLuis R. Rodriguez 	 * and avoid a deadlock with the usermode_lock.
16195d6d1dddSLuis R. Rodriguez 	 */
162087ffa98eSMukesh Ojha 	kill_pending_fw_fallback_reqs(true);
16215d6d1dddSLuis R. Rodriguez 
16225d6d1dddSLuis R. Rodriguez 	return NOTIFY_DONE;
16235d6d1dddSLuis R. Rodriguez }
16245d6d1dddSLuis R. Rodriguez 
16255d6d1dddSLuis R. Rodriguez static struct notifier_block fw_shutdown_nb = {
16265d6d1dddSLuis R. Rodriguez 	.notifier_call = fw_shutdown_notify,
16275d6d1dddSLuis R. Rodriguez };
16285d6d1dddSLuis R. Rodriguez 
firmware_class_init(void)16295d6d1dddSLuis R. Rodriguez static int __init firmware_class_init(void)
16305d6d1dddSLuis R. Rodriguez {
16315d6d1dddSLuis R. Rodriguez 	int ret;
16325d6d1dddSLuis R. Rodriguez 
16335d6d1dddSLuis R. Rodriguez 	/* No need to unfold these on exit */
16345d6d1dddSLuis R. Rodriguez 	fw_cache_init();
16355d6d1dddSLuis R. Rodriguez 
16365d6d1dddSLuis R. Rodriguez 	ret = register_fw_pm_ops();
16375d6d1dddSLuis R. Rodriguez 	if (ret)
16385d6d1dddSLuis R. Rodriguez 		return ret;
16395d6d1dddSLuis R. Rodriguez 
16405d6d1dddSLuis R. Rodriguez 	ret = register_reboot_notifier(&fw_shutdown_nb);
16415d6d1dddSLuis R. Rodriguez 	if (ret)
16425d6d1dddSLuis R. Rodriguez 		goto out;
16435d6d1dddSLuis R. Rodriguez 
16445d6d1dddSLuis R. Rodriguez 	return register_sysfs_loader();
16455d6d1dddSLuis R. Rodriguez 
16465d6d1dddSLuis R. Rodriguez out:
16475d6d1dddSLuis R. Rodriguez 	unregister_fw_pm_ops();
16485d6d1dddSLuis R. Rodriguez 	return ret;
16495d6d1dddSLuis R. Rodriguez }
16505d6d1dddSLuis R. Rodriguez 
firmware_class_exit(void)16515d6d1dddSLuis R. Rodriguez static void __exit firmware_class_exit(void)
16525d6d1dddSLuis R. Rodriguez {
16535d6d1dddSLuis R. Rodriguez 	unregister_fw_pm_ops();
16545d6d1dddSLuis R. Rodriguez 	unregister_reboot_notifier(&fw_shutdown_nb);
16555d6d1dddSLuis R. Rodriguez 	unregister_sysfs_loader();
16565d6d1dddSLuis R. Rodriguez }
16575d6d1dddSLuis R. Rodriguez 
16585d6d1dddSLuis R. Rodriguez fs_initcall(firmware_class_init);
16595d6d1dddSLuis R. Rodriguez module_exit(firmware_class_exit);
1660