aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/firmware_class.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2012-08-04 00:01:21 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 16:22:45 -0400
commit1f2b79599ee8f5fc82cc73c6c090eb6cdff881d6 (patch)
tree6b3fed8d355f708cc6a001e772f07783a300d2cd /drivers/base/firmware_class.c
parent1244691c73b250be522e77ac1a00ad53b601b4c4 (diff)
firmware loader: always let firmware_buf own the pages buffer
This patch always let firmware_buf own the pages buffer allocated inside firmware_data_write, and add all instances of firmware_buf into the firmware cache global list. Also introduce one private field in 'struct firmware', so release_firmware will see the instance of firmware_buf associated with the current firmware instance, then just 'free' the instance of firmware_buf. The firmware_buf instance represents one pages buffer for one firmware image, so lots of firmware loading requests can share the same firmware_buf instance if they request the same firmware image file. This patch will make implementation of the following cache_firmware/ uncache_firmware very easy and simple. In fact, the patch improves request_formware/release_firmware: - only request userspace to write firmware image once if several devices share one same firmware image and its drivers call request_firmware concurrently. 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.c240
1 files changed, 171 insertions, 69 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5f2076e5d5b1..848ad97e8d79 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -21,6 +21,7 @@
21#include <linux/firmware.h> 21#include <linux/firmware.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/sched.h> 23#include <linux/sched.h>
24#include <linux/list.h>
24 25
25MODULE_AUTHOR("Manuel Estrada Sainz"); 26MODULE_AUTHOR("Manuel Estrada Sainz");
26MODULE_DESCRIPTION("Multi purpose firmware loading support"); 27MODULE_DESCRIPTION("Multi purpose firmware loading support");
@@ -85,13 +86,17 @@ static inline long firmware_loading_timeout(void)
85 return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT; 86 return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
86} 87}
87 88
88/* fw_lock could be moved to 'struct firmware_priv' but since it is just 89struct firmware_cache {
89 * guarding for corner cases a global lock should be OK */ 90 /* firmware_buf instance will be added into the below list */
90static DEFINE_MUTEX(fw_lock); 91 spinlock_t lock;
92 struct list_head head;
93};
91 94
92struct firmware_buf { 95struct firmware_buf {
96 struct kref ref;
97 struct list_head list;
93 struct completion completion; 98 struct completion completion;
94 struct firmware *fw; 99 struct firmware_cache *fwc;
95 unsigned long status; 100 unsigned long status;
96 void *data; 101 void *data;
97 size_t size; 102 size_t size;
@@ -106,8 +111,94 @@ struct firmware_priv {
106 bool nowait; 111 bool nowait;
107 struct device dev; 112 struct device dev;
108 struct firmware_buf *buf; 113 struct firmware_buf *buf;
114 struct firmware *fw;
109}; 115};
110 116
117#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
118
119/* fw_lock could be moved to 'struct firmware_priv' but since it is just
120 * guarding for corner cases a global lock should be OK */
121static DEFINE_MUTEX(fw_lock);
122
123static struct firmware_cache fw_cache;
124
125static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
126 struct firmware_cache *fwc)
127{
128 struct firmware_buf *buf;
129
130 buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1 , GFP_ATOMIC);
131
132 if (!buf)
133 return buf;
134
135 kref_init(&buf->ref);
136 strcpy(buf->fw_id, fw_name);
137 buf->fwc = fwc;
138 init_completion(&buf->completion);
139
140 pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf);
141
142 return buf;
143}
144
145static int fw_lookup_and_allocate_buf(const char *fw_name,
146 struct firmware_cache *fwc,
147 struct firmware_buf **buf)
148{
149 struct firmware_buf *tmp;
150
151 spin_lock(&fwc->lock);
152 list_for_each_entry(tmp, &fwc->head, list)
153 if (!strcmp(tmp->fw_id, fw_name)) {
154 kref_get(&tmp->ref);
155 spin_unlock(&fwc->lock);
156 *buf = tmp;
157 return 1;
158 }
159
160 tmp = __allocate_fw_buf(fw_name, fwc);
161 if (tmp)
162 list_add(&tmp->list, &fwc->head);
163 spin_unlock(&fwc->lock);
164
165 *buf = tmp;
166
167 return tmp ? 0 : -ENOMEM;
168}
169
170static void __fw_free_buf(struct kref *ref)
171{
172 struct firmware_buf *buf = to_fwbuf(ref);
173 struct firmware_cache *fwc = buf->fwc;
174 int i;
175
176 pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
177 __func__, buf->fw_id, buf, buf->data,
178 (unsigned int)buf->size);
179
180 spin_lock(&fwc->lock);
181 list_del(&buf->list);
182 spin_unlock(&fwc->lock);
183
184 vunmap(buf->data);
185 for (i = 0; i < buf->nr_pages; i++)
186 __free_page(buf->pages[i]);
187 kfree(buf->pages);
188 kfree(buf);
189}
190
191static void fw_free_buf(struct firmware_buf *buf)
192{
193 kref_put(&buf->ref, __fw_free_buf);
194}
195
196static void __init fw_cache_init(void)
197{
198 spin_lock_init(&fw_cache.lock);
199 INIT_LIST_HEAD(&fw_cache.head);
200}
201
111static struct firmware_priv *to_firmware_priv(struct device *dev) 202static struct firmware_priv *to_firmware_priv(struct device *dev)
112{ 203{
113 return container_of(dev, struct firmware_priv, dev); 204 return container_of(dev, struct firmware_priv, dev);
@@ -118,7 +209,7 @@ static void fw_load_abort(struct firmware_priv *fw_priv)
118 struct firmware_buf *buf = fw_priv->buf; 209 struct firmware_buf *buf = fw_priv->buf;
119 210
120 set_bit(FW_STATUS_ABORT, &buf->status); 211 set_bit(FW_STATUS_ABORT, &buf->status);
121 complete(&buf->completion); 212 complete_all(&buf->completion);
122} 213}
123 214
124static ssize_t firmware_timeout_show(struct class *class, 215static ssize_t firmware_timeout_show(struct class *class,
@@ -158,18 +249,6 @@ static struct class_attribute firmware_class_attrs[] = {
158 __ATTR_NULL 249 __ATTR_NULL
159}; 250};
160 251
161static void fw_free_buf(struct firmware_buf *buf)
162{
163 int i;
164
165 if (!buf)
166 return;
167
168 for (i = 0; i < buf->nr_pages; i++)
169 __free_page(buf->pages[i]);
170 kfree(buf->pages);
171}
172
173static void fw_dev_release(struct device *dev) 252static void fw_dev_release(struct device *dev)
174{ 253{
175 struct firmware_priv *fw_priv = to_firmware_priv(dev); 254 struct firmware_priv *fw_priv = to_firmware_priv(dev);
@@ -212,13 +291,8 @@ static ssize_t firmware_loading_show(struct device *dev,
212/* firmware holds the ownership of pages */ 291/* firmware holds the ownership of pages */
213static void firmware_free_data(const struct firmware *fw) 292static void firmware_free_data(const struct firmware *fw)
214{ 293{
215 int i; 294 WARN_ON(!fw->priv);
216 vunmap(fw->data); 295 fw_free_buf(fw->priv);
217 if (fw->pages) {
218 for (i = 0; i < PFN_UP(fw->size); i++)
219 __free_page(fw->pages[i]);
220 kfree(fw->pages);
221 }
222} 296}
223 297
224/* Some architectures don't have PAGE_KERNEL_RO */ 298/* Some architectures don't have PAGE_KERNEL_RO */
@@ -269,7 +343,7 @@ static ssize_t firmware_loading_store(struct device *dev,
269 if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { 343 if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
270 set_bit(FW_STATUS_DONE, &fw_buf->status); 344 set_bit(FW_STATUS_DONE, &fw_buf->status);
271 clear_bit(FW_STATUS_LOADING, &fw_buf->status); 345 clear_bit(FW_STATUS_LOADING, &fw_buf->status);
272 complete(&fw_buf->completion); 346 complete_all(&fw_buf->completion);
273 break; 347 break;
274 } 348 }
275 /* fallthrough */ 349 /* fallthrough */
@@ -448,7 +522,6 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
448 struct device *device, bool uevent, bool nowait) 522 struct device *device, bool uevent, bool nowait)
449{ 523{
450 struct firmware_priv *fw_priv; 524 struct firmware_priv *fw_priv;
451 struct firmware_buf *buf;
452 struct device *f_dev; 525 struct device *f_dev;
453 526
454 fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL); 527 fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL);
@@ -458,21 +531,10 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
458 goto exit; 531 goto exit;
459 } 532 }
460 533
461 buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1, GFP_KERNEL);
462 if (!buf) {
463 dev_err(device, "%s: kmalloc failed\n", __func__);
464 kfree(fw_priv);
465 fw_priv = ERR_PTR(-ENOMEM);
466 goto exit;
467 }
468
469 buf->fw = firmware;
470 fw_priv->buf = buf;
471 fw_priv->nowait = nowait; 534 fw_priv->nowait = nowait;
535 fw_priv->fw = firmware;
472 setup_timer(&fw_priv->timeout, 536 setup_timer(&fw_priv->timeout,
473 firmware_class_timeout, (u_long) fw_priv); 537 firmware_class_timeout, (u_long) fw_priv);
474 strcpy(buf->fw_id, fw_name);
475 init_completion(&buf->completion);
476 538
477 f_dev = &fw_priv->dev; 539 f_dev = &fw_priv->dev;
478 540
@@ -484,12 +546,42 @@ exit:
484 return fw_priv; 546 return fw_priv;
485} 547}
486 548
549/* one pages buffer is mapped/unmapped only once */
550static int fw_map_pages_buf(struct firmware_buf *buf)
551{
552 buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO);
553 if (!buf->data)
554 return -ENOMEM;
555 return 0;
556}
557
558/* store the pages buffer info firmware from buf */
559static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
560{
561 fw->priv = buf;
562 fw->pages = buf->pages;
563 fw->size = buf->size;
564 fw->data = buf->data;
565
566 pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
567 __func__, buf->fw_id, buf, buf->data,
568 (unsigned int)buf->size);
569}
570
571static void _request_firmware_cleanup(const struct firmware **firmware_p)
572{
573 release_firmware(*firmware_p);
574 *firmware_p = NULL;
575}
576
487static struct firmware_priv * 577static struct firmware_priv *
488_request_firmware_prepare(const struct firmware **firmware_p, const char *name, 578_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
489 struct device *device, bool uevent, bool nowait) 579 struct device *device, bool uevent, bool nowait)
490{ 580{
491 struct firmware *firmware; 581 struct firmware *firmware;
492 struct firmware_priv *fw_priv; 582 struct firmware_priv *fw_priv = NULL;
583 struct firmware_buf *buf;
584 int ret;
493 585
494 if (!firmware_p) 586 if (!firmware_p)
495 return ERR_PTR(-EINVAL); 587 return ERR_PTR(-EINVAL);
@@ -506,35 +598,45 @@ _request_firmware_prepare(const struct firmware **firmware_p, const char *name,
506 return NULL; 598 return NULL;
507 } 599 }
508 600
509 fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); 601 ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
510 if (IS_ERR(fw_priv)) { 602 if (!ret)
511 release_firmware(firmware); 603 fw_priv = fw_create_instance(firmware, name, device,
604 uevent, nowait);
605
606 if (IS_ERR(fw_priv) || ret < 0) {
607 kfree(firmware);
512 *firmware_p = NULL; 608 *firmware_p = NULL;
609 return ERR_PTR(-ENOMEM);
610 } else if (fw_priv) {
611 fw_priv->buf = buf;
612
613 /*
614 * bind with 'buf' now to avoid warning in failure path
615 * of requesting firmware.
616 */
617 firmware->priv = buf;
618 return fw_priv;
513 } 619 }
514 return fw_priv;
515}
516
517static void _request_firmware_cleanup(const struct firmware **firmware_p)
518{
519 release_firmware(*firmware_p);
520 *firmware_p = NULL;
521}
522 620
523/* transfer the ownership of pages to firmware */ 621 /* share the cached buf, which is inprogessing or completed */
524static int fw_set_page_data(struct firmware_buf *buf) 622 check_status:
525{ 623 mutex_lock(&fw_lock);
526 struct firmware *fw = buf->fw; 624 if (test_bit(FW_STATUS_ABORT, &buf->status)) {
527 625 fw_priv = ERR_PTR(-ENOENT);
528 buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); 626 _request_firmware_cleanup(firmware_p);
529 if (!buf->data) 627 goto exit;
530 return -ENOMEM; 628 } else if (test_bit(FW_STATUS_DONE, &buf->status)) {
531 629 fw_priv = NULL;
532 fw->data = buf->data; 630 fw_set_page_data(buf, firmware);
533 fw->pages = buf->pages; 631 goto exit;
534 fw->size = buf->size; 632 }
535 WARN_ON(PFN_UP(fw->size) != buf->nr_pages); 633 mutex_unlock(&fw_lock);
634 wait_for_completion(&buf->completion);
635 goto check_status;
536 636
537 return 0; 637exit:
638 mutex_unlock(&fw_lock);
639 return fw_priv;
538} 640}
539 641
540static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, 642static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
@@ -585,13 +687,12 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
585 if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status)) 687 if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
586 retval = -ENOENT; 688 retval = -ENOENT;
587 689
588 /* transfer pages ownership at the last minute */
589 if (!retval) 690 if (!retval)
590 retval = fw_set_page_data(buf); 691 retval = fw_map_pages_buf(buf);
591 if (retval) 692
592 fw_free_buf(buf); /* free untransfered pages buffer */ 693 /* pass the pages buffer to driver at the last minute */
694 fw_set_page_data(buf, fw_priv->fw);
593 695
594 kfree(buf);
595 fw_priv->buf = NULL; 696 fw_priv->buf = NULL;
596 mutex_unlock(&fw_lock); 697 mutex_unlock(&fw_lock);
597 698
@@ -753,6 +854,7 @@ request_firmware_nowait(
753 854
754static int __init firmware_class_init(void) 855static int __init firmware_class_init(void)
755{ 856{
857 fw_cache_init();
756 return class_register(&firmware_class); 858 return class_register(&firmware_class);
757} 859}
758 860