diff mbox

[V4,1/2] firmware: add more flexible request_firmware_async function

Message ID 20170223183018.16704-1-zajec5@gmail.com (mailing list archive)
State Not Applicable
Delegated to: Kalle Valo
Headers show

Commit Message

Rafał Miłecki Feb. 23, 2017, 6:30 p.m. UTC
From: Rafał Miłecki <rafal@milecki.pl>

So far we got only one function for loading firmware asynchronously:
request_firmware_nowait. It didn't allow much customization of firmware
loading process - there is only one bool uevent argument. Moreover this
bool also controls user helper in an unclear way.

Resolve this problem by adding one internally shared  function that
allows specifying any flags manually.

This implementation:
1) Allows keeping old request_firmware_nowait API unchanged
2) Doesn't require adjusting / rewriting current drivers
3) Minimizes risk of regressions
4) Adds new function for drivers that need more control over loading a
   firmware.

The new function takes options struct pointer as an argument to make
further improvements possible (without any big reworks).

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V3: Don't expose all FW_OPT_* flags.
    As Luis noted we want a struct so add struct firmware_opts for real
    flexibility.
    Thank you Luis for your review!

Ming/Luis/Greg: assuming this gets a positive review, could someone of you pick
this patchset?
---
 drivers/base/firmware_class.c | 43 ++++++++++++++++++++++++++++++++++---------
 include/linux/firmware.h      | 15 ++++++++++++++-
 2 files changed, 48 insertions(+), 10 deletions(-)

Comments

Rafał Miłecki March 16, 2017, 9:57 a.m. UTC | #1
On 23 February 2017 at 19:30, Rafał Miłecki <zajec5@gmail.com> wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> So far we got only one function for loading firmware asynchronously:
> request_firmware_nowait. It didn't allow much customization of firmware
> loading process - there is only one bool uevent argument. Moreover this
> bool also controls user helper in an unclear way.
>
> Resolve this problem by adding one internally shared  function that
> allows specifying any flags manually.
>
> This implementation:
> 1) Allows keeping old request_firmware_nowait API unchanged
> 2) Doesn't require adjusting / rewriting current drivers
> 3) Minimizes risk of regressions
> 4) Adds new function for drivers that need more control over loading a
>    firmware.
>
> The new function takes options struct pointer as an argument to make
> further improvements possible (without any big reworks).
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> ---
> V3: Don't expose all FW_OPT_* flags.
>     As Luis noted we want a struct so add struct firmware_opts for real
>     flexibility.
>     Thank you Luis for your review!
>
> Ming/Luis/Greg: assuming this gets a positive review, could someone of you pick
> this patchset?

Ping. I hope it's relatively simple and non-intrusive change with a
proper design now.

Is there some who could pick this small patchset?
Greg Kroah-Hartman March 16, 2017, 1:31 p.m. UTC | #2
On Thu, Mar 16, 2017 at 10:57:00AM +0100, Rafał Miłecki wrote:
> On 23 February 2017 at 19:30, Rafał Miłecki <zajec5@gmail.com> wrote:
> > From: Rafał Miłecki <rafal@milecki.pl>
> >
> > So far we got only one function for loading firmware asynchronously:
> > request_firmware_nowait. It didn't allow much customization of firmware
> > loading process - there is only one bool uevent argument. Moreover this
> > bool also controls user helper in an unclear way.
> >
> > Resolve this problem by adding one internally shared  function that
> > allows specifying any flags manually.
> >
> > This implementation:
> > 1) Allows keeping old request_firmware_nowait API unchanged
> > 2) Doesn't require adjusting / rewriting current drivers
> > 3) Minimizes risk of regressions
> > 4) Adds new function for drivers that need more control over loading a
> >    firmware.
> >
> > The new function takes options struct pointer as an argument to make
> > further improvements possible (without any big reworks).
> >
> > Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> > ---
> > V3: Don't expose all FW_OPT_* flags.
> >     As Luis noted we want a struct so add struct firmware_opts for real
> >     flexibility.
> >     Thank you Luis for your review!
> >
> > Ming/Luis/Greg: assuming this gets a positive review, could someone of you pick
> > this patchset?
> 
> Ping. I hope it's relatively simple and non-intrusive change with a
> proper design now.
> 
> Is there some who could pick this small patchset?

