Re: [PATCH v1 1/3] firmware loader: Introduce new API - request_firmware_abort()

2014-11-02 Thread Ming Lei
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

2014-11-02 Thread Kweh Hock Leong
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

2014-11-02 Thread Kweh Hock Leong
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

2014-11-02 Thread Kweh Hock Leong
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()

2014-11-02 Thread Kweh Hock Leong
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