2018-03-10 06:14:49 -08:00
// SPDX-License-Identifier: GPL-2.0
# include <linux/types.h>
# include <linux/kconfig.h>
# include <linux/list.h>
# include <linux/security.h>
# include <linux/umh.h>
2018-03-10 06:14:51 -08:00
# include <linux/sysctl.h>
2020-04-24 18:49:16 +00:00
# include <linux/module.h>
2018-03-10 06:14:49 -08:00
2018-03-10 06:14:50 -08:00
# include "fallback.h"
# include "firmware.h"
2018-03-10 06:14:49 -08:00
/*
* firmware fallback mechanism
*/
/*
* use small loading timeout for caching devices ' firmware because all these
* firmware images have been loaded successfully at lease once , also system is
* ready for completing firmware loading now . The maximum size of firmware in
* current distributions is about 2 M bytes , so 10 secs should be enough .
*/
void fw_fallback_set_cache_timeout ( void )
{
fw_fallback_config . old_timeout = __firmware_loading_timeout ( ) ;
__fw_fallback_set_timeout ( 10 ) ;
}
/* Restores the timeout to the value last configured during normal operation */
void fw_fallback_set_default_timeout ( void )
{
__fw_fallback_set_timeout ( fw_fallback_config . old_timeout ) ;
}
static long firmware_loading_timeout ( void )
{
return __firmware_loading_timeout ( ) > 0 ?
__firmware_loading_timeout ( ) * HZ : MAX_JIFFY_OFFSET ;
}
static inline int fw_sysfs_wait_timeout ( struct fw_priv * fw_priv , long timeout )
{
return __fw_state_wait_common ( fw_priv , timeout ) ;
}
static LIST_HEAD ( pending_fw_head ) ;
void kill_pending_fw_fallback_reqs ( bool only_kill_custom )
{
struct fw_priv * fw_priv ;
struct fw_priv * next ;
mutex_lock ( & fw_lock ) ;
list_for_each_entry_safe ( fw_priv , next , & pending_fw_head ,
pending_list ) {
if ( ! fw_priv - > need_uevent | | ! only_kill_custom )
__fw_load_abort ( fw_priv ) ;
}
mutex_unlock ( & fw_lock ) ;
}
2018-03-10 06:14:55 -08:00
/**
2018-05-10 13:08:38 -07:00
* fw_load_sysfs_fallback ( ) - load a firmware via the sysfs fallback mechanism
2018-04-25 12:25:39 -04:00
* @ fw_sysfs : firmware sysfs information for the firmware to load
2018-03-10 06:14:55 -08:00
* @ timeout : timeout to wait for the load
*
* In charge of constructing a sysfs fallback interface for firmware loading .
* */
2020-10-02 10:38:26 -07:00
static int fw_load_sysfs_fallback ( struct fw_sysfs * fw_sysfs , long timeout )
2018-03-10 06:14:49 -08:00
{
int retval = 0 ;
struct device * f_dev = & fw_sysfs - > dev ;
struct fw_priv * fw_priv = fw_sysfs - > fw_priv ;
/* fall back on userspace loading */
if ( ! fw_priv - > data )
fw_priv - > is_paged_buf = true ;
dev_set_uevent_suppress ( f_dev , true ) ;
retval = device_add ( f_dev ) ;
if ( retval ) {
dev_err ( f_dev , " %s: device_register failed \n " , __func__ ) ;
goto err_put_dev ;
}
mutex_lock ( & fw_lock ) ;
2021-07-28 14:21:07 +05:30
if ( fw_state_is_aborted ( fw_priv ) ) {
mutex_unlock ( & fw_lock ) ;
retval = - EINTR ;
goto out ;
}
2018-03-10 06:14:49 -08:00
list_add ( & fw_priv - > pending_list , & pending_fw_head ) ;
mutex_unlock ( & fw_lock ) ;
2020-10-02 10:38:26 -07:00
if ( fw_priv - > opt_flags & FW_OPT_UEVENT ) {
2018-03-10 06:14:49 -08:00
fw_priv - > need_uevent = true ;
dev_set_uevent_suppress ( f_dev , false ) ;
dev_dbg ( f_dev , " firmware: requesting %s \n " , fw_priv - > fw_name ) ;
kobject_uevent ( & fw_sysfs - > dev . kobj , KOBJ_ADD ) ;
} else {
timeout = MAX_JIFFY_OFFSET ;
}
retval = fw_sysfs_wait_timeout ( fw_priv , timeout ) ;
firmware: fix a double abort case with fw_load_sysfs_fallback
fw_sysfs_wait_timeout may return err with -ENOENT
at fw_load_sysfs_fallback and firmware is already
in abort status, no need to abort again, so skip it.
This issue is caused by concurrent situation like below:
when thread 1# wait firmware loading, thread 2# may write
-1 to abort loading and wakeup thread 1# before it timeout.
so wait_for_completion_killable_timeout of thread 1# would
return remaining time which is != 0 with fw_st->status
FW_STATUS_ABORTED.And the results would be converted into
err -ENOENT in __fw_state_wait_common and transfered to
fw_load_sysfs_fallback in thread 1#.
The -ENOENT means firmware status is already at ABORTED,
so fw_load_sysfs_fallback no need to get mutex to abort again.
-----------------------------
thread 1#,wait for loading
fw_load_sysfs_fallback
->fw_sysfs_wait_timeout
->__fw_state_wait_common
->wait_for_completion_killable_timeout
in __fw_state_wait_common,
...
93 ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout);
94 if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
95 return -ENOENT;
96 if (!ret)
97 return -ETIMEDOUT;
98
99 return ret < 0 ? ret : 0;
-----------------------------
thread 2#, write -1 to abort loading
firmware_loading_store
->fw_load_abort
->__fw_load_abort
->fw_state_aborted
->__fw_state_set
->complete_all
in __fw_state_set,
...
111 if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
112 complete_all(&fw_st->completion);
-------------------------------------------
BTW,the double abort issue would not cause kernel panic or create an issue,
but slow down it sometimes.The change is just a minor optimization.
Signed-off-by: Junyong Sun <sunjunyong@xiaomi.com>
Acked-by: Luis Chamberlain <mcgrof@kernel.org>
Link: https://lore.kernel.org/r/1583202968-28792-1-git-send-email-sunjunyong@xiaomi.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-03-03 10:36:08 +08:00
if ( retval < 0 & & retval ! = - ENOENT ) {
2018-03-10 06:14:49 -08:00
mutex_lock ( & fw_lock ) ;
fw_load_abort ( fw_sysfs ) ;
mutex_unlock ( & fw_lock ) ;
}
if ( fw_state_is_aborted ( fw_priv ) ) {
if ( retval = = - ERESTARTSYS )
retval = - EINTR ;
} else if ( fw_priv - > is_paged_buf & & ! fw_priv - > data )
retval = - ENOMEM ;
2021-07-28 14:21:07 +05:30
out :
2018-03-10 06:14:49 -08:00
device_del ( f_dev ) ;
err_put_dev :
put_device ( f_dev ) ;
return retval ;
}
static int fw_load_from_user_helper ( struct firmware * firmware ,
const char * name , struct device * device ,
2020-05-22 16:12:02 -07:00
u32 opt_flags )
2018-03-10 06:14:49 -08:00
{
struct fw_sysfs * fw_sysfs ;
long timeout ;
int ret ;
timeout = firmware_loading_timeout ( ) ;
if ( opt_flags & FW_OPT_NOWAIT ) {
timeout = usermodehelper_read_lock_wait ( timeout ) ;
if ( ! timeout ) {
dev_dbg ( device , " firmware: %s loading timed out \n " ,
name ) ;
return - EBUSY ;
}
} else {
ret = usermodehelper_read_trylock ( ) ;
if ( WARN_ON ( ret ) ) {
dev_err ( device , " firmware: %s will not be loaded \n " ,
name ) ;
return ret ;
}
}
fw_sysfs = fw_create_instance ( firmware , name , device , opt_flags ) ;
if ( IS_ERR ( fw_sysfs ) ) {
ret = PTR_ERR ( fw_sysfs ) ;
goto out_unlock ;
}
fw_sysfs - > fw_priv = firmware - > priv ;
2020-10-02 10:38:26 -07:00
ret = fw_load_sysfs_fallback ( fw_sysfs , timeout ) ;
2018-03-10 06:14:49 -08:00
if ( ! ret )
2020-10-02 10:38:26 -07:00
ret = assign_fw ( firmware , device ) ;
2018-03-10 06:14:49 -08:00
out_unlock :
usermodehelper_read_unlock ( ) ;
return ret ;
}
2020-05-22 16:12:02 -07:00
static bool fw_force_sysfs_fallback ( u32 opt_flags )
2018-03-10 06:14:49 -08:00
{
if ( fw_fallback_config . force_sysfs_fallback )
return true ;
if ( ! ( opt_flags & FW_OPT_USERHELPER ) )
return false ;
return true ;
}
2020-05-22 16:12:02 -07:00
static bool fw_run_sysfs_fallback ( u32 opt_flags )
2018-03-10 06:14:49 -08:00
{
2018-07-13 14:05:59 -04:00
int ret ;
2018-03-10 06:14:52 -08:00
if ( fw_fallback_config . ignore_sysfs_fallback ) {
2018-03-21 15:34:28 -07:00
pr_info_once ( " Ignoring firmware sysfs fallback due to sysctl knob \n " ) ;
2018-03-10 06:14:52 -08:00
return false ;
}
2020-01-15 17:35:47 +01:00
if ( ( opt_flags & FW_OPT_NOFALLBACK_SYSFS ) )
2018-03-10 06:14:49 -08:00
return false ;
2018-07-13 14:05:59 -04:00
/* Also permit LSMs and IMA to fail firmware sysfs fallback */
2020-10-02 10:38:21 -07:00
ret = security_kernel_load_data ( LOADING_FIRMWARE , true ) ;
2018-07-13 14:05:59 -04:00
if ( ret < 0 )
2019-06-17 14:23:54 -04:00
return false ;
2018-07-13 14:05:59 -04:00
2018-03-10 06:14:49 -08:00
return fw_force_sysfs_fallback ( opt_flags ) ;
}
2018-05-10 13:08:40 -07:00
/**
* firmware_fallback_sysfs ( ) - use the fallback mechanism to find firmware
* @ fw : pointer to firmware image
* @ name : name of firmware file to look for
* @ device : device for which firmware is being loaded
2020-10-06 15:21:33 +02:00
* @ opt_flags : options to control firmware loading behaviour , as defined by
* & enum fw_opt
2018-05-10 13:08:40 -07:00
* @ ret : return value from direct lookup which triggered the fallback mechanism
*
* This function is called if direct lookup for the firmware failed , it enables
* a fallback mechanism through userspace by exposing a sysfs loading
2019-04-30 16:56:10 +02:00
* interface . Userspace is in charge of loading the firmware through the sysfs
* loading interface . This sysfs fallback mechanism may be disabled completely
2018-05-10 13:08:40 -07:00
* on a system by setting the proc sysctl value ignore_sysfs_fallback to true .
2020-01-15 17:35:47 +01:00
* If this is false we check if the internal API caller set the
* @ FW_OPT_NOFALLBACK_SYSFS flag , if so it would also disable the fallback
* mechanism . A system may want to enforce the sysfs fallback mechanism at all
* times , it can do this by setting ignore_sysfs_fallback to false and
* force_sysfs_fallback to true .
2018-05-10 13:08:40 -07:00
* Enabling force_sysfs_fallback is functionally equivalent to build a kernel
* with CONFIG_FW_LOADER_USER_HELPER_FALLBACK .
* */
2018-05-10 13:08:39 -07:00
int firmware_fallback_sysfs ( struct firmware * fw , const char * name ,
struct device * device ,
2020-05-22 16:12:02 -07:00
u32 opt_flags ,
2018-05-10 13:08:39 -07:00
int ret )
2018-03-10 06:14:49 -08:00
{
if ( ! fw_run_sysfs_fallback ( opt_flags ) )
return ret ;
2018-05-10 13:08:44 -07:00
if ( ! ( opt_flags & FW_OPT_NO_WARN ) )
2019-04-30 16:56:10 +02:00
dev_warn ( device , " Falling back to sysfs fallback for: %s \n " ,
2018-05-10 13:08:44 -07:00
name ) ;
else
dev_dbg ( device , " Falling back to sysfs fallback for: %s \n " ,
name ) ;
2018-03-10 06:14:49 -08:00
return fw_load_from_user_helper ( fw , name , device , opt_flags ) ;
}