aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/firmware_class.c171
1 files changed, 100 insertions, 71 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index f2882511a9c1..a095d84ddfd9 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -36,68 +36,6 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
36MODULE_DESCRIPTION("Multi purpose firmware loading support"); 36MODULE_DESCRIPTION("Multi purpose firmware loading support");
37MODULE_LICENSE("GPL"); 37MODULE_LICENSE("GPL");
38 38
39static const char *fw_path[] = {
40 "/lib/firmware/updates/" UTS_RELEASE,
41 "/lib/firmware/updates",
42 "/lib/firmware/" UTS_RELEASE,
43 "/lib/firmware"
44};
45
46/* Don't inline this: 'struct kstat' is biggish */
47static noinline long fw_file_size(struct file *file)
48{
49 struct kstat st;
50 if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st))
51 return -1;
52 if (!S_ISREG(st.mode))
53 return -1;
54 if (st.size != (long)st.size)
55 return -1;
56 return st.size;
57}
58
59static bool fw_read_file_contents(struct file *file, struct firmware *fw)
60{
61 long size;
62 char *buf;
63
64 size = fw_file_size(file);
65 if (size < 0)
66 return false;
67 buf = vmalloc(size);
68 if (!buf)
69 return false;
70 if (kernel_read(file, 0, buf, size) != size) {
71 vfree(buf);
72 return false;
73 }
74 fw->data = buf;
75 fw->size = size;
76 return true;
77}
78
79static bool fw_get_filesystem_firmware(struct firmware *fw, const char *name)
80{
81 int i;
82 bool success = false;
83 char *path = __getname();
84
85 for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
86 struct file *file;
87 snprintf(path, PATH_MAX, "%s/%s", fw_path[i], name);
88
89 file = filp_open(path, O_RDONLY, 0);
90 if (IS_ERR(file))
91 continue;
92 success = fw_read_file_contents(file, fw);
93 fput(file);
94 if (success)
95 break;
96 }
97 __putname(path);
98 return success;
99}
100
101/* Builtin firmware support */ 39/* Builtin firmware support */
102 40
103#ifdef CONFIG_FW_LOADER 41#ifdef CONFIG_FW_LOADER
@@ -150,6 +88,11 @@ enum {
150 FW_STATUS_ABORT, 88 FW_STATUS_ABORT,
151}; 89};
152 90
91enum fw_buf_fmt {
92 VMALLOC_BUF, /* used in direct loading */
93 PAGE_BUF, /* used in loading via userspace */
94};
95
153static int loading_timeout = 60; /* In seconds */ 96static int loading_timeout = 60; /* In seconds */
154 97
155static inline long firmware_loading_timeout(void) 98static inline long firmware_loading_timeout(void)
@@ -187,6 +130,7 @@ struct firmware_buf {
187 struct completion completion; 130 struct completion completion;
188 struct firmware_cache *fwc; 131 struct firmware_cache *fwc;
189 unsigned long status; 132 unsigned long status;
133 enum fw_buf_fmt fmt;
190 void *data; 134 void *data;
191 size_t size; 135 size_t size;
192 struct page **pages; 136 struct page **pages;
@@ -240,6 +184,7 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
240 strcpy(buf->fw_id, fw_name); 184 strcpy(buf->fw_id, fw_name);
241 buf->fwc = fwc; 185 buf->fwc = fwc;
242 init_completion(&buf->completion); 186 init_completion(&buf->completion);
187 buf->fmt = VMALLOC_BUF;
243 188
244 pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); 189 pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf);
245 190
@@ -307,10 +252,14 @@ static void __fw_free_buf(struct kref *ref)
307 list_del(&buf->list); 252 list_del(&buf->list);
308 spin_unlock(&fwc->lock); 253 spin_unlock(&fwc->lock);
309 254
310 vunmap(buf->data); 255
311 for (i = 0; i < buf->nr_pages; i++) 256 if (buf->fmt == PAGE_BUF) {
312 __free_page(buf->pages[i]); 257 vunmap(buf->data);
313 kfree(buf->pages); 258 for (i = 0; i < buf->nr_pages; i++)
259 __free_page(buf->pages[i]);
260 kfree(buf->pages);
261 } else
262 vfree(buf->data);
314 kfree(buf); 263 kfree(buf);
315} 264}
316 265
@@ -319,6 +268,69 @@ static void fw_free_buf(struct firmware_buf *buf)
319 kref_put(&buf->ref, __fw_free_buf); 268 kref_put(&buf->ref, __fw_free_buf);
320} 269}
321 270
271/* direct firmware loading support */
272static const char *fw_path[] = {
273 "/lib/firmware/updates/" UTS_RELEASE,
274 "/lib/firmware/updates",
275 "/lib/firmware/" UTS_RELEASE,
276 "/lib/firmware"
277};
278
279/* Don't inline this: 'struct kstat' is biggish */
280static noinline long fw_file_size(struct file *file)
281{
282 struct kstat st;
283 if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st))
284 return -1;
285 if (!S_ISREG(st.mode))
286 return -1;
287 if (st.size != (long)st.size)
288 return -1;
289 return st.size;
290}
291
292static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
293{
294 long size;
295 char *buf;
296
297 size = fw_file_size(file);
298 if (size < 0)
299 return false;
300 buf = vmalloc(size);
301 if (!buf)
302 return false;
303 if (kernel_read(file, 0, buf, size) != size) {
304 vfree(buf);
305 return false;
306 }
307 fw_buf->data = buf;
308 fw_buf->size = size;
309 return true;
310}
311
312static bool fw_get_filesystem_firmware(struct firmware_buf *buf)
313{
314 int i;
315 bool success = false;
316 char *path = __getname();
317
318 for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
319 struct file *file;
320 snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id);
321
322 file = filp_open(path, O_RDONLY, 0);
323 if (IS_ERR(file))
324 continue;
325 success = fw_read_file_contents(file, buf);
326 fput(file);
327 if (success)
328 break;
329 }
330 __putname(path);
331 return success;
332}
333
322static struct firmware_priv *to_firmware_priv(struct device *dev) 334static struct firmware_priv *to_firmware_priv(struct device *dev)
323{ 335{
324 return container_of(dev, struct firmware_priv, dev); 336 return container_of(dev, struct firmware_priv, dev);
@@ -427,6 +439,9 @@ static void firmware_free_data(const struct firmware *fw)
427/* one pages buffer should be mapped/unmapped only once */ 439/* one pages buffer should be mapped/unmapped only once */
428static int fw_map_pages_buf(struct firmware_buf *buf) 440static int fw_map_pages_buf(struct firmware_buf *buf)
429{ 441{
442 if (buf->fmt != PAGE_BUF)
443 return 0;
444
430 if (buf->data) 445 if (buf->data)
431 vunmap(buf->data); 446 vunmap(buf->data);
432 buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); 447 buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO);
@@ -789,11 +804,6 @@ _request_firmware_prepare(const struct firmware **firmware_p, const char *name,
789 return NULL; 804 return NULL;
790 } 805 }
791 806
792 if (fw_get_filesystem_firmware(firmware, name)) {
793 dev_dbg(device, "firmware: direct-loading firmware %s\n", name);
794 return NULL;
795 }
796
797 ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf); 807 ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
798 if (!ret) 808 if (!ret)
799 fw_priv = fw_create_instance(firmware, name, device, 809 fw_priv = fw_create_instance(firmware, name, device,
@@ -843,6 +853,21 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
843 struct device *f_dev = &fw_priv->dev; 853 struct device *f_dev = &fw_priv->dev;
844 struct firmware_buf *buf = fw_priv->buf; 854 struct firmware_buf *buf = fw_priv->buf;
845 struct firmware_cache *fwc = &fw_cache; 855 struct firmware_cache *fwc = &fw_cache;
856 int direct_load = 0;
857
858 /* try direct loading from fs first */
859 if (fw_get_filesystem_firmware(buf)) {
860 dev_dbg(f_dev->parent, "firmware: direct-loading"
861 " firmware %s\n", buf->fw_id);
862
863 set_bit(FW_STATUS_DONE, &buf->status);
864 complete_all(&buf->completion);
865 direct_load = 1;
866 goto handle_fw;
867 }
868
869 /* fall back on userspace loading */
870 buf->fmt = PAGE_BUF;
846 871
847 dev_set_uevent_suppress(f_dev, true); 872 dev_set_uevent_suppress(f_dev, true);
848 873
@@ -881,6 +906,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
881 906
882 del_timer_sync(&fw_priv->timeout); 907 del_timer_sync(&fw_priv->timeout);
883 908
909handle_fw:
884 mutex_lock(&fw_lock); 910 mutex_lock(&fw_lock);
885 if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status)) 911 if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
886 retval = -ENOENT; 912 retval = -ENOENT;
@@ -910,6 +936,9 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
910 fw_priv->buf = NULL; 936 fw_priv->buf = NULL;
911 mutex_unlock(&fw_lock); 937 mutex_unlock(&fw_lock);
912 938
939 if (direct_load)
940 goto err_put_dev;
941
913 device_remove_file(f_dev, &dev_attr_loading); 942 device_remove_file(f_dev, &dev_attr_loading);
914err_del_bin_attr: 943err_del_bin_attr:
915 device_remove_bin_file(f_dev, &firmware_attr_data); 944 device_remove_bin_file(f_dev, &firmware_attr_data);