diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/Kconfig | 90 | ||||
-rw-r--r-- | drivers/base/bus.c | 16 | ||||
-rw-r--r-- | drivers/base/core.c | 18 | ||||
-rw-r--r-- | drivers/base/dd.c | 8 | ||||
-rw-r--r-- | drivers/base/driver.c | 6 | ||||
-rw-r--r-- | drivers/base/firmware_loader/Kconfig | 154 | ||||
-rw-r--r-- | drivers/base/firmware_loader/fallback.c | 53 | ||||
-rw-r--r-- | drivers/base/firmware_loader/fallback.h | 18 | ||||
-rw-r--r-- | drivers/base/firmware_loader/firmware.h | 37 | ||||
-rw-r--r-- | drivers/base/firmware_loader/main.c | 57 | ||||
-rw-r--r-- | drivers/base/memory.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/testmode.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 1 |
14 files changed, 332 insertions, 138 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 29b0eb452b3a..3e63a900b330 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -70,81 +70,25 @@ config STANDALONE If unsure, say Y. config PREVENT_FIRMWARE_BUILD - bool "Prevent firmware from being built" + bool "Disable drivers features which enable custom firmware building" default y help - Say yes to avoid building firmware. Firmware is usually shipped - with the driver and only when updating the firmware should a - rebuild be made. - If unsure, say Y here. - -config FW_LOADER - tristate "Userspace firmware loading support" if EXPERT - default y - ---help--- - This option is provided for the case where none of the in-tree modules - require userspace firmware loading support, but a module built - out-of-tree does. - -config EXTRA_FIRMWARE - string "External firmware blobs to build into the kernel binary" - depends on FW_LOADER - help - Various drivers in the kernel source tree may require firmware, - which is generally available in your distribution's linux-firmware - package. - - The linux-firmware package should install firmware into - /lib/firmware/ on your system, so they can be loaded by userspace - helpers on request. - - This option allows firmware to be built into the kernel for the case - where the user either cannot or doesn't want to provide it from - userspace at runtime (for example, when the firmware in question is - required for accessing the boot device, and the user doesn't want to - use an initrd). - - This option is a string and takes the (space-separated) names of the - firmware files -- the same names that appear in MODULE_FIRMWARE() - and request_firmware() in the source. These files should exist under - the directory specified by the EXTRA_FIRMWARE_DIR option, which is - /lib/firmware by default. - - For example, you might set CONFIG_EXTRA_FIRMWARE="usb8388.bin", copy - the usb8388.bin file into /lib/firmware, and build the kernel. Then - any request_firmware("usb8388.bin") will be satisfied internally - without needing to call out to userspace. - - WARNING: If you include additional firmware files into your binary - kernel image that are not available under the terms of the GPL, - then it may be a violation of the GPL to distribute the resulting - image since it combines both GPL and non-GPL work. You should - consult a lawyer of your own before distributing such an image. - -config EXTRA_FIRMWARE_DIR - string "Firmware blobs root directory" - depends on EXTRA_FIRMWARE != "" - default "/lib/firmware" - help - This option controls the directory in which the kernel build system - looks for the firmware files listed in the EXTRA_FIRMWARE option. - -config FW_LOADER_USER_HELPER - bool - -config FW_LOADER_USER_HELPER_FALLBACK - bool "Fallback user-helper invocation for firmware loading" - depends on FW_LOADER - select FW_LOADER_USER_HELPER - help - This option enables / disables the invocation of user-helper - (e.g. udev) for loading firmware files as a fallback after the - direct file loading in kernel fails. The user-mode helper is - no longer required unless you have a special firmware file that - resides in a non-standard path. Moreover, the udev support has - been deprecated upstream. - - If you are unsure about this, say N here. + Say yes to disable driver features which enable building a custom + driver firmware at kernel build time. These drivers do not use the + kernel firmware API to load firmware (CONFIG_FW_LOADER), instead they + use their own custom loading mechanism. The required firmware is + usually shipped with the driver, building the driver firmware + should only be needed if you have an updated firmware source. + + Firmware should not be being built as part of kernel, these days + you should always prevent this and say Y here. There are only two + old drivers which enable building of its firmware at kernel build + time: + + o CONFIG_WANXL through CONFIG_WANXL_BUILD_FIRMWARE + o CONFIG_SCSI_AIC79XX through CONFIG_AIC79XX_BUILD_FIRMWARE + +source "drivers/base/firmware_loader/Kconfig" config WANT_DEV_COREDUMP bool diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ef6183306b40..8bfd27ec73d6 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -184,10 +184,10 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf, dev = bus_find_device_by_name(bus, NULL, buf); if (dev && dev->driver == drv) { - if (dev->parent) /* Needed for USB */ + if (dev->parent && dev->bus->need_parent_lock) device_lock(dev->parent); device_release_driver(dev); - if (dev->parent) + if (dev->parent && dev->bus->need_parent_lock) device_unlock(dev->parent); err = count; } @@ -211,12 +211,12 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, dev = bus_find_device_by_name(bus, NULL, buf); if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { - if (dev->parent) /* Needed for USB */ + if (dev->parent && bus->need_parent_lock) device_lock(dev->parent); device_lock(dev); err = driver_probe_device(drv, dev); device_unlock(dev); - if (dev->parent) + if (dev->parent && bus->need_parent_lock) device_unlock(dev->parent); if (err > 0) { @@ -735,10 +735,10 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, int ret = 0; if (!dev->driver) { - if (dev->parent) /* Needed for USB */ + if (dev->parent && dev->bus->need_parent_lock) device_lock(dev->parent); ret = device_attach(dev); - if (dev->parent) + if (dev->parent && dev->bus->need_parent_lock) device_unlock(dev->parent); } return ret < 0 ? ret : 0; @@ -770,10 +770,10 @@ EXPORT_SYMBOL_GPL(bus_rescan_devices); int device_reprobe(struct device *dev) { if (dev->driver) { - if (dev->parent) /* Needed for USB */ + if (dev->parent && dev->bus->need_parent_lock) device_lock(dev->parent); device_release_driver(dev); - if (dev->parent) + if (dev->parent && dev->bus->need_parent_lock) device_unlock(dev->parent); } return bus_rescan_devices_helper(dev, NULL); diff --git a/drivers/base/core.c b/drivers/base/core.c index ad7b50897bcc..36622b52e419 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1487,7 +1487,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) dir = kzalloc(sizeof(*dir), GFP_KERNEL); if (!dir) - return NULL; + return ERR_PTR(-ENOMEM); dir->class = class; kobject_init(&dir->kobj, &class_dir_ktype); @@ -1497,7 +1497,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); if (retval < 0) { kobject_put(&dir->kobj); - return NULL; + return ERR_PTR(retval); } return &dir->kobj; } @@ -1804,6 +1804,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) { + error = PTR_ERR(kobj); + goto parent_error; + } if (kobj) dev->kobj.parent = kobj; @@ -1902,6 +1906,7 @@ done: kobject_del(&dev->kobj); Error: cleanup_glue_dir(dev, glue_dir); +parent_error: put_device(parent); name_error: kfree(dev->p); @@ -2426,7 +2431,7 @@ static void device_create_release(struct device *dev) kfree(dev); } -static struct device * +static __printf(6, 0) struct device * device_create_groups_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, @@ -2704,7 +2709,7 @@ static int device_move_class_links(struct device *dev, /** * device_move - moves a device to a new parent * @dev: the pointer to the struct device to be moved - * @new_parent: the new parent of the device (can by NULL) + * @new_parent: the new parent of the device (can be NULL) * @dpm_order: how to reorder the dpm_list */ int device_move(struct device *dev, struct device *new_parent, @@ -2721,6 +2726,11 @@ int device_move(struct device *dev, struct device *new_parent, device_pm_lock(); new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); + goto out; + } pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), __func__, new_parent ? dev_name(new_parent) : "<NULL>"); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a41c91bfac0e..fb4e2df68d95 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -814,13 +814,13 @@ static int __driver_attach(struct device *dev, void *data) return ret; } /* ret > 0 means positive match */ - if (dev->parent) /* Needed for USB */ + if (dev->parent && dev->bus->need_parent_lock) device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); - if (dev->parent) + if (dev->parent && dev->bus->need_parent_lock) device_unlock(dev->parent); return 0; @@ -916,7 +916,7 @@ void device_release_driver_internal(struct device *dev, struct device_driver *drv, struct device *parent) { - if (parent) + if (parent && dev->bus->need_parent_lock) device_lock(parent); device_lock(dev); @@ -924,7 +924,7 @@ void device_release_driver_internal(struct device *dev, __device_release_driver(dev, parent); device_unlock(dev); - if (parent) + if (parent && dev->bus->need_parent_lock) device_unlock(parent); } diff --git a/drivers/base/driver.c b/drivers/base/driver.c index ba912558a510..857c8f1b876e 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -148,7 +148,11 @@ int driver_register(struct device_driver *drv) int ret; struct device_driver *other; - BUG_ON(!drv->bus->p); + if (!drv->bus->p) { + pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n", + drv->name, drv->bus->name); + return -EINVAL; + } if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig new file mode 100644 index 000000000000..eb15d976a9ea --- /dev/null +++ b/drivers/base/firmware_loader/Kconfig @@ -0,0 +1,154 @@ +menu "Firmware loader" + +config FW_LOADER + tristate "Firmware loading facility" if EXPERT + default y + help + This enables the firmware loading facility in the kernel. The kernel + will first look for built-in firmware, if it has any. Next, it will + look for the requested firmware in a series of filesystem paths: + + o firmware_class path module parameter or kernel boot param + o /lib/firmware/updates/UTS_RELEASE + o /lib/firmware/updates + o /lib/firmware/UTS_RELEASE + o /lib/firmware + + Enabling this feature only increases your kernel image by about + 828 bytes, enable this option unless you are certain you don't + need firmware. + + You typically want this built-in (=y) but you can also enable this + as a module, in which case the firmware_class module will be built. + You also want to be sure to enable this built-in if you are going to + enable built-in firmware (CONFIG_EXTRA_FIRMWARE). + +if FW_LOADER + +config EXTRA_FIRMWARE + string "Build named firmware blobs into the kernel binary" + help + Device drivers which require firmware can typically deal with + having the kernel load firmware from the various supported + /lib/firmware/ paths. This option enables you to build into the + kernel firmware files. Built-in firmware searches are preceded + over firmware lookups using your filesystem over the supported + /lib/firmware paths documented on CONFIG_FW_LOADER. + + This may be useful for testing or if the firmware is required early on + in boot and cannot rely on the firmware being placed in an initrd or + initramfs. + + This option is a string and takes the (space-separated) names of the + firmware files -- the same names that appear in MODULE_FIRMWARE() + and request_firmware() in the source. These files should exist under + the directory specified by the EXTRA_FIRMWARE_DIR option, which is + /lib/firmware by default. + + For example, you might set CONFIG_EXTRA_FIRMWARE="usb8388.bin", copy + the usb8388.bin file into /lib/firmware, and build the kernel. Then + any request_firmware("usb8388.bin") will be satisfied internally + inside the kernel without ever looking at your filesystem at runtime. + + WARNING: If you include additional firmware files into your binary + kernel image that are not available under the terms of the GPL, + then it may be a violation of the GPL to distribute the resulting + image since it combines both GPL and non-GPL work. You should + consult a lawyer of your own before distributing such an image. + +config EXTRA_FIRMWARE_DIR + string "Firmware blobs root directory" + depends on EXTRA_FIRMWARE != "" + default "/lib/firmware" + help + This option controls the directory in which the kernel build system + looks for the firmware files listed in the EXTRA_FIRMWARE option. + +config FW_LOADER_USER_HELPER + bool "Enable the firmware sysfs fallback mechanism" + help + This option enables a sysfs loading facility to enable firmware + loading to the kernel through userspace as a fallback mechanism + if and only if the kernel's direct filesystem lookup for the + firmware failed using the different /lib/firmware/ paths, or the + path specified in the firmware_class path module parameter, or the + firmware_class path kernel boot parameter if the firmware_class is + built-in. For details on how to work with the sysfs fallback mechanism + refer to Documentation/driver-api/firmware/fallback-mechanisms.rst. + + The direct filesystem lookup for firmware is always used first now. + + If the kernel's direct filesystem lookup for firmware fails to find + the requested firmware a sysfs fallback loading facility is made + available and userspace is informed about this through uevents. + The uevent can be suppressed if the driver explicitly requested it, + this is known as the driver using the custom fallback mechanism. + If the custom fallback mechanism is used userspace must always + acknowledge failure to find firmware as the timeout for the fallback + mechanism is disabled, and failed requests will linger forever. + + This used to be the default firmware loading facility, and udev used + to listen for uvents to load firmware for the kernel. The firmware + loading facility functionality in udev has been removed, as such it + can no longer be relied upon as a fallback mechanism. Linux no longer + relies on or uses a fallback mechanism in userspace. If you need to + rely on one refer to the permissively licensed firmwared: + + https://github.com/teg/firmwared + + Since this was the default firmware loading facility at one point, + old userspace may exist which relies upon it, and as such this + mechanism can never be removed from the kernel. + + You should only enable this functionality if you are certain you + require a fallback mechanism and have a userspace mechanism ready to + load firmware in case it is not found. One main reason for this may + be if you have drivers which require firmware built-in and for + whatever reason cannot place the required firmware in initramfs. + Another reason kernels may have this feature enabled is to support a + driver which explicitly relies on this fallback mechanism. Only two + drivers need this today: + + o CONFIG_LEDS_LP55XX_COMMON + o CONFIG_DELL_RBU + + Outside of supporting the above drivers, another reason for needing + this may be that your firmware resides outside of the paths the kernel + looks for and cannot possibly be specified using the firmware_class + path module parameter or kernel firmware_class path boot parameter + if firmware_class is built-in. + + A modern use case may be to temporarily mount a custom partition + during provisioning which is only accessible to userspace, and then + to use it to look for and fetch the required firmware. Such type of + driver functionality may not even ever be desirable upstream by + vendors, and as such is only required to be supported as an interface + for provisioning. Since udev's firmware loading facility has been + removed you can use firmwared or a fork of it to customize how you + want to load firmware based on uevents issued. + + Enabling this option will increase your kernel image size by about + 13436 bytes. + + If you are unsure about this, say N here, unless you are Linux + distribution and need to support the above two drivers, or you are + certain you need to support some really custom firmware loading + facility in userspace. + +config FW_LOADER_USER_HELPER_FALLBACK + bool "Force the firmware sysfs fallback mechanism when possible" + depends on FW_LOADER_USER_HELPER + help + Enabling this option forces a sysfs userspace fallback mechanism + to be used for all firmware requests which explicitly do not disable a + a fallback mechanism. Firmware calls which do prohibit a fallback + mechanism is request_firmware_direct(). This option is kept for + backward compatibility purposes given this precise mechanism can also + be enabled by setting the proc sysctl value to true: + + /proc/sys/kernel/firmware_config/force_sysfs_fallback + + If you are unsure about this, say N here. + +endif # FW_LOADER +endmenu diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 358354148dec..b676a99c469c 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -125,7 +125,7 @@ static ssize_t timeout_show(struct class *class, struct class_attribute *attr, } /** - * firmware_timeout_store - set number of seconds to wait for firmware + * firmware_timeout_store() - set number of seconds to wait for firmware * @class: device class pointer * @attr: device attribute pointer * @buf: buffer to scan for timeout value @@ -239,7 +239,7 @@ static int map_fw_priv_pages(struct fw_priv *fw_priv) } /** - * firmware_loading_store - set value in the 'loading' control file + * firmware_loading_store() - set value in the 'loading' control file * @dev: device pointer * @attr: device attribute pointer * @buf: buffer to scan for loading control value @@ -431,7 +431,7 @@ static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) } /** - * firmware_data_write - write method for firmware + * firmware_data_write() - write method for firmware * @filp: open sysfs file * @kobj: kobject for the device * @bin_attr: bin_attr structure @@ -512,7 +512,7 @@ static const struct attribute_group *fw_dev_attr_groups[] = { static struct fw_sysfs * fw_create_instance(struct firmware *firmware, const char *fw_name, - struct device *device, unsigned int opt_flags) + struct device *device, enum fw_opt opt_flags) { struct fw_sysfs *fw_sysfs; struct device *f_dev; @@ -537,7 +537,7 @@ exit: } /** - * fw_load_sysfs_fallback - load a firmware via the sysfs fallback mechanism + * fw_load_sysfs_fallback() - load a firmware via the sysfs fallback mechanism * @fw_sysfs: firmware sysfs information for the firmware to load * @opt_flags: flags of options, FW_OPT_* * @timeout: timeout to wait for the load @@ -545,7 +545,7 @@ exit: * In charge of constructing a sysfs fallback interface for firmware loading. **/ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, - unsigned int opt_flags, long timeout) + enum fw_opt opt_flags, long timeout) { int retval = 0; struct device *f_dev = &fw_sysfs->dev; @@ -599,7 +599,7 @@ err_put_dev: static int fw_load_from_user_helper(struct firmware *firmware, const char *name, struct device *device, - unsigned int opt_flags) + enum fw_opt opt_flags) { struct fw_sysfs *fw_sysfs; long timeout; @@ -640,7 +640,7 @@ out_unlock: return ret; } -static bool fw_force_sysfs_fallback(unsigned int opt_flags) +static bool fw_force_sysfs_fallback(enum fw_opt opt_flags) { if (fw_fallback_config.force_sysfs_fallback) return true; @@ -649,7 +649,7 @@ static bool fw_force_sysfs_fallback(unsigned int opt_flags) return true; } -static bool fw_run_sysfs_fallback(unsigned int opt_flags) +static bool fw_run_sysfs_fallback(enum fw_opt opt_flags) { if (fw_fallback_config.ignore_sysfs_fallback) { pr_info_once("Ignoring firmware sysfs fallback due to sysctl knob\n"); @@ -662,14 +662,39 @@ static bool fw_run_sysfs_fallback(unsigned int opt_flags) return fw_force_sysfs_fallback(opt_flags); } -int fw_sysfs_fallback(struct firmware *fw, const char *name, - struct device *device, - unsigned int opt_flags, - int ret) +/** + * 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 + * @opt_flags: options to control firmware loading behaviour + * @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 + * interface. Userspace is in charge of loading the firmware through the syfs + * loading interface. This syfs fallback mechanism may be disabled completely + * on a system by setting the proc sysctl value ignore_sysfs_fallback to true. + * If this false we check if the internal API caller set the @FW_OPT_NOFALLBACK + * flag, if so it would also disable the fallback mechanism. A system may want + * to enfoce the sysfs fallback mechanism at all times, it can do this by + * setting ignore_sysfs_fallback to false and force_sysfs_fallback to true. + * Enabling force_sysfs_fallback is functionally equivalent to build a kernel + * with CONFIG_FW_LOADER_USER_HELPER_FALLBACK. + **/ +int firmware_fallback_sysfs(struct firmware *fw, const char *name, + struct device *device, + enum fw_opt opt_flags, + int ret) { if (!fw_run_sysfs_fallback(opt_flags)) return ret; - dev_warn(device, "Falling back to user helper\n"); + if (!(opt_flags & FW_OPT_NO_WARN)) + dev_warn(device, "Falling back to syfs fallback for: %s\n", + name); + else + dev_dbg(device, "Falling back to sysfs fallback for: %s\n", + name); return fw_load_from_user_helper(fw, name, device, opt_flags); } diff --git a/drivers/base/firmware_loader/fallback.h b/drivers/base/firmware_loader/fallback.h index f8255670a663..21063503e4ea 100644 --- a/drivers/base/firmware_loader/fallback.h +++ b/drivers/base/firmware_loader/fallback.h @@ -5,6 +5,8 @@ #include <linux/firmware.h> #include <linux/device.h> +#include "firmware.h" + /** * struct firmware_fallback_config - firmware fallback configuration settings * @@ -29,10 +31,10 @@ struct firmware_fallback_config { }; #ifdef CONFIG_FW_LOADER_USER_HELPER -int fw_sysfs_fallback(struct firmware *fw, const char *name, - struct device *device, - unsigned int opt_flags, - int ret); +int firmware_fallback_sysfs(struct firmware *fw, const char *name, + struct device *device, + enum fw_opt opt_flags, + int ret); void kill_pending_fw_fallback_reqs(bool only_kill_custom); void fw_fallback_set_cache_timeout(void); @@ -41,10 +43,10 @@ void fw_fallback_set_default_timeout(void); int register_sysfs_loader(void); void unregister_sysfs_loader(void); #else /* CONFIG_FW_LOADER_USER_HELPER */ -static inline int fw_sysfs_fallback(struct firmware *fw, const char *name, - struct device *device, - unsigned int opt_flags, - int ret) +static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name, + struct device *device, + enum fw_opt opt_flags, + int ret) { /* Keep carrying over the same error */ return ret; diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 64acbb1a392c..4c1395f8e7ed 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -2,6 +2,7 @@ #ifndef __FIRMWARE_LOADER_H #define __FIRMWARE_LOADER_H +#include <linux/bitops.h> #include <linux/firmware.h> #include <linux/types.h> #include <linux/kref.h> @@ -10,13 +11,33 @@ #include <generated/utsrelease.h> -/* firmware behavior options */ -#define FW_OPT_UEVENT (1U << 0) -#define FW_OPT_NOWAIT (1U << 1) -#define FW_OPT_USERHELPER (1U << 2) -#define FW_OPT_NO_WARN (1U << 3) -#define FW_OPT_NOCACHE (1U << 4) -#define FW_OPT_NOFALLBACK (1U << 5) +/** + * enum fw_opt - options to control firmware loading behaviour + * + * @FW_OPT_UEVENT: Enables the fallback mechanism to send a kobject uevent + * when the firmware is not found. Userspace is in charge to load the + * firmware using the sysfs loading facility. + * @FW_OPT_NOWAIT: Used to describe the firmware request is asynchronous. + * @FW_OPT_USERHELPER: Enable the fallback mechanism, in case the direct + * filesystem lookup fails at finding the firmware. For details refer to + * firmware_fallback_sysfs(). + * @FW_OPT_NO_WARN: Quiet, avoid printing warning messages. + * @FW_OPT_NOCACHE: Disables firmware caching. Firmware caching is used to + * cache the firmware upon suspend, so that upon resume races against the + * firmware file lookup on storage is avoided. Used for calls where the + * file may be too big, or where the driver takes charge of its own + * firmware caching mechanism. + * @FW_OPT_NOFALLBACK: Disable the fallback mechanism. Takes precedence over + * &FW_OPT_UEVENT and &FW_OPT_USERHELPER. + */ +enum fw_opt { + FW_OPT_UEVENT = BIT(0), + FW_OPT_NOWAIT = BIT(1), + FW_OPT_USERHELPER = BIT(2), + FW_OPT_NO_WARN = BIT(3), + FW_OPT_NOCACHE = BIT(4), + FW_OPT_NOFALLBACK = BIT(5), +}; enum fw_status { FW_STATUS_UNKNOWN, @@ -110,6 +131,6 @@ static inline void fw_state_done(struct fw_priv *fw_priv) } int assign_fw(struct firmware *fw, struct device *device, - unsigned int opt_flags); + enum fw_opt opt_flags); #endif /* __FIRMWARE_LOADER_H */ diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index eb34089e4299..0943e7065e0e 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -443,7 +443,7 @@ static int fw_add_devm_name(struct device *dev, const char *name) #endif int assign_fw(struct firmware *fw, struct device *device, - unsigned int opt_flags) + enum fw_opt opt_flags) { struct fw_priv *fw_priv = fw->priv; int ret; @@ -558,7 +558,7 @@ static void fw_abort_batch_reqs(struct firmware *fw) static int _request_firmware(const struct firmware **firmware_p, const char *name, struct device *device, void *buf, size_t size, - unsigned int opt_flags) + enum fw_opt opt_flags) { struct firmware *fw = NULL; int ret; @@ -581,7 +581,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name, dev_warn(device, "Direct firmware load for %s failed with error %d\n", name, ret); - ret = fw_sysfs_fallback(fw, name, device, opt_flags, ret); + ret = firmware_fallback_sysfs(fw, name, device, opt_flags, ret); } else ret = assign_fw(fw, device, opt_flags); @@ -597,7 +597,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name, } /** - * request_firmware: - send firmware request and wait for it + * request_firmware() - send firmware request and wait for it * @firmware_p: pointer to firmware image * @name: name of firmware file * @device: device for which firmware is being loaded @@ -632,7 +632,34 @@ request_firmware(const struct firmware **firmware_p, const char *name, EXPORT_SYMBOL(request_firmware); /** - * request_firmware_direct: - load firmware directly without usermode helper + * firmware_request_nowarn() - request for an optional fw module + * @firmware: pointer to firmware image + * @name: name of firmware file + * @device: device for which firmware is being loaded + * + * This function is similar in behaviour to request_firmware(), except + * it doesn't produce warning messages when the file is not found. + * The sysfs fallback mechanism is enabled if direct filesystem lookup fails, + * however, however failures to find the firmware file with it are still + * suppressed. It is therefore up to the driver to check for the return value + * of this call and to decide when to inform the users of errors. + **/ +int firmware_request_nowarn(const struct firmware **firmware, const char *name, + struct device *device) +{ + int ret; + + /* Need to pin this module until return */ + __module_get(THIS_MODULE); + ret = _request_firmware(firmware, name, device, NULL, 0, + FW_OPT_UEVENT | FW_OPT_NO_WARN); + module_put(THIS_MODULE); + return ret; +} +EXPORT_SYMBOL_GPL(firmware_request_nowarn); + +/** + * request_firmware_direct() - 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 @@ -657,7 +684,7 @@ int request_firmware_direct(const struct firmware **firmware_p, EXPORT_SYMBOL_GPL(request_firmware_direct); /** - * firmware_request_cache: - cache firmware for suspend so resume can use it + * firmware_request_cache() - cache firmware for suspend so resume can use it * @name: name of firmware file * @device: device for which firmware should be cached for * @@ -681,7 +708,7 @@ int firmware_request_cache(struct device *device, const char *name) EXPORT_SYMBOL_GPL(firmware_request_cache); /** - * request_firmware_into_buf - load firmware into a previously allocated buffer + * request_firmware_into_buf() - load firmware into a previously allocated buffer * @firmware_p: pointer to firmware image * @name: name of firmware file * @device: device for which firmware is being loaded and DMA region allocated @@ -713,7 +740,7 @@ request_firmware_into_buf(const struct firmware **firmware_p, const char *name, EXPORT_SYMBOL(request_firmware_into_buf); /** - * release_firmware: - release the resource associated with a firmware image + * release_firmware() - release the resource associated with a firmware image * @fw: firmware resource to release **/ void release_firmware(const struct firmware *fw) @@ -734,7 +761,7 @@ struct firmware_work { struct device *device; void *context; void (*cont)(const struct firmware *fw, void *context); - unsigned int opt_flags; + enum fw_opt opt_flags; }; static void request_firmware_work_func(struct work_struct *work) @@ -755,7 +782,7 @@ 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. @@ -824,7 +851,7 @@ EXPORT_SYMBOL(request_firmware_nowait); static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); /** - * cache_firmware - cache one firmware image in kernel memory space + * cache_firmware() - cache one firmware image in kernel memory space * @fw_name: the firmware image name * * Cache firmware in kernel memory so that drivers can use it when @@ -866,7 +893,7 @@ static struct fw_priv *lookup_fw_priv(const char *fw_name) } /** - * uncache_firmware - remove one cached firmware image + * uncache_firmware() - remove one cached firmware image * @fw_name: the firmware image name * * Uncache one firmware image which has been cached successfully @@ -1042,7 +1069,7 @@ static void __device_uncache_fw_images(void) } /** - * device_cache_fw_images - cache devices' firmware + * device_cache_fw_images() - cache devices' firmware * * If one device called request_firmware or its nowait version * successfully before, the firmware names are recored into the @@ -1075,7 +1102,7 @@ static void device_cache_fw_images(void) } /** - * device_uncache_fw_images - uncache devices' firmware + * device_uncache_fw_images() - uncache devices' firmware * * uncache all firmwares which have been cached successfully * by device_uncache_fw_images earlier @@ -1092,7 +1119,7 @@ static void device_uncache_fw_images_work(struct work_struct *work) } /** - * device_uncache_fw_images_delay - uncache devices firmwares + * device_uncache_fw_images_delay() - uncache devices firmwares * @delay: number of milliseconds to delay uncache device firmwares * * uncache all devices's firmwares which has been cached successfully diff --git a/drivers/base/memory.c b/drivers/base/memory.c index bffe8616bd55..f5e560188a18 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -649,13 +649,19 @@ static const struct attribute_group *memory_memblk_attr_groups[] = { static int register_memory(struct memory_block *memory) { + int ret; + memory->dev.bus = &memory_subsys; memory->dev.id = memory->start_section_nr / sections_per_block; memory->dev.release = memory_block_release; memory->dev.groups = memory_memblk_attr_groups; memory->dev.offline = memory->state == MEM_OFFLINE; - return device_register(&memory->dev); + ret = device_register(&memory->dev); + if (ret) + put_device(&memory->dev); + + return ret; } static int init_memory_block(struct memory_block **memory, diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 8a3020dbd4cf..936907227b9e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -653,7 +653,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, dir = "."; snprintf(filename, sizeof(filename), "%s/%s", dir, file); - ret = request_firmware(&fw, filename, ar->dev); + ret = firmware_request_nowarn(&fw, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", filename, ret); diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index 568810b41657..c24ee616833c 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -157,7 +157,7 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar, ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE); /* load utf firmware image */ - ret = request_firmware_direct(&fw_file->firmware, filename, ar->dev); + ret = firmware_request_nowarn(&fw_file->firmware, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n", filename, ret); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9792cedfc351..e76e95f62f76 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1922,4 +1922,5 @@ struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .uevent = usb_uevent, + .need_parent_lock = true, }; |