Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7c870ae authored by Vikram Mulukutla's avatar Vikram Mulukutla Committed by David Keitel
Browse files

firmware_class: Provide infrastructure to make fw caching optional



Some low memory systems with complex peripherals cannot
afford to have the relatively large firmware images taking
up valuable memory during suspend and resume. Change the
internal implementation of firmware_class to disallow
caching based on a configurable option. In the near future,
variants of request_firmware will take advantage of this
configurability.

Change-Id: I44be7ce3b308b642fb018086def99fcb800a1109
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
[joshc: reworked to use opt_flags instead of 'nocache' bool in fw_desc]
Signed-off-by: default avatarJosh Cartwright <joshc@codeaurora.org>
[vmulukut: adjusted for upstream additions to opt_flags]
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
parent 7fcfead5
Loading
Loading
Loading
Loading
+21 −5
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ static inline long firmware_loading_timeout(void)
#define FW_OPT_FALLBACK		0
#endif
#define FW_OPT_NO_WARN	(1U << 3)
#define FW_OPT_NOCACHE	(1U << 4)

struct firmware_cache {
	/* firmware_buf instance will be added into the below list */
@@ -1072,6 +1073,14 @@ _request_firmware_prepare(struct firmware **firmware_p, struct fw_desc *desc)
		return 0; /* assigned */
	}

	if (desc->opt_flags & FW_OPT_NOCACHE) {
		buf = __allocate_fw_buf(desc->name, NULL);
		if (!buf)
			return -ENOMEM;
		firmware->priv = buf;
		return 1;
	}

	ret = fw_lookup_and_allocate_buf(desc->name, &fw_cache, &buf);

	/*
@@ -1111,15 +1120,19 @@ 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.
	 */
	/* don't cache firmware handled without uevent */
	if (device && (opt_flags & FW_OPT_UEVENT))
	/* don't cache firmware handled without uevent, or when explicitly
	 * disabled
	 */
	if (device && (opt_flags & FW_OPT_UEVENT)
	    && !(opt_flags & FW_OPT_NOCACHE))
		fw_add_devm_name(device, buf->fw_id);

	/*
	 * After caching firmware image is started, let it piggyback
	 * on request firmware.
	 */
	if (buf->fwc->state == FW_LOADER_START_CACHE) {
	if (!(opt_flags & FW_OPT_NOCACHE)
	    && (buf->fwc->state == FW_LOADER_START_CACHE)) {
		if (fw_cache_piggyback_on_request(buf->fw_id))
			kref_get(&buf->ref);
	}
@@ -1299,7 +1312,8 @@ 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))
	void (*cont)(const struct firmware *fw, void *context),
	bool nocache)
{
	struct fw_desc *desc;

@@ -1318,6 +1332,8 @@ _request_firmware_nowait(
		desc->opt_flags |= FW_OPT_UEVENT;
	else
		desc->opt_flags |= FW_OPT_USERHELPER;
	if (nocache)
		desc->opt_flags |= FW_OPT_NOCACHE;

	if (!try_module_get(module)) {
		kfree(desc);
@@ -1360,7 +1376,7 @@ request_firmware_nowait(
	void (*cont)(const struct firmware *fw, void *context))
{
	return _request_firmware_nowait(module, uevent, name, device, gfp,
					context, cont);
					context, cont, false);
}
EXPORT_SYMBOL(request_firmware_nowait);