diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-01-31 05:13:56 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-02-03 20:57:40 -0500 |
commit | cd7239fab7d32e56909027bfb5a6c2d7d3d862f8 (patch) | |
tree | d951829a1bf1461ced3e763c766310b78c6a4a7d /drivers/base | |
parent | 7b1269f778782d2f42994a74bf4014d0cbebbf9f (diff) |
firmware: Reduce ifdef CONFIG_FW_LOADER_USER_HELPER
By shuffling the code, reduce a few ifdefs in firmware_class.c.
Also, firmware_buf fmt field is changed to is_pages_buf boolean for
simplification.
Acked-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/firmware_class.c | 313 |
1 files changed, 151 insertions, 162 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 84b1c8d0ea56..51e62ca1d574 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -88,13 +88,6 @@ enum { | |||
88 | FW_STATUS_ABORT, | 88 | FW_STATUS_ABORT, |
89 | }; | 89 | }; |
90 | 90 | ||
91 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
92 | enum fw_buf_fmt { | ||
93 | VMALLOC_BUF, /* used in direct loading */ | ||
94 | PAGE_BUF, /* used in loading via userspace */ | ||
95 | }; | ||
96 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
97 | |||
98 | static int loading_timeout = 60; /* In seconds */ | 91 | static int loading_timeout = 60; /* In seconds */ |
99 | 92 | ||
100 | static inline long firmware_loading_timeout(void) | 93 | static inline long firmware_loading_timeout(void) |
@@ -133,7 +126,7 @@ struct firmware_buf { | |||
133 | void *data; | 126 | void *data; |
134 | size_t size; | 127 | size_t size; |
135 | #ifdef CONFIG_FW_LOADER_USER_HELPER | 128 | #ifdef CONFIG_FW_LOADER_USER_HELPER |
136 | enum fw_buf_fmt fmt; | 129 | bool is_paged_buf; |
137 | struct page **pages; | 130 | struct page **pages; |
138 | int nr_pages; | 131 | int nr_pages; |
139 | int page_array_size; | 132 | int page_array_size; |
@@ -146,16 +139,6 @@ struct fw_cache_entry { | |||
146 | char name[]; | 139 | char name[]; |
147 | }; | 140 | }; |
148 | 141 | ||
149 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
150 | struct firmware_priv { | ||
151 | struct delayed_work timeout_work; | ||
152 | bool nowait; | ||
153 | struct device dev; | ||
154 | struct firmware_buf *buf; | ||
155 | struct firmware *fw; | ||
156 | }; | ||
157 | #endif | ||
158 | |||
159 | struct fw_name_devm { | 142 | struct fw_name_devm { |
160 | unsigned long magic; | 143 | unsigned long magic; |
161 | char name[]; | 144 | char name[]; |
@@ -188,9 +171,6 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, | |||
188 | strcpy(buf->fw_id, fw_name); | 171 | strcpy(buf->fw_id, fw_name); |
189 | buf->fwc = fwc; | 172 | buf->fwc = fwc; |
190 | init_completion(&buf->completion); | 173 | init_completion(&buf->completion); |
191 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
192 | buf->fmt = VMALLOC_BUF; | ||
193 | #endif | ||
194 | 174 | ||
195 | pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); | 175 | pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); |
196 | 176 | ||
@@ -256,9 +236,8 @@ static void __fw_free_buf(struct kref *ref) | |||
256 | list_del(&buf->list); | 236 | list_del(&buf->list); |
257 | spin_unlock(&fwc->lock); | 237 | spin_unlock(&fwc->lock); |
258 | 238 | ||
259 | |||
260 | #ifdef CONFIG_FW_LOADER_USER_HELPER | 239 | #ifdef CONFIG_FW_LOADER_USER_HELPER |
261 | if (buf->fmt == PAGE_BUF) { | 240 | if (buf->is_paged_buf) { |
262 | int i; | 241 | int i; |
263 | vunmap(buf->data); | 242 | vunmap(buf->data); |
264 | for (i = 0; i < buf->nr_pages; i++) | 243 | for (i = 0; i < buf->nr_pages; i++) |
@@ -378,7 +357,89 @@ static void firmware_free_data(const struct firmware *fw) | |||
378 | fw_free_buf(fw->priv); | 357 | fw_free_buf(fw->priv); |
379 | } | 358 | } |
380 | 359 | ||
360 | /* store the pages buffer info firmware from buf */ | ||
361 | static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) | ||
362 | { | ||
363 | fw->priv = buf; | ||
364 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
365 | fw->pages = buf->pages; | ||
366 | #endif | ||
367 | fw->size = buf->size; | ||
368 | fw->data = buf->data; | ||
369 | |||
370 | pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", | ||
371 | __func__, buf->fw_id, buf, buf->data, | ||
372 | (unsigned int)buf->size); | ||
373 | } | ||
374 | |||
375 | #ifdef CONFIG_PM_SLEEP | ||
376 | static void fw_name_devm_release(struct device *dev, void *res) | ||
377 | { | ||
378 | struct fw_name_devm *fwn = res; | ||
379 | |||
380 | if (fwn->magic == (unsigned long)&fw_cache) | ||
381 | pr_debug("%s: fw_name-%s devm-%p released\n", | ||
382 | __func__, fwn->name, res); | ||
383 | } | ||
384 | |||
385 | static int fw_devm_match(struct device *dev, void *res, | ||
386 | void *match_data) | ||
387 | { | ||
388 | struct fw_name_devm *fwn = res; | ||
389 | |||
390 | return (fwn->magic == (unsigned long)&fw_cache) && | ||
391 | !strcmp(fwn->name, match_data); | ||
392 | } | ||
393 | |||
394 | static struct fw_name_devm *fw_find_devm_name(struct device *dev, | ||
395 | const char *name) | ||
396 | { | ||
397 | struct fw_name_devm *fwn; | ||
398 | |||
399 | fwn = devres_find(dev, fw_name_devm_release, | ||
400 | fw_devm_match, (void *)name); | ||
401 | return fwn; | ||
402 | } | ||
403 | |||
404 | /* add firmware name into devres list */ | ||
405 | static int fw_add_devm_name(struct device *dev, const char *name) | ||
406 | { | ||
407 | struct fw_name_devm *fwn; | ||
408 | |||
409 | fwn = fw_find_devm_name(dev, name); | ||
410 | if (fwn) | ||
411 | return 1; | ||
412 | |||
413 | fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) + | ||
414 | strlen(name) + 1, GFP_KERNEL); | ||
415 | if (!fwn) | ||
416 | return -ENOMEM; | ||
417 | |||
418 | fwn->magic = (unsigned long)&fw_cache; | ||
419 | strcpy(fwn->name, name); | ||
420 | devres_add(dev, fwn); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | #else | ||
425 | static int fw_add_devm_name(struct device *dev, const char *name) | ||
426 | { | ||
427 | return 0; | ||
428 | } | ||
429 | #endif | ||
430 | |||
431 | |||
432 | /* | ||
433 | * user-mode helper code | ||
434 | */ | ||
381 | #ifdef CONFIG_FW_LOADER_USER_HELPER | 435 | #ifdef CONFIG_FW_LOADER_USER_HELPER |
436 | struct firmware_priv { | ||
437 | struct delayed_work timeout_work; | ||
438 | bool nowait; | ||
439 | struct device dev; | ||
440 | struct firmware_buf *buf; | ||
441 | struct firmware *fw; | ||
442 | }; | ||
382 | 443 | ||
383 | static struct firmware_priv *to_firmware_priv(struct device *dev) | 444 | static struct firmware_priv *to_firmware_priv(struct device *dev) |
384 | { | 445 | { |
@@ -477,7 +538,7 @@ static ssize_t firmware_loading_show(struct device *dev, | |||
477 | /* one pages buffer should be mapped/unmapped only once */ | 538 | /* one pages buffer should be mapped/unmapped only once */ |
478 | static int fw_map_pages_buf(struct firmware_buf *buf) | 539 | static int fw_map_pages_buf(struct firmware_buf *buf) |
479 | { | 540 | { |
480 | if (buf->fmt != PAGE_BUF) | 541 | if (!buf->is_paged_buf) |
481 | return 0; | 542 | return 0; |
482 | 543 | ||
483 | if (buf->data) | 544 | if (buf->data) |
@@ -749,78 +810,89 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, | |||
749 | exit: | 810 | exit: |
750 | return fw_priv; | 811 | return fw_priv; |
751 | } | 812 | } |
752 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
753 | 813 | ||
754 | /* store the pages buffer info firmware from buf */ | 814 | /* load a firmware via user helper */ |
755 | static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) | 815 | static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, |
816 | long timeout) | ||
756 | { | 817 | { |
757 | fw->priv = buf; | 818 | int retval = 0; |
758 | #ifdef CONFIG_FW_LOADER_USER_HELPER | 819 | struct device *f_dev = &fw_priv->dev; |
759 | fw->pages = buf->pages; | 820 | struct firmware_buf *buf = fw_priv->buf; |
760 | #endif | ||
761 | fw->size = buf->size; | ||
762 | fw->data = buf->data; | ||
763 | 821 | ||
764 | pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", | 822 | /* fall back on userspace loading */ |
765 | __func__, buf->fw_id, buf, buf->data, | 823 | buf->is_paged_buf = true; |
766 | (unsigned int)buf->size); | ||
767 | } | ||
768 | 824 | ||
769 | #ifdef CONFIG_PM_SLEEP | 825 | dev_set_uevent_suppress(f_dev, true); |
770 | static void fw_name_devm_release(struct device *dev, void *res) | ||
771 | { | ||
772 | struct fw_name_devm *fwn = res; | ||
773 | 826 | ||
774 | if (fwn->magic == (unsigned long)&fw_cache) | 827 | /* Need to pin this module until class device is destroyed */ |
775 | pr_debug("%s: fw_name-%s devm-%p released\n", | 828 | __module_get(THIS_MODULE); |
776 | __func__, fwn->name, res); | ||
777 | } | ||
778 | 829 | ||
779 | static int fw_devm_match(struct device *dev, void *res, | 830 | retval = device_add(f_dev); |
780 | void *match_data) | 831 | if (retval) { |
781 | { | 832 | dev_err(f_dev, "%s: device_register failed\n", __func__); |
782 | struct fw_name_devm *fwn = res; | 833 | goto err_put_dev; |
834 | } | ||
783 | 835 | ||
784 | return (fwn->magic == (unsigned long)&fw_cache) && | 836 | retval = device_create_bin_file(f_dev, &firmware_attr_data); |
785 | !strcmp(fwn->name, match_data); | 837 | if (retval) { |
786 | } | 838 | dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); |
839 | goto err_del_dev; | ||
840 | } | ||
787 | 841 | ||
788 | static struct fw_name_devm *fw_find_devm_name(struct device *dev, | 842 | retval = device_create_file(f_dev, &dev_attr_loading); |
789 | const char *name) | 843 | if (retval) { |
790 | { | 844 | dev_err(f_dev, "%s: device_create_file failed\n", __func__); |
791 | struct fw_name_devm *fwn; | 845 | goto err_del_bin_attr; |
846 | } | ||
792 | 847 | ||
793 | fwn = devres_find(dev, fw_name_devm_release, | 848 | if (uevent) { |
794 | fw_devm_match, (void *)name); | 849 | dev_set_uevent_suppress(f_dev, false); |
795 | return fwn; | 850 | dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); |
796 | } | 851 | if (timeout != MAX_SCHEDULE_TIMEOUT) |
852 | schedule_delayed_work(&fw_priv->timeout_work, timeout); | ||
797 | 853 | ||
798 | /* add firmware name into devres list */ | 854 | kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); |
799 | static int fw_add_devm_name(struct device *dev, const char *name) | 855 | } |
800 | { | ||
801 | struct fw_name_devm *fwn; | ||
802 | 856 | ||
803 | fwn = fw_find_devm_name(dev, name); | 857 | wait_for_completion(&buf->completion); |
804 | if (fwn) | ||
805 | return 1; | ||
806 | 858 | ||
807 | fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) + | 859 | cancel_delayed_work_sync(&fw_priv->timeout_work); |
808 | strlen(name) + 1, GFP_KERNEL); | ||
809 | if (!fwn) | ||
810 | return -ENOMEM; | ||
811 | 860 | ||
812 | fwn->magic = (unsigned long)&fw_cache; | 861 | fw_priv->buf = NULL; |
813 | strcpy(fwn->name, name); | ||
814 | devres_add(dev, fwn); | ||
815 | 862 | ||
816 | return 0; | 863 | device_remove_file(f_dev, &dev_attr_loading); |
864 | err_del_bin_attr: | ||
865 | device_remove_bin_file(f_dev, &firmware_attr_data); | ||
866 | err_del_dev: | ||
867 | device_del(f_dev); | ||
868 | err_put_dev: | ||
869 | put_device(f_dev); | ||
870 | return retval; | ||
817 | } | 871 | } |
818 | #else | 872 | |
819 | static int fw_add_devm_name(struct device *dev, const char *name) | 873 | static int fw_load_from_user_helper(struct firmware *firmware, |
874 | const char *name, struct device *device, | ||
875 | bool uevent, bool nowait, long timeout) | ||
820 | { | 876 | { |
821 | return 0; | 877 | struct firmware_priv *fw_priv; |
878 | |||
879 | fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); | ||
880 | if (IS_ERR(fw_priv)) | ||
881 | return PTR_ERR(fw_priv); | ||
882 | |||
883 | fw_priv->buf = firmware->priv; | ||
884 | return _request_firmware_load(fw_priv, uevent, timeout); | ||
822 | } | 885 | } |
823 | #endif | 886 | #else /* CONFIG_FW_LOADER_USER_HELPER */ |
887 | static inline int | ||
888 | fw_load_from_user_helper(struct firmware *firmware, const char *name, | ||
889 | struct device *device, bool uevent, bool nowait, | ||
890 | long timeout) | ||
891 | { | ||
892 | return -ENOENT; | ||
893 | } | ||
894 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
895 | |||
824 | 896 | ||
825 | /* wait until the shared firmware_buf becomes ready (or error) */ | 897 | /* wait until the shared firmware_buf becomes ready (or error) */ |
826 | static int sync_cached_firmware_buf(struct firmware_buf *buf) | 898 | static int sync_cached_firmware_buf(struct firmware_buf *buf) |
@@ -921,89 +993,6 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device) | |||
921 | return 0; | 993 | return 0; |
922 | } | 994 | } |
923 | 995 | ||
924 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
925 | /* load a firmware via user helper */ | ||
926 | static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, | ||
927 | long timeout) | ||
928 | { | ||
929 | int retval = 0; | ||
930 | struct device *f_dev = &fw_priv->dev; | ||
931 | struct firmware_buf *buf = fw_priv->buf; | ||
932 | |||
933 | /* fall back on userspace loading */ | ||
934 | buf->fmt = PAGE_BUF; | ||
935 | |||
936 | dev_set_uevent_suppress(f_dev, true); | ||
937 | |||
938 | /* Need to pin this module until class device is destroyed */ | ||
939 | __module_get(THIS_MODULE); | ||
940 | |||
941 | retval = device_add(f_dev); | ||
942 | if (retval) { | ||
943 | dev_err(f_dev, "%s: device_register failed\n", __func__); | ||
944 | goto err_put_dev; | ||
945 | } | ||
946 | |||
947 | retval = device_create_bin_file(f_dev, &firmware_attr_data); | ||
948 | if (retval) { | ||
949 | dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); | ||
950 | goto err_del_dev; | ||
951 | } | ||
952 | |||
953 | retval = device_create_file(f_dev, &dev_attr_loading); | ||
954 | if (retval) { | ||
955 | dev_err(f_dev, "%s: device_create_file failed\n", __func__); | ||
956 | goto err_del_bin_attr; | ||
957 | } | ||
958 | |||
959 | if (uevent) { | ||
960 | dev_set_uevent_suppress(f_dev, false); | ||
961 | dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); | ||
962 | if (timeout != MAX_SCHEDULE_TIMEOUT) | ||
963 | schedule_delayed_work(&fw_priv->timeout_work, timeout); | ||
964 | |||
965 | kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); | ||
966 | } | ||
967 | |||
968 | wait_for_completion(&buf->completion); | ||
969 | |||
970 | cancel_delayed_work_sync(&fw_priv->timeout_work); | ||
971 | |||
972 | fw_priv->buf = NULL; | ||
973 | |||
974 | device_remove_file(f_dev, &dev_attr_loading); | ||
975 | err_del_bin_attr: | ||
976 | device_remove_bin_file(f_dev, &firmware_attr_data); | ||
977 | err_del_dev: | ||
978 | device_del(f_dev); | ||
979 | err_put_dev: | ||
980 | put_device(f_dev); | ||
981 | return retval; | ||
982 | } | ||
983 | |||
984 | static int fw_load_from_user_helper(struct firmware *firmware, | ||
985 | const char *name, struct device *device, | ||
986 | bool uevent, bool nowait, long timeout) | ||
987 | { | ||
988 | struct firmware_priv *fw_priv; | ||
989 | |||
990 | fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); | ||
991 | if (IS_ERR(fw_priv)) | ||
992 | return PTR_ERR(fw_priv); | ||
993 | |||
994 | fw_priv->buf = firmware->priv; | ||
995 | return _request_firmware_load(fw_priv, uevent, timeout); | ||
996 | } | ||
997 | #else /* CONFIG_FW_LOADER_USER_HELPER */ | ||
998 | static inline int | ||
999 | fw_load_from_user_helper(struct firmware *firmware, const char *name, | ||
1000 | struct device *device, bool uevent, bool nowait, | ||
1001 | long timeout) | ||
1002 | { | ||
1003 | return -ENOENT; | ||
1004 | } | ||
1005 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
1006 | |||
1007 | /* called from request_firmware() and request_firmware_work_func() */ | 996 | /* called from request_firmware() and request_firmware_work_func() */ |
1008 | static int | 997 | static int |
1009 | _request_firmware(const struct firmware **firmware_p, const char *name, | 998 | _request_firmware(const struct firmware **firmware_p, const char *name, |