Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 324374
b: refs/heads/master
c: f531f05
h: refs/heads/master
v: v3
  • Loading branch information
Ming Lei authored and Greg Kroah-Hartman committed Aug 16, 2012
1 parent 03c2dc0 commit 14b8b81
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6f21a62a58bc3c80cd8b05cacb55003cccd4863e
refs/heads/master: f531f05ae9437df5ba1ebd90017e4dd5526048e9
64 changes: 64 additions & 0 deletions trunk/drivers/base/firmware_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ struct firmware_priv {
struct firmware *fw;
};

struct fw_name_devm {
unsigned long magic;
char name[];
};

#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
Expand Down Expand Up @@ -590,6 +595,55 @@ static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
(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)
{
release_firmware(*firmware_p);
Expand Down Expand Up @@ -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))
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)
retval = fw_map_pages_buf(buf);

Expand Down

0 comments on commit 14b8b81

Please sign in to comment.