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

Commit 2cc9ac24 authored by Vikram Mulukutla's avatar Vikram Mulukutla Committed by Prasad Sodagudi
Browse files

firmware: Avoid caching firmware when FW_OPT_NOCACHE is set



When calling request_firmware_into_buf(), we pass the FW_OPT_NOCACHE
flag with the intent of skipping the caching mechanism of the
firmware loader. Unfortunately, that doesn't work, because
fw_lookup_and_allocate_buf() isn't told to _not_ add the struct
firmware_buf to the firmware cache (fwc) list. So when we call
request_firmware_into_buf() the second time, we find the buffer in
the cache and return it immediately without reloading.

This may break users of request_firmware_into_buf that are expecting
a fresh copy of the firmware to be reloaded into memory. The existing
copy may either be modified by drivers, remote processors or even
freed. Fix fw_lookup_and_allocate_buf to not add to the fwc list
if FW_OPT_NOCACHE is set, and also don't do the lookup in the list.

Fixes: 0e742e9271 ("firmware: provide infrastructure to make fw caching optional")

Change-Id: I39fa4657ab5993b2b8e39ac65000dfc1640db866
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
Signed-off-by: default avatarPrasad Sodagudi <psodagud@codeaurora.org>
parent 337c6c94
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -334,11 +334,12 @@ static struct firmware_buf *__fw_lookup_buf(const char *fw_name)
static int fw_lookup_and_allocate_buf(const char *fw_name,
				      struct firmware_cache *fwc,
				      struct firmware_buf **buf, void *dbuf,
				      size_t size)
				      size_t size, unsigned int opt_flags)
{
	struct firmware_buf *tmp;

	spin_lock(&fwc->lock);
	if (!(opt_flags & FW_OPT_NOCACHE)) {
		tmp = __fw_lookup_buf(fw_name);
		if (tmp) {
			kref_get(&tmp->ref);
@@ -346,8 +347,9 @@ static int fw_lookup_and_allocate_buf(const char *fw_name,
			*buf = tmp;
			return 1;
		}
	}
	tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
	if (tmp)
	if (tmp && !(opt_flags & FW_OPT_NOCACHE))
		list_add(&tmp->list, &fwc->head);
	spin_unlock(&fwc->lock);

@@ -1157,7 +1159,8 @@ static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { }
 */
static int
_request_firmware_prepare(struct firmware **firmware_p, const char *name,
			  struct device *device, void *dbuf, size_t size)
			  struct device *device, void *dbuf, size_t size,
			  unsigned int opt_flags)
{
	struct firmware *firmware;
	struct firmware_buf *buf;
@@ -1175,7 +1178,8 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
		return 0; /* assigned */
	}

	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size,
					opt_flags);

	/*
	 * bind with 'buf' now to avoid warning in failure path
@@ -1235,7 +1239,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
		goto out;
	}

	ret = _request_firmware_prepare(&fw, name, device, buf, size);
	ret = _request_firmware_prepare(&fw, name, device, buf, size,
					opt_flags);
	if (ret <= 0) /* error or already assigned */
		goto out;