aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-10-09 00:01:03 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-22 11:37:17 -0400
commit746058f4304343507e48d39f80d7a3b0d8550e3a (patch)
treec372c4a60a4a5b00b408de1c09f27bba077f9fc0 /drivers/base
parent253c9240ee09fd2a05d315ea44ac037a893d8981 (diff)
firmware loader: let direct loading back on 'firmware_buf'
Firstly 'firmware_buf' is introduced to make all loading requests to share one firmware kernel buffer, so firmware_buf should be used in direct loading for saving memory and speedup firmware loading. Secondly, the commit below abb139e75c2cdbb955e840d6331cb5863e409d0e(firmware:teach the kernel to load firmware files directly from the filesystem) introduces direct loading for fixing udev regression, but it bypasses the firmware cache meachnism, so this patch enables caching firmware for direct loading case since it is still needed to solve drivers' dependency during system resume. Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
-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);