diff options
| -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, |
