aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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