162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * main.c - Multi purpose firmware loading support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2003 Manuel Estrada Sainz 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Please see Documentation/driver-api/firmware/ for more information. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/capability.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/kernel_read_file.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/initrd.h> 1962306a36Sopenharmony_ci#include <linux/timer.h> 2062306a36Sopenharmony_ci#include <linux/vmalloc.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/bitops.h> 2362306a36Sopenharmony_ci#include <linux/mutex.h> 2462306a36Sopenharmony_ci#include <linux/workqueue.h> 2562306a36Sopenharmony_ci#include <linux/highmem.h> 2662306a36Sopenharmony_ci#include <linux/firmware.h> 2762306a36Sopenharmony_ci#include <linux/slab.h> 2862306a36Sopenharmony_ci#include <linux/sched.h> 2962306a36Sopenharmony_ci#include <linux/file.h> 3062306a36Sopenharmony_ci#include <linux/list.h> 3162306a36Sopenharmony_ci#include <linux/fs.h> 3262306a36Sopenharmony_ci#include <linux/async.h> 3362306a36Sopenharmony_ci#include <linux/pm.h> 3462306a36Sopenharmony_ci#include <linux/suspend.h> 3562306a36Sopenharmony_ci#include <linux/syscore_ops.h> 3662306a36Sopenharmony_ci#include <linux/reboot.h> 3762306a36Sopenharmony_ci#include <linux/security.h> 3862306a36Sopenharmony_ci#include <linux/zstd.h> 3962306a36Sopenharmony_ci#include <linux/xz.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <generated/utsrelease.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "../base.h" 4462306a36Sopenharmony_ci#include "firmware.h" 4562306a36Sopenharmony_ci#include "fallback.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciMODULE_AUTHOR("Manuel Estrada Sainz"); 4862306a36Sopenharmony_ciMODULE_DESCRIPTION("Multi purpose firmware loading support"); 4962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct firmware_cache { 5262306a36Sopenharmony_ci /* firmware_buf instance will be added into the below list */ 5362306a36Sopenharmony_ci spinlock_t lock; 5462306a36Sopenharmony_ci struct list_head head; 5562306a36Sopenharmony_ci int state; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#ifdef CONFIG_FW_CACHE 5862306a36Sopenharmony_ci /* 5962306a36Sopenharmony_ci * Names of firmware images which have been cached successfully 6062306a36Sopenharmony_ci * will be added into the below list so that device uncache 6162306a36Sopenharmony_ci * helper can trace which firmware images have been cached 6262306a36Sopenharmony_ci * before. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci spinlock_t name_lock; 6562306a36Sopenharmony_ci struct list_head fw_names; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci struct delayed_work work; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci struct notifier_block pm_notify; 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct fw_cache_entry { 7462306a36Sopenharmony_ci struct list_head list; 7562306a36Sopenharmony_ci const char *name; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct fw_name_devm { 7962306a36Sopenharmony_ci unsigned long magic; 8062306a36Sopenharmony_ci const char *name; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic inline struct fw_priv *to_fw_priv(struct kref *ref) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci return container_of(ref, struct fw_priv, ref); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define FW_LOADER_NO_CACHE 0 8962306a36Sopenharmony_ci#define FW_LOADER_START_CACHE 1 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* fw_lock could be moved to 'struct fw_sysfs' but since it is just 9262306a36Sopenharmony_ci * guarding for corner cases a global lock should be OK */ 9362306a36Sopenharmony_ciDEFINE_MUTEX(fw_lock); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct firmware_cache fw_cache; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_civoid fw_state_init(struct fw_priv *fw_priv) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct fw_state *fw_st = &fw_priv->fw_st; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci init_completion(&fw_st->completion); 10262306a36Sopenharmony_ci fw_st->status = FW_STATUS_UNKNOWN; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic inline int fw_state_wait(struct fw_priv *fw_priv) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci return __fw_state_wait_common(fw_priv, MAX_SCHEDULE_TIMEOUT); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void fw_cache_piggyback_on_request(struct fw_priv *fw_priv); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic struct fw_priv *__allocate_fw_priv(const char *fw_name, 11362306a36Sopenharmony_ci struct firmware_cache *fwc, 11462306a36Sopenharmony_ci void *dbuf, 11562306a36Sopenharmony_ci size_t size, 11662306a36Sopenharmony_ci size_t offset, 11762306a36Sopenharmony_ci u32 opt_flags) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct fw_priv *fw_priv; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* For a partial read, the buffer must be preallocated. */ 12262306a36Sopenharmony_ci if ((opt_flags & FW_OPT_PARTIAL) && !dbuf) 12362306a36Sopenharmony_ci return NULL; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Only partial reads are allowed to use an offset. */ 12662306a36Sopenharmony_ci if (offset != 0 && !(opt_flags & FW_OPT_PARTIAL)) 12762306a36Sopenharmony_ci return NULL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci fw_priv = kzalloc(sizeof(*fw_priv), GFP_ATOMIC); 13062306a36Sopenharmony_ci if (!fw_priv) 13162306a36Sopenharmony_ci return NULL; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci fw_priv->fw_name = kstrdup_const(fw_name, GFP_ATOMIC); 13462306a36Sopenharmony_ci if (!fw_priv->fw_name) { 13562306a36Sopenharmony_ci kfree(fw_priv); 13662306a36Sopenharmony_ci return NULL; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci kref_init(&fw_priv->ref); 14062306a36Sopenharmony_ci fw_priv->fwc = fwc; 14162306a36Sopenharmony_ci fw_priv->data = dbuf; 14262306a36Sopenharmony_ci fw_priv->allocated_size = size; 14362306a36Sopenharmony_ci fw_priv->offset = offset; 14462306a36Sopenharmony_ci fw_priv->opt_flags = opt_flags; 14562306a36Sopenharmony_ci fw_state_init(fw_priv); 14662306a36Sopenharmony_ci#ifdef CONFIG_FW_LOADER_USER_HELPER 14762306a36Sopenharmony_ci INIT_LIST_HEAD(&fw_priv->pending_list); 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci pr_debug("%s: fw-%s fw_priv=%p\n", __func__, fw_name, fw_priv); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return fw_priv; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic struct fw_priv *__lookup_fw_priv(const char *fw_name) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct fw_priv *tmp; 15862306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci list_for_each_entry(tmp, &fwc->head, list) 16162306a36Sopenharmony_ci if (!strcmp(tmp->fw_name, fw_name)) 16262306a36Sopenharmony_ci return tmp; 16362306a36Sopenharmony_ci return NULL; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* Returns 1 for batching firmware requests with the same name */ 16762306a36Sopenharmony_ciint alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, 16862306a36Sopenharmony_ci struct fw_priv **fw_priv, void *dbuf, size_t size, 16962306a36Sopenharmony_ci size_t offset, u32 opt_flags) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct fw_priv *tmp; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spin_lock(&fwc->lock); 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * Do not merge requests that are marked to be non-cached or 17662306a36Sopenharmony_ci * are performing partial reads. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci if (!(opt_flags & (FW_OPT_NOCACHE | FW_OPT_PARTIAL))) { 17962306a36Sopenharmony_ci tmp = __lookup_fw_priv(fw_name); 18062306a36Sopenharmony_ci if (tmp) { 18162306a36Sopenharmony_ci kref_get(&tmp->ref); 18262306a36Sopenharmony_ci spin_unlock(&fwc->lock); 18362306a36Sopenharmony_ci *fw_priv = tmp; 18462306a36Sopenharmony_ci pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); 18562306a36Sopenharmony_ci return 1; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, offset, opt_flags); 19062306a36Sopenharmony_ci if (tmp) { 19162306a36Sopenharmony_ci INIT_LIST_HEAD(&tmp->list); 19262306a36Sopenharmony_ci if (!(opt_flags & FW_OPT_NOCACHE)) 19362306a36Sopenharmony_ci list_add(&tmp->list, &fwc->head); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci spin_unlock(&fwc->lock); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci *fw_priv = tmp; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return tmp ? 0 : -ENOMEM; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void __free_fw_priv(struct kref *ref) 20362306a36Sopenharmony_ci __releases(&fwc->lock) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct fw_priv *fw_priv = to_fw_priv(ref); 20662306a36Sopenharmony_ci struct firmware_cache *fwc = fw_priv->fwc; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n", 20962306a36Sopenharmony_ci __func__, fw_priv->fw_name, fw_priv, fw_priv->data, 21062306a36Sopenharmony_ci (unsigned int)fw_priv->size); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci list_del(&fw_priv->list); 21362306a36Sopenharmony_ci spin_unlock(&fwc->lock); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (fw_is_paged_buf(fw_priv)) 21662306a36Sopenharmony_ci fw_free_paged_buf(fw_priv); 21762306a36Sopenharmony_ci else if (!fw_priv->allocated_size) 21862306a36Sopenharmony_ci vfree(fw_priv->data); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci kfree_const(fw_priv->fw_name); 22162306a36Sopenharmony_ci kfree(fw_priv); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_civoid free_fw_priv(struct fw_priv *fw_priv) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct firmware_cache *fwc = fw_priv->fwc; 22762306a36Sopenharmony_ci spin_lock(&fwc->lock); 22862306a36Sopenharmony_ci if (!kref_put(&fw_priv->ref, __free_fw_priv)) 22962306a36Sopenharmony_ci spin_unlock(&fwc->lock); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#ifdef CONFIG_FW_LOADER_PAGED_BUF 23362306a36Sopenharmony_cibool fw_is_paged_buf(struct fw_priv *fw_priv) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci return fw_priv->is_paged_buf; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_civoid fw_free_paged_buf(struct fw_priv *fw_priv) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int i; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!fw_priv->pages) 24362306a36Sopenharmony_ci return; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci vunmap(fw_priv->data); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci for (i = 0; i < fw_priv->nr_pages; i++) 24862306a36Sopenharmony_ci __free_page(fw_priv->pages[i]); 24962306a36Sopenharmony_ci kvfree(fw_priv->pages); 25062306a36Sopenharmony_ci fw_priv->pages = NULL; 25162306a36Sopenharmony_ci fw_priv->page_array_size = 0; 25262306a36Sopenharmony_ci fw_priv->nr_pages = 0; 25362306a36Sopenharmony_ci fw_priv->data = NULL; 25462306a36Sopenharmony_ci fw_priv->size = 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciint fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci /* If the array of pages is too small, grow it */ 26062306a36Sopenharmony_ci if (fw_priv->page_array_size < pages_needed) { 26162306a36Sopenharmony_ci int new_array_size = max(pages_needed, 26262306a36Sopenharmony_ci fw_priv->page_array_size * 2); 26362306a36Sopenharmony_ci struct page **new_pages; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci new_pages = kvmalloc_array(new_array_size, sizeof(void *), 26662306a36Sopenharmony_ci GFP_KERNEL); 26762306a36Sopenharmony_ci if (!new_pages) 26862306a36Sopenharmony_ci return -ENOMEM; 26962306a36Sopenharmony_ci memcpy(new_pages, fw_priv->pages, 27062306a36Sopenharmony_ci fw_priv->page_array_size * sizeof(void *)); 27162306a36Sopenharmony_ci memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * 27262306a36Sopenharmony_ci (new_array_size - fw_priv->page_array_size)); 27362306a36Sopenharmony_ci kvfree(fw_priv->pages); 27462306a36Sopenharmony_ci fw_priv->pages = new_pages; 27562306a36Sopenharmony_ci fw_priv->page_array_size = new_array_size; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci while (fw_priv->nr_pages < pages_needed) { 27962306a36Sopenharmony_ci fw_priv->pages[fw_priv->nr_pages] = 28062306a36Sopenharmony_ci alloc_page(GFP_KERNEL | __GFP_HIGHMEM); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!fw_priv->pages[fw_priv->nr_pages]) 28362306a36Sopenharmony_ci return -ENOMEM; 28462306a36Sopenharmony_ci fw_priv->nr_pages++; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ciint fw_map_paged_buf(struct fw_priv *fw_priv) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci /* one pages buffer should be mapped/unmapped only once */ 29362306a36Sopenharmony_ci if (!fw_priv->pages) 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci vunmap(fw_priv->data); 29762306a36Sopenharmony_ci fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, 29862306a36Sopenharmony_ci PAGE_KERNEL_RO); 29962306a36Sopenharmony_ci if (!fw_priv->data) 30062306a36Sopenharmony_ci return -ENOMEM; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci#endif 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* 30762306a36Sopenharmony_ci * ZSTD-compressed firmware support 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci#ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD 31062306a36Sopenharmony_cistatic int fw_decompress_zstd(struct device *dev, struct fw_priv *fw_priv, 31162306a36Sopenharmony_ci size_t in_size, const void *in_buffer) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci size_t len, out_size, workspace_size; 31462306a36Sopenharmony_ci void *workspace, *out_buf; 31562306a36Sopenharmony_ci zstd_dctx *ctx; 31662306a36Sopenharmony_ci int err; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (fw_priv->allocated_size) { 31962306a36Sopenharmony_ci out_size = fw_priv->allocated_size; 32062306a36Sopenharmony_ci out_buf = fw_priv->data; 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci zstd_frame_header params; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (zstd_get_frame_header(¶ms, in_buffer, in_size) || 32562306a36Sopenharmony_ci params.frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN) { 32662306a36Sopenharmony_ci dev_dbg(dev, "%s: invalid zstd header\n", __func__); 32762306a36Sopenharmony_ci return -EINVAL; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci out_size = params.frameContentSize; 33062306a36Sopenharmony_ci out_buf = vzalloc(out_size); 33162306a36Sopenharmony_ci if (!out_buf) 33262306a36Sopenharmony_ci return -ENOMEM; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci workspace_size = zstd_dctx_workspace_bound(); 33662306a36Sopenharmony_ci workspace = kvzalloc(workspace_size, GFP_KERNEL); 33762306a36Sopenharmony_ci if (!workspace) { 33862306a36Sopenharmony_ci err = -ENOMEM; 33962306a36Sopenharmony_ci goto error; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ctx = zstd_init_dctx(workspace, workspace_size); 34362306a36Sopenharmony_ci if (!ctx) { 34462306a36Sopenharmony_ci dev_dbg(dev, "%s: failed to initialize context\n", __func__); 34562306a36Sopenharmony_ci err = -EINVAL; 34662306a36Sopenharmony_ci goto error; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci len = zstd_decompress_dctx(ctx, out_buf, out_size, in_buffer, in_size); 35062306a36Sopenharmony_ci if (zstd_is_error(len)) { 35162306a36Sopenharmony_ci dev_dbg(dev, "%s: failed to decompress: %d\n", __func__, 35262306a36Sopenharmony_ci zstd_get_error_code(len)); 35362306a36Sopenharmony_ci err = -EINVAL; 35462306a36Sopenharmony_ci goto error; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (!fw_priv->allocated_size) 35862306a36Sopenharmony_ci fw_priv->data = out_buf; 35962306a36Sopenharmony_ci fw_priv->size = len; 36062306a36Sopenharmony_ci err = 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci error: 36362306a36Sopenharmony_ci kvfree(workspace); 36462306a36Sopenharmony_ci if (err && !fw_priv->allocated_size) 36562306a36Sopenharmony_ci vfree(out_buf); 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci#endif /* CONFIG_FW_LOADER_COMPRESS_ZSTD */ 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* 37162306a36Sopenharmony_ci * XZ-compressed firmware support 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci#ifdef CONFIG_FW_LOADER_COMPRESS_XZ 37462306a36Sopenharmony_ci/* show an error and return the standard error code */ 37562306a36Sopenharmony_cistatic int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci if (xz_ret != XZ_STREAM_END) { 37862306a36Sopenharmony_ci dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret); 37962306a36Sopenharmony_ci return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci/* single-shot decompression onto the pre-allocated buffer */ 38562306a36Sopenharmony_cistatic int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv, 38662306a36Sopenharmony_ci size_t in_size, const void *in_buffer) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct xz_dec *xz_dec; 38962306a36Sopenharmony_ci struct xz_buf xz_buf; 39062306a36Sopenharmony_ci enum xz_ret xz_ret; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1); 39362306a36Sopenharmony_ci if (!xz_dec) 39462306a36Sopenharmony_ci return -ENOMEM; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci xz_buf.in_size = in_size; 39762306a36Sopenharmony_ci xz_buf.in = in_buffer; 39862306a36Sopenharmony_ci xz_buf.in_pos = 0; 39962306a36Sopenharmony_ci xz_buf.out_size = fw_priv->allocated_size; 40062306a36Sopenharmony_ci xz_buf.out = fw_priv->data; 40162306a36Sopenharmony_ci xz_buf.out_pos = 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci xz_ret = xz_dec_run(xz_dec, &xz_buf); 40462306a36Sopenharmony_ci xz_dec_end(xz_dec); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci fw_priv->size = xz_buf.out_pos; 40762306a36Sopenharmony_ci return fw_decompress_xz_error(dev, xz_ret); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/* decompression on paged buffer and map it */ 41162306a36Sopenharmony_cistatic int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv, 41262306a36Sopenharmony_ci size_t in_size, const void *in_buffer) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct xz_dec *xz_dec; 41562306a36Sopenharmony_ci struct xz_buf xz_buf; 41662306a36Sopenharmony_ci enum xz_ret xz_ret; 41762306a36Sopenharmony_ci struct page *page; 41862306a36Sopenharmony_ci int err = 0; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1); 42162306a36Sopenharmony_ci if (!xz_dec) 42262306a36Sopenharmony_ci return -ENOMEM; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci xz_buf.in_size = in_size; 42562306a36Sopenharmony_ci xz_buf.in = in_buffer; 42662306a36Sopenharmony_ci xz_buf.in_pos = 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci fw_priv->is_paged_buf = true; 42962306a36Sopenharmony_ci fw_priv->size = 0; 43062306a36Sopenharmony_ci do { 43162306a36Sopenharmony_ci if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) { 43262306a36Sopenharmony_ci err = -ENOMEM; 43362306a36Sopenharmony_ci goto out; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* decompress onto the new allocated page */ 43762306a36Sopenharmony_ci page = fw_priv->pages[fw_priv->nr_pages - 1]; 43862306a36Sopenharmony_ci xz_buf.out = kmap_local_page(page); 43962306a36Sopenharmony_ci xz_buf.out_pos = 0; 44062306a36Sopenharmony_ci xz_buf.out_size = PAGE_SIZE; 44162306a36Sopenharmony_ci xz_ret = xz_dec_run(xz_dec, &xz_buf); 44262306a36Sopenharmony_ci kunmap_local(xz_buf.out); 44362306a36Sopenharmony_ci fw_priv->size += xz_buf.out_pos; 44462306a36Sopenharmony_ci /* partial decompression means either end or error */ 44562306a36Sopenharmony_ci if (xz_buf.out_pos != PAGE_SIZE) 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci } while (xz_ret == XZ_OK); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci err = fw_decompress_xz_error(dev, xz_ret); 45062306a36Sopenharmony_ci if (!err) 45162306a36Sopenharmony_ci err = fw_map_paged_buf(fw_priv); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci out: 45462306a36Sopenharmony_ci xz_dec_end(xz_dec); 45562306a36Sopenharmony_ci return err; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv, 45962306a36Sopenharmony_ci size_t in_size, const void *in_buffer) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci /* if the buffer is pre-allocated, we can perform in single-shot mode */ 46262306a36Sopenharmony_ci if (fw_priv->data) 46362306a36Sopenharmony_ci return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer); 46462306a36Sopenharmony_ci else 46562306a36Sopenharmony_ci return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci#endif /* CONFIG_FW_LOADER_COMPRESS_XZ */ 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* direct firmware loading support */ 47062306a36Sopenharmony_cistatic char fw_path_para[256]; 47162306a36Sopenharmony_cistatic const char * const fw_path[] = { 47262306a36Sopenharmony_ci fw_path_para, 47362306a36Sopenharmony_ci "/lib/firmware/updates/" UTS_RELEASE, 47462306a36Sopenharmony_ci "/lib/firmware/updates", 47562306a36Sopenharmony_ci "/lib/firmware/" UTS_RELEASE, 47662306a36Sopenharmony_ci "/lib/firmware" 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/* 48062306a36Sopenharmony_ci * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH' 48162306a36Sopenharmony_ci * from kernel command line because firmware_class is generally built in 48262306a36Sopenharmony_ci * kernel instead of module. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_cimodule_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); 48562306a36Sopenharmony_ciMODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int 48862306a36Sopenharmony_cifw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, 48962306a36Sopenharmony_ci const char *suffix, 49062306a36Sopenharmony_ci int (*decompress)(struct device *dev, 49162306a36Sopenharmony_ci struct fw_priv *fw_priv, 49262306a36Sopenharmony_ci size_t in_size, 49362306a36Sopenharmony_ci const void *in_buffer)) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci size_t size; 49662306a36Sopenharmony_ci int i, len, maxlen = 0; 49762306a36Sopenharmony_ci int rc = -ENOENT; 49862306a36Sopenharmony_ci char *path, *nt = NULL; 49962306a36Sopenharmony_ci size_t msize = INT_MAX; 50062306a36Sopenharmony_ci void *buffer = NULL; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Already populated data member means we're loading into a buffer */ 50362306a36Sopenharmony_ci if (!decompress && fw_priv->data) { 50462306a36Sopenharmony_ci buffer = fw_priv->data; 50562306a36Sopenharmony_ci msize = fw_priv->allocated_size; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci path = __getname(); 50962306a36Sopenharmony_ci if (!path) 51062306a36Sopenharmony_ci return -ENOMEM; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci wait_for_initramfs(); 51362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fw_path); i++) { 51462306a36Sopenharmony_ci size_t file_size = 0; 51562306a36Sopenharmony_ci size_t *file_size_ptr = NULL; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* skip the unset customized path */ 51862306a36Sopenharmony_ci if (!fw_path[i][0]) 51962306a36Sopenharmony_ci continue; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* strip off \n from customized path */ 52262306a36Sopenharmony_ci maxlen = strlen(fw_path[i]); 52362306a36Sopenharmony_ci if (i == 0) { 52462306a36Sopenharmony_ci nt = strchr(fw_path[i], '\n'); 52562306a36Sopenharmony_ci if (nt) 52662306a36Sopenharmony_ci maxlen = nt - fw_path[i]; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci len = snprintf(path, PATH_MAX, "%.*s/%s%s", 53062306a36Sopenharmony_ci maxlen, fw_path[i], 53162306a36Sopenharmony_ci fw_priv->fw_name, suffix); 53262306a36Sopenharmony_ci if (len >= PATH_MAX) { 53362306a36Sopenharmony_ci rc = -ENAMETOOLONG; 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci fw_priv->size = 0; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* 54062306a36Sopenharmony_ci * The total file size is only examined when doing a partial 54162306a36Sopenharmony_ci * read; the "full read" case needs to fail if the whole 54262306a36Sopenharmony_ci * firmware was not completely loaded. 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ci if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && buffer) 54562306a36Sopenharmony_ci file_size_ptr = &file_size; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* load firmware files from the mount namespace of init */ 54862306a36Sopenharmony_ci rc = kernel_read_file_from_path_initns(path, fw_priv->offset, 54962306a36Sopenharmony_ci &buffer, msize, 55062306a36Sopenharmony_ci file_size_ptr, 55162306a36Sopenharmony_ci READING_FIRMWARE); 55262306a36Sopenharmony_ci if (rc < 0) { 55362306a36Sopenharmony_ci if (rc != -ENOENT) 55462306a36Sopenharmony_ci dev_warn(device, "loading %s failed with error %d\n", 55562306a36Sopenharmony_ci path, rc); 55662306a36Sopenharmony_ci else 55762306a36Sopenharmony_ci dev_dbg(device, "loading %s failed for no such file or directory.\n", 55862306a36Sopenharmony_ci path); 55962306a36Sopenharmony_ci continue; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci size = rc; 56262306a36Sopenharmony_ci rc = 0; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci dev_dbg(device, "Loading firmware from %s\n", path); 56562306a36Sopenharmony_ci if (decompress) { 56662306a36Sopenharmony_ci dev_dbg(device, "f/w decompressing %s\n", 56762306a36Sopenharmony_ci fw_priv->fw_name); 56862306a36Sopenharmony_ci rc = decompress(device, fw_priv, size, buffer); 56962306a36Sopenharmony_ci /* discard the superfluous original content */ 57062306a36Sopenharmony_ci vfree(buffer); 57162306a36Sopenharmony_ci buffer = NULL; 57262306a36Sopenharmony_ci if (rc) { 57362306a36Sopenharmony_ci fw_free_paged_buf(fw_priv); 57462306a36Sopenharmony_ci continue; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci } else { 57762306a36Sopenharmony_ci dev_dbg(device, "direct-loading %s\n", 57862306a36Sopenharmony_ci fw_priv->fw_name); 57962306a36Sopenharmony_ci if (!fw_priv->data) 58062306a36Sopenharmony_ci fw_priv->data = buffer; 58162306a36Sopenharmony_ci fw_priv->size = size; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci fw_state_done(fw_priv); 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci __putname(path); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return rc; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/* firmware holds the ownership of pages */ 59262306a36Sopenharmony_cistatic void firmware_free_data(const struct firmware *fw) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci /* Loaded directly? */ 59562306a36Sopenharmony_ci if (!fw->priv) { 59662306a36Sopenharmony_ci vfree(fw->data); 59762306a36Sopenharmony_ci return; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci free_fw_priv(fw->priv); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/* store the pages buffer info firmware from buf */ 60362306a36Sopenharmony_cistatic void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci fw->priv = fw_priv; 60662306a36Sopenharmony_ci fw->size = fw_priv->size; 60762306a36Sopenharmony_ci fw->data = fw_priv->data; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n", 61062306a36Sopenharmony_ci __func__, fw_priv->fw_name, fw_priv, fw_priv->data, 61162306a36Sopenharmony_ci (unsigned int)fw_priv->size); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci#ifdef CONFIG_FW_CACHE 61562306a36Sopenharmony_cistatic void fw_name_devm_release(struct device *dev, void *res) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct fw_name_devm *fwn = res; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (fwn->magic == (unsigned long)&fw_cache) 62062306a36Sopenharmony_ci pr_debug("%s: fw_name-%s devm-%p released\n", 62162306a36Sopenharmony_ci __func__, fwn->name, res); 62262306a36Sopenharmony_ci kfree_const(fwn->name); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int fw_devm_match(struct device *dev, void *res, 62662306a36Sopenharmony_ci void *match_data) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct fw_name_devm *fwn = res; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return (fwn->magic == (unsigned long)&fw_cache) && 63162306a36Sopenharmony_ci !strcmp(fwn->name, match_data); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic struct fw_name_devm *fw_find_devm_name(struct device *dev, 63562306a36Sopenharmony_ci const char *name) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct fw_name_devm *fwn; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci fwn = devres_find(dev, fw_name_devm_release, 64062306a36Sopenharmony_ci fw_devm_match, (void *)name); 64162306a36Sopenharmony_ci return fwn; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic bool fw_cache_is_setup(struct device *dev, const char *name) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct fw_name_devm *fwn; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci fwn = fw_find_devm_name(dev, name); 64962306a36Sopenharmony_ci if (fwn) 65062306a36Sopenharmony_ci return true; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return false; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/* add firmware name into devres list */ 65662306a36Sopenharmony_cistatic int fw_add_devm_name(struct device *dev, const char *name) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct fw_name_devm *fwn; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (fw_cache_is_setup(dev, name)) 66162306a36Sopenharmony_ci return 0; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm), 66462306a36Sopenharmony_ci GFP_KERNEL); 66562306a36Sopenharmony_ci if (!fwn) 66662306a36Sopenharmony_ci return -ENOMEM; 66762306a36Sopenharmony_ci fwn->name = kstrdup_const(name, GFP_KERNEL); 66862306a36Sopenharmony_ci if (!fwn->name) { 66962306a36Sopenharmony_ci devres_free(fwn); 67062306a36Sopenharmony_ci return -ENOMEM; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci fwn->magic = (unsigned long)&fw_cache; 67462306a36Sopenharmony_ci devres_add(dev, fwn); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci#else 67962306a36Sopenharmony_cistatic bool fw_cache_is_setup(struct device *dev, const char *name) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci return false; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic int fw_add_devm_name(struct device *dev, const char *name) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci#endif 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ciint assign_fw(struct firmware *fw, struct device *device) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct fw_priv *fw_priv = fw->priv; 69362306a36Sopenharmony_ci int ret; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci mutex_lock(&fw_lock); 69662306a36Sopenharmony_ci if (!fw_priv->size || fw_state_is_aborted(fw_priv)) { 69762306a36Sopenharmony_ci mutex_unlock(&fw_lock); 69862306a36Sopenharmony_ci return -ENOENT; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* 70262306a36Sopenharmony_ci * add firmware name into devres list so that we can auto cache 70362306a36Sopenharmony_ci * and uncache firmware for device. 70462306a36Sopenharmony_ci * 70562306a36Sopenharmony_ci * device may has been deleted already, but the problem 70662306a36Sopenharmony_ci * should be fixed in devres or driver core. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci /* don't cache firmware handled without uevent */ 70962306a36Sopenharmony_ci if (device && (fw_priv->opt_flags & FW_OPT_UEVENT) && 71062306a36Sopenharmony_ci !(fw_priv->opt_flags & FW_OPT_NOCACHE)) { 71162306a36Sopenharmony_ci ret = fw_add_devm_name(device, fw_priv->fw_name); 71262306a36Sopenharmony_ci if (ret) { 71362306a36Sopenharmony_ci mutex_unlock(&fw_lock); 71462306a36Sopenharmony_ci return ret; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * After caching firmware image is started, let it piggyback 72062306a36Sopenharmony_ci * on request firmware. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci if (!(fw_priv->opt_flags & FW_OPT_NOCACHE) && 72362306a36Sopenharmony_ci fw_priv->fwc->state == FW_LOADER_START_CACHE) 72462306a36Sopenharmony_ci fw_cache_piggyback_on_request(fw_priv); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* pass the pages buffer to driver at the last minute */ 72762306a36Sopenharmony_ci fw_set_page_data(fw_priv, fw); 72862306a36Sopenharmony_ci mutex_unlock(&fw_lock); 72962306a36Sopenharmony_ci return 0; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci/* prepare firmware and firmware_buf structs; 73362306a36Sopenharmony_ci * return 0 if a firmware is already assigned, 1 if need to load one, 73462306a36Sopenharmony_ci * or a negative error code 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_cistatic int 73762306a36Sopenharmony_ci_request_firmware_prepare(struct firmware **firmware_p, const char *name, 73862306a36Sopenharmony_ci struct device *device, void *dbuf, size_t size, 73962306a36Sopenharmony_ci size_t offset, u32 opt_flags) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct firmware *firmware; 74262306a36Sopenharmony_ci struct fw_priv *fw_priv; 74362306a36Sopenharmony_ci int ret; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); 74662306a36Sopenharmony_ci if (!firmware) { 74762306a36Sopenharmony_ci dev_err(device, "%s: kmalloc(struct firmware) failed\n", 74862306a36Sopenharmony_ci __func__); 74962306a36Sopenharmony_ci return -ENOMEM; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (firmware_request_builtin_buf(firmware, name, dbuf, size)) { 75362306a36Sopenharmony_ci dev_dbg(device, "using built-in %s\n", name); 75462306a36Sopenharmony_ci return 0; /* assigned */ 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size, 75862306a36Sopenharmony_ci offset, opt_flags); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* 76162306a36Sopenharmony_ci * bind with 'priv' now to avoid warning in failure path 76262306a36Sopenharmony_ci * of requesting firmware. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_ci firmware->priv = fw_priv; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (ret > 0) { 76762306a36Sopenharmony_ci ret = fw_state_wait(fw_priv); 76862306a36Sopenharmony_ci if (!ret) { 76962306a36Sopenharmony_ci fw_set_page_data(fw_priv, firmware); 77062306a36Sopenharmony_ci return 0; /* assigned */ 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (ret < 0) 77562306a36Sopenharmony_ci return ret; 77662306a36Sopenharmony_ci return 1; /* need to load */ 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/* 78062306a36Sopenharmony_ci * Batched requests need only one wake, we need to do this step last due to the 78162306a36Sopenharmony_ci * fallback mechanism. The buf is protected with kref_get(), and it won't be 78262306a36Sopenharmony_ci * released until the last user calls release_firmware(). 78362306a36Sopenharmony_ci * 78462306a36Sopenharmony_ci * Failed batched requests are possible as well, in such cases we just share 78562306a36Sopenharmony_ci * the struct fw_priv and won't release it until all requests are woken 78662306a36Sopenharmony_ci * and have gone through this same path. 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_cistatic void fw_abort_batch_reqs(struct firmware *fw) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct fw_priv *fw_priv; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* Loaded directly? */ 79362306a36Sopenharmony_ci if (!fw || !fw->priv) 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci fw_priv = fw->priv; 79762306a36Sopenharmony_ci mutex_lock(&fw_lock); 79862306a36Sopenharmony_ci if (!fw_state_is_aborted(fw_priv)) 79962306a36Sopenharmony_ci fw_state_aborted(fw_priv); 80062306a36Sopenharmony_ci mutex_unlock(&fw_lock); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci#if defined(CONFIG_FW_LOADER_DEBUG) 80462306a36Sopenharmony_ci#include <crypto/hash.h> 80562306a36Sopenharmony_ci#include <crypto/sha2.h> 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic void fw_log_firmware_info(const struct firmware *fw, const char *name, struct device *device) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct shash_desc *shash; 81062306a36Sopenharmony_ci struct crypto_shash *alg; 81162306a36Sopenharmony_ci u8 *sha256buf; 81262306a36Sopenharmony_ci char *outbuf; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci alg = crypto_alloc_shash("sha256", 0, 0); 81562306a36Sopenharmony_ci if (IS_ERR(alg)) 81662306a36Sopenharmony_ci return; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); 81962306a36Sopenharmony_ci outbuf = kmalloc(SHA256_BLOCK_SIZE + 1, GFP_KERNEL); 82062306a36Sopenharmony_ci shash = kmalloc(sizeof(*shash) + crypto_shash_descsize(alg), GFP_KERNEL); 82162306a36Sopenharmony_ci if (!sha256buf || !outbuf || !shash) 82262306a36Sopenharmony_ci goto out_free; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci shash->tfm = alg; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0) 82762306a36Sopenharmony_ci goto out_shash; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci for (int i = 0; i < SHA256_DIGEST_SIZE; i++) 83062306a36Sopenharmony_ci sprintf(&outbuf[i * 2], "%02x", sha256buf[i]); 83162306a36Sopenharmony_ci outbuf[SHA256_BLOCK_SIZE] = 0; 83262306a36Sopenharmony_ci dev_dbg(device, "Loaded FW: %s, sha256: %s\n", name, outbuf); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ciout_shash: 83562306a36Sopenharmony_ci crypto_free_shash(alg); 83662306a36Sopenharmony_ciout_free: 83762306a36Sopenharmony_ci kfree(shash); 83862306a36Sopenharmony_ci kfree(outbuf); 83962306a36Sopenharmony_ci kfree(sha256buf); 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci#else 84262306a36Sopenharmony_cistatic void fw_log_firmware_info(const struct firmware *fw, const char *name, 84362306a36Sopenharmony_ci struct device *device) 84462306a36Sopenharmony_ci{} 84562306a36Sopenharmony_ci#endif 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/* called from request_firmware() and request_firmware_work_func() */ 84862306a36Sopenharmony_cistatic int 84962306a36Sopenharmony_ci_request_firmware(const struct firmware **firmware_p, const char *name, 85062306a36Sopenharmony_ci struct device *device, void *buf, size_t size, 85162306a36Sopenharmony_ci size_t offset, u32 opt_flags) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct firmware *fw = NULL; 85462306a36Sopenharmony_ci struct cred *kern_cred = NULL; 85562306a36Sopenharmony_ci const struct cred *old_cred; 85662306a36Sopenharmony_ci bool nondirect = false; 85762306a36Sopenharmony_ci int ret; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!firmware_p) 86062306a36Sopenharmony_ci return -EINVAL; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (!name || name[0] == '\0') { 86362306a36Sopenharmony_ci ret = -EINVAL; 86462306a36Sopenharmony_ci goto out; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci ret = _request_firmware_prepare(&fw, name, device, buf, size, 86862306a36Sopenharmony_ci offset, opt_flags); 86962306a36Sopenharmony_ci if (ret <= 0) /* error or already assigned */ 87062306a36Sopenharmony_ci goto out; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci /* 87362306a36Sopenharmony_ci * We are about to try to access the firmware file. Because we may have been 87462306a36Sopenharmony_ci * called by a driver when serving an unrelated request from userland, we use 87562306a36Sopenharmony_ci * the kernel credentials to read the file. 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_ci kern_cred = prepare_kernel_cred(&init_task); 87862306a36Sopenharmony_ci if (!kern_cred) { 87962306a36Sopenharmony_ci ret = -ENOMEM; 88062306a36Sopenharmony_ci goto out; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci old_cred = override_creds(kern_cred); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* Only full reads can support decompression, platform, and sysfs. */ 88762306a36Sopenharmony_ci if (!(opt_flags & FW_OPT_PARTIAL)) 88862306a36Sopenharmony_ci nondirect = true; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci#ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD 89162306a36Sopenharmony_ci if (ret == -ENOENT && nondirect) 89262306a36Sopenharmony_ci ret = fw_get_filesystem_firmware(device, fw->priv, ".zst", 89362306a36Sopenharmony_ci fw_decompress_zstd); 89462306a36Sopenharmony_ci#endif 89562306a36Sopenharmony_ci#ifdef CONFIG_FW_LOADER_COMPRESS_XZ 89662306a36Sopenharmony_ci if (ret == -ENOENT && nondirect) 89762306a36Sopenharmony_ci ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", 89862306a36Sopenharmony_ci fw_decompress_xz); 89962306a36Sopenharmony_ci#endif 90062306a36Sopenharmony_ci if (ret == -ENOENT && nondirect) 90162306a36Sopenharmony_ci ret = firmware_fallback_platform(fw->priv); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (ret) { 90462306a36Sopenharmony_ci if (!(opt_flags & FW_OPT_NO_WARN)) 90562306a36Sopenharmony_ci dev_warn(device, 90662306a36Sopenharmony_ci "Direct firmware load for %s failed with error %d\n", 90762306a36Sopenharmony_ci name, ret); 90862306a36Sopenharmony_ci if (nondirect) 90962306a36Sopenharmony_ci ret = firmware_fallback_sysfs(fw, name, device, 91062306a36Sopenharmony_ci opt_flags, ret); 91162306a36Sopenharmony_ci } else 91262306a36Sopenharmony_ci ret = assign_fw(fw, device); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci revert_creds(old_cred); 91562306a36Sopenharmony_ci put_cred(kern_cred); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ciout: 91862306a36Sopenharmony_ci if (ret < 0) { 91962306a36Sopenharmony_ci fw_abort_batch_reqs(fw); 92062306a36Sopenharmony_ci release_firmware(fw); 92162306a36Sopenharmony_ci fw = NULL; 92262306a36Sopenharmony_ci } else { 92362306a36Sopenharmony_ci fw_log_firmware_info(fw, name, device); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci *firmware_p = fw; 92762306a36Sopenharmony_ci return ret; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci/** 93162306a36Sopenharmony_ci * request_firmware() - send firmware request and wait for it 93262306a36Sopenharmony_ci * @firmware_p: pointer to firmware image 93362306a36Sopenharmony_ci * @name: name of firmware file 93462306a36Sopenharmony_ci * @device: device for which firmware is being loaded 93562306a36Sopenharmony_ci * 93662306a36Sopenharmony_ci * @firmware_p will be used to return a firmware image by the name 93762306a36Sopenharmony_ci * of @name for device @device. 93862306a36Sopenharmony_ci * 93962306a36Sopenharmony_ci * Should be called from user context where sleeping is allowed. 94062306a36Sopenharmony_ci * 94162306a36Sopenharmony_ci * @name will be used as $FIRMWARE in the uevent environment and 94262306a36Sopenharmony_ci * should be distinctive enough not to be confused with any other 94362306a36Sopenharmony_ci * firmware image for this or any other device. 94462306a36Sopenharmony_ci * 94562306a36Sopenharmony_ci * Caller must hold the reference count of @device. 94662306a36Sopenharmony_ci * 94762306a36Sopenharmony_ci * The function can be called safely inside device's suspend and 94862306a36Sopenharmony_ci * resume callback. 94962306a36Sopenharmony_ci **/ 95062306a36Sopenharmony_ciint 95162306a36Sopenharmony_cirequest_firmware(const struct firmware **firmware_p, const char *name, 95262306a36Sopenharmony_ci struct device *device) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci int ret; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Need to pin this module until return */ 95762306a36Sopenharmony_ci __module_get(THIS_MODULE); 95862306a36Sopenharmony_ci ret = _request_firmware(firmware_p, name, device, NULL, 0, 0, 95962306a36Sopenharmony_ci FW_OPT_UEVENT); 96062306a36Sopenharmony_ci module_put(THIS_MODULE); 96162306a36Sopenharmony_ci return ret; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ciEXPORT_SYMBOL(request_firmware); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/** 96662306a36Sopenharmony_ci * firmware_request_nowarn() - request for an optional fw module 96762306a36Sopenharmony_ci * @firmware: pointer to firmware image 96862306a36Sopenharmony_ci * @name: name of firmware file 96962306a36Sopenharmony_ci * @device: device for which firmware is being loaded 97062306a36Sopenharmony_ci * 97162306a36Sopenharmony_ci * This function is similar in behaviour to request_firmware(), except it 97262306a36Sopenharmony_ci * doesn't produce warning messages when the file is not found. The sysfs 97362306a36Sopenharmony_ci * fallback mechanism is enabled if direct filesystem lookup fails. However, 97462306a36Sopenharmony_ci * failures to find the firmware file with it are still suppressed. It is 97562306a36Sopenharmony_ci * therefore up to the driver to check for the return value of this call and to 97662306a36Sopenharmony_ci * decide when to inform the users of errors. 97762306a36Sopenharmony_ci **/ 97862306a36Sopenharmony_ciint firmware_request_nowarn(const struct firmware **firmware, const char *name, 97962306a36Sopenharmony_ci struct device *device) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci int ret; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* Need to pin this module until return */ 98462306a36Sopenharmony_ci __module_get(THIS_MODULE); 98562306a36Sopenharmony_ci ret = _request_firmware(firmware, name, device, NULL, 0, 0, 98662306a36Sopenharmony_ci FW_OPT_UEVENT | FW_OPT_NO_WARN); 98762306a36Sopenharmony_ci module_put(THIS_MODULE); 98862306a36Sopenharmony_ci return ret; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(firmware_request_nowarn); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci/** 99362306a36Sopenharmony_ci * request_firmware_direct() - load firmware directly without usermode helper 99462306a36Sopenharmony_ci * @firmware_p: pointer to firmware image 99562306a36Sopenharmony_ci * @name: name of firmware file 99662306a36Sopenharmony_ci * @device: device for which firmware is being loaded 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * This function works pretty much like request_firmware(), but this doesn't 99962306a36Sopenharmony_ci * fall back to usermode helper even if the firmware couldn't be loaded 100062306a36Sopenharmony_ci * directly from fs. Hence it's useful for loading optional firmwares, which 100162306a36Sopenharmony_ci * aren't always present, without extra long timeouts of udev. 100262306a36Sopenharmony_ci **/ 100362306a36Sopenharmony_ciint request_firmware_direct(const struct firmware **firmware_p, 100462306a36Sopenharmony_ci const char *name, struct device *device) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci int ret; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci __module_get(THIS_MODULE); 100962306a36Sopenharmony_ci ret = _request_firmware(firmware_p, name, device, NULL, 0, 0, 101062306a36Sopenharmony_ci FW_OPT_UEVENT | FW_OPT_NO_WARN | 101162306a36Sopenharmony_ci FW_OPT_NOFALLBACK_SYSFS); 101262306a36Sopenharmony_ci module_put(THIS_MODULE); 101362306a36Sopenharmony_ci return ret; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(request_firmware_direct); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci/** 101862306a36Sopenharmony_ci * firmware_request_platform() - request firmware with platform-fw fallback 101962306a36Sopenharmony_ci * @firmware: pointer to firmware image 102062306a36Sopenharmony_ci * @name: name of firmware file 102162306a36Sopenharmony_ci * @device: device for which firmware is being loaded 102262306a36Sopenharmony_ci * 102362306a36Sopenharmony_ci * This function is similar in behaviour to request_firmware, except that if 102462306a36Sopenharmony_ci * direct filesystem lookup fails, it will fallback to looking for a copy of the 102562306a36Sopenharmony_ci * requested firmware embedded in the platform's main (e.g. UEFI) firmware. 102662306a36Sopenharmony_ci **/ 102762306a36Sopenharmony_ciint firmware_request_platform(const struct firmware **firmware, 102862306a36Sopenharmony_ci const char *name, struct device *device) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci int ret; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* Need to pin this module until return */ 103362306a36Sopenharmony_ci __module_get(THIS_MODULE); 103462306a36Sopenharmony_ci ret = _request_firmware(firmware, name, device, NULL, 0, 0, 103562306a36Sopenharmony_ci FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM); 103662306a36Sopenharmony_ci module_put(THIS_MODULE); 103762306a36Sopenharmony_ci return ret; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(firmware_request_platform); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci/** 104262306a36Sopenharmony_ci * firmware_request_cache() - cache firmware for suspend so resume can use it 104362306a36Sopenharmony_ci * @name: name of firmware file 104462306a36Sopenharmony_ci * @device: device for which firmware should be cached for 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * There are some devices with an optimization that enables the device to not 104762306a36Sopenharmony_ci * require loading firmware on system reboot. This optimization may still 104862306a36Sopenharmony_ci * require the firmware present on resume from suspend. This routine can be 104962306a36Sopenharmony_ci * used to ensure the firmware is present on resume from suspend in these 105062306a36Sopenharmony_ci * situations. This helper is not compatible with drivers which use 105162306a36Sopenharmony_ci * request_firmware_into_buf() or request_firmware_nowait() with no uevent set. 105262306a36Sopenharmony_ci **/ 105362306a36Sopenharmony_ciint firmware_request_cache(struct device *device, const char *name) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci int ret; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci mutex_lock(&fw_lock); 105862306a36Sopenharmony_ci ret = fw_add_devm_name(device, name); 105962306a36Sopenharmony_ci mutex_unlock(&fw_lock); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci return ret; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(firmware_request_cache); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci/** 106662306a36Sopenharmony_ci * request_firmware_into_buf() - load firmware into a previously allocated buffer 106762306a36Sopenharmony_ci * @firmware_p: pointer to firmware image 106862306a36Sopenharmony_ci * @name: name of firmware file 106962306a36Sopenharmony_ci * @device: device for which firmware is being loaded and DMA region allocated 107062306a36Sopenharmony_ci * @buf: address of buffer to load firmware into 107162306a36Sopenharmony_ci * @size: size of buffer 107262306a36Sopenharmony_ci * 107362306a36Sopenharmony_ci * This function works pretty much like request_firmware(), but it doesn't 107462306a36Sopenharmony_ci * allocate a buffer to hold the firmware data. Instead, the firmware 107562306a36Sopenharmony_ci * is loaded directly into the buffer pointed to by @buf and the @firmware_p 107662306a36Sopenharmony_ci * data member is pointed at @buf. 107762306a36Sopenharmony_ci * 107862306a36Sopenharmony_ci * This function doesn't cache firmware either. 107962306a36Sopenharmony_ci */ 108062306a36Sopenharmony_ciint 108162306a36Sopenharmony_cirequest_firmware_into_buf(const struct firmware **firmware_p, const char *name, 108262306a36Sopenharmony_ci struct device *device, void *buf, size_t size) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci int ret; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (fw_cache_is_setup(device, name)) 108762306a36Sopenharmony_ci return -EOPNOTSUPP; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci __module_get(THIS_MODULE); 109062306a36Sopenharmony_ci ret = _request_firmware(firmware_p, name, device, buf, size, 0, 109162306a36Sopenharmony_ci FW_OPT_UEVENT | FW_OPT_NOCACHE); 109262306a36Sopenharmony_ci module_put(THIS_MODULE); 109362306a36Sopenharmony_ci return ret; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ciEXPORT_SYMBOL(request_firmware_into_buf); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci/** 109862306a36Sopenharmony_ci * request_partial_firmware_into_buf() - load partial firmware into a previously allocated buffer 109962306a36Sopenharmony_ci * @firmware_p: pointer to firmware image 110062306a36Sopenharmony_ci * @name: name of firmware file 110162306a36Sopenharmony_ci * @device: device for which firmware is being loaded and DMA region allocated 110262306a36Sopenharmony_ci * @buf: address of buffer to load firmware into 110362306a36Sopenharmony_ci * @size: size of buffer 110462306a36Sopenharmony_ci * @offset: offset into file to read 110562306a36Sopenharmony_ci * 110662306a36Sopenharmony_ci * This function works pretty much like request_firmware_into_buf except 110762306a36Sopenharmony_ci * it allows a partial read of the file. 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ciint 111062306a36Sopenharmony_cirequest_partial_firmware_into_buf(const struct firmware **firmware_p, 111162306a36Sopenharmony_ci const char *name, struct device *device, 111262306a36Sopenharmony_ci void *buf, size_t size, size_t offset) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci int ret; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (fw_cache_is_setup(device, name)) 111762306a36Sopenharmony_ci return -EOPNOTSUPP; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci __module_get(THIS_MODULE); 112062306a36Sopenharmony_ci ret = _request_firmware(firmware_p, name, device, buf, size, offset, 112162306a36Sopenharmony_ci FW_OPT_UEVENT | FW_OPT_NOCACHE | 112262306a36Sopenharmony_ci FW_OPT_PARTIAL); 112362306a36Sopenharmony_ci module_put(THIS_MODULE); 112462306a36Sopenharmony_ci return ret; 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ciEXPORT_SYMBOL(request_partial_firmware_into_buf); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci/** 112962306a36Sopenharmony_ci * release_firmware() - release the resource associated with a firmware image 113062306a36Sopenharmony_ci * @fw: firmware resource to release 113162306a36Sopenharmony_ci **/ 113262306a36Sopenharmony_civoid release_firmware(const struct firmware *fw) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci if (fw) { 113562306a36Sopenharmony_ci if (!firmware_is_builtin(fw)) 113662306a36Sopenharmony_ci firmware_free_data(fw); 113762306a36Sopenharmony_ci kfree(fw); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ciEXPORT_SYMBOL(release_firmware); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci/* Async support */ 114362306a36Sopenharmony_cistruct firmware_work { 114462306a36Sopenharmony_ci struct work_struct work; 114562306a36Sopenharmony_ci struct module *module; 114662306a36Sopenharmony_ci const char *name; 114762306a36Sopenharmony_ci struct device *device; 114862306a36Sopenharmony_ci void *context; 114962306a36Sopenharmony_ci void (*cont)(const struct firmware *fw, void *context); 115062306a36Sopenharmony_ci u32 opt_flags; 115162306a36Sopenharmony_ci}; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic void request_firmware_work_func(struct work_struct *work) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct firmware_work *fw_work; 115662306a36Sopenharmony_ci const struct firmware *fw; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci fw_work = container_of(work, struct firmware_work, work); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0, 116162306a36Sopenharmony_ci fw_work->opt_flags); 116262306a36Sopenharmony_ci fw_work->cont(fw, fw_work->context); 116362306a36Sopenharmony_ci put_device(fw_work->device); /* taken in request_firmware_nowait() */ 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci module_put(fw_work->module); 116662306a36Sopenharmony_ci kfree_const(fw_work->name); 116762306a36Sopenharmony_ci kfree(fw_work); 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci/** 117162306a36Sopenharmony_ci * request_firmware_nowait() - asynchronous version of request_firmware 117262306a36Sopenharmony_ci * @module: module requesting the firmware 117362306a36Sopenharmony_ci * @uevent: sends uevent to copy the firmware image if this flag 117462306a36Sopenharmony_ci * is non-zero else the firmware copy must be done manually. 117562306a36Sopenharmony_ci * @name: name of firmware file 117662306a36Sopenharmony_ci * @device: device for which firmware is being loaded 117762306a36Sopenharmony_ci * @gfp: allocation flags 117862306a36Sopenharmony_ci * @context: will be passed over to @cont, and 117962306a36Sopenharmony_ci * @fw may be %NULL if firmware request fails. 118062306a36Sopenharmony_ci * @cont: function will be called asynchronously when the firmware 118162306a36Sopenharmony_ci * request is over. 118262306a36Sopenharmony_ci * 118362306a36Sopenharmony_ci * Caller must hold the reference count of @device. 118462306a36Sopenharmony_ci * 118562306a36Sopenharmony_ci * Asynchronous variant of request_firmware() for user contexts: 118662306a36Sopenharmony_ci * - sleep for as small periods as possible since it may 118762306a36Sopenharmony_ci * increase kernel boot time of built-in device drivers 118862306a36Sopenharmony_ci * requesting firmware in their ->probe() methods, if 118962306a36Sopenharmony_ci * @gfp is GFP_KERNEL. 119062306a36Sopenharmony_ci * 119162306a36Sopenharmony_ci * - can't sleep at all if @gfp is GFP_ATOMIC. 119262306a36Sopenharmony_ci **/ 119362306a36Sopenharmony_ciint 119462306a36Sopenharmony_cirequest_firmware_nowait( 119562306a36Sopenharmony_ci struct module *module, bool uevent, 119662306a36Sopenharmony_ci const char *name, struct device *device, gfp_t gfp, void *context, 119762306a36Sopenharmony_ci void (*cont)(const struct firmware *fw, void *context)) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci struct firmware_work *fw_work; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci fw_work = kzalloc(sizeof(struct firmware_work), gfp); 120262306a36Sopenharmony_ci if (!fw_work) 120362306a36Sopenharmony_ci return -ENOMEM; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci fw_work->module = module; 120662306a36Sopenharmony_ci fw_work->name = kstrdup_const(name, gfp); 120762306a36Sopenharmony_ci if (!fw_work->name) { 120862306a36Sopenharmony_ci kfree(fw_work); 120962306a36Sopenharmony_ci return -ENOMEM; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci fw_work->device = device; 121262306a36Sopenharmony_ci fw_work->context = context; 121362306a36Sopenharmony_ci fw_work->cont = cont; 121462306a36Sopenharmony_ci fw_work->opt_flags = FW_OPT_NOWAIT | 121562306a36Sopenharmony_ci (uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (!uevent && fw_cache_is_setup(device, name)) { 121862306a36Sopenharmony_ci kfree_const(fw_work->name); 121962306a36Sopenharmony_ci kfree(fw_work); 122062306a36Sopenharmony_ci return -EOPNOTSUPP; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (!try_module_get(module)) { 122462306a36Sopenharmony_ci kfree_const(fw_work->name); 122562306a36Sopenharmony_ci kfree(fw_work); 122662306a36Sopenharmony_ci return -EFAULT; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci get_device(fw_work->device); 123062306a36Sopenharmony_ci INIT_WORK(&fw_work->work, request_firmware_work_func); 123162306a36Sopenharmony_ci schedule_work(&fw_work->work); 123262306a36Sopenharmony_ci return 0; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ciEXPORT_SYMBOL(request_firmware_nowait); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci#ifdef CONFIG_FW_CACHE 123762306a36Sopenharmony_cistatic ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci/** 124062306a36Sopenharmony_ci * cache_firmware() - cache one firmware image in kernel memory space 124162306a36Sopenharmony_ci * @fw_name: the firmware image name 124262306a36Sopenharmony_ci * 124362306a36Sopenharmony_ci * Cache firmware in kernel memory so that drivers can use it when 124462306a36Sopenharmony_ci * system isn't ready for them to request firmware image from userspace. 124562306a36Sopenharmony_ci * Once it returns successfully, driver can use request_firmware or its 124662306a36Sopenharmony_ci * nowait version to get the cached firmware without any interacting 124762306a36Sopenharmony_ci * with userspace 124862306a36Sopenharmony_ci * 124962306a36Sopenharmony_ci * Return 0 if the firmware image has been cached successfully 125062306a36Sopenharmony_ci * Return !0 otherwise 125162306a36Sopenharmony_ci * 125262306a36Sopenharmony_ci */ 125362306a36Sopenharmony_cistatic int cache_firmware(const char *fw_name) 125462306a36Sopenharmony_ci{ 125562306a36Sopenharmony_ci int ret; 125662306a36Sopenharmony_ci const struct firmware *fw; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, fw_name); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci ret = request_firmware(&fw, fw_name, NULL); 126162306a36Sopenharmony_ci if (!ret) 126262306a36Sopenharmony_ci kfree(fw); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return ret; 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic struct fw_priv *lookup_fw_priv(const char *fw_name) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci struct fw_priv *tmp; 127262306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci spin_lock(&fwc->lock); 127562306a36Sopenharmony_ci tmp = __lookup_fw_priv(fw_name); 127662306a36Sopenharmony_ci spin_unlock(&fwc->lock); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci return tmp; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci/** 128262306a36Sopenharmony_ci * uncache_firmware() - remove one cached firmware image 128362306a36Sopenharmony_ci * @fw_name: the firmware image name 128462306a36Sopenharmony_ci * 128562306a36Sopenharmony_ci * Uncache one firmware image which has been cached successfully 128662306a36Sopenharmony_ci * before. 128762306a36Sopenharmony_ci * 128862306a36Sopenharmony_ci * Return 0 if the firmware cache has been removed successfully 128962306a36Sopenharmony_ci * Return !0 otherwise 129062306a36Sopenharmony_ci * 129162306a36Sopenharmony_ci */ 129262306a36Sopenharmony_cistatic int uncache_firmware(const char *fw_name) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci struct fw_priv *fw_priv; 129562306a36Sopenharmony_ci struct firmware fw; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, fw_name); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (firmware_request_builtin(&fw, fw_name)) 130062306a36Sopenharmony_ci return 0; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci fw_priv = lookup_fw_priv(fw_name); 130362306a36Sopenharmony_ci if (fw_priv) { 130462306a36Sopenharmony_ci free_fw_priv(fw_priv); 130562306a36Sopenharmony_ci return 0; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return -EINVAL; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic struct fw_cache_entry *alloc_fw_cache_entry(const char *name) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct fw_cache_entry *fce; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci fce = kzalloc(sizeof(*fce), GFP_ATOMIC); 131662306a36Sopenharmony_ci if (!fce) 131762306a36Sopenharmony_ci goto exit; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci fce->name = kstrdup_const(name, GFP_ATOMIC); 132062306a36Sopenharmony_ci if (!fce->name) { 132162306a36Sopenharmony_ci kfree(fce); 132262306a36Sopenharmony_ci fce = NULL; 132362306a36Sopenharmony_ci goto exit; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ciexit: 132662306a36Sopenharmony_ci return fce; 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistatic int __fw_entry_found(const char *name) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 133262306a36Sopenharmony_ci struct fw_cache_entry *fce; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci list_for_each_entry(fce, &fwc->fw_names, list) { 133562306a36Sopenharmony_ci if (!strcmp(fce->name, name)) 133662306a36Sopenharmony_ci return 1; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci return 0; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic void fw_cache_piggyback_on_request(struct fw_priv *fw_priv) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci const char *name = fw_priv->fw_name; 134462306a36Sopenharmony_ci struct firmware_cache *fwc = fw_priv->fwc; 134562306a36Sopenharmony_ci struct fw_cache_entry *fce; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci spin_lock(&fwc->name_lock); 134862306a36Sopenharmony_ci if (__fw_entry_found(name)) 134962306a36Sopenharmony_ci goto found; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci fce = alloc_fw_cache_entry(name); 135262306a36Sopenharmony_ci if (fce) { 135362306a36Sopenharmony_ci list_add(&fce->list, &fwc->fw_names); 135462306a36Sopenharmony_ci kref_get(&fw_priv->ref); 135562306a36Sopenharmony_ci pr_debug("%s: fw: %s\n", __func__, name); 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_cifound: 135862306a36Sopenharmony_ci spin_unlock(&fwc->name_lock); 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic void free_fw_cache_entry(struct fw_cache_entry *fce) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci kfree_const(fce->name); 136462306a36Sopenharmony_ci kfree(fce); 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic void __async_dev_cache_fw_image(void *fw_entry, 136862306a36Sopenharmony_ci async_cookie_t cookie) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct fw_cache_entry *fce = fw_entry; 137162306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 137262306a36Sopenharmony_ci int ret; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci ret = cache_firmware(fce->name); 137562306a36Sopenharmony_ci if (ret) { 137662306a36Sopenharmony_ci spin_lock(&fwc->name_lock); 137762306a36Sopenharmony_ci list_del(&fce->list); 137862306a36Sopenharmony_ci spin_unlock(&fwc->name_lock); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci free_fw_cache_entry(fce); 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci/* called with dev->devres_lock held */ 138562306a36Sopenharmony_cistatic void dev_create_fw_entry(struct device *dev, void *res, 138662306a36Sopenharmony_ci void *data) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci struct fw_name_devm *fwn = res; 138962306a36Sopenharmony_ci const char *fw_name = fwn->name; 139062306a36Sopenharmony_ci struct list_head *head = data; 139162306a36Sopenharmony_ci struct fw_cache_entry *fce; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci fce = alloc_fw_cache_entry(fw_name); 139462306a36Sopenharmony_ci if (fce) 139562306a36Sopenharmony_ci list_add(&fce->list, head); 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_cistatic int devm_name_match(struct device *dev, void *res, 139962306a36Sopenharmony_ci void *match_data) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci struct fw_name_devm *fwn = res; 140262306a36Sopenharmony_ci return (fwn->magic == (unsigned long)match_data); 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cistatic void dev_cache_fw_image(struct device *dev, void *data) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci LIST_HEAD(todo); 140862306a36Sopenharmony_ci struct fw_cache_entry *fce; 140962306a36Sopenharmony_ci struct fw_cache_entry *fce_next; 141062306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci devres_for_each_res(dev, fw_name_devm_release, 141362306a36Sopenharmony_ci devm_name_match, &fw_cache, 141462306a36Sopenharmony_ci dev_create_fw_entry, &todo); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci list_for_each_entry_safe(fce, fce_next, &todo, list) { 141762306a36Sopenharmony_ci list_del(&fce->list); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci spin_lock(&fwc->name_lock); 142062306a36Sopenharmony_ci /* only one cache entry for one firmware */ 142162306a36Sopenharmony_ci if (!__fw_entry_found(fce->name)) { 142262306a36Sopenharmony_ci list_add(&fce->list, &fwc->fw_names); 142362306a36Sopenharmony_ci } else { 142462306a36Sopenharmony_ci free_fw_cache_entry(fce); 142562306a36Sopenharmony_ci fce = NULL; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci spin_unlock(&fwc->name_lock); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci if (fce) 143062306a36Sopenharmony_ci async_schedule_domain(__async_dev_cache_fw_image, 143162306a36Sopenharmony_ci (void *)fce, 143262306a36Sopenharmony_ci &fw_cache_domain); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic void __device_uncache_fw_images(void) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 143962306a36Sopenharmony_ci struct fw_cache_entry *fce; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci spin_lock(&fwc->name_lock); 144262306a36Sopenharmony_ci while (!list_empty(&fwc->fw_names)) { 144362306a36Sopenharmony_ci fce = list_entry(fwc->fw_names.next, 144462306a36Sopenharmony_ci struct fw_cache_entry, list); 144562306a36Sopenharmony_ci list_del(&fce->list); 144662306a36Sopenharmony_ci spin_unlock(&fwc->name_lock); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci uncache_firmware(fce->name); 144962306a36Sopenharmony_ci free_fw_cache_entry(fce); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci spin_lock(&fwc->name_lock); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci spin_unlock(&fwc->name_lock); 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci/** 145762306a36Sopenharmony_ci * device_cache_fw_images() - cache devices' firmware 145862306a36Sopenharmony_ci * 145962306a36Sopenharmony_ci * If one device called request_firmware or its nowait version 146062306a36Sopenharmony_ci * successfully before, the firmware names are recored into the 146162306a36Sopenharmony_ci * device's devres link list, so device_cache_fw_images can call 146262306a36Sopenharmony_ci * cache_firmware() to cache these firmwares for the device, 146362306a36Sopenharmony_ci * then the device driver can load its firmwares easily at 146462306a36Sopenharmony_ci * time when system is not ready to complete loading firmware. 146562306a36Sopenharmony_ci */ 146662306a36Sopenharmony_cistatic void device_cache_fw_images(void) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct firmware_cache *fwc = &fw_cache; 146962306a36Sopenharmony_ci DEFINE_WAIT(wait); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci pr_debug("%s\n", __func__); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* cancel uncache work */ 147462306a36Sopenharmony_ci cancel_delayed_work_sync(&fwc->work); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci fw_fallback_set_cache_timeout(); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci mutex_lock(&fw_lock); 147962306a36Sopenharmony_ci fwc->state = FW_LOADER_START_CACHE; 148062306a36Sopenharmony_ci dpm_for_each_dev(NULL, dev_cache_fw_image); 148162306a36Sopenharmony_ci mutex_unlock(&fw_lock); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci /* wait for completion of caching firmware for all devices */ 148462306a36Sopenharmony_ci async_synchronize_full_domain(&fw_cache_domain); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci fw_fallback_set_default_timeout(); 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci/** 149062306a36Sopenharmony_ci * device_uncache_fw_images() - uncache devices' firmware 149162306a36Sopenharmony_ci * 149262306a36Sopenharmony_ci * uncache all firmwares which have been cached successfully 149362306a36Sopenharmony_ci * by device_uncache_fw_images earlier 149462306a36Sopenharmony_ci */ 149562306a36Sopenharmony_cistatic void device_uncache_fw_images(void) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci pr_debug("%s\n", __func__); 149862306a36Sopenharmony_ci __device_uncache_fw_images(); 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic void device_uncache_fw_images_work(struct work_struct *work) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci device_uncache_fw_images(); 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci/** 150762306a36Sopenharmony_ci * device_uncache_fw_images_delay() - uncache devices firmwares 150862306a36Sopenharmony_ci * @delay: number of milliseconds to delay uncache device firmwares 150962306a36Sopenharmony_ci * 151062306a36Sopenharmony_ci * uncache all devices's firmwares which has been cached successfully 151162306a36Sopenharmony_ci * by device_cache_fw_images after @delay milliseconds. 151262306a36Sopenharmony_ci */ 151362306a36Sopenharmony_cistatic void device_uncache_fw_images_delay(unsigned long delay) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci queue_delayed_work(system_power_efficient_wq, &fw_cache.work, 151662306a36Sopenharmony_ci msecs_to_jiffies(delay)); 151762306a36Sopenharmony_ci} 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_cistatic int fw_pm_notify(struct notifier_block *notify_block, 152062306a36Sopenharmony_ci unsigned long mode, void *unused) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci switch (mode) { 152362306a36Sopenharmony_ci case PM_HIBERNATION_PREPARE: 152462306a36Sopenharmony_ci case PM_SUSPEND_PREPARE: 152562306a36Sopenharmony_ci case PM_RESTORE_PREPARE: 152662306a36Sopenharmony_ci /* 152762306a36Sopenharmony_ci * kill pending fallback requests with a custom fallback 152862306a36Sopenharmony_ci * to avoid stalling suspend. 152962306a36Sopenharmony_ci */ 153062306a36Sopenharmony_ci kill_pending_fw_fallback_reqs(true); 153162306a36Sopenharmony_ci device_cache_fw_images(); 153262306a36Sopenharmony_ci break; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci case PM_POST_SUSPEND: 153562306a36Sopenharmony_ci case PM_POST_HIBERNATION: 153662306a36Sopenharmony_ci case PM_POST_RESTORE: 153762306a36Sopenharmony_ci /* 153862306a36Sopenharmony_ci * In case that system sleep failed and syscore_suspend is 153962306a36Sopenharmony_ci * not called. 154062306a36Sopenharmony_ci */ 154162306a36Sopenharmony_ci mutex_lock(&fw_lock); 154262306a36Sopenharmony_ci fw_cache.state = FW_LOADER_NO_CACHE; 154362306a36Sopenharmony_ci mutex_unlock(&fw_lock); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci device_uncache_fw_images_delay(10 * MSEC_PER_SEC); 154662306a36Sopenharmony_ci break; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci return 0; 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci/* stop caching firmware once syscore_suspend is reached */ 155362306a36Sopenharmony_cistatic int fw_suspend(void) 155462306a36Sopenharmony_ci{ 155562306a36Sopenharmony_ci fw_cache.state = FW_LOADER_NO_CACHE; 155662306a36Sopenharmony_ci return 0; 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic struct syscore_ops fw_syscore_ops = { 156062306a36Sopenharmony_ci .suspend = fw_suspend, 156162306a36Sopenharmony_ci}; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic int __init register_fw_pm_ops(void) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci int ret; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci spin_lock_init(&fw_cache.name_lock); 156862306a36Sopenharmony_ci INIT_LIST_HEAD(&fw_cache.fw_names); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci INIT_DELAYED_WORK(&fw_cache.work, 157162306a36Sopenharmony_ci device_uncache_fw_images_work); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci fw_cache.pm_notify.notifier_call = fw_pm_notify; 157462306a36Sopenharmony_ci ret = register_pm_notifier(&fw_cache.pm_notify); 157562306a36Sopenharmony_ci if (ret) 157662306a36Sopenharmony_ci return ret; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci register_syscore_ops(&fw_syscore_ops); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci return ret; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic inline void unregister_fw_pm_ops(void) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci unregister_syscore_ops(&fw_syscore_ops); 158662306a36Sopenharmony_ci unregister_pm_notifier(&fw_cache.pm_notify); 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci#else 158962306a36Sopenharmony_cistatic void fw_cache_piggyback_on_request(struct fw_priv *fw_priv) 159062306a36Sopenharmony_ci{ 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_cistatic inline int register_fw_pm_ops(void) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci return 0; 159562306a36Sopenharmony_ci} 159662306a36Sopenharmony_cistatic inline void unregister_fw_pm_ops(void) 159762306a36Sopenharmony_ci{ 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci#endif 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic void __init fw_cache_init(void) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci spin_lock_init(&fw_cache.lock); 160462306a36Sopenharmony_ci INIT_LIST_HEAD(&fw_cache.head); 160562306a36Sopenharmony_ci fw_cache.state = FW_LOADER_NO_CACHE; 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic int fw_shutdown_notify(struct notifier_block *unused1, 160962306a36Sopenharmony_ci unsigned long unused2, void *unused3) 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci /* 161262306a36Sopenharmony_ci * Kill all pending fallback requests to avoid both stalling shutdown, 161362306a36Sopenharmony_ci * and avoid a deadlock with the usermode_lock. 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_ci kill_pending_fw_fallback_reqs(false); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci return NOTIFY_DONE; 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic struct notifier_block fw_shutdown_nb = { 162162306a36Sopenharmony_ci .notifier_call = fw_shutdown_notify, 162262306a36Sopenharmony_ci}; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic int __init firmware_class_init(void) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci int ret; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* No need to unfold these on exit */ 162962306a36Sopenharmony_ci fw_cache_init(); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci ret = register_fw_pm_ops(); 163262306a36Sopenharmony_ci if (ret) 163362306a36Sopenharmony_ci return ret; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci ret = register_reboot_notifier(&fw_shutdown_nb); 163662306a36Sopenharmony_ci if (ret) 163762306a36Sopenharmony_ci goto out; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci return register_sysfs_loader(); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ciout: 164262306a36Sopenharmony_ci unregister_fw_pm_ops(); 164362306a36Sopenharmony_ci return ret; 164462306a36Sopenharmony_ci} 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_cistatic void __exit firmware_class_exit(void) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci unregister_fw_pm_ops(); 164962306a36Sopenharmony_ci unregister_reboot_notifier(&fw_shutdown_nb); 165062306a36Sopenharmony_ci unregister_sysfs_loader(); 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cifs_initcall(firmware_class_init); 165462306a36Sopenharmony_cimodule_exit(firmware_class_exit); 1655