mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v4 0/4] Add request_firmware_direct() for microcode loader
@ 2013-12-02 14:38 Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 1/4] firmware: Introduce request_firmware_direct() Takashi Iwai
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Takashi Iwai @ 2013-12-02 14:38 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

Hi Greg,

this is the revised patchset, just rebased to be applicable cleanly
to 3.13-rc tree.  Other than that, there is no change since v3.

 [PATCH v4 1/4] firmware: Introduce request_firmware_direct()
 [PATCH v4 2/4] microcode: Use request_firmware_direct()
 [PATCH v4 3/4] firmware: Use bit flags instead of boolean combos
 [PATCH v4 4/4] firmware: Suppress fallback warnings when


thanks,

Takashi


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 1/4] firmware: Introduce request_firmware_direct()
  2013-12-02 14:38 [PATCH v4 0/4] Add request_firmware_direct() for microcode loader Takashi Iwai
@ 2013-12-02 14:38 ` Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 2/4] microcode: Use request_firmware_direct() Takashi Iwai
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2013-12-02 14:38 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

When CONFIG_FW_LOADER_USER_HELPER is set, request_firmware() falls
back to the usermode helper for loading via udev when the direct
loading fails.  But the recent udev takes way too long timeout (60
seconds) for non-existing firmware.  This is unacceptable for the
drivers like microcode loader where they load firmwares optionally,
i.e. it's no error even if no requested file exists.

This patch provides a new helper function, request_firmware_direct().
It behaves as same as request_firmware() except for that it doesn't
fall back to usermode helper but returns an error immediately if the
f/w can't be loaded directly in kernel.

Without CONFIG_FW_LOADER_USER_HELPER=y, request_firmware_direct() is
just an alias of request_firmware(), due to obvious reason.

Tested-by: Prarit Bhargava <prarit@redhat.com>
Acked-by: Ming Lei <ming.lei@canonical.com>
Acked-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/base/firmware_class.c | 41 ++++++++++++++++++++++++++++++++++-------
 include/linux/firmware.h      |  7 +++++++
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index eb8fb94ae2c5..1af03648daf8 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1061,7 +1061,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
 /* called from request_firmware() and request_firmware_work_func() */
 static int
 _request_firmware(const struct firmware **firmware_p, const char *name,
-		  struct device *device, bool uevent, bool nowait)
+		  struct device *device, bool uevent, bool nowait, bool fallback)
 {
 	struct firmware *fw;
 	long timeout;
@@ -1095,11 +1095,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 
 	ret = fw_get_filesystem_firmware(device, fw->priv);
 	if (ret) {
-		dev_warn(device, "Direct firmware load failed with error %d\n",
-			 ret);
-		dev_warn(device, "Falling back to user helper\n");
-		ret = fw_load_from_user_helper(fw, name, device,
+		if (fallback) {
+			dev_warn(device,
+				 "Direct firmware load failed with error %d\n",
+				 ret);
+			dev_warn(device, "Falling back to user helper\n");
+			ret = fw_load_from_user_helper(fw, name, device,
 					       uevent, nowait, timeout);
+		}
 	}
 
 	/* don't cache firmware handled without uevent */
@@ -1146,12 +1149,36 @@ request_firmware(const struct firmware **firmware_p, const char *name,
 
 	/* Need to pin this module until return */
 	__module_get(THIS_MODULE);
-	ret = _request_firmware(firmware_p, name, device, true, false);
+	ret = _request_firmware(firmware_p, name, device, true, false, true);
 	module_put(THIS_MODULE);
 	return ret;
 }
 EXPORT_SYMBOL(request_firmware);
 
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+/**
+ * request_firmware: - load firmware directly without usermode helper
+ * @firmware_p: pointer to firmware image
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded
+ *
+ * This function works pretty much like request_firmware(), but this doesn't
+ * fall back to usermode helper even if the firmware couldn't be loaded
+ * directly from fs.  Hence it's useful for loading optional firmwares, which
+ * aren't always present, without extra long timeouts of udev.
+ **/
+int request_firmware_direct(const struct firmware **firmware_p,
+			    const char *name, struct device *device)
+{
+	int ret;
+	__module_get(THIS_MODULE);
+	ret = _request_firmware(firmware_p, name, device, true, false, false);
+	module_put(THIS_MODULE);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(request_firmware_direct);
+#endif
+
 /**
  * release_firmware: - release the resource associated with a firmware image
  * @fw: firmware resource to release
@@ -1185,7 +1212,7 @@ static void request_firmware_work_func(struct work_struct *work)
 	fw_work = container_of(work, struct firmware_work, work);
 
 	_request_firmware(&fw, fw_work->name, fw_work->device,
-			  fw_work->uevent, true);
+			  fw_work->uevent, true, true);
 	fw_work->cont(fw, fw_work->context);
 	put_device(fw_work->device); /* taken in request_firmware_nowait() */
 
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index e154c1005cd1..59529330efd6 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -68,4 +68,11 @@ static inline void release_firmware(const struct firmware *fw)
 
 #endif
 
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+int request_firmware_direct(const struct firmware **fw, const char *name,
+			    struct device *device);
+#else
+#define request_firmware_direct	request_firmware
+#endif
+
 #endif
-- 
1.8.4.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 2/4] microcode: Use request_firmware_direct()
  2013-12-02 14:38 [PATCH v4 0/4] Add request_firmware_direct() for microcode loader Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 1/4] firmware: Introduce request_firmware_direct() Takashi Iwai
@ 2013-12-02 14:38 ` Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 3/4] firmware: Use bit flags instead of boolean combos Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 4/4] firmware: Suppress fallback warnings when CONFIG_FW_LOADER_USER_HELPER=n Takashi Iwai
  3 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2013-12-02 14:38 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

