diff options
| author | Ming Lei <ming.lei@canonical.com> | 2012-08-04 00:01:22 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-16 16:24:21 -0400 |
| commit | 2887b3959c8b2f6ed1f62ce95c0888aedb1ea84b (patch) | |
| tree | d8706698f44593c7c0075912c6e2a4b81ebf32a6 /drivers/base | |
| parent | 1f2b79599ee8f5fc82cc73c6c090eb6cdff881d6 (diff) | |
firmware loader: introduce cache_firmware and uncache_firmware
This patches introduce two kernel APIs of cache_firmware and
uncache_firmware, both of which take the firmware file name
as the only parameter.
So any drivers can call cache_firmware to cache the specified
firmware file into kernel memory, and can use the cached firmware
in situations which can't request firmware from user space.
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>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/firmware_class.c | 100 |
1 files changed, 92 insertions, 8 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 848ad97e8d79..fc119ce6fdb8 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -142,6 +142,17 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, | |||
| 142 | return buf; | 142 | return buf; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static struct firmware_buf *__fw_lookup_buf(const char *fw_name) | ||
| 146 | { | ||
| 147 | struct firmware_buf *tmp; | ||
| 148 | struct firmware_cache *fwc = &fw_cache; | ||
| 149 | |||
| 150 | list_for_each_entry(tmp, &fwc->head, list) | ||
| 151 | if (!strcmp(tmp->fw_id, fw_name)) | ||
| 152 | return tmp; | ||
| 153 | return NULL; | ||
| 154 | } | ||
| 155 | |||
| 145 | static int fw_lookup_and_allocate_buf(const char *fw_name, | 156 | static int fw_lookup_and_allocate_buf(const char *fw_name, |
| 146 | struct firmware_cache *fwc, | 157 | struct firmware_cache *fwc, |
| 147 | struct firmware_buf **buf) | 158 | struct firmware_buf **buf) |
| @@ -149,14 +160,13 @@ static int fw_lookup_and_allocate_buf(const char *fw_name, | |||
| 149 | struct firmware_buf *tmp; | 160 | struct firmware_buf *tmp; |
| 150 | 161 | ||
| 151 | spin_lock(&fwc->lock); | 162 | spin_lock(&fwc->lock); |
| 152 | list_for_each_entry(tmp, &fwc->head, list) | 163 | tmp = __fw_lookup_buf(fw_name); |
| 153 | if (!strcmp(tmp->fw_id, fw_name)) { | 164 | if (tmp) { |
| 154 | kref_get(&tmp->ref); | 165 | kref_get(&tmp->ref); |
| 155 | spin_unlock(&fwc->lock); | 166 | spin_unlock(&fwc->lock); |
| 156 | *buf = tmp; | 167 | *buf = tmp; |
| 157 | return 1; | 168 | return 1; |
| 158 | } | 169 | } |
| 159 | |||
| 160 | tmp = __allocate_fw_buf(fw_name, fwc); | 170 | tmp = __allocate_fw_buf(fw_name, fwc); |
| 161 | if (tmp) | 171 | if (tmp) |
| 162 | list_add(&tmp->list, &fwc->head); | 172 | list_add(&tmp->list, &fwc->head); |
| @@ -167,6 +177,18 @@ static int fw_lookup_and_allocate_buf(const char *fw_name, | |||
| 167 | return tmp ? 0 : -ENOMEM; | 177 | return tmp ? 0 : -ENOMEM; |
| 168 | } | 178 | } |
| 169 | 179 | ||
| 180 | static struct firmware_buf *fw_lookup_buf(const char *fw_name) | ||
| 181 | { | ||
| 182 | struct firmware_buf *tmp; | ||
| 183 | struct firmware_cache *fwc = &fw_cache; | ||
| 184 | |||
| 185 | spin_lock(&fwc->lock); | ||
| 186 | tmp = __fw_lookup_buf(fw_name); | ||
| 187 | spin_unlock(&fwc->lock); | ||
| 188 | |||
| 189 | return tmp; | ||
| 190 | } | ||
| 191 | |||
| 170 | static void __fw_free_buf(struct kref *ref) | 192 | static void __fw_free_buf(struct kref *ref) |
| 171 | { | 193 | { |
| 172 | struct firmware_buf *buf = to_fwbuf(ref); | 194 | struct firmware_buf *buf = to_fwbuf(ref); |
| @@ -852,6 +874,66 @@ request_firmware_nowait( | |||
| 852 | return 0; | 874 | return 0; |
| 853 | } | 875 | } |
| 854 | 876 | ||
| 877 | /** | ||
| 878 | * cache_firmware - cache one firmware image in kernel memory space | ||
| 879 | * @fw_name: the firmware image name | ||
| 880 | * | ||
| 881 | * Cache firmware in kernel memory so that drivers can use it when | ||
| 882 | * system isn't ready for them to request firmware image from userspace. | ||
| 883 | * Once it returns successfully, driver can use request_firmware or its | ||
| 884 | * nowait version to get the cached firmware without any interacting | ||
| 885 | * with userspace | ||
| 886 | * | ||
| 887 | * Return 0 if the firmware image has been cached successfully | ||
| 888 | * Return !0 otherwise | ||
| 889 | * | ||
| 890 | */ | ||
| 891 | int cache_firmware(const char *fw_name) | ||
| 892 | { | ||
| 893 | int ret; | ||
| 894 | const struct firmware *fw; | ||
| 895 | |||
| 896 | pr_debug("%s: %s\n", __func__, fw_name); | ||
| 897 | |||
| 898 | ret = request_firmware(&fw, fw_name, NULL); | ||
| 899 | if (!ret) | ||
| 900 | kfree(fw); | ||
| 901 | |||
| 902 | pr_debug("%s: %s ret=%d\n", __func__, fw_name, ret); | ||
| 903 | |||
| 904 | return ret; | ||
| 905 | } | ||
| 906 | |||
| 907 | /** | ||
| 908 | * uncache_firmware - remove one cached firmware image | ||
| 909 | * @fw_name: the firmware image name | ||
| 910 | * | ||
| 911 | * Uncache one firmware image which has been cached successfully | ||
| 912 | * before. | ||
| 913 | * | ||
| 914 | * Return 0 if the firmware cache has been removed successfully | ||
| 915 | * Return !0 otherwise | ||
| 916 | * | ||
| 917 | */ | ||
| 918 | int uncache_firmware(const char *fw_name) | ||
| 919 | { | ||
| 920 | struct firmware_buf *buf; | ||
| 921 | struct firmware fw; | ||
| 922 | |||
| 923 | pr_debug("%s: %s\n", __func__, fw_name); | ||
| 924 | |||
| 925 | if (fw_get_builtin_firmware(&fw, fw_name)) | ||
| 926 | return 0; | ||
| 927 | |||
| 928 | buf = fw_lookup_buf(fw_name); | ||
| 929 | if (buf) { | ||
| 930 | fw_free_buf(buf); | ||
| 931 | return 0; | ||
| 932 | } | ||
| 933 | |||
| 934 | return -EINVAL; | ||
| 935 | } | ||
| 936 | |||
| 855 | static int __init firmware_class_init(void) | 937 | static int __init firmware_class_init(void) |
| 856 | { | 938 | { |
| 857 | fw_cache_init(); | 939 | fw_cache_init(); |
| @@ -869,3 +951,5 @@ module_exit(firmware_class_exit); | |||
| 869 | EXPORT_SYMBOL(release_firmware); | 951 | EXPORT_SYMBOL(release_firmware); |
| 870 | EXPORT_SYMBOL(request_firmware); | 952 | EXPORT_SYMBOL(request_firmware); |
| 871 | EXPORT_SYMBOL(request_firmware_nowait); | 953 | EXPORT_SYMBOL(request_firmware_nowait); |
| 954 | EXPORT_SYMBOL_GPL(cache_firmware); | ||
| 955 | EXPORT_SYMBOL_GPL(uncache_firmware); | ||
