Re: [PATCH v1 1/3] firmware loader: Introduce new API - request_firmware_abort()
On Wed, Oct 29, 2014 at 11:04 AM, Kweh, Hock Leong hock.leong.k...@intel.com wrote: -Original Message- From: Ming Lei [mailto:ming@canonical.com] Sent: Monday, October 27, 2014 12:00 AM You can call fw_lookup_buf() directly, otherwise feel free to add: Acked-by: Ming Lei ming@canonical.com Hi Ming Lei, The fw_lookup_buf() is defined inside the conditional preprocessor directive for CONFIG_PM_SLEEP. Since the request_firmware_abort() may not only be used in PM_SLEEP, could I move the fw_lookup_buf() out from the CONFIG_PM_SLEEP block if we want to call fw_lookup_buf() instead of __fw_lookup_buf()? Sure. Thanks, -- To unsubscribe from this list: send the line unsubscribe linux-efi in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/3] Enable user helper interface for efi capsule update
From: Kweh, Hock Leong hock.leong.k...@intel.com Hi Guys, This patchset is created on top of efi: Capsule update support patch: http://permalink.gmane.org/gmane.linux.kernel.efi/4837 It leverages the request_firmware_nowait() to expose the user helper interface for user to upload the capsule binary and calling the efi_capsule_update() API to pass the binary to EFI firmware. Besides build in kernel, the design also cater for build as kernel driver module. This patchset introduce a new API (request_firmware_abort()) at firmware_class so that the driver module could be unloaded by calling the API to properly stop user helper interface and release the device. Thanks. --- changelog v2: [PATCH 1/3] * use fw_lookup_buf() instead of __fw_lookup_buf() function call * move the fw_lookup_buf() function out of the CONFIG_PM_SLEEP block [PATCH 2/3] * no change [PATCH 3/3] * no change Kweh, Hock Leong (3): firmware loader: Introduce new API - request_firmware_abort() firmware loader: fix hung task warning dump efi: Capsule update with user helper interface drivers/base/firmware_class.c | 56 -- drivers/firmware/efi/Kconfig | 13 ++ drivers/firmware/efi/Makefile |1 + drivers/firmware/efi/efi-capsule-user-helper.c | 246 include/linux/firmware.h |4 + 5 files changed, 306 insertions(+), 14 deletions(-) create mode 100644 drivers/firmware/efi/efi-capsule-user-helper.c -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-efi in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/3] firmware loader: fix hung task warning dump
From: Kweh, Hock Leong hock.leong.k...@intel.com When using request_firmware_nowait() with FW_ACTION_NOHOTPLUG param to expose user helper interface, if the user do not react immediately, after 120 seconds there will be a hung task warning message dumped as below: [ 3000.784235] INFO: task kworker/0:0:8259 blocked for more than 120 seconds. [ 3000.791281] Tainted: GE 3.16.0-rc1-yocto-standard #41 [ 3000.798082] echo 0 /proc/sys/kernel/hung_task_timeout_secs disables this message. [ 3000.806072] kworker/0:0 D cd0075c8 0 8259 2 0x [ 3000.812765] Workqueue: events request_firmware_work_func [ 3000.818253] cd375e18 0046 000e cd0075c8 00f0 cd40ea00 cd375fec 1b883e89 [ 3000.826374] 026b cd40ea00 8000 0001 cd0075c8 cd375de4 c119917f [ 3000.834492] cd563360 cd375df4 c119a0ab cd563360 cd375e24 c119a1d6 [ 3000.842616] Call Trace: [ 3000.845252] [c119917f] ? kernfs_next_descendant_post+0x3f/0x50 [ 3000.851543] [c119a0ab] ? kernfs_activate+0x6b/0xc0 [ 3000.856790] [c119a1d6] ? kernfs_add_one+0xd6/0x130 [ 3000.862047] [c15fdb02] schedule+0x22/0x60 [ 3000.866548] [c15fd195] schedule_timeout+0x175/0x1d0 [ 3000.871887] [c119b391] ? __kernfs_create_file+0x71/0xa0 [ 3000.877574] [c119bb9a] ? sysfs_add_file_mode_ns+0xaa/0x180 [ 3000.883533] [c15fe84f] wait_for_completion+0x6f/0xb0 [ 3000.888961] [c1065200] ? wake_up_process+0x40/0x40 [ 3000.894219] [c13cb600] _request_firmware+0x750/0x9f0 [ 3000.899666] [c1382a7f] ? n_tty_receive_buf2+0x1f/0x30 [ 3000.905200] [c13cba02] request_firmware_work_func+0x22/0x50 [ 3000.911235] [c10550d2] process_one_work+0x122/0x380 [ 3000.916571] [c1055859] worker_thread+0xf9/0x470 [ 3000.921555] [c1055760] ? create_and_start_worker+0x50/0x50 [ 3000.927497] [c1055760] ? create_and_start_worker+0x50/0x50 [ 3000.933448] [c105a5ff] kthread+0x9f/0xc0 [ 3000.937850] [c15ffd40] ret_from_kernel_thread+0x20/0x30 [ 3000.943548] [c105a560] ? kthread_worker_fn+0x100/0x100 This patch change the wait_for_completion() function call to wait_for_completion_interruptible() function call for solving the issue. Cc: Matt Fleming matt.flem...@intel.com Signed-off-by: Kweh, Hock Leong hock.leong.k...@intel.com --- drivers/base/firmware_class.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index a238a46..639eeff 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -908,7 +908,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, kobject_uevent(fw_priv-dev.kobj, KOBJ_ADD); } - wait_for_completion(buf-completion); + retval = wait_for_completion_interruptible(buf-completion); cancel_delayed_work_sync(fw_priv-timeout_work); if (!buf-data) @@ -985,7 +985,7 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf) break; } mutex_unlock(fw_lock); - wait_for_completion(buf-completion); + ret = wait_for_completion_interruptible(buf-completion); mutex_lock(fw_lock); } mutex_unlock(fw_lock); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-efi in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/3] efi: Capsule update with user helper interface
From: Kweh, Hock Leong hock.leong.k...@intel.com Introducing a kernel module to expose user helper interface for user to upload capsule binaries. This module leverage the request_firmware_nowait() to expose an interface to user. Example steps to load the capsule binary: 1.) echo 1 /sys/class/firmware/efi-capsule-file/loading 2.) cat capsule.bin /sys/class/firmware/efi-capsule-file/data 3.) echo 0 /sys/class/firmware/efi-capsule-file/loading Whereas, this module does not allow the capsule binaries to be obtained from the request_firmware library search path. If any capsule binary loaded from firmware seach path, the module will stop functioning. Besides the request_firmware user helper interface, this module also expose a 'capsule_loaded' file note for user to verify the number of successfully uploaded capsule binaries. This file note has the read only attribute. Cc: Matt Fleming matt.flem...@intel.com Signed-off-by: Kweh, Hock Leong hock.leong.k...@intel.com --- drivers/firmware/efi/Kconfig | 13 ++ drivers/firmware/efi/Makefile |1 + drivers/firmware/efi/efi-capsule-user-helper.c | 246 3 files changed, 260 insertions(+) create mode 100644 drivers/firmware/efi/efi-capsule-user-helper.c diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index f712d47..7dc814e 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -60,6 +60,19 @@ config EFI_RUNTIME_WRAPPERS config EFI_ARMSTUB bool +config EFI_CAPSULE_USER_HELPER + tristate EFI capsule user mode helper + depends on EFI + select FW_LOADER + select FW_LOADER_USER_HELPER + help + This option exposes the user mode helper interface for user to load + EFI capsule binary and update the EFI firmware after system reboot. + This feature does not support auto locating capsule binaries at the + firmware lib search path. + + If unsure, say N. + endmenu config UEFI_CPER diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 698846e..63f6910 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_STUB) += libstub/ +obj-$(CONFIG_EFI_CAPSULE_USER_HELPER) += efi-capsule-user-helper.o diff --git a/drivers/firmware/efi/efi-capsule-user-helper.c b/drivers/firmware/efi/efi-capsule-user-helper.c new file mode 100644 index 000..84a1628 --- /dev/null +++ b/drivers/firmware/efi/efi-capsule-user-helper.c @@ -0,0 +1,246 @@ +/* + * EFI capsule user mode helper interface driver. + * + * Copyright 2014 Intel Corporation + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME : fmt + +#include linux/kernel.h +#include linux/module.h +#include linux/platform_device.h +#include linux/delay.h +#include linux/highmem.h +#include linux/slab.h +#include linux/mutex.h +#include linux/reboot.h +#include linux/efi.h +#include linux/firmware.h + +#define CAPSULE_NAME efi-capsule-file +#define DEV_NAME efi_capsule_user_helper +#define STRING_INTEGER_MAX_LENGTH 13 + +static DEFINE_MUTEX(user_helper_lock); +static int capsule_count; +static int stop_request; +static struct platform_device *efi_capsule_pdev; + +/* + * This function will store the capsule binary and pass it to + * efi_capsule_update() API in capsule.c + */ +static int efi_capsule_store(const struct firmware *fw) +{ + int i; + int ret; + int count = fw-size; + int copy_size = (fw-size PAGE_SIZE) ? PAGE_SIZE : fw-size; + int pages_needed = ALIGN(fw-size, PAGE_SIZE) PAGE_SHIFT; + struct page **pages; + void *page_data; + efi_capsule_header_t *capsule = NULL; + + pages = kmalloc_array(pages_needed, sizeof(void *), GFP_KERNEL); + if (!pages) { + pr_err(%s: kmalloc_array() failed\n, __func__); + return -ENOMEM; + } + + for (i = 0; i pages_needed; i++) { + pages[i] = alloc_page(GFP_KERNEL); + if (!pages[i]) { + pr_err(%s: alloc_page() failed\n, __func__); + --i; + ret = -ENOMEM; + goto failed; + } + } + + for (i = 0; i pages_needed; i++) { + page_data = kmap(pages[i]); + memcpy(page_data, fw-data + (i * PAGE_SIZE), copy_size); + + if (i == 0) + capsule = (efi_capsule_header_t *)page_data; + else + kunmap(pages[i]); + + count -= copy_size; + if (count PAGE_SIZE) +
[PATCH v2 1/3] firmware loader: Introduce new API - request_firmware_abort()
From: Kweh, Hock Leong hock.leong.k...@intel.com Besides aborting through user helper interface, a new API request_firmware_abort() allows kernel driver module to abort the request_firmware() / request_firmware_nowait() when they are no longer needed. It is useful for cancelling an outstanding firmware load if initiated from inside a module where that module is in the process of being unloaded, since the unload function may not have a handle to the struct firmware_buf. Note for people who use request_firmware_nowait(): You are required to do your own synchronization after you call request_firmware_abort() in order to continue unloading the module. The example synchronization code shows below: while (THIS_MODULE module_refcount(THIS_MODULE)) msleep(20); Cc: Matt Fleming matt.flem...@intel.com Signed-off-by: Kweh, Hock Leong hock.leong.k...@intel.com --- drivers/base/firmware_class.c | 52 +++-- include/linux/firmware.h |4 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index d276e33..a238a46 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1291,6 +1291,46 @@ request_firmware_nowait( } EXPORT_SYMBOL(request_firmware_nowait); +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); + tmp = __fw_lookup_buf(fw_name); + spin_unlock(fwc-lock); + + return tmp; +} + +/** + * request_firmware_abort - abort the waiting of firmware request + * @fw_name: name of firmware file + * + * @fw_name is the same name string while calling to request_firmware() + * or request_firmware_nowait(). + **/ +int request_firmware_abort(const char *fw_name) +{ + struct firmware_buf *buf; + struct firmware_buf *entry; + + buf = fw_lookup_buf(fw_name); + if (!buf) + return -ENOENT; + + mutex_lock(fw_lock); + list_for_each_entry(entry, pending_fw_head, pending_list) { + if (entry == buf) { + __fw_load_abort(buf); + break; + } + } + mutex_unlock(fw_lock); + return 0; +} +EXPORT_SYMBOL(request_firmware_abort); + #ifdef CONFIG_PM_SLEEP static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); @@ -1324,18 +1364,6 @@ static int cache_firmware(const char *fw_name) return ret; } -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); - tmp = __fw_lookup_buf(fw_name); - spin_unlock(fwc-lock); - - return tmp; -} - /** * uncache_firmware - remove one cached firmware image * @fw_name: the firmware image name diff --git a/include/linux/firmware.h b/include/linux/firmware.h index 5952933..ed90c8b 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -47,6 +47,7 @@ int request_firmware_nowait( void (*cont)(const struct firmware *fw, void *context)); void release_firmware(const struct firmware *fw); +int request_firmware_abort(const char *fw_name); #else static inline int request_firmware(const struct firmware **fw, const char *name, @@ -66,6 +67,9 @@ static inline void release_firmware(const struct firmware *fw) { } +static inline int request_firmware_abort(const char *fw_name) +{ +} #endif #ifdef CONFIG_FW_LOADER_USER_HELPER -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe linux-efi in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html