Use the new helper, request_firmware_direct(), for avoiding the
lengthy timeout of non-existing firmware loads.  Especially the Intel
microcode driver suffers from this problem because each CPU triggers
the f/w loading, thus it ends up taking (literally) hours with many
cores.

Tested-by: Prarit Bhargava <prarit@redhat.com>
Acked-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 arch/x86/kernel/microcode_amd.c   | 2 +-
 arch/x86/kernel/microcode_intel.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index c3d4cc972eca..22b3a1191ab3 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -430,7 +430,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
 	if (c->x86 >= 0x15)
 		snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
 
-	if (request_firmware(&fw, (const char *)fw_name, device)) {
+	if (request_firmware_direct(&fw, (const char *)fw_name, device)) {
 		pr_debug("failed to load file %s\n", fw_name);
 		goto out;
 	}
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 5fb2cebf556b..a276fa75d9b5 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -278,7 +278,7 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device,
 	sprintf(name, "intel-ucode/%02x-%02x-%02x",
 		c->x86, c->x86_model, c->x86_mask);
 
-	if (request_firmware(&firmware, name, device)) {
+	if (request_firmware_direct(&firmware, name, device)) {
 		pr_debug("data file %s load failed\n", name);
 		return UCODE_NFOUND;
 	}
-- 
1.8.4.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 3/4] firmware: Use bit flags instead of boolean combos
  2013-12-02 14:38 [PATCH v4 0/4] Add request_firmware_direct() for microcode loader Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 1/4] firmware: Introduce request_firmware_direct() Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 2/4] microcode: Use request_firmware_direct() Takashi Iwai
@ 2013-12-02 14:38 ` Takashi Iwai
  2013-12-02 14:38 ` [PATCH v4 4/4] firmware: Suppress fallback warnings when CONFIG_FW_LOADER_USER_HELPER=n Takashi Iwai
  3 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2013-12-02 14:38 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

More than two boolean arguments to a function are rather confusing and
error-prone for callers.  Let's make the behavior bit flags instead of
triple combos.

A nice suggestion by Borislav Petkov.

Acked-by: Borislav Petkov <bp@suse.de>
Acked-by: Prarit Bhargava <prarit@redhat.com>
Acked-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/base/firmware_class.c | 51 ++++++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 1af03648daf8..65797742c6b6 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -96,6 +96,11 @@ static inline long firmware_loading_timeout(void)
 	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
 }
 
+/* firmware behavior options */
+#define FW_OPT_UEVENT	(1U << 0)
+#define FW_OPT_NOWAIT	(1U << 1)
+#define FW_OPT_FALLBACK	(1U << 2)
+
 struct firmware_cache {
 	/* firmware_buf instance will be added into the below list */
 	spinlock_t lock;
@@ -820,7 +825,7 @@ static void firmware_class_timeout_work(struct work_struct *work)
 
 static struct firmware_priv *
 fw_create_instance(struct firmware *firmware, const char *fw_name,
-		   struct device *device, bool uevent, bool nowait)
+		   struct device *device, unsigned int opt_flags)
 {
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
@@ -832,7 +837,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
 		goto exit;
 	}
 