It would be nice if the firmware maintainer could review it, I can't do
anything with this until then...

thanks,

greg k-h
Rafał Miłecki March 16, 2017, 1:55 p.m. UTC | #3
On 02/23/2017 07:30 PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> So far we got only one function for loading firmware asynchronously:
> request_firmware_nowait. It didn't allow much customization of firmware
> loading process - there is only one bool uevent argument. Moreover this
> bool also controls user helper in an unclear way.
>
> Resolve this problem by adding one internally shared  function that
> allows specifying any flags manually.
>
> This implementation:
> 1) Allows keeping old request_firmware_nowait API unchanged
> 2) Doesn't require adjusting / rewriting current drivers
> 3) Minimizes risk of regressions
> 4) Adds new function for drivers that need more control over loading a
>    firmware.
>
> The new function takes options struct pointer as an argument to make
> further improvements possible (without any big reworks).
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> ---
> V3: Don't expose all FW_OPT_* flags.
>     As Luis noted we want a struct so add struct firmware_opts for real
>     flexibility.
>     Thank you Luis for your review!
>
> Ming/Luis/Greg: assuming this gets a positive review, could someone of you pick
> this patchset?

Hi Ming,

It seems you changed e-mail address somewhere between V3 and V4 of this
patchset. Could you review/comment/ack this, please?

Luis: would you ack this patch now I followed your guidance?


