aboutsummaryrefslogtreecommitdiffstats
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
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>
-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)