-	fw_priv->nowait = nowait;
+	fw_priv->nowait = !!(opt_flags & FW_OPT_NOWAIT);
 	fw_priv->fw = firmware;
 	INIT_DELAYED_WORK(&fw_priv->timeout_work,
 		firmware_class_timeout_work);
@@ -848,8 +853,8 @@ exit:
 }
 
 /* load a firmware via user helper */
-static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
-				  long timeout)
+static int _request_firmware_load(struct firmware_priv *fw_priv,
+				  unsigned int opt_flags, long timeout)
 {
 	int retval = 0;
 	struct device *f_dev = &fw_priv->dev;
@@ -885,7 +890,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
 		goto err_del_bin_attr;
 	}
 
-	if (uevent) {
+	if (opt_flags & FW_OPT_UEVENT) {
 		buf->need_uevent = true;
 		dev_set_uevent_suppress(f_dev, false);
 		dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
@@ -911,16 +916,16 @@ err_put_dev:
 
 static int fw_load_from_user_helper(struct firmware *firmware,
 				    const char *name, struct device *device,
-				    bool uevent, bool nowait, long timeout)
+				    unsigned int opt_flags, long timeout)
 {
 	struct firmware_priv *fw_priv;
 
-	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+	fw_priv = fw_create_instance(firmware, name, device, opt_flags);
 	if (IS_ERR(fw_priv))
 		return PTR_ERR(fw_priv);
 
 	fw_priv->buf = firmware->priv;
-	return _request_firmware_load(fw_priv, uevent, timeout);
+	return _request_firmware_load(fw_priv, opt_flags, timeout);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -942,7 +947,7 @@ static void kill_requests_without_uevent(void)
 #else /* CONFIG_FW_LOADER_USER_HELPER */
 static inline int
 fw_load_from_user_helper(struct firmware *firmware, const char *name,
-			 struct device *device, bool uevent, bool nowait,
+			 struct device *device, unsigned int opt_flags,
 			 long timeout)
 {
 	return -ENOENT;
@@ -1023,7 +1028,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
 }
 
 static int assign_firmware_buf(struct firmware *fw, struct device *device,
-				bool skip_cache)
+			       unsigned int opt_flags)
 {
 	struct firmware_buf *buf = fw->priv;
 
@@ -1040,7 +1045,8 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
 	 * device may has been deleted already, but the problem
 	 * should be fixed in devres or driver core.
 	 */
-	if (device && !skip_cache)
+	/* don't cache firmware handled without uevent */
+	if (device && (opt_flags & FW_OPT_UEVENT))
 		fw_add_devm_name(device, buf->fw_id);
 
 	/*
@@ -1061,7 +1067,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
 /* called from request_firmware() and request_firmware_work_func() */
 static int
 _request_firmware(const struct firmware **firmware_p, const char *name,
-		  struct device *device, bool uevent, bool nowait, bool fallback)
+		  struct device *device, unsigned int opt_flags)
 {
 	struct firmware *fw;
 	long timeout;
@@ -1076,7 +1082,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 
 	ret = 0;
 	timeout = firmware_loading_timeout();
-	if (nowait) {
+	if (opt_flags & FW_OPT_NOWAIT) {
 		timeout = usermodehelper_read_lock_wait(timeout);
 		if (!timeout) {
 			dev_dbg(device, "firmware: %s loading timed out\n",
@@ -1095,19 +1101,18 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 
 	ret = fw_get_filesystem_firmware(device, fw->priv);
 	if (ret) {
-		if (fallback) {
+		if (opt_flags & FW_OPT_FALLBACK) {
 			dev_warn(device,
 				 "Direct firmware load failed with error %d\n",
 				 ret);
 			dev_warn(device, "Falling back to user helper\n");
 			ret = fw_load_from_user_helper(fw, name, device,
-					       uevent, nowait, timeout);
+						       opt_flags, timeout);
 		}
 	}
 
-	/* don't cache firmware handled without uevent */
 	if (!ret)
-		ret = assign_firmware_buf(fw, device, !uevent);
+		ret = assign_firmware_buf(fw, device, opt_flags);
 
 	usermodehelper_read_unlock();
 
@@ -1149,7 +1154,8 @@ request_firmware(const struct firmware **firmware_p, const char *name,
 
 	/* Need to pin this module until return */
 	__module_get(THIS_MODULE);
-	ret = _request_firmware(firmware_p, name, device, true, false, true);
+	ret = _request_firmware(firmware_p, name, device,
+				FW_OPT_UEVENT | FW_OPT_FALLBACK);
 	module_put(THIS_MODULE);
 	return ret;
 }
@@ -1172,7 +1178,7 @@ int request_firmware_direct(const struct firmware **firmware_p,
 {
 	int ret;
 	__module_get(THIS_MODULE);
-	ret = _request_firmware(firmware_p, name, device, true, false, false);
+	ret = _request_firmware(firmware_p, name, device, FW_OPT_UEVENT);
 	module_put(THIS_MODULE);
 	return ret;
 }
@@ -1201,7 +1207,7 @@ struct firmware_work {
 	struct device *device;
 	void *context;
 	void (*cont)(const struct firmware *fw, void *context);
-	bool uevent;
+	unsigned int opt_flags;
 };
 
 static void request_firmware_work_func(struct work_struct *work)
@@ -1212,7 +1218,7 @@ static void request_firmware_work_func(struct work_struct *work)
 	fw_work = container_of(work, struct firmware_work, work);
 
 	_request_firmware(&fw, fw_work->name, fw_work->device,
-			  fw_work->uevent, true, true);
+			  fw_work->opt_flags);
 	fw_work->cont(fw, fw_work->context);
 	put_device(fw_work->device); /* taken in request_firmware_nowait() */
 
@@ -1260,7 +1266,8 @@ request_firmware_nowait(
 	fw_work->device = device;
 	fw_work->context = context;
 	fw_work->cont = cont;
-	fw_work->uevent = uevent;
+	fw_work->opt_flags = FW_OPT_NOWAIT | FW_OPT_FALLBACK |
+		(uevent ? FW_OPT_UEVENT : 0);
 
 	if (!try_module_get(module)) {
 		kfree(fw_work);
-- 
1.8.4.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 4/4] firmware: Suppress fallback warnings when CONFIG_FW_LOADER_USER_HELPER=n
  2013-12-02 14:38 [PATCH v4 0/4] Add request_firmware_direct() for microcode loader Takashi Iwai
                   ` (2 preceding siblings ...)
  2013-12-02 14:38 ` [PATCH v4 3/4] firmware: Use bit flags instead of boolean combos Takashi Iwai
@ 2013-12-02 14:38 ` Takashi Iwai
  3 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2013-12-02 14:38 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel

The commit [3e358ac2bb5b: firmware: Be a bit more verbose about direct
firmware loading failure] introduced a new warning message about
falling back to user helper, but this isn't true when
CONFIG_FW_LOADER_USER_HELPER isn't set.

In this patch, clear the FW_OPT_FALLBACK flag in the case without
userhelper, so that the corresponding code will be disabled.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/base/firmware_class.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 65797742c6b6..33b87bf664ab 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -99,7 +99,11 @@ static inline long firmware_loading_timeout(void)
 /* firmware behavior options */
 #define FW_OPT_UEVENT	(1U << 0)
 #define FW_OPT_NOWAIT	(1U << 1)
+#ifdef CONFIG_FW_LOADER_USER_HELPER
 #define FW_OPT_FALLBACK	(1U << 2)
+#else
+#define FW_OPT_FALLBACK	0
+#endif
 
 struct firmware_cache {
 	/* firmware_buf instance will be added into the below list */
-- 
1.8.4.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-12-02 14:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-02 14:38 [PATCH v4 0/4] Add request_firmware_direct() for microcode loader Takashi Iwai
2013-12-02 14:38 ` [PATCH v4 1/4] firmware: Introduce request_firmware_direct() Takashi Iwai
2013-12-02 14:38 ` [PATCH v4 2/4] microcode: Use request_firmware_direct() Takashi Iwai
2013-12-02 14:38 ` [PATCH v4 3/4] firmware: Use bit flags instead of boolean combos Takashi Iwai
2013-12-02 14:38 ` [PATCH v4 4/4] firmware: Suppress fallback warnings when CONFIG_FW_LOADER_USER_HELPER=n Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®