> ---
>  drivers/base/firmware_class.c | 43 ++++++++++++++++++++++++++++++++++---------
>  include/linux/firmware.h      | 15 ++++++++++++++-
>  2 files changed, 48 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index d05be1732c8b..b67b294eb31a 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -1356,7 +1356,7 @@ static void request_firmware_work_func(struct work_struct *work)
>  	_request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0,
>  			  fw_work->opt_flags);
>  	fw_work->cont(fw, fw_work->context);
> -	put_device(fw_work->device); /* taken in request_firmware_nowait() */
> +	put_device(fw_work->device); /* taken in __request_firmware_nowait() */
>
>  	module_put(fw_work->module);
>  	kfree_const(fw_work->name);
> @@ -1364,10 +1364,9 @@ static void request_firmware_work_func(struct work_struct *work)
>  }
>
>  /**
> - * request_firmware_nowait - asynchronous version of request_firmware
> + * __request_firmware_nowait - asynchronous version of request_firmware
>   * @module: module requesting the firmware
> - * @uevent: sends uevent to copy the firmware image if this flag
> - *	is non-zero else the firmware copy must be done manually.
> + * @opt_flags: flags that control firmware loading process, see FW_OPT_*
>   * @name: name of firmware file
>   * @device: device for which firmware is being loaded
>   * @gfp: allocation flags
> @@ -1386,9 +1385,9 @@ static void request_firmware_work_func(struct work_struct *work)
>   *
>   *		- can't sleep at all if @gfp is GFP_ATOMIC.
>   **/
> -int
> -request_firmware_nowait(
> -	struct module *module, bool uevent,
> +static int
> +__request_firmware_nowait(
> +	struct module *module, unsigned int opt_flags,
>  	const char *name, struct device *device, gfp_t gfp, void *context,
>  	void (*cont)(const struct firmware *fw, void *context))
>  {
> @@ -1407,8 +1406,7 @@ request_firmware_nowait(
>  	fw_work->device = device;
>  	fw_work->context = context;
>  	fw_work->cont = cont;
> -	fw_work->opt_flags = FW_OPT_NOWAIT | FW_OPT_FALLBACK |
> -		(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
> +	fw_work->opt_flags = FW_OPT_NOWAIT | opt_flags;
>
>  	if (!try_module_get(module)) {
>  		kfree_const(fw_work->name);
> @@ -1421,8 +1419,35 @@ request_firmware_nowait(
>  	schedule_work(&fw_work->work);
>  	return 0;
>  }
> +
> +int request_firmware_nowait(struct module *module, bool uevent,
> +			    const char *name, struct device *device, gfp_t gfp,
> +			    void *context,
> +			    void (*cont)(const struct firmware *fw, void *context))
> +{
> +	unsigned int opt_flags = FW_OPT_FALLBACK |
> +		(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
> +
> +	return __request_firmware_nowait(module, opt_flags, name, device, gfp,
> +					 context, cont);
> +}
>  EXPORT_SYMBOL(request_firmware_nowait);
>
> +int __request_firmware_async(struct module *module, const char *name,
> +			     struct firmware_opts *fw_opts, struct device *dev,
> +			     void *context,
> +			     void (*cont)(const struct firmware *fw, void *context))
> +{
> +	unsigned int opt_flags = FW_OPT_UEVENT;
> +
> +	if (fw_opts->optional)
> +		opt_flags |= FW_OPT_NO_WARN;
> +
> +	return __request_firmware_nowait(module, opt_flags, name, dev,
> +					 GFP_KERNEL, context, cont);
> +}
> +EXPORT_SYMBOL(__request_firmware_async);
> +
>  #ifdef CONFIG_PM_SLEEP
>  static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
>
> diff --git a/include/linux/firmware.h b/include/linux/firmware.h
> index b1f9f0ccb8ac..a32b6e67462d 100644
> --- a/include/linux/firmware.h
> +++ b/include/linux/firmware.h
> @@ -82,6 +82,19 @@ static inline int request_firmware_into_buf(const struct firmware **firmware_p,
>  {
>  	return -EINVAL;
>  }
> -
>  #endif
> +
> +struct firmware_opts {
> +	bool optional;
> +};
> +
> +int __request_firmware_async(struct module *module, const char *name,
> +			     struct firmware_opts *fw_opts, struct device *dev,
> +			     void *context,
> +			     void (*cont)(const struct firmware *fw, void *context));
> +
> +#define request_firmware_async(name, fw_opts, dev, context, cont)	\
> +	__request_firmware_async(THIS_MODULE, name, fw_opts, dev,	\
> +				 context, cont)
> +
>  #endif
>
Greg Kroah-Hartman March 16, 2017, 2:03 p.m. UTC | #4
On Thu, Mar 16, 2017 at 02:55:09PM +0100, Rafał Miłecki wrote:
> On 02/23/2017 07:30 PM, Rafał Miłecki wrote:
> > From: Rafał Miłecki <rafal@milecki.pl>
> > 
> > So far we got only one function for loading firmware asynchronously:
> > request_firmware_nowait. It didn't allow much customization of firmware
> > loading process - there is only one bool uevent argument. Moreover this
> > bool also controls user helper in an unclear way.
> > 
> > Resolve this problem by adding one internally shared  function that
> > allows specifying any flags manually.
> > 
> > This implementation:
> > 1) Allows keeping old request_firmware_nowait API unchanged
> > 2) Doesn't require adjusting / rewriting current drivers
> > 3) Minimizes risk of regressions
> > 4) Adds new function for drivers that need more control over loading a
> >    firmware.
> > 
> > The new function takes options struct pointer as an argument to make
> > further improvements possible (without any big reworks).
> > 
> > Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> > ---
> > V3: Don't expose all FW_OPT_* flags.
> >     As Luis noted we want a struct so add struct firmware_opts for real
> >     flexibility.
> >     Thank you Luis for your review!
> > 
> > Ming/Luis/Greg: assuming this gets a positive review, could someone of you pick
> > this patchset?
> 
> Hi Ming,
> 
> It seems you changed e-mail address somewhere between V3 and V4 of this
> patchset. Could you review/comment/ack this, please?

Ming isn't the firmware maintainer anymore :(

> Luis: would you ack this patch now I followed your guidance?

It's up to Luis now :)

greg k-h
Luis Chamberlain March 17, 2017, 5:29 p.m. UTC | #5
On Thu, Mar 16, 2017 at 11:03:52PM +0900, Greg KH wrote:
> On Thu, Mar 16, 2017 at 02:55:09PM +0100, Rafał Miłecki wrote:
> > Luis: would you ack this patch now I followed your guidance?
> 
> It's up to Luis now :)

I'm reviewing now!

  Luis
Luis Chamberlain March 27, 2017, 7:28 p.m. UTC | #6
On Fri, Mar 17, 2017 at 06:29:36PM +0100, Luis R. Rodriguez wrote:
> On Thu, Mar 16, 2017 at 11:03:52PM +0900, Greg KH wrote:
> > On Thu, Mar 16, 2017 at 02:55:09PM +0100, Rafał Miłecki wrote:
> > > Luis: would you ack this patch now I followed your guidance?
> > 
> > It's up to Luis now :)
> 
> I'm reviewing now!

This review has taken longer than expected given I was also reviewing
how to mesh in the new API I had been working on longer than this
patch series, and also address the long standing issues with the
UMH I have cringed over. Last week and this weekend I did most of
the hard work to feel happy with a resolution, and will now be folding
this functionality into my series.

So -- please have a bit of patience, and I will be spinning out a new
series which incorporates the functionality you have requested, just
meshed more in line with the other requirements we have had for a
while.

  Luis
diff mbox

Patch

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index d05be1732c8b..b67b294eb31a 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1356,7 +1356,7 @@  static void request_firmware_work_func(struct work_struct *work)
 	_request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0,
 			  fw_work->opt_flags);
 	fw_work->cont(fw, fw_work->context);
-	put_device(fw_work->device); /* taken in request_firmware_nowait() */
+	put_device(fw_work->device); /* taken in __request_firmware_nowait() */
 
 	module_put(fw_work->module);
 	kfree_const(fw_work->name);
@@ -1364,10 +1364,9 @@  static void request_firmware_work_func(struct work_struct *work)
 }
 
 /**
- * request_firmware_nowait - asynchronous version of request_firmware
+ * __request_firmware_nowait - asynchronous version of request_firmware
  * @module: module requesting the firmware
- * @uevent: sends uevent to copy the firmware image if this flag
- *	is non-zero else the firmware copy must be done manually.
+ * @opt_flags: flags that control firmware loading process, see FW_OPT_*
  * @name: name of firmware file
  * @device: device for which firmware is being loaded
  * @gfp: allocation flags
@@ -1386,9 +1385,9 @@  static void request_firmware_work_func(struct work_struct *work)
  *
  *		- can't sleep at all if @gfp is GFP_ATOMIC.
  **/
-int
-request_firmware_nowait(
-	struct module *module, bool uevent,
+static int
+__request_firmware_nowait(
+	struct module *module, unsigned int opt_flags,
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
@@ -1407,8 +1406,7 @@  request_firmware_nowait(
 	fw_work->device = device;
 	fw_work->context = context;
 	fw_work->cont = cont;
-	fw_work->opt_flags = FW_OPT_NOWAIT | FW_OPT_FALLBACK |
-		(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
+	fw_work->opt_flags = FW_OPT_NOWAIT | opt_flags;
 
 	if (!try_module_get(module)) {
 		kfree_const(fw_work->name);
@@ -1421,8 +1419,35 @@  request_firmware_nowait(
 	schedule_work(&fw_work->work);
 	return 0;
 }
+
+int request_firmware_nowait(struct module *module, bool uevent,
+			    const char *name, struct device *device, gfp_t gfp,
+			    void *context,
+			    void (*cont)(const struct firmware *fw, void *context))
+{
+	unsigned int opt_flags = FW_OPT_FALLBACK |
+		(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
+
+	return __request_firmware_nowait(module, opt_flags, name, device, gfp,
+					 context, cont);
+}
 EXPORT_SYMBOL(request_firmware_nowait);
 
+int __request_firmware_async(struct module *module, const char *name,
+			     struct firmware_opts *fw_opts, struct device *dev,
+			     void *context,
+			     void (*cont)(const struct firmware *fw, void *context))
+{
+	unsigned int opt_flags = FW_OPT_UEVENT;
+
+	if (fw_opts->optional)
+		opt_flags |= FW_OPT_NO_WARN;
+
+	return __request_firmware_nowait(module, opt_flags, name, dev,
+					 GFP_KERNEL, context, cont);
+}
+EXPORT_SYMBOL(__request_firmware_async);
+
 #ifdef CONFIG_PM_SLEEP
 static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
 
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index b1f9f0ccb8ac..a32b6e67462d 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -82,6 +82,19 @@  static inline int request_firmware_into_buf(const struct firmware **firmware_p,
 {
 	return -EINVAL;
 }
-
 #endif
+
+struct firmware_opts {
+	bool optional;
+};
+
+int __request_firmware_async(struct module *module, const char *name,
+			     struct firmware_opts *fw_opts, struct device *dev,
+			     void *context,
+			     void (*cont)(const struct firmware *fw, void *context));
+
+#define request_firmware_async(name, fw_opts, dev, context, cont)	\
+	__request_firmware_async(THIS_MODULE, name, fw_opts, dev,	\
+				 context, cont)
+
 #endif