Messages in this thread Patch in this message | | | From | Ming Lei <> | Subject | [RFC PATCH 07/13] driver core: firmware loader: introduce cache_firmware and uncache_firmware | Date | Wed, 25 Jul 2012 01:00:07 +0800 |
| |
This patches introduce two kernel APIs of cache_firmware and uncache_firmware, both of which take the firmware file name as the only parameter.
So any drivers can call cache_firmware to cache the specified firmware file into kernel memory, and can use the cached firmware in situations which can't request firmware from user space.
Signed-off-by: Ming Lei <ming.lei@canonical.com> --- drivers/base/firmware_class.c | 79 +++++++++++++++++++++++++++++++++++++++++ include/linux/firmware.h | 12 +++++++ 2 files changed, 91 insertions(+)
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 225898e..674cb11 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -168,6 +168,22 @@ static int fw_lookup_and_alloate_buf(const char *fw_name, return tmp ? 0 : -1; } +static struct firmware_buf *fw_lookup_buf(const char *fw_name) +{ + struct firmware_buf *tmp; + struct firmware_cache *fwc = &fw_cache; + + spin_lock(&fwc->lock); + list_for_each_entry(tmp, &fwc->head, list) + if (!strcmp(tmp->fw_id, fw_name)) { + spin_unlock(&fwc->lock); + return tmp; + } + spin_unlock(&fwc->lock); + + return NULL; +} + static void __fw_free_buf(struct kref *ref) { struct firmware_buf *buf = to_fwbuf(ref); @@ -833,6 +849,67 @@ request_firmware_nowait( return 0; } +/** + * cache_firmware - cache one firmware image in kernel memory space + * @fw_name: the firmware image name + * + * Cache firmware in kernel memory so that drivers can use the firmware + * when system isn't ready for drivers to request firmware image from + * userspace. Once returns successfully, driver can use request_firmware* + * to get the cached firmware without any interacting with user space + * + * Return 0 if the firmware image has been cached successfully + * Return !0 if it is not successfully + * + */ +int cache_firmware(const char *fw_name) +{ + int ret; + const struct firmware *fw; + + pr_debug("%s: %s\n", __func__, fw_name); + + ret = request_firmware(&fw, fw_name, NULL); + + if (!ret) + kfree(fw); + + pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret); + + return ret; +} + +/** + * uncache_firmware - remove one cached firmware image + * + * @fw_name: the firmware image name + * + * Uncache one firmware image which has been cached successfully + * before. + * + * Return 0 if the firmware cache has been removed successfully + * Return !0 if it is not successfully + * + */ +int uncache_firmware(const char *fw_name) +{ + struct firmware_buf *buf; + struct firmware fw; + + pr_debug("%s: %s\n", __func__, fw_name); + + if (fw_get_builtin_firmware(&fw, fw_name)) + return 0; + + buf = fw_lookup_buf(fw_name); + if (buf) { + fw_free_buf(buf); + return 0; + } + + return -EINVAL; +} + static int __init firmware_class_init(void) { fw_cache_init(); @@ -850,3 +927,5 @@ module_exit(firmware_class_exit); EXPORT_SYMBOL(release_firmware); EXPORT_SYMBOL(request_firmware); EXPORT_SYMBOL(request_firmware_nowait); +EXPORT_SYMBOL_GPL(cache_firmware); +EXPORT_SYMBOL_GPL(uncache_firmware); diff --git a/include/linux/firmware.h b/include/linux/firmware.h index e85b771..1bfa202 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -47,6 +47,8 @@ int request_firmware_nowait( void (*cont)(const struct firmware *fw, void *context)); void release_firmware(const struct firmware *fw); +int cache_firmware(const char *name); +int uncache_firmware(const char *name); #else static inline int request_firmware(const struct firmware **fw, const char *name, @@ -65,6 +67,16 @@ static inline int request_firmware_nowait( static inline void release_firmware(const struct firmware *fw) { } + +int cache_firmware(const char *name) +{ + return -ENOENT; +} + +int uncache_firmware(const char *name) +{ + return -EINVAL; +} #endif #endif -- 1.7.9.5
| |