firmware loader: store firmware name into devres list
This patch will store firmware name into devres list of the device which is requesting firmware loading, so that we can implement auto cache and uncache firmware for devices in need. Signed-off-by: Ming Lei <ming.lei@canonical.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
6f21a62a58
commit
f531f05ae9
|
@ -114,6 +114,11 @@ struct firmware_priv {
|
||||||
struct firmware *fw;
|
struct firmware *fw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fw_name_devm {
|
||||||
|
unsigned long magic;
|
||||||
|
char name[];
|
||||||
|
};
|
||||||
|
|
||||||
#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
|
#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
|
||||||
|
|
||||||
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
|
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
|
||||||
|
@ -590,6 +595,55 @@ static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
|
||||||
(unsigned int)buf->size);
|
(unsigned int)buf->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fw_name_devm_release(struct device *dev, void *res)
|
||||||
|
{
|
||||||
|
struct fw_name_devm *fwn = res;
|
||||||
|
|
||||||
|
if (fwn->magic == (unsigned long)&fw_cache)
|
||||||
|
pr_debug("%s: fw_name-%s devm-%p released\n",
|
||||||
|
__func__, fwn->name, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fw_devm_match(struct device *dev, void *res,
|
||||||
|
void *match_data)
|
||||||
|
{
|
||||||
|
struct fw_name_devm *fwn = res;
|
||||||
|
|
||||||
|
return (fwn->magic == (unsigned long)&fw_cache) &&
|
||||||
|
!strcmp(fwn->name, match_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fw_name_devm *fw_find_devm_name(struct device *dev,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct fw_name_devm *fwn;
|
||||||
|
|
||||||
|
fwn = devres_find(dev, fw_name_devm_release,
|
||||||
|
fw_devm_match, (void *)name);
|
||||||
|
return fwn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add firmware name into devres list */
|
||||||
|
static int fw_add_devm_name(struct device *dev, const char *name)
|
||||||
|
{
|
||||||
|
struct fw_name_devm *fwn;
|
||||||
|
|
||||||
|
fwn = fw_find_devm_name(dev, name);
|
||||||
|
if (fwn)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
|
||||||
|
strlen(name) + 1, GFP_KERNEL);
|
||||||
|
if (!fwn)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fwn->magic = (unsigned long)&fw_cache;
|
||||||
|
strcpy(fwn->name, name);
|
||||||
|
devres_add(dev, fwn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void _request_firmware_cleanup(const struct firmware **firmware_p)
|
static void _request_firmware_cleanup(const struct firmware **firmware_p)
|
||||||
{
|
{
|
||||||
release_firmware(*firmware_p);
|
release_firmware(*firmware_p);
|
||||||
|
@ -709,6 +763,16 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
|
||||||
if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
|
if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
|
||||||
retval = -ENOENT;
|
retval = -ENOENT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add firmware name into devres list so that we can auto cache
|
||||||
|
* and uncache firmware for device.
|
||||||
|
*
|
||||||
|
* f_dev->parent may has been deleted already, but the problem
|
||||||
|
* should be fixed in devres or driver core.
|
||||||
|
*/
|
||||||
|
if (!retval && f_dev->parent)
|
||||||
|
fw_add_devm_name(f_dev->parent, buf->fw_id);
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
retval = fw_map_pages_buf(buf);
|
retval = fw_map_pages_buf(buf);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue