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/firmware_class.c | |
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/firmware_class.c')
-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); | ||