From: Jaswinder Singh <jaswinder@infradead.org>
To: LKML <linux-kernel@vger.kernel.org>,
David Woodhouse <dwmw2@infradead.org>
Subject: [PATCH] firmware: avoiding multiple replication for same firmware file
Date: Fri, 01 Aug 2008 11:30:59 +0530 [thread overview]
Message-ID: <1217570459.2902.1.camel@jaswinder.satnam> (raw)
Now when request_firmware will be called it will check whether firmware
is already allocated or not. If already allocated then it provide handle
of old firmware handle and increase count of firmware.
release_firmware will decrease count of firmware, if count is one only then
firmware will be release.
Added release_firmware_all() can be called from driver cleanup or exit
to release firmware forcefully.
Signed-off-by: Jaswinder Singh <jaswinder@infradead.org>
---
drivers/base/firmware_class.c | 112 ++++++++++++++++++++++++++++++++++++-----
include/linux/firmware.h | 5 ++
2 files changed, 104 insertions(+), 13 deletions(-)
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b0be1d1..9743a3d 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -49,6 +49,15 @@ struct firmware_priv {
struct timer_list timeout;
};
+struct firmware_list {
+ const struct firmware *fw;
+ char *name;
+ int count;
+ struct list_head list;
+};
+
+static struct firmware_list firmwarelist;
+
#ifdef CONFIG_FW_LOADER
extern struct builtin_fw __start_builtin_fw[];
extern struct builtin_fw __end_builtin_fw[];
@@ -400,11 +409,21 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
struct firmware_priv *fw_priv;
struct firmware *firmware;
struct builtin_fw *builtin;
+ struct firmware_list *tmp;
int retval;
if (!firmware_p)
return -EINVAL;
+ /* Return firmware pointer from firmware list if already allocated */
+ list_for_each_entry(tmp, &firmwarelist.list, list) {
+ if (strcmp(name, tmp->name) == 0) {
+ tmp->count++;
+ *firmware_p = tmp->fw;
+ break;
+ }
+ }
+
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
@@ -413,6 +432,27 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
goto out;
}
+ tmp = kzalloc(sizeof(struct firmware_list), GFP_KERNEL);
+ if (!tmp) {
+ printk(KERN_ERR "%s: kmalloc(struct firmware_list) failed\n",
+ __func__);
+ retval = -ENOMEM;
+ goto error_kfree_fw;
+ }
+
+ tmp->name = kzalloc(strlen(name), GFP_KERNEL);
+ if (!tmp->name) {
+ printk(KERN_ERR "%s: kmalloc firmware_list->name failed\n",
+ __func__);
+ retval = -ENOMEM;
+ goto error_kfree_fw_list;
+ }
+
+ tmp->fw = *firmware_p;
+ tmp->count = 1;
+ strcpy(tmp->name, name);
+ list_add(&(tmp->list), &(firmwarelist.list));
+
for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
builtin++) {
if (strcmp(name, builtin->name))
@@ -429,7 +469,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
if (retval)
- goto error_kfree_fw;
+ goto error_kfree_fw_name;
fw_priv = dev_get_drvdata(f_dev);
@@ -451,12 +491,20 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
retval = -ENOENT;
release_firmware(fw_priv->fw);
*firmware_p = NULL;
+ list_del(&tmp->list);
+ kfree(tmp->name);
+ kfree(tmp);
}
fw_priv->fw = NULL;
mutex_unlock(&fw_lock);
device_unregister(f_dev);
goto out;
+error_kfree_fw_name:
+ list_del(&tmp->list);
+ kfree(tmp->name);
+error_kfree_fw_list:
+ kfree(tmp);
error_kfree_fw:
kfree(firmware);
*firmware_p = NULL;
@@ -487,24 +535,60 @@ request_firmware(const struct firmware **firmware_p, const char *name,
return _request_firmware(firmware_p, name, device, uevent);
}
-/**
+static void __release_firmware(const struct firmware *fw,
+ struct firmware_list *tmp)
+{
+ struct builtin_fw *builtin;
+
+ for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
+ builtin++) {
+ if (fw->data == builtin->data)
+ goto free_fw;
+ }
+ vfree(fw->data);
+free_fw:
+ kfree(fw);
+ list_del(&tmp->list);
+ kfree(tmp->name);
+ kfree(tmp);
+}
+
+/*
* release_firmware: - release the resource associated with a firmware image
* @fw: firmware resource to release
- **/
-void
-release_firmware(const struct firmware *fw)
+ */
+void release_firmware(const struct firmware *fw)
{
- struct builtin_fw *builtin;
+ struct firmware_list *tmp;
if (fw) {
- for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
- builtin++) {
- if (fw->data == builtin->data)
- goto free_fw;
+ list_for_each_entry(tmp, &firmwarelist.list, list) {
+ if (fw == tmp->fw) {
+ if (tmp->count > 1) {
+ tmp->count--;
+ return;
+ } else
+ break;
+ }
}
- vfree(fw->data);
- free_fw:
- kfree(fw);
+ __release_firmware(fw, tmp);
+ }
+}
+
+/*
+ * release_firmware_all: - release the resource associated with a firmware
+ * image forcefully
+ * @fw: firmware resource to release
+ */
+void release_firmware_all(const struct firmware *fw)
+{
+ struct firmware_list *tmp;
+
+ if (fw) {
+ list_for_each_entry(tmp, &firmwarelist.list, list)
+ if (fw == tmp->fw)
+ break;
+ __release_firmware(fw, tmp);
}
}
@@ -610,6 +694,8 @@ firmware_class_init(void)
__func__);
class_unregister(&firmware_class);
}
+
+ INIT_LIST_HEAD(&firmwarelist.list);
return error;
}
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index c8ecf5b..238f1e4 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -43,6 +43,7 @@ int request_firmware_nowait(
void (*cont)(const struct firmware *fw, void *context));
void release_firmware(const struct firmware *fw);
+void release_firmware_all(const struct firmware *fw);
#else
static inline int request_firmware(const struct firmware **fw,
const char *name,
@@ -61,6 +62,10 @@ static inline int request_firmware_nowait(
static inline void release_firmware(const struct firmware *fw)
{
}
+
+static inline void release_firmware_all(const struct firmware *fw)
+{
+}
#endif
#endif
--
1.5.5.1
next reply other threads:[~2008-08-01 6:02 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-08-01 6:00 Jaswinder Singh [this message]
2008-08-01 20:04 ` [PATCH] firmware: avoiding multiple replication for same firmware file David Woodhouse
2008-08-05 21:03 ` Andrew Morton
2008-08-06 9:35 ` Jaswinder Singh
2008-08-06 9:46 ` Jaswinder Singh
2008-08-06 10:16 ` Jaswinder Singh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1217570459.2902.1.camel@jaswinder.satnam \
--to=jaswinder@infradead.org \
--cc=dwmw2@infradead.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox