aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-08-04 00:01:25 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 16:28:50 -0400
commitf531f05ae9437df5ba1ebd90017e4dd5526048e9 (patch)
tree521f6c0009ceb08ace740a185faf525677ec6bd9
parent6f21a62a58bc3c80cd8b05cacb55003cccd4863e (diff)
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>
-rw-r--r--drivers/base/firmware_class.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a47266ccfc60..65c60666685b 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -114,6 +114,11 @@ struct firmware_priv {
114 struct firmware *fw; 114 struct firmware *fw;
115}; 115};
116 116
117struct fw_name_devm {
118 unsigned long magic;
119 char name[];
120};
121
117#define to_fwbuf(d) container_of(d, struct firmware_buf, ref) 122#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
118 123
119/* fw_lock could be moved to 'struct firmware_priv' but since it is just 124/* 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)
590 (unsigned int)buf->size); 595 (unsigned int)buf->size);
591} 596}
592 597
598static void fw_name_devm_release(struct device *dev, void *res)
599{
600 struct fw_name_devm *fwn = res;
601
602 if (fwn->magic == (unsigned long)&fw_cache)
603 pr_debug("%s: fw_name-%s devm-%p released\n",
604 __func__, fwn->name, res);
605}
606
607static int fw_devm_match(struct device *dev, void *res,
608 void *match_data)
609{
610 struct fw_name_devm *fwn = res;
611
612 return (fwn->magic == (unsigned long)&fw_cache) &&
613 !strcmp(fwn->name, match_data);
614}
615
616static struct fw_name_devm *fw_find_devm_name(struct device *dev,
617 const char *name)
618{
619 struct fw_name_devm *fwn;
620
621 fwn = devres_find(dev, fw_name_devm_release,
622 fw_devm_match, (void *)name);
623 return fwn;
624}
625
626/* add firmware name into devres list */
627static int fw_add_devm_name(struct device *dev, const char *name)
628{
629 struct fw_name_devm *fwn;
630
631 fwn = fw_find_devm_name(dev, name);
632 if (fwn)
633 return 1;
634
635 fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
636 strlen(name) + 1, GFP_KERNEL);
637 if (!fwn)
638 return -ENOMEM;
639
640 fwn->magic = (unsigned long)&fw_cache;
641 strcpy(fwn->name, name);
642 devres_add(dev, fwn);
643
644 return 0;
645}
646
593static void _request_firmware_cleanup(const struct firmware **firmware_p) 647static void _request_firmware_cleanup(const struct firmware **firmware_p)
594{ 648{
595 release_firmware(*firmware_p); 649 release_firmware(*firmware_p);
@@ -709,6 +763,16 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
709 if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status)) 763 if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
710 retval = -ENOENT; 764 retval = -ENOENT;
711 765
766 /*
767 * add firmware name into devres list so that we can auto cache
768 * and uncache firmware for device.
769 *
770 * f_dev->parent may has been deleted already, but the problem
771 * should be fixed in devres or driver core.
772 */
773 if (!retval && f_dev->parent)
774 fw_add_devm_name(f_dev->parent, buf->fw_id);
775
712 if (!retval) 776 if (!retval)
713 retval = fw_map_pages_buf(buf); 777 retval = fw_map_pages_buf(buf);
714 778