18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * main.c - Multi purpose firmware loading support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2003 Manuel Estrada Sainz
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Please see Documentation/driver-api/firmware/ for more information.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/capability.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel_read_file.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/timer.h>
198c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
208c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
218c2ecf20Sopenharmony_ci#include <linux/bitops.h>
228c2ecf20Sopenharmony_ci#include <linux/mutex.h>
238c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
248c2ecf20Sopenharmony_ci#include <linux/highmem.h>
258c2ecf20Sopenharmony_ci#include <linux/firmware.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include <linux/sched.h>
288c2ecf20Sopenharmony_ci#include <linux/file.h>
298c2ecf20Sopenharmony_ci#include <linux/list.h>
308c2ecf20Sopenharmony_ci#include <linux/fs.h>
318c2ecf20Sopenharmony_ci#include <linux/async.h>
328c2ecf20Sopenharmony_ci#include <linux/pm.h>
338c2ecf20Sopenharmony_ci#include <linux/suspend.h>
348c2ecf20Sopenharmony_ci#include <linux/syscore_ops.h>
358c2ecf20Sopenharmony_ci#include <linux/reboot.h>
368c2ecf20Sopenharmony_ci#include <linux/security.h>
378c2ecf20Sopenharmony_ci#include <linux/xz.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include <generated/utsrelease.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "../base.h"
428c2ecf20Sopenharmony_ci#include "firmware.h"
438c2ecf20Sopenharmony_ci#include "fallback.h"
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Manuel Estrada Sainz");
468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Multi purpose firmware loading support");
478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct firmware_cache {
508c2ecf20Sopenharmony_ci	/* firmware_buf instance will be added into the below list */
518c2ecf20Sopenharmony_ci	spinlock_t lock;
528c2ecf20Sopenharmony_ci	struct list_head head;
538c2ecf20Sopenharmony_ci	int state;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_CACHE
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * Names of firmware images which have been cached successfully
588c2ecf20Sopenharmony_ci	 * will be added into the below list so that device uncache
598c2ecf20Sopenharmony_ci	 * helper can trace which firmware images have been cached
608c2ecf20Sopenharmony_ci	 * before.
618c2ecf20Sopenharmony_ci	 */
628c2ecf20Sopenharmony_ci	spinlock_t name_lock;
638c2ecf20Sopenharmony_ci	struct list_head fw_names;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	struct delayed_work work;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	struct notifier_block   pm_notify;
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistruct fw_cache_entry {
728c2ecf20Sopenharmony_ci	struct list_head list;
738c2ecf20Sopenharmony_ci	const char *name;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistruct fw_name_devm {
778c2ecf20Sopenharmony_ci	unsigned long magic;
788c2ecf20Sopenharmony_ci	const char *name;
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic inline struct fw_priv *to_fw_priv(struct kref *ref)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	return container_of(ref, struct fw_priv, ref);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define	FW_LOADER_NO_CACHE	0
878c2ecf20Sopenharmony_ci#define	FW_LOADER_START_CACHE	1
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* fw_lock could be moved to 'struct fw_sysfs' but since it is just
908c2ecf20Sopenharmony_ci * guarding for corner cases a global lock should be OK */
918c2ecf20Sopenharmony_ciDEFINE_MUTEX(fw_lock);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic struct firmware_cache fw_cache;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/* Builtin firmware support */
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_LOADER
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciextern struct builtin_fw __start_builtin_fw[];
1008c2ecf20Sopenharmony_ciextern struct builtin_fw __end_builtin_fw[];
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic bool fw_copy_to_prealloc_buf(struct firmware *fw,
1038c2ecf20Sopenharmony_ci				    void *buf, size_t size)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	if (!buf)
1068c2ecf20Sopenharmony_ci		return true;
1078c2ecf20Sopenharmony_ci	if (size < fw->size)
1088c2ecf20Sopenharmony_ci		return false;
1098c2ecf20Sopenharmony_ci	memcpy(buf, fw->data, fw->size);
1108c2ecf20Sopenharmony_ci	return true;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
1148c2ecf20Sopenharmony_ci				    void *buf, size_t size)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct builtin_fw *b_fw;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) {
1198c2ecf20Sopenharmony_ci		if (strcmp(name, b_fw->name) == 0) {
1208c2ecf20Sopenharmony_ci			fw->size = b_fw->size;
1218c2ecf20Sopenharmony_ci			fw->data = b_fw->data;
1228c2ecf20Sopenharmony_ci			return fw_copy_to_prealloc_buf(fw, buf, size);
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return false;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic bool fw_is_builtin_firmware(const struct firmware *fw)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct builtin_fw *b_fw;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++)
1348c2ecf20Sopenharmony_ci		if (fw->data == b_fw->data)
1358c2ecf20Sopenharmony_ci			return true;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return false;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci#else /* Module case - no builtin firmware support */
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic inline bool fw_get_builtin_firmware(struct firmware *fw,
1438c2ecf20Sopenharmony_ci					   const char *name, void *buf,
1448c2ecf20Sopenharmony_ci					   size_t size)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	return false;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic inline bool fw_is_builtin_firmware(const struct firmware *fw)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	return false;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci#endif
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic void fw_state_init(struct fw_priv *fw_priv)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct fw_state *fw_st = &fw_priv->fw_st;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	init_completion(&fw_st->completion);
1608c2ecf20Sopenharmony_ci	fw_st->status = FW_STATUS_UNKNOWN;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic inline int fw_state_wait(struct fw_priv *fw_priv)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	return __fw_state_wait_common(fw_priv, MAX_SCHEDULE_TIMEOUT);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic void fw_cache_piggyback_on_request(struct fw_priv *fw_priv);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic struct fw_priv *__allocate_fw_priv(const char *fw_name,
1718c2ecf20Sopenharmony_ci					  struct firmware_cache *fwc,
1728c2ecf20Sopenharmony_ci					  void *dbuf,
1738c2ecf20Sopenharmony_ci					  size_t size,
1748c2ecf20Sopenharmony_ci					  size_t offset,
1758c2ecf20Sopenharmony_ci					  u32 opt_flags)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct fw_priv *fw_priv;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* For a partial read, the buffer must be preallocated. */
1808c2ecf20Sopenharmony_ci	if ((opt_flags & FW_OPT_PARTIAL) && !dbuf)
1818c2ecf20Sopenharmony_ci		return NULL;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Only partial reads are allowed to use an offset. */
1848c2ecf20Sopenharmony_ci	if (offset != 0 && !(opt_flags & FW_OPT_PARTIAL))
1858c2ecf20Sopenharmony_ci		return NULL;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	fw_priv = kzalloc(sizeof(*fw_priv), GFP_ATOMIC);
1888c2ecf20Sopenharmony_ci	if (!fw_priv)
1898c2ecf20Sopenharmony_ci		return NULL;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	fw_priv->fw_name = kstrdup_const(fw_name, GFP_ATOMIC);
1928c2ecf20Sopenharmony_ci	if (!fw_priv->fw_name) {
1938c2ecf20Sopenharmony_ci		kfree(fw_priv);
1948c2ecf20Sopenharmony_ci		return NULL;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	kref_init(&fw_priv->ref);
1988c2ecf20Sopenharmony_ci	fw_priv->fwc = fwc;
1998c2ecf20Sopenharmony_ci	fw_priv->data = dbuf;
2008c2ecf20Sopenharmony_ci	fw_priv->allocated_size = size;
2018c2ecf20Sopenharmony_ci	fw_priv->offset = offset;
2028c2ecf20Sopenharmony_ci	fw_priv->opt_flags = opt_flags;
2038c2ecf20Sopenharmony_ci	fw_state_init(fw_priv);
2048c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_LOADER_USER_HELPER
2058c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fw_priv->pending_list);
2068c2ecf20Sopenharmony_ci#endif
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	pr_debug("%s: fw-%s fw_priv=%p\n", __func__, fw_name, fw_priv);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return fw_priv;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic struct fw_priv *__lookup_fw_priv(const char *fw_name)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct fw_priv *tmp;
2168c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &fwc->head, list)
2198c2ecf20Sopenharmony_ci		if (!strcmp(tmp->fw_name, fw_name))
2208c2ecf20Sopenharmony_ci			return tmp;
2218c2ecf20Sopenharmony_ci	return NULL;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/* Returns 1 for batching firmware requests with the same name */
2258c2ecf20Sopenharmony_cistatic int alloc_lookup_fw_priv(const char *fw_name,
2268c2ecf20Sopenharmony_ci				struct firmware_cache *fwc,
2278c2ecf20Sopenharmony_ci				struct fw_priv **fw_priv,
2288c2ecf20Sopenharmony_ci				void *dbuf,
2298c2ecf20Sopenharmony_ci				size_t size,
2308c2ecf20Sopenharmony_ci				size_t offset,
2318c2ecf20Sopenharmony_ci				u32 opt_flags)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct fw_priv *tmp;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	spin_lock(&fwc->lock);
2368c2ecf20Sopenharmony_ci	/*
2378c2ecf20Sopenharmony_ci	 * Do not merge requests that are marked to be non-cached or
2388c2ecf20Sopenharmony_ci	 * are performing partial reads.
2398c2ecf20Sopenharmony_ci	 */
2408c2ecf20Sopenharmony_ci	if (!(opt_flags & (FW_OPT_NOCACHE | FW_OPT_PARTIAL))) {
2418c2ecf20Sopenharmony_ci		tmp = __lookup_fw_priv(fw_name);
2428c2ecf20Sopenharmony_ci		if (tmp) {
2438c2ecf20Sopenharmony_ci			kref_get(&tmp->ref);
2448c2ecf20Sopenharmony_ci			spin_unlock(&fwc->lock);
2458c2ecf20Sopenharmony_ci			*fw_priv = tmp;
2468c2ecf20Sopenharmony_ci			pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n");
2478c2ecf20Sopenharmony_ci			return 1;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, offset, opt_flags);
2528c2ecf20Sopenharmony_ci	if (tmp) {
2538c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&tmp->list);
2548c2ecf20Sopenharmony_ci		if (!(opt_flags & FW_OPT_NOCACHE))
2558c2ecf20Sopenharmony_ci			list_add(&tmp->list, &fwc->head);
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci	spin_unlock(&fwc->lock);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	*fw_priv = tmp;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return tmp ? 0 : -ENOMEM;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic void __free_fw_priv(struct kref *ref)
2658c2ecf20Sopenharmony_ci	__releases(&fwc->lock)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct fw_priv *fw_priv = to_fw_priv(ref);
2688c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = fw_priv->fwc;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n",
2718c2ecf20Sopenharmony_ci		 __func__, fw_priv->fw_name, fw_priv, fw_priv->data,
2728c2ecf20Sopenharmony_ci		 (unsigned int)fw_priv->size);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	list_del(&fw_priv->list);
2758c2ecf20Sopenharmony_ci	spin_unlock(&fwc->lock);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (fw_is_paged_buf(fw_priv))
2788c2ecf20Sopenharmony_ci		fw_free_paged_buf(fw_priv);
2798c2ecf20Sopenharmony_ci	else if (!fw_priv->allocated_size)
2808c2ecf20Sopenharmony_ci		vfree(fw_priv->data);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	kfree_const(fw_priv->fw_name);
2838c2ecf20Sopenharmony_ci	kfree(fw_priv);
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic void free_fw_priv(struct fw_priv *fw_priv)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = fw_priv->fwc;
2898c2ecf20Sopenharmony_ci	spin_lock(&fwc->lock);
2908c2ecf20Sopenharmony_ci	if (!kref_put(&fw_priv->ref, __free_fw_priv))
2918c2ecf20Sopenharmony_ci		spin_unlock(&fwc->lock);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_LOADER_PAGED_BUF
2958c2ecf20Sopenharmony_cibool fw_is_paged_buf(struct fw_priv *fw_priv)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	return fw_priv->is_paged_buf;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_civoid fw_free_paged_buf(struct fw_priv *fw_priv)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	int i;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (!fw_priv->pages)
3058c2ecf20Sopenharmony_ci		return;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	vunmap(fw_priv->data);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	for (i = 0; i < fw_priv->nr_pages; i++)
3108c2ecf20Sopenharmony_ci		__free_page(fw_priv->pages[i]);
3118c2ecf20Sopenharmony_ci	kvfree(fw_priv->pages);
3128c2ecf20Sopenharmony_ci	fw_priv->pages = NULL;
3138c2ecf20Sopenharmony_ci	fw_priv->page_array_size = 0;
3148c2ecf20Sopenharmony_ci	fw_priv->nr_pages = 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ciint fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	/* If the array of pages is too small, grow it */
3208c2ecf20Sopenharmony_ci	if (fw_priv->page_array_size < pages_needed) {
3218c2ecf20Sopenharmony_ci		int new_array_size = max(pages_needed,
3228c2ecf20Sopenharmony_ci					 fw_priv->page_array_size * 2);
3238c2ecf20Sopenharmony_ci		struct page **new_pages;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		new_pages = kvmalloc_array(new_array_size, sizeof(void *),
3268c2ecf20Sopenharmony_ci					   GFP_KERNEL);
3278c2ecf20Sopenharmony_ci		if (!new_pages)
3288c2ecf20Sopenharmony_ci			return -ENOMEM;
3298c2ecf20Sopenharmony_ci		memcpy(new_pages, fw_priv->pages,
3308c2ecf20Sopenharmony_ci		       fw_priv->page_array_size * sizeof(void *));
3318c2ecf20Sopenharmony_ci		memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
3328c2ecf20Sopenharmony_ci		       (new_array_size - fw_priv->page_array_size));
3338c2ecf20Sopenharmony_ci		kvfree(fw_priv->pages);
3348c2ecf20Sopenharmony_ci		fw_priv->pages = new_pages;
3358c2ecf20Sopenharmony_ci		fw_priv->page_array_size = new_array_size;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	while (fw_priv->nr_pages < pages_needed) {
3398c2ecf20Sopenharmony_ci		fw_priv->pages[fw_priv->nr_pages] =
3408c2ecf20Sopenharmony_ci			alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		if (!fw_priv->pages[fw_priv->nr_pages])
3438c2ecf20Sopenharmony_ci			return -ENOMEM;
3448c2ecf20Sopenharmony_ci		fw_priv->nr_pages++;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	return 0;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ciint fw_map_paged_buf(struct fw_priv *fw_priv)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	/* one pages buffer should be mapped/unmapped only once */
3538c2ecf20Sopenharmony_ci	if (!fw_priv->pages)
3548c2ecf20Sopenharmony_ci		return 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	vunmap(fw_priv->data);
3578c2ecf20Sopenharmony_ci	fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
3588c2ecf20Sopenharmony_ci			     PAGE_KERNEL_RO);
3598c2ecf20Sopenharmony_ci	if (!fw_priv->data)
3608c2ecf20Sopenharmony_ci		return -ENOMEM;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return 0;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci#endif
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci/*
3678c2ecf20Sopenharmony_ci * XZ-compressed firmware support
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_LOADER_COMPRESS
3708c2ecf20Sopenharmony_ci/* show an error and return the standard error code */
3718c2ecf20Sopenharmony_cistatic int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	if (xz_ret != XZ_STREAM_END) {
3748c2ecf20Sopenharmony_ci		dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret);
3758c2ecf20Sopenharmony_ci		return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/* single-shot decompression onto the pre-allocated buffer */
3818c2ecf20Sopenharmony_cistatic int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv,
3828c2ecf20Sopenharmony_ci				   size_t in_size, const void *in_buffer)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct xz_dec *xz_dec;
3858c2ecf20Sopenharmony_ci	struct xz_buf xz_buf;
3868c2ecf20Sopenharmony_ci	enum xz_ret xz_ret;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1);
3898c2ecf20Sopenharmony_ci	if (!xz_dec)
3908c2ecf20Sopenharmony_ci		return -ENOMEM;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	xz_buf.in_size = in_size;
3938c2ecf20Sopenharmony_ci	xz_buf.in = in_buffer;
3948c2ecf20Sopenharmony_ci	xz_buf.in_pos = 0;
3958c2ecf20Sopenharmony_ci	xz_buf.out_size = fw_priv->allocated_size;
3968c2ecf20Sopenharmony_ci	xz_buf.out = fw_priv->data;
3978c2ecf20Sopenharmony_ci	xz_buf.out_pos = 0;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	xz_ret = xz_dec_run(xz_dec, &xz_buf);
4008c2ecf20Sopenharmony_ci	xz_dec_end(xz_dec);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	fw_priv->size = xz_buf.out_pos;
4038c2ecf20Sopenharmony_ci	return fw_decompress_xz_error(dev, xz_ret);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/* decompression on paged buffer and map it */
4078c2ecf20Sopenharmony_cistatic int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv,
4088c2ecf20Sopenharmony_ci				  size_t in_size, const void *in_buffer)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct xz_dec *xz_dec;
4118c2ecf20Sopenharmony_ci	struct xz_buf xz_buf;
4128c2ecf20Sopenharmony_ci	enum xz_ret xz_ret;
4138c2ecf20Sopenharmony_ci	struct page *page;
4148c2ecf20Sopenharmony_ci	int err = 0;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1);
4178c2ecf20Sopenharmony_ci	if (!xz_dec)
4188c2ecf20Sopenharmony_ci		return -ENOMEM;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	xz_buf.in_size = in_size;
4218c2ecf20Sopenharmony_ci	xz_buf.in = in_buffer;
4228c2ecf20Sopenharmony_ci	xz_buf.in_pos = 0;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	fw_priv->is_paged_buf = true;
4258c2ecf20Sopenharmony_ci	fw_priv->size = 0;
4268c2ecf20Sopenharmony_ci	do {
4278c2ecf20Sopenharmony_ci		if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) {
4288c2ecf20Sopenharmony_ci			err = -ENOMEM;
4298c2ecf20Sopenharmony_ci			goto out;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		/* decompress onto the new allocated page */
4338c2ecf20Sopenharmony_ci		page = fw_priv->pages[fw_priv->nr_pages - 1];
4348c2ecf20Sopenharmony_ci		xz_buf.out = kmap(page);
4358c2ecf20Sopenharmony_ci		xz_buf.out_pos = 0;
4368c2ecf20Sopenharmony_ci		xz_buf.out_size = PAGE_SIZE;
4378c2ecf20Sopenharmony_ci		xz_ret = xz_dec_run(xz_dec, &xz_buf);
4388c2ecf20Sopenharmony_ci		kunmap(page);
4398c2ecf20Sopenharmony_ci		fw_priv->size += xz_buf.out_pos;
4408c2ecf20Sopenharmony_ci		/* partial decompression means either end or error */
4418c2ecf20Sopenharmony_ci		if (xz_buf.out_pos != PAGE_SIZE)
4428c2ecf20Sopenharmony_ci			break;
4438c2ecf20Sopenharmony_ci	} while (xz_ret == XZ_OK);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	err = fw_decompress_xz_error(dev, xz_ret);
4468c2ecf20Sopenharmony_ci	if (!err)
4478c2ecf20Sopenharmony_ci		err = fw_map_paged_buf(fw_priv);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci out:
4508c2ecf20Sopenharmony_ci	xz_dec_end(xz_dec);
4518c2ecf20Sopenharmony_ci	return err;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv,
4558c2ecf20Sopenharmony_ci			    size_t in_size, const void *in_buffer)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	/* if the buffer is pre-allocated, we can perform in single-shot mode */
4588c2ecf20Sopenharmony_ci	if (fw_priv->data)
4598c2ecf20Sopenharmony_ci		return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer);
4608c2ecf20Sopenharmony_ci	else
4618c2ecf20Sopenharmony_ci		return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer);
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci#endif /* CONFIG_FW_LOADER_COMPRESS */
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/* direct firmware loading support */
4668c2ecf20Sopenharmony_cistatic char fw_path_para[256];
4678c2ecf20Sopenharmony_cistatic const char * const fw_path[] = {
4688c2ecf20Sopenharmony_ci	fw_path_para,
4698c2ecf20Sopenharmony_ci	"/lib/firmware/updates/" UTS_RELEASE,
4708c2ecf20Sopenharmony_ci	"/lib/firmware/updates",
4718c2ecf20Sopenharmony_ci	"/lib/firmware/" UTS_RELEASE,
4728c2ecf20Sopenharmony_ci	"/lib/firmware"
4738c2ecf20Sopenharmony_ci};
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci/*
4768c2ecf20Sopenharmony_ci * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH'
4778c2ecf20Sopenharmony_ci * from kernel command line because firmware_class is generally built in
4788c2ecf20Sopenharmony_ci * kernel instead of module.
4798c2ecf20Sopenharmony_ci */
4808c2ecf20Sopenharmony_cimodule_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
4818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int
4848c2ecf20Sopenharmony_cifw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
4858c2ecf20Sopenharmony_ci			   const char *suffix,
4868c2ecf20Sopenharmony_ci			   int (*decompress)(struct device *dev,
4878c2ecf20Sopenharmony_ci					     struct fw_priv *fw_priv,
4888c2ecf20Sopenharmony_ci					     size_t in_size,
4898c2ecf20Sopenharmony_ci					     const void *in_buffer))
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	size_t size;
4928c2ecf20Sopenharmony_ci	int i, len;
4938c2ecf20Sopenharmony_ci	int rc = -ENOENT;
4948c2ecf20Sopenharmony_ci	char *path;
4958c2ecf20Sopenharmony_ci	size_t msize = INT_MAX;
4968c2ecf20Sopenharmony_ci	void *buffer = NULL;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* Already populated data member means we're loading into a buffer */
4998c2ecf20Sopenharmony_ci	if (!decompress && fw_priv->data) {
5008c2ecf20Sopenharmony_ci		buffer = fw_priv->data;
5018c2ecf20Sopenharmony_ci		msize = fw_priv->allocated_size;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	path = __getname();
5058c2ecf20Sopenharmony_ci	if (!path)
5068c2ecf20Sopenharmony_ci		return -ENOMEM;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
5098c2ecf20Sopenharmony_ci		size_t file_size = 0;
5108c2ecf20Sopenharmony_ci		size_t *file_size_ptr = NULL;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		/* skip the unset customized path */
5138c2ecf20Sopenharmony_ci		if (!fw_path[i][0])
5148c2ecf20Sopenharmony_ci			continue;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		len = snprintf(path, PATH_MAX, "%s/%s%s",
5178c2ecf20Sopenharmony_ci			       fw_path[i], fw_priv->fw_name, suffix);
5188c2ecf20Sopenharmony_ci		if (len >= PATH_MAX) {
5198c2ecf20Sopenharmony_ci			rc = -ENAMETOOLONG;
5208c2ecf20Sopenharmony_ci			break;
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		fw_priv->size = 0;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		/*
5268c2ecf20Sopenharmony_ci		 * The total file size is only examined when doing a partial
5278c2ecf20Sopenharmony_ci		 * read; the "full read" case needs to fail if the whole
5288c2ecf20Sopenharmony_ci		 * firmware was not completely loaded.
5298c2ecf20Sopenharmony_ci		 */
5308c2ecf20Sopenharmony_ci		if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && buffer)
5318c2ecf20Sopenharmony_ci			file_size_ptr = &file_size;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		/* load firmware files from the mount namespace of init */
5348c2ecf20Sopenharmony_ci		rc = kernel_read_file_from_path_initns(path, fw_priv->offset,
5358c2ecf20Sopenharmony_ci						       &buffer, msize,
5368c2ecf20Sopenharmony_ci						       file_size_ptr,
5378c2ecf20Sopenharmony_ci						       READING_FIRMWARE);
5388c2ecf20Sopenharmony_ci		if (rc < 0) {
5398c2ecf20Sopenharmony_ci			if (rc != -ENOENT)
5408c2ecf20Sopenharmony_ci				dev_warn(device, "loading %s failed with error %d\n",
5418c2ecf20Sopenharmony_ci					 path, rc);
5428c2ecf20Sopenharmony_ci			else
5438c2ecf20Sopenharmony_ci				dev_dbg(device, "loading %s failed for no such file or directory.\n",
5448c2ecf20Sopenharmony_ci					 path);
5458c2ecf20Sopenharmony_ci			continue;
5468c2ecf20Sopenharmony_ci		}
5478c2ecf20Sopenharmony_ci		size = rc;
5488c2ecf20Sopenharmony_ci		rc = 0;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		dev_dbg(device, "Loading firmware from %s\n", path);
5518c2ecf20Sopenharmony_ci		if (decompress) {
5528c2ecf20Sopenharmony_ci			dev_dbg(device, "f/w decompressing %s\n",
5538c2ecf20Sopenharmony_ci				fw_priv->fw_name);
5548c2ecf20Sopenharmony_ci			rc = decompress(device, fw_priv, size, buffer);
5558c2ecf20Sopenharmony_ci			/* discard the superfluous original content */
5568c2ecf20Sopenharmony_ci			vfree(buffer);
5578c2ecf20Sopenharmony_ci			buffer = NULL;
5588c2ecf20Sopenharmony_ci			if (rc) {
5598c2ecf20Sopenharmony_ci				fw_free_paged_buf(fw_priv);
5608c2ecf20Sopenharmony_ci				continue;
5618c2ecf20Sopenharmony_ci			}
5628c2ecf20Sopenharmony_ci		} else {
5638c2ecf20Sopenharmony_ci			dev_dbg(device, "direct-loading %s\n",
5648c2ecf20Sopenharmony_ci				fw_priv->fw_name);
5658c2ecf20Sopenharmony_ci			if (!fw_priv->data)
5668c2ecf20Sopenharmony_ci				fw_priv->data = buffer;
5678c2ecf20Sopenharmony_ci			fw_priv->size = size;
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci		fw_state_done(fw_priv);
5708c2ecf20Sopenharmony_ci		break;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci	__putname(path);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return rc;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/* firmware holds the ownership of pages */
5788c2ecf20Sopenharmony_cistatic void firmware_free_data(const struct firmware *fw)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	/* Loaded directly? */
5818c2ecf20Sopenharmony_ci	if (!fw->priv) {
5828c2ecf20Sopenharmony_ci		vfree(fw->data);
5838c2ecf20Sopenharmony_ci		return;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci	free_fw_priv(fw->priv);
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci/* store the pages buffer info firmware from buf */
5898c2ecf20Sopenharmony_cistatic void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	fw->priv = fw_priv;
5928c2ecf20Sopenharmony_ci	fw->size = fw_priv->size;
5938c2ecf20Sopenharmony_ci	fw->data = fw_priv->data;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n",
5968c2ecf20Sopenharmony_ci		 __func__, fw_priv->fw_name, fw_priv, fw_priv->data,
5978c2ecf20Sopenharmony_ci		 (unsigned int)fw_priv->size);
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_CACHE
6018c2ecf20Sopenharmony_cistatic void fw_name_devm_release(struct device *dev, void *res)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn = res;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	if (fwn->magic == (unsigned long)&fw_cache)
6068c2ecf20Sopenharmony_ci		pr_debug("%s: fw_name-%s devm-%p released\n",
6078c2ecf20Sopenharmony_ci				__func__, fwn->name, res);
6088c2ecf20Sopenharmony_ci	kfree_const(fwn->name);
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic int fw_devm_match(struct device *dev, void *res,
6128c2ecf20Sopenharmony_ci		void *match_data)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn = res;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return (fwn->magic == (unsigned long)&fw_cache) &&
6178c2ecf20Sopenharmony_ci		!strcmp(fwn->name, match_data);
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic struct fw_name_devm *fw_find_devm_name(struct device *dev,
6218c2ecf20Sopenharmony_ci		const char *name)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	fwn = devres_find(dev, fw_name_devm_release,
6268c2ecf20Sopenharmony_ci			  fw_devm_match, (void *)name);
6278c2ecf20Sopenharmony_ci	return fwn;
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic bool fw_cache_is_setup(struct device *dev, const char *name)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	fwn = fw_find_devm_name(dev, name);
6358c2ecf20Sopenharmony_ci	if (fwn)
6368c2ecf20Sopenharmony_ci		return true;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return false;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci/* add firmware name into devres list */
6428c2ecf20Sopenharmony_cistatic int fw_add_devm_name(struct device *dev, const char *name)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (fw_cache_is_setup(dev, name))
6478c2ecf20Sopenharmony_ci		return 0;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
6508c2ecf20Sopenharmony_ci			   GFP_KERNEL);
6518c2ecf20Sopenharmony_ci	if (!fwn)
6528c2ecf20Sopenharmony_ci		return -ENOMEM;
6538c2ecf20Sopenharmony_ci	fwn->name = kstrdup_const(name, GFP_KERNEL);
6548c2ecf20Sopenharmony_ci	if (!fwn->name) {
6558c2ecf20Sopenharmony_ci		devres_free(fwn);
6568c2ecf20Sopenharmony_ci		return -ENOMEM;
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	fwn->magic = (unsigned long)&fw_cache;
6608c2ecf20Sopenharmony_ci	devres_add(dev, fwn);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	return 0;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci#else
6658c2ecf20Sopenharmony_cistatic bool fw_cache_is_setup(struct device *dev, const char *name)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	return false;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistatic int fw_add_devm_name(struct device *dev, const char *name)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	return 0;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci#endif
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ciint assign_fw(struct firmware *fw, struct device *device)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct fw_priv *fw_priv = fw->priv;
6798c2ecf20Sopenharmony_ci	int ret;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	mutex_lock(&fw_lock);
6828c2ecf20Sopenharmony_ci	if (!fw_priv->size || fw_state_is_aborted(fw_priv)) {
6838c2ecf20Sopenharmony_ci		mutex_unlock(&fw_lock);
6848c2ecf20Sopenharmony_ci		return -ENOENT;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	/*
6888c2ecf20Sopenharmony_ci	 * add firmware name into devres list so that we can auto cache
6898c2ecf20Sopenharmony_ci	 * and uncache firmware for device.
6908c2ecf20Sopenharmony_ci	 *
6918c2ecf20Sopenharmony_ci	 * device may has been deleted already, but the problem
6928c2ecf20Sopenharmony_ci	 * should be fixed in devres or driver core.
6938c2ecf20Sopenharmony_ci	 */
6948c2ecf20Sopenharmony_ci	/* don't cache firmware handled without uevent */
6958c2ecf20Sopenharmony_ci	if (device && (fw_priv->opt_flags & FW_OPT_UEVENT) &&
6968c2ecf20Sopenharmony_ci	    !(fw_priv->opt_flags & FW_OPT_NOCACHE)) {
6978c2ecf20Sopenharmony_ci		ret = fw_add_devm_name(device, fw_priv->fw_name);
6988c2ecf20Sopenharmony_ci		if (ret) {
6998c2ecf20Sopenharmony_ci			mutex_unlock(&fw_lock);
7008c2ecf20Sopenharmony_ci			return ret;
7018c2ecf20Sopenharmony_ci		}
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	/*
7058c2ecf20Sopenharmony_ci	 * After caching firmware image is started, let it piggyback
7068c2ecf20Sopenharmony_ci	 * on request firmware.
7078c2ecf20Sopenharmony_ci	 */
7088c2ecf20Sopenharmony_ci	if (!(fw_priv->opt_flags & FW_OPT_NOCACHE) &&
7098c2ecf20Sopenharmony_ci	    fw_priv->fwc->state == FW_LOADER_START_CACHE)
7108c2ecf20Sopenharmony_ci		fw_cache_piggyback_on_request(fw_priv);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	/* pass the pages buffer to driver at the last minute */
7138c2ecf20Sopenharmony_ci	fw_set_page_data(fw_priv, fw);
7148c2ecf20Sopenharmony_ci	mutex_unlock(&fw_lock);
7158c2ecf20Sopenharmony_ci	return 0;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci/* prepare firmware and firmware_buf structs;
7198c2ecf20Sopenharmony_ci * return 0 if a firmware is already assigned, 1 if need to load one,
7208c2ecf20Sopenharmony_ci * or a negative error code
7218c2ecf20Sopenharmony_ci */
7228c2ecf20Sopenharmony_cistatic int
7238c2ecf20Sopenharmony_ci_request_firmware_prepare(struct firmware **firmware_p, const char *name,
7248c2ecf20Sopenharmony_ci			  struct device *device, void *dbuf, size_t size,
7258c2ecf20Sopenharmony_ci			  size_t offset, u32 opt_flags)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	struct firmware *firmware;
7288c2ecf20Sopenharmony_ci	struct fw_priv *fw_priv;
7298c2ecf20Sopenharmony_ci	int ret;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
7328c2ecf20Sopenharmony_ci	if (!firmware) {
7338c2ecf20Sopenharmony_ci		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
7348c2ecf20Sopenharmony_ci			__func__);
7358c2ecf20Sopenharmony_ci		return -ENOMEM;
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	if (fw_get_builtin_firmware(firmware, name, dbuf, size)) {
7398c2ecf20Sopenharmony_ci		dev_dbg(device, "using built-in %s\n", name);
7408c2ecf20Sopenharmony_ci		return 0; /* assigned */
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size,
7448c2ecf20Sopenharmony_ci				   offset, opt_flags);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/*
7478c2ecf20Sopenharmony_ci	 * bind with 'priv' now to avoid warning in failure path
7488c2ecf20Sopenharmony_ci	 * of requesting firmware.
7498c2ecf20Sopenharmony_ci	 */
7508c2ecf20Sopenharmony_ci	firmware->priv = fw_priv;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (ret > 0) {
7538c2ecf20Sopenharmony_ci		ret = fw_state_wait(fw_priv);
7548c2ecf20Sopenharmony_ci		if (!ret) {
7558c2ecf20Sopenharmony_ci			fw_set_page_data(fw_priv, firmware);
7568c2ecf20Sopenharmony_ci			return 0; /* assigned */
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (ret < 0)
7618c2ecf20Sopenharmony_ci		return ret;
7628c2ecf20Sopenharmony_ci	return 1; /* need to load */
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci/*
7668c2ecf20Sopenharmony_ci * Batched requests need only one wake, we need to do this step last due to the
7678c2ecf20Sopenharmony_ci * fallback mechanism. The buf is protected with kref_get(), and it won't be
7688c2ecf20Sopenharmony_ci * released until the last user calls release_firmware().
7698c2ecf20Sopenharmony_ci *
7708c2ecf20Sopenharmony_ci * Failed batched requests are possible as well, in such cases we just share
7718c2ecf20Sopenharmony_ci * the struct fw_priv and won't release it until all requests are woken
7728c2ecf20Sopenharmony_ci * and have gone through this same path.
7738c2ecf20Sopenharmony_ci */
7748c2ecf20Sopenharmony_cistatic void fw_abort_batch_reqs(struct firmware *fw)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	struct fw_priv *fw_priv;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	/* Loaded directly? */
7798c2ecf20Sopenharmony_ci	if (!fw || !fw->priv)
7808c2ecf20Sopenharmony_ci		return;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	fw_priv = fw->priv;
7838c2ecf20Sopenharmony_ci	mutex_lock(&fw_lock);
7848c2ecf20Sopenharmony_ci	if (!fw_state_is_aborted(fw_priv))
7858c2ecf20Sopenharmony_ci		fw_state_aborted(fw_priv);
7868c2ecf20Sopenharmony_ci	mutex_unlock(&fw_lock);
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci/* called from request_firmware() and request_firmware_work_func() */
7908c2ecf20Sopenharmony_cistatic int
7918c2ecf20Sopenharmony_ci_request_firmware(const struct firmware **firmware_p, const char *name,
7928c2ecf20Sopenharmony_ci		  struct device *device, void *buf, size_t size,
7938c2ecf20Sopenharmony_ci		  size_t offset, u32 opt_flags)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct firmware *fw = NULL;
7968c2ecf20Sopenharmony_ci	struct cred *kern_cred = NULL;
7978c2ecf20Sopenharmony_ci	const struct cred *old_cred;
7988c2ecf20Sopenharmony_ci	bool nondirect = false;
7998c2ecf20Sopenharmony_ci	int ret;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (!firmware_p)
8028c2ecf20Sopenharmony_ci		return -EINVAL;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	if (!name || name[0] == '\0') {
8058c2ecf20Sopenharmony_ci		ret = -EINVAL;
8068c2ecf20Sopenharmony_ci		goto out;
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	ret = _request_firmware_prepare(&fw, name, device, buf, size,
8108c2ecf20Sopenharmony_ci					offset, opt_flags);
8118c2ecf20Sopenharmony_ci	if (ret <= 0) /* error or already assigned */
8128c2ecf20Sopenharmony_ci		goto out;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	/*
8158c2ecf20Sopenharmony_ci	 * We are about to try to access the firmware file. Because we may have been
8168c2ecf20Sopenharmony_ci	 * called by a driver when serving an unrelated request from userland, we use
8178c2ecf20Sopenharmony_ci	 * the kernel credentials to read the file.
8188c2ecf20Sopenharmony_ci	 */
8198c2ecf20Sopenharmony_ci	kern_cred = prepare_kernel_cred(NULL);
8208c2ecf20Sopenharmony_ci	if (!kern_cred) {
8218c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8228c2ecf20Sopenharmony_ci		goto out;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci	old_cred = override_creds(kern_cred);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	/* Only full reads can support decompression, platform, and sysfs. */
8298c2ecf20Sopenharmony_ci	if (!(opt_flags & FW_OPT_PARTIAL))
8308c2ecf20Sopenharmony_ci		nondirect = true;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_LOADER_COMPRESS
8338c2ecf20Sopenharmony_ci	if (ret == -ENOENT && nondirect)
8348c2ecf20Sopenharmony_ci		ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
8358c2ecf20Sopenharmony_ci						 fw_decompress_xz);
8368c2ecf20Sopenharmony_ci#endif
8378c2ecf20Sopenharmony_ci	if (ret == -ENOENT && nondirect)
8388c2ecf20Sopenharmony_ci		ret = firmware_fallback_platform(fw->priv);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	if (ret) {
8418c2ecf20Sopenharmony_ci		if (!(opt_flags & FW_OPT_NO_WARN))
8428c2ecf20Sopenharmony_ci			dev_warn(device,
8438c2ecf20Sopenharmony_ci				 "Direct firmware load for %s failed with error %d\n",
8448c2ecf20Sopenharmony_ci				 name, ret);
8458c2ecf20Sopenharmony_ci		if (nondirect)
8468c2ecf20Sopenharmony_ci			ret = firmware_fallback_sysfs(fw, name, device,
8478c2ecf20Sopenharmony_ci						      opt_flags, ret);
8488c2ecf20Sopenharmony_ci	} else
8498c2ecf20Sopenharmony_ci		ret = assign_fw(fw, device);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	revert_creds(old_cred);
8528c2ecf20Sopenharmony_ci	put_cred(kern_cred);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci out:
8558c2ecf20Sopenharmony_ci	if (ret < 0) {
8568c2ecf20Sopenharmony_ci		fw_abort_batch_reqs(fw);
8578c2ecf20Sopenharmony_ci		release_firmware(fw);
8588c2ecf20Sopenharmony_ci		fw = NULL;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	*firmware_p = fw;
8628c2ecf20Sopenharmony_ci	return ret;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/**
8668c2ecf20Sopenharmony_ci * request_firmware() - send firmware request and wait for it
8678c2ecf20Sopenharmony_ci * @firmware_p: pointer to firmware image
8688c2ecf20Sopenharmony_ci * @name: name of firmware file
8698c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded
8708c2ecf20Sopenharmony_ci *
8718c2ecf20Sopenharmony_ci *      @firmware_p will be used to return a firmware image by the name
8728c2ecf20Sopenharmony_ci *      of @name for device @device.
8738c2ecf20Sopenharmony_ci *
8748c2ecf20Sopenharmony_ci *      Should be called from user context where sleeping is allowed.
8758c2ecf20Sopenharmony_ci *
8768c2ecf20Sopenharmony_ci *      @name will be used as $FIRMWARE in the uevent environment and
8778c2ecf20Sopenharmony_ci *      should be distinctive enough not to be confused with any other
8788c2ecf20Sopenharmony_ci *      firmware image for this or any other device.
8798c2ecf20Sopenharmony_ci *
8808c2ecf20Sopenharmony_ci *	Caller must hold the reference count of @device.
8818c2ecf20Sopenharmony_ci *
8828c2ecf20Sopenharmony_ci *	The function can be called safely inside device's suspend and
8838c2ecf20Sopenharmony_ci *	resume callback.
8848c2ecf20Sopenharmony_ci **/
8858c2ecf20Sopenharmony_ciint
8868c2ecf20Sopenharmony_cirequest_firmware(const struct firmware **firmware_p, const char *name,
8878c2ecf20Sopenharmony_ci		 struct device *device)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	int ret;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	/* Need to pin this module until return */
8928c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
8938c2ecf20Sopenharmony_ci	ret = _request_firmware(firmware_p, name, device, NULL, 0, 0,
8948c2ecf20Sopenharmony_ci				FW_OPT_UEVENT);
8958c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
8968c2ecf20Sopenharmony_ci	return ret;
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(request_firmware);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci/**
9018c2ecf20Sopenharmony_ci * firmware_request_nowarn() - request for an optional fw module
9028c2ecf20Sopenharmony_ci * @firmware: pointer to firmware image
9038c2ecf20Sopenharmony_ci * @name: name of firmware file
9048c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded
9058c2ecf20Sopenharmony_ci *
9068c2ecf20Sopenharmony_ci * This function is similar in behaviour to request_firmware(), except it
9078c2ecf20Sopenharmony_ci * doesn't produce warning messages when the file is not found. The sysfs
9088c2ecf20Sopenharmony_ci * fallback mechanism is enabled if direct filesystem lookup fails. However,
9098c2ecf20Sopenharmony_ci * failures to find the firmware file with it are still suppressed. It is
9108c2ecf20Sopenharmony_ci * therefore up to the driver to check for the return value of this call and to
9118c2ecf20Sopenharmony_ci * decide when to inform the users of errors.
9128c2ecf20Sopenharmony_ci **/
9138c2ecf20Sopenharmony_ciint firmware_request_nowarn(const struct firmware **firmware, const char *name,
9148c2ecf20Sopenharmony_ci			    struct device *device)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	int ret;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	/* Need to pin this module until return */
9198c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
9208c2ecf20Sopenharmony_ci	ret = _request_firmware(firmware, name, device, NULL, 0, 0,
9218c2ecf20Sopenharmony_ci				FW_OPT_UEVENT | FW_OPT_NO_WARN);
9228c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
9238c2ecf20Sopenharmony_ci	return ret;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(firmware_request_nowarn);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci/**
9288c2ecf20Sopenharmony_ci * request_firmware_direct() - load firmware directly without usermode helper
9298c2ecf20Sopenharmony_ci * @firmware_p: pointer to firmware image
9308c2ecf20Sopenharmony_ci * @name: name of firmware file
9318c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded
9328c2ecf20Sopenharmony_ci *
9338c2ecf20Sopenharmony_ci * This function works pretty much like request_firmware(), but this doesn't
9348c2ecf20Sopenharmony_ci * fall back to usermode helper even if the firmware couldn't be loaded
9358c2ecf20Sopenharmony_ci * directly from fs.  Hence it's useful for loading optional firmwares, which
9368c2ecf20Sopenharmony_ci * aren't always present, without extra long timeouts of udev.
9378c2ecf20Sopenharmony_ci **/
9388c2ecf20Sopenharmony_ciint request_firmware_direct(const struct firmware **firmware_p,
9398c2ecf20Sopenharmony_ci			    const char *name, struct device *device)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	int ret;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
9448c2ecf20Sopenharmony_ci	ret = _request_firmware(firmware_p, name, device, NULL, 0, 0,
9458c2ecf20Sopenharmony_ci				FW_OPT_UEVENT | FW_OPT_NO_WARN |
9468c2ecf20Sopenharmony_ci				FW_OPT_NOFALLBACK_SYSFS);
9478c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
9488c2ecf20Sopenharmony_ci	return ret;
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(request_firmware_direct);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci/**
9538c2ecf20Sopenharmony_ci * firmware_request_platform() - request firmware with platform-fw fallback
9548c2ecf20Sopenharmony_ci * @firmware: pointer to firmware image
9558c2ecf20Sopenharmony_ci * @name: name of firmware file
9568c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded
9578c2ecf20Sopenharmony_ci *
9588c2ecf20Sopenharmony_ci * This function is similar in behaviour to request_firmware, except that if
9598c2ecf20Sopenharmony_ci * direct filesystem lookup fails, it will fallback to looking for a copy of the
9608c2ecf20Sopenharmony_ci * requested firmware embedded in the platform's main (e.g. UEFI) firmware.
9618c2ecf20Sopenharmony_ci **/
9628c2ecf20Sopenharmony_ciint firmware_request_platform(const struct firmware **firmware,
9638c2ecf20Sopenharmony_ci			      const char *name, struct device *device)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	int ret;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/* Need to pin this module until return */
9688c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
9698c2ecf20Sopenharmony_ci	ret = _request_firmware(firmware, name, device, NULL, 0, 0,
9708c2ecf20Sopenharmony_ci				FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM);
9718c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
9728c2ecf20Sopenharmony_ci	return ret;
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(firmware_request_platform);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci/**
9778c2ecf20Sopenharmony_ci * firmware_request_cache() - cache firmware for suspend so resume can use it
9788c2ecf20Sopenharmony_ci * @name: name of firmware file
9798c2ecf20Sopenharmony_ci * @device: device for which firmware should be cached for
9808c2ecf20Sopenharmony_ci *
9818c2ecf20Sopenharmony_ci * There are some devices with an optimization that enables the device to not
9828c2ecf20Sopenharmony_ci * require loading firmware on system reboot. This optimization may still
9838c2ecf20Sopenharmony_ci * require the firmware present on resume from suspend. This routine can be
9848c2ecf20Sopenharmony_ci * used to ensure the firmware is present on resume from suspend in these
9858c2ecf20Sopenharmony_ci * situations. This helper is not compatible with drivers which use
9868c2ecf20Sopenharmony_ci * request_firmware_into_buf() or request_firmware_nowait() with no uevent set.
9878c2ecf20Sopenharmony_ci **/
9888c2ecf20Sopenharmony_ciint firmware_request_cache(struct device *device, const char *name)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	int ret;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	mutex_lock(&fw_lock);
9938c2ecf20Sopenharmony_ci	ret = fw_add_devm_name(device, name);
9948c2ecf20Sopenharmony_ci	mutex_unlock(&fw_lock);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	return ret;
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(firmware_request_cache);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci/**
10018c2ecf20Sopenharmony_ci * request_firmware_into_buf() - load firmware into a previously allocated buffer
10028c2ecf20Sopenharmony_ci * @firmware_p: pointer to firmware image
10038c2ecf20Sopenharmony_ci * @name: name of firmware file
10048c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded and DMA region allocated
10058c2ecf20Sopenharmony_ci * @buf: address of buffer to load firmware into
10068c2ecf20Sopenharmony_ci * @size: size of buffer
10078c2ecf20Sopenharmony_ci *
10088c2ecf20Sopenharmony_ci * This function works pretty much like request_firmware(), but it doesn't
10098c2ecf20Sopenharmony_ci * allocate a buffer to hold the firmware data. Instead, the firmware
10108c2ecf20Sopenharmony_ci * is loaded directly into the buffer pointed to by @buf and the @firmware_p
10118c2ecf20Sopenharmony_ci * data member is pointed at @buf.
10128c2ecf20Sopenharmony_ci *
10138c2ecf20Sopenharmony_ci * This function doesn't cache firmware either.
10148c2ecf20Sopenharmony_ci */
10158c2ecf20Sopenharmony_ciint
10168c2ecf20Sopenharmony_cirequest_firmware_into_buf(const struct firmware **firmware_p, const char *name,
10178c2ecf20Sopenharmony_ci			  struct device *device, void *buf, size_t size)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	int ret;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if (fw_cache_is_setup(device, name))
10228c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
10258c2ecf20Sopenharmony_ci	ret = _request_firmware(firmware_p, name, device, buf, size, 0,
10268c2ecf20Sopenharmony_ci				FW_OPT_UEVENT | FW_OPT_NOCACHE);
10278c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
10288c2ecf20Sopenharmony_ci	return ret;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(request_firmware_into_buf);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci/**
10338c2ecf20Sopenharmony_ci * request_partial_firmware_into_buf() - load partial firmware into a previously allocated buffer
10348c2ecf20Sopenharmony_ci * @firmware_p: pointer to firmware image
10358c2ecf20Sopenharmony_ci * @name: name of firmware file
10368c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded and DMA region allocated
10378c2ecf20Sopenharmony_ci * @buf: address of buffer to load firmware into
10388c2ecf20Sopenharmony_ci * @size: size of buffer
10398c2ecf20Sopenharmony_ci * @offset: offset into file to read
10408c2ecf20Sopenharmony_ci *
10418c2ecf20Sopenharmony_ci * This function works pretty much like request_firmware_into_buf except
10428c2ecf20Sopenharmony_ci * it allows a partial read of the file.
10438c2ecf20Sopenharmony_ci */
10448c2ecf20Sopenharmony_ciint
10458c2ecf20Sopenharmony_cirequest_partial_firmware_into_buf(const struct firmware **firmware_p,
10468c2ecf20Sopenharmony_ci				  const char *name, struct device *device,
10478c2ecf20Sopenharmony_ci				  void *buf, size_t size, size_t offset)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	int ret;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	if (fw_cache_is_setup(device, name))
10528c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
10558c2ecf20Sopenharmony_ci	ret = _request_firmware(firmware_p, name, device, buf, size, offset,
10568c2ecf20Sopenharmony_ci				FW_OPT_UEVENT | FW_OPT_NOCACHE |
10578c2ecf20Sopenharmony_ci				FW_OPT_PARTIAL);
10588c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
10598c2ecf20Sopenharmony_ci	return ret;
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(request_partial_firmware_into_buf);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci/**
10648c2ecf20Sopenharmony_ci * release_firmware() - release the resource associated with a firmware image
10658c2ecf20Sopenharmony_ci * @fw: firmware resource to release
10668c2ecf20Sopenharmony_ci **/
10678c2ecf20Sopenharmony_civoid release_firmware(const struct firmware *fw)
10688c2ecf20Sopenharmony_ci{
10698c2ecf20Sopenharmony_ci	if (fw) {
10708c2ecf20Sopenharmony_ci		if (!fw_is_builtin_firmware(fw))
10718c2ecf20Sopenharmony_ci			firmware_free_data(fw);
10728c2ecf20Sopenharmony_ci		kfree(fw);
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(release_firmware);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/* Async support */
10788c2ecf20Sopenharmony_cistruct firmware_work {
10798c2ecf20Sopenharmony_ci	struct work_struct work;
10808c2ecf20Sopenharmony_ci	struct module *module;
10818c2ecf20Sopenharmony_ci	const char *name;
10828c2ecf20Sopenharmony_ci	struct device *device;
10838c2ecf20Sopenharmony_ci	void *context;
10848c2ecf20Sopenharmony_ci	void (*cont)(const struct firmware *fw, void *context);
10858c2ecf20Sopenharmony_ci	u32 opt_flags;
10868c2ecf20Sopenharmony_ci};
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_cistatic void request_firmware_work_func(struct work_struct *work)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	struct firmware_work *fw_work;
10918c2ecf20Sopenharmony_ci	const struct firmware *fw;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	fw_work = container_of(work, struct firmware_work, work);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	_request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0,
10968c2ecf20Sopenharmony_ci			  fw_work->opt_flags);
10978c2ecf20Sopenharmony_ci	fw_work->cont(fw, fw_work->context);
10988c2ecf20Sopenharmony_ci	put_device(fw_work->device); /* taken in request_firmware_nowait() */
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	module_put(fw_work->module);
11018c2ecf20Sopenharmony_ci	kfree_const(fw_work->name);
11028c2ecf20Sopenharmony_ci	kfree(fw_work);
11038c2ecf20Sopenharmony_ci}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci/**
11068c2ecf20Sopenharmony_ci * request_firmware_nowait() - asynchronous version of request_firmware
11078c2ecf20Sopenharmony_ci * @module: module requesting the firmware
11088c2ecf20Sopenharmony_ci * @uevent: sends uevent to copy the firmware image if this flag
11098c2ecf20Sopenharmony_ci *	is non-zero else the firmware copy must be done manually.
11108c2ecf20Sopenharmony_ci * @name: name of firmware file
11118c2ecf20Sopenharmony_ci * @device: device for which firmware is being loaded
11128c2ecf20Sopenharmony_ci * @gfp: allocation flags
11138c2ecf20Sopenharmony_ci * @context: will be passed over to @cont, and
11148c2ecf20Sopenharmony_ci *	@fw may be %NULL if firmware request fails.
11158c2ecf20Sopenharmony_ci * @cont: function will be called asynchronously when the firmware
11168c2ecf20Sopenharmony_ci *	request is over.
11178c2ecf20Sopenharmony_ci *
11188c2ecf20Sopenharmony_ci *	Caller must hold the reference count of @device.
11198c2ecf20Sopenharmony_ci *
11208c2ecf20Sopenharmony_ci *	Asynchronous variant of request_firmware() for user contexts:
11218c2ecf20Sopenharmony_ci *		- sleep for as small periods as possible since it may
11228c2ecf20Sopenharmony_ci *		  increase kernel boot time of built-in device drivers
11238c2ecf20Sopenharmony_ci *		  requesting firmware in their ->probe() methods, if
11248c2ecf20Sopenharmony_ci *		  @gfp is GFP_KERNEL.
11258c2ecf20Sopenharmony_ci *
11268c2ecf20Sopenharmony_ci *		- can't sleep at all if @gfp is GFP_ATOMIC.
11278c2ecf20Sopenharmony_ci **/
11288c2ecf20Sopenharmony_ciint
11298c2ecf20Sopenharmony_cirequest_firmware_nowait(
11308c2ecf20Sopenharmony_ci	struct module *module, bool uevent,
11318c2ecf20Sopenharmony_ci	const char *name, struct device *device, gfp_t gfp, void *context,
11328c2ecf20Sopenharmony_ci	void (*cont)(const struct firmware *fw, void *context))
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	struct firmware_work *fw_work;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	fw_work = kzalloc(sizeof(struct firmware_work), gfp);
11378c2ecf20Sopenharmony_ci	if (!fw_work)
11388c2ecf20Sopenharmony_ci		return -ENOMEM;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	fw_work->module = module;
11418c2ecf20Sopenharmony_ci	fw_work->name = kstrdup_const(name, gfp);
11428c2ecf20Sopenharmony_ci	if (!fw_work->name) {
11438c2ecf20Sopenharmony_ci		kfree(fw_work);
11448c2ecf20Sopenharmony_ci		return -ENOMEM;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci	fw_work->device = device;
11478c2ecf20Sopenharmony_ci	fw_work->context = context;
11488c2ecf20Sopenharmony_ci	fw_work->cont = cont;
11498c2ecf20Sopenharmony_ci	fw_work->opt_flags = FW_OPT_NOWAIT |
11508c2ecf20Sopenharmony_ci		(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (!uevent && fw_cache_is_setup(device, name)) {
11538c2ecf20Sopenharmony_ci		kfree_const(fw_work->name);
11548c2ecf20Sopenharmony_ci		kfree(fw_work);
11558c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	if (!try_module_get(module)) {
11598c2ecf20Sopenharmony_ci		kfree_const(fw_work->name);
11608c2ecf20Sopenharmony_ci		kfree(fw_work);
11618c2ecf20Sopenharmony_ci		return -EFAULT;
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	get_device(fw_work->device);
11658c2ecf20Sopenharmony_ci	INIT_WORK(&fw_work->work, request_firmware_work_func);
11668c2ecf20Sopenharmony_ci	schedule_work(&fw_work->work);
11678c2ecf20Sopenharmony_ci	return 0;
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(request_firmware_nowait);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci#ifdef CONFIG_FW_CACHE
11728c2ecf20Sopenharmony_cistatic ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci/**
11758c2ecf20Sopenharmony_ci * cache_firmware() - cache one firmware image in kernel memory space
11768c2ecf20Sopenharmony_ci * @fw_name: the firmware image name
11778c2ecf20Sopenharmony_ci *
11788c2ecf20Sopenharmony_ci * Cache firmware in kernel memory so that drivers can use it when
11798c2ecf20Sopenharmony_ci * system isn't ready for them to request firmware image from userspace.
11808c2ecf20Sopenharmony_ci * Once it returns successfully, driver can use request_firmware or its
11818c2ecf20Sopenharmony_ci * nowait version to get the cached firmware without any interacting
11828c2ecf20Sopenharmony_ci * with userspace
11838c2ecf20Sopenharmony_ci *
11848c2ecf20Sopenharmony_ci * Return 0 if the firmware image has been cached successfully
11858c2ecf20Sopenharmony_ci * Return !0 otherwise
11868c2ecf20Sopenharmony_ci *
11878c2ecf20Sopenharmony_ci */
11888c2ecf20Sopenharmony_cistatic int cache_firmware(const char *fw_name)
11898c2ecf20Sopenharmony_ci{
11908c2ecf20Sopenharmony_ci	int ret;
11918c2ecf20Sopenharmony_ci	const struct firmware *fw;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	pr_debug("%s: %s\n", __func__, fw_name);
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, fw_name, NULL);
11968c2ecf20Sopenharmony_ci	if (!ret)
11978c2ecf20Sopenharmony_ci		kfree(fw);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret);
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	return ret;
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_cistatic struct fw_priv *lookup_fw_priv(const char *fw_name)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct fw_priv *tmp;
12078c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	spin_lock(&fwc->lock);
12108c2ecf20Sopenharmony_ci	tmp = __lookup_fw_priv(fw_name);
12118c2ecf20Sopenharmony_ci	spin_unlock(&fwc->lock);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	return tmp;
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci/**
12178c2ecf20Sopenharmony_ci * uncache_firmware() - remove one cached firmware image
12188c2ecf20Sopenharmony_ci * @fw_name: the firmware image name
12198c2ecf20Sopenharmony_ci *
12208c2ecf20Sopenharmony_ci * Uncache one firmware image which has been cached successfully
12218c2ecf20Sopenharmony_ci * before.
12228c2ecf20Sopenharmony_ci *
12238c2ecf20Sopenharmony_ci * Return 0 if the firmware cache has been removed successfully
12248c2ecf20Sopenharmony_ci * Return !0 otherwise
12258c2ecf20Sopenharmony_ci *
12268c2ecf20Sopenharmony_ci */
12278c2ecf20Sopenharmony_cistatic int uncache_firmware(const char *fw_name)
12288c2ecf20Sopenharmony_ci{
12298c2ecf20Sopenharmony_ci	struct fw_priv *fw_priv;
12308c2ecf20Sopenharmony_ci	struct firmware fw;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	pr_debug("%s: %s\n", __func__, fw_name);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if (fw_get_builtin_firmware(&fw, fw_name, NULL, 0))
12358c2ecf20Sopenharmony_ci		return 0;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	fw_priv = lookup_fw_priv(fw_name);
12388c2ecf20Sopenharmony_ci	if (fw_priv) {
12398c2ecf20Sopenharmony_ci		free_fw_priv(fw_priv);
12408c2ecf20Sopenharmony_ci		return 0;
12418c2ecf20Sopenharmony_ci	}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	return -EINVAL;
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	fce = kzalloc(sizeof(*fce), GFP_ATOMIC);
12518c2ecf20Sopenharmony_ci	if (!fce)
12528c2ecf20Sopenharmony_ci		goto exit;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	fce->name = kstrdup_const(name, GFP_ATOMIC);
12558c2ecf20Sopenharmony_ci	if (!fce->name) {
12568c2ecf20Sopenharmony_ci		kfree(fce);
12578c2ecf20Sopenharmony_ci		fce = NULL;
12588c2ecf20Sopenharmony_ci		goto exit;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ciexit:
12618c2ecf20Sopenharmony_ci	return fce;
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_cistatic int __fw_entry_found(const char *name)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
12678c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce;
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	list_for_each_entry(fce, &fwc->fw_names, list) {
12708c2ecf20Sopenharmony_ci		if (!strcmp(fce->name, name))
12718c2ecf20Sopenharmony_ci			return 1;
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ci	return 0;
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic void fw_cache_piggyback_on_request(struct fw_priv *fw_priv)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	const char *name = fw_priv->fw_name;
12798c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = fw_priv->fwc;
12808c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	spin_lock(&fwc->name_lock);
12838c2ecf20Sopenharmony_ci	if (__fw_entry_found(name))
12848c2ecf20Sopenharmony_ci		goto found;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	fce = alloc_fw_cache_entry(name);
12878c2ecf20Sopenharmony_ci	if (fce) {
12888c2ecf20Sopenharmony_ci		list_add(&fce->list, &fwc->fw_names);
12898c2ecf20Sopenharmony_ci		kref_get(&fw_priv->ref);
12908c2ecf20Sopenharmony_ci		pr_debug("%s: fw: %s\n", __func__, name);
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_cifound:
12938c2ecf20Sopenharmony_ci	spin_unlock(&fwc->name_lock);
12948c2ecf20Sopenharmony_ci}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_cistatic void free_fw_cache_entry(struct fw_cache_entry *fce)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	kfree_const(fce->name);
12998c2ecf20Sopenharmony_ci	kfree(fce);
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_cistatic void __async_dev_cache_fw_image(void *fw_entry,
13038c2ecf20Sopenharmony_ci				       async_cookie_t cookie)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce = fw_entry;
13068c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
13078c2ecf20Sopenharmony_ci	int ret;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	ret = cache_firmware(fce->name);
13108c2ecf20Sopenharmony_ci	if (ret) {
13118c2ecf20Sopenharmony_ci		spin_lock(&fwc->name_lock);
13128c2ecf20Sopenharmony_ci		list_del(&fce->list);
13138c2ecf20Sopenharmony_ci		spin_unlock(&fwc->name_lock);
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		free_fw_cache_entry(fce);
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci/* called with dev->devres_lock held */
13208c2ecf20Sopenharmony_cistatic void dev_create_fw_entry(struct device *dev, void *res,
13218c2ecf20Sopenharmony_ci				void *data)
13228c2ecf20Sopenharmony_ci{
13238c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn = res;
13248c2ecf20Sopenharmony_ci	const char *fw_name = fwn->name;
13258c2ecf20Sopenharmony_ci	struct list_head *head = data;
13268c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	fce = alloc_fw_cache_entry(fw_name);
13298c2ecf20Sopenharmony_ci	if (fce)
13308c2ecf20Sopenharmony_ci		list_add(&fce->list, head);
13318c2ecf20Sopenharmony_ci}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_cistatic int devm_name_match(struct device *dev, void *res,
13348c2ecf20Sopenharmony_ci			   void *match_data)
13358c2ecf20Sopenharmony_ci{
13368c2ecf20Sopenharmony_ci	struct fw_name_devm *fwn = res;
13378c2ecf20Sopenharmony_ci	return (fwn->magic == (unsigned long)match_data);
13388c2ecf20Sopenharmony_ci}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_cistatic void dev_cache_fw_image(struct device *dev, void *data)
13418c2ecf20Sopenharmony_ci{
13428c2ecf20Sopenharmony_ci	LIST_HEAD(todo);
13438c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce;
13448c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce_next;
13458c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	devres_for_each_res(dev, fw_name_devm_release,
13488c2ecf20Sopenharmony_ci			    devm_name_match, &fw_cache,
13498c2ecf20Sopenharmony_ci			    dev_create_fw_entry, &todo);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fce, fce_next, &todo, list) {
13528c2ecf20Sopenharmony_ci		list_del(&fce->list);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci		spin_lock(&fwc->name_lock);
13558c2ecf20Sopenharmony_ci		/* only one cache entry for one firmware */
13568c2ecf20Sopenharmony_ci		if (!__fw_entry_found(fce->name)) {
13578c2ecf20Sopenharmony_ci			list_add(&fce->list, &fwc->fw_names);
13588c2ecf20Sopenharmony_ci		} else {
13598c2ecf20Sopenharmony_ci			free_fw_cache_entry(fce);
13608c2ecf20Sopenharmony_ci			fce = NULL;
13618c2ecf20Sopenharmony_ci		}
13628c2ecf20Sopenharmony_ci		spin_unlock(&fwc->name_lock);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci		if (fce)
13658c2ecf20Sopenharmony_ci			async_schedule_domain(__async_dev_cache_fw_image,
13668c2ecf20Sopenharmony_ci					      (void *)fce,
13678c2ecf20Sopenharmony_ci					      &fw_cache_domain);
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_cistatic void __device_uncache_fw_images(void)
13728c2ecf20Sopenharmony_ci{
13738c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
13748c2ecf20Sopenharmony_ci	struct fw_cache_entry *fce;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	spin_lock(&fwc->name_lock);
13778c2ecf20Sopenharmony_ci	while (!list_empty(&fwc->fw_names)) {
13788c2ecf20Sopenharmony_ci		fce = list_entry(fwc->fw_names.next,
13798c2ecf20Sopenharmony_ci				struct fw_cache_entry, list);
13808c2ecf20Sopenharmony_ci		list_del(&fce->list);
13818c2ecf20Sopenharmony_ci		spin_unlock(&fwc->name_lock);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		uncache_firmware(fce->name);
13848c2ecf20Sopenharmony_ci		free_fw_cache_entry(fce);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		spin_lock(&fwc->name_lock);
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci	spin_unlock(&fwc->name_lock);
13898c2ecf20Sopenharmony_ci}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci/**
13928c2ecf20Sopenharmony_ci * device_cache_fw_images() - cache devices' firmware
13938c2ecf20Sopenharmony_ci *
13948c2ecf20Sopenharmony_ci * If one device called request_firmware or its nowait version
13958c2ecf20Sopenharmony_ci * successfully before, the firmware names are recored into the
13968c2ecf20Sopenharmony_ci * device's devres link list, so device_cache_fw_images can call
13978c2ecf20Sopenharmony_ci * cache_firmware() to cache these firmwares for the device,
13988c2ecf20Sopenharmony_ci * then the device driver can load its firmwares easily at
13998c2ecf20Sopenharmony_ci * time when system is not ready to complete loading firmware.
14008c2ecf20Sopenharmony_ci */
14018c2ecf20Sopenharmony_cistatic void device_cache_fw_images(void)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	struct firmware_cache *fwc = &fw_cache;
14048c2ecf20Sopenharmony_ci	DEFINE_WAIT(wait);
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	/* cancel uncache work */
14098c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&fwc->work);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	fw_fallback_set_cache_timeout();
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	mutex_lock(&fw_lock);
14148c2ecf20Sopenharmony_ci	fwc->state = FW_LOADER_START_CACHE;
14158c2ecf20Sopenharmony_ci	dpm_for_each_dev(NULL, dev_cache_fw_image);
14168c2ecf20Sopenharmony_ci	mutex_unlock(&fw_lock);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	/* wait for completion of caching firmware for all devices */
14198c2ecf20Sopenharmony_ci	async_synchronize_full_domain(&fw_cache_domain);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	fw_fallback_set_default_timeout();
14228c2ecf20Sopenharmony_ci}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci/**
14258c2ecf20Sopenharmony_ci * device_uncache_fw_images() - uncache devices' firmware
14268c2ecf20Sopenharmony_ci *
14278c2ecf20Sopenharmony_ci * uncache all firmwares which have been cached successfully
14288c2ecf20Sopenharmony_ci * by device_uncache_fw_images earlier
14298c2ecf20Sopenharmony_ci */
14308c2ecf20Sopenharmony_cistatic void device_uncache_fw_images(void)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
14338c2ecf20Sopenharmony_ci	__device_uncache_fw_images();
14348c2ecf20Sopenharmony_ci}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_cistatic void device_uncache_fw_images_work(struct work_struct *work)
14378c2ecf20Sopenharmony_ci{
14388c2ecf20Sopenharmony_ci	device_uncache_fw_images();
14398c2ecf20Sopenharmony_ci}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci/**
14428c2ecf20Sopenharmony_ci * device_uncache_fw_images_delay() - uncache devices firmwares
14438c2ecf20Sopenharmony_ci * @delay: number of milliseconds to delay uncache device firmwares
14448c2ecf20Sopenharmony_ci *
14458c2ecf20Sopenharmony_ci * uncache all devices's firmwares which has been cached successfully
14468c2ecf20Sopenharmony_ci * by device_cache_fw_images after @delay milliseconds.
14478c2ecf20Sopenharmony_ci */
14488c2ecf20Sopenharmony_cistatic void device_uncache_fw_images_delay(unsigned long delay)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	queue_delayed_work(system_power_efficient_wq, &fw_cache.work,
14518c2ecf20Sopenharmony_ci			   msecs_to_jiffies(delay));
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_cistatic int fw_pm_notify(struct notifier_block *notify_block,
14558c2ecf20Sopenharmony_ci			unsigned long mode, void *unused)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	switch (mode) {
14588c2ecf20Sopenharmony_ci	case PM_HIBERNATION_PREPARE:
14598c2ecf20Sopenharmony_ci	case PM_SUSPEND_PREPARE:
14608c2ecf20Sopenharmony_ci	case PM_RESTORE_PREPARE:
14618c2ecf20Sopenharmony_ci		/*
14628c2ecf20Sopenharmony_ci		 * kill pending fallback requests with a custom fallback
14638c2ecf20Sopenharmony_ci		 * to avoid stalling suspend.
14648c2ecf20Sopenharmony_ci		 */
14658c2ecf20Sopenharmony_ci		kill_pending_fw_fallback_reqs(true);
14668c2ecf20Sopenharmony_ci		device_cache_fw_images();
14678c2ecf20Sopenharmony_ci		break;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	case PM_POST_SUSPEND:
14708c2ecf20Sopenharmony_ci	case PM_POST_HIBERNATION:
14718c2ecf20Sopenharmony_ci	case PM_POST_RESTORE:
14728c2ecf20Sopenharmony_ci		/*
14738c2ecf20Sopenharmony_ci		 * In case that system sleep failed and syscore_suspend is
14748c2ecf20Sopenharmony_ci		 * not called.
14758c2ecf20Sopenharmony_ci		 */
14768c2ecf20Sopenharmony_ci		mutex_lock(&fw_lock);
14778c2ecf20Sopenharmony_ci		fw_cache.state = FW_LOADER_NO_CACHE;
14788c2ecf20Sopenharmony_ci		mutex_unlock(&fw_lock);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		device_uncache_fw_images_delay(10 * MSEC_PER_SEC);
14818c2ecf20Sopenharmony_ci		break;
14828c2ecf20Sopenharmony_ci	}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	return 0;
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci/* stop caching firmware once syscore_suspend is reached */
14888c2ecf20Sopenharmony_cistatic int fw_suspend(void)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	fw_cache.state = FW_LOADER_NO_CACHE;
14918c2ecf20Sopenharmony_ci	return 0;
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_cistatic struct syscore_ops fw_syscore_ops = {
14958c2ecf20Sopenharmony_ci	.suspend = fw_suspend,
14968c2ecf20Sopenharmony_ci};
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic int __init register_fw_pm_ops(void)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	int ret;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	spin_lock_init(&fw_cache.name_lock);
15038c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fw_cache.fw_names);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&fw_cache.work,
15068c2ecf20Sopenharmony_ci			  device_uncache_fw_images_work);
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	fw_cache.pm_notify.notifier_call = fw_pm_notify;
15098c2ecf20Sopenharmony_ci	ret = register_pm_notifier(&fw_cache.pm_notify);
15108c2ecf20Sopenharmony_ci	if (ret)
15118c2ecf20Sopenharmony_ci		return ret;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	register_syscore_ops(&fw_syscore_ops);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	return ret;
15168c2ecf20Sopenharmony_ci}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_cistatic inline void unregister_fw_pm_ops(void)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	unregister_syscore_ops(&fw_syscore_ops);
15218c2ecf20Sopenharmony_ci	unregister_pm_notifier(&fw_cache.pm_notify);
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci#else
15248c2ecf20Sopenharmony_cistatic void fw_cache_piggyback_on_request(struct fw_priv *fw_priv)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci}
15278c2ecf20Sopenharmony_cistatic inline int register_fw_pm_ops(void)
15288c2ecf20Sopenharmony_ci{
15298c2ecf20Sopenharmony_ci	return 0;
15308c2ecf20Sopenharmony_ci}
15318c2ecf20Sopenharmony_cistatic inline void unregister_fw_pm_ops(void)
15328c2ecf20Sopenharmony_ci{
15338c2ecf20Sopenharmony_ci}
15348c2ecf20Sopenharmony_ci#endif
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_cistatic void __init fw_cache_init(void)
15378c2ecf20Sopenharmony_ci{
15388c2ecf20Sopenharmony_ci	spin_lock_init(&fw_cache.lock);
15398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fw_cache.head);
15408c2ecf20Sopenharmony_ci	fw_cache.state = FW_LOADER_NO_CACHE;
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cistatic int fw_shutdown_notify(struct notifier_block *unused1,
15448c2ecf20Sopenharmony_ci			      unsigned long unused2, void *unused3)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	/*
15478c2ecf20Sopenharmony_ci	 * Kill all pending fallback requests to avoid both stalling shutdown,
15488c2ecf20Sopenharmony_ci	 * and avoid a deadlock with the usermode_lock.
15498c2ecf20Sopenharmony_ci	 */
15508c2ecf20Sopenharmony_ci	kill_pending_fw_fallback_reqs(false);
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	return NOTIFY_DONE;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_cistatic struct notifier_block fw_shutdown_nb = {
15568c2ecf20Sopenharmony_ci	.notifier_call = fw_shutdown_notify,
15578c2ecf20Sopenharmony_ci};
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_cistatic int __init firmware_class_init(void)
15608c2ecf20Sopenharmony_ci{
15618c2ecf20Sopenharmony_ci	int ret;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	/* No need to unfold these on exit */
15648c2ecf20Sopenharmony_ci	fw_cache_init();
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	ret = register_fw_pm_ops();
15678c2ecf20Sopenharmony_ci	if (ret)
15688c2ecf20Sopenharmony_ci		return ret;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	ret = register_reboot_notifier(&fw_shutdown_nb);
15718c2ecf20Sopenharmony_ci	if (ret)
15728c2ecf20Sopenharmony_ci		goto out;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	return register_sysfs_loader();
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ciout:
15778c2ecf20Sopenharmony_ci	unregister_fw_pm_ops();
15788c2ecf20Sopenharmony_ci	return ret;
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic void __exit firmware_class_exit(void)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	unregister_fw_pm_ops();
15848c2ecf20Sopenharmony_ci	unregister_reboot_notifier(&fw_shutdown_nb);
15858c2ecf20Sopenharmony_ci	unregister_sysfs_loader();
15868c2ecf20Sopenharmony_ci}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_cifs_initcall(firmware_class_init);
15898c2ecf20Sopenharmony_cimodule_exit(firmware_class_exit);
1590