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