Skip to content

Commit 1244691

Browse files
Ming Leigregkh
authored andcommitted
firmware loader: introduce firmware_buf
This patch introduces struct firmware_buf to describe the buffer which holds the firmware data, which will make the following cache_firmware/uncache_firmware implemented easily. Signed-off-by: Ming Lei <[email protected]> Cc: Linus Torvalds <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 99c2aa7 commit 1244691

File tree

1 file changed

+102
-78
lines changed

1 file changed

+102
-78
lines changed

drivers/base/firmware_class.c

Lines changed: 102 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ static inline long firmware_loading_timeout(void)
8989
* guarding for corner cases a global lock should be OK */
9090
static DEFINE_MUTEX(fw_lock);
9191

92-
struct firmware_priv {
92+
struct firmware_buf {
9393
struct completion completion;
9494
struct firmware *fw;
9595
unsigned long status;
@@ -98,10 +98,14 @@ struct firmware_priv {
9898
struct page **pages;
9999
int nr_pages;
100100
int page_array_size;
101+
char fw_id[];
102+
};
103+
104+
struct firmware_priv {
101105
struct timer_list timeout;
102-
struct device dev;
103106
bool nowait;
104-
char fw_id[];
107+
struct device dev;
108+
struct firmware_buf *buf;
105109
};
106110

107111
static struct firmware_priv *to_firmware_priv(struct device *dev)
@@ -111,8 +115,10 @@ static struct firmware_priv *to_firmware_priv(struct device *dev)
111115

112116
static void fw_load_abort(struct firmware_priv *fw_priv)
113117
{
114-
set_bit(FW_STATUS_ABORT, &fw_priv->status);
115-
complete(&fw_priv->completion);
118+
struct firmware_buf *buf = fw_priv->buf;
119+
120+
set_bit(FW_STATUS_ABORT, &buf->status);
121+
complete(&buf->completion);
116122
}
117123

118124
static ssize_t firmware_timeout_show(struct class *class,
@@ -152,15 +158,21 @@ static struct class_attribute firmware_class_attrs[] = {
152158
__ATTR_NULL
153159
};
154160

155-
static void fw_dev_release(struct device *dev)
161+
static void fw_free_buf(struct firmware_buf *buf)
156162
{
157-
struct firmware_priv *fw_priv = to_firmware_priv(dev);
158163
int i;
159164

160-
/* free untransfered pages buffer */
161-
for (i = 0; i < fw_priv->nr_pages; i++)
162-
__free_page(fw_priv->pages[i]);
163-
kfree(fw_priv->pages);
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+
173+
static void fw_dev_release(struct device *dev)
174+
{
175+
struct firmware_priv *fw_priv = to_firmware_priv(dev);
164176

165177
kfree(fw_priv);
166178

@@ -171,7 +183,7 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
171183
{
172184
struct firmware_priv *fw_priv = to_firmware_priv(dev);
173185

174-
if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
186+
if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id))
175187
return -ENOMEM;
176188
if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
177189
return -ENOMEM;
@@ -192,7 +204,7 @@ static ssize_t firmware_loading_show(struct device *dev,
192204
struct device_attribute *attr, char *buf)
193205
{
194206
struct firmware_priv *fw_priv = to_firmware_priv(dev);
195-
int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
207+
int loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status);
196208

197209
return sprintf(buf, "%d\n", loading);
198210
}
@@ -231,32 +243,33 @@ static ssize_t firmware_loading_store(struct device *dev,
231243
const char *buf, size_t count)
232244
{
233245
struct firmware_priv *fw_priv = to_firmware_priv(dev);
246+
struct firmware_buf *fw_buf = fw_priv->buf;
234247
int loading = simple_strtol(buf, NULL, 10);
235248
int i;
236249

237250
mutex_lock(&fw_lock);
238251

239-
if (!fw_priv->fw)
252+
if (!fw_buf)
240253
goto out;
241254

242255
switch (loading) {
243256
case 1:
244257
/* discarding any previous partial load */
245-
if (!test_bit(FW_STATUS_DONE, &fw_priv->status)) {
246-
for (i = 0; i < fw_priv->nr_pages; i++)
247-
__free_page(fw_priv->pages[i]);
248-
kfree(fw_priv->pages);
249-
fw_priv->pages = NULL;
250-
fw_priv->page_array_size = 0;
251-
fw_priv->nr_pages = 0;
252-
set_bit(FW_STATUS_LOADING, &fw_priv->status);
258+
if (!test_bit(FW_STATUS_DONE, &fw_buf->status)) {
259+
for (i = 0; i < fw_buf->nr_pages; i++)
260+
__free_page(fw_buf->pages[i]);
261+
kfree(fw_buf->pages);
262+
fw_buf->pages = NULL;
263+
fw_buf->page_array_size = 0;
264+
fw_buf->nr_pages = 0;
265+
set_bit(FW_STATUS_LOADING, &fw_buf->status);
253266
}
254267
break;
255268
case 0:
256-
if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
257-
set_bit(FW_STATUS_DONE, &fw_priv->status);
258-
clear_bit(FW_STATUS_LOADING, &fw_priv->status);
259-
complete(&fw_priv->completion);
269+
if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
270+
set_bit(FW_STATUS_DONE, &fw_buf->status);
271+
clear_bit(FW_STATUS_LOADING, &fw_buf->status);
272+
complete(&fw_buf->completion);
260273
break;
261274
}
262275
/* fallthrough */
@@ -280,21 +293,21 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
280293
{
281294
struct device *dev = kobj_to_dev(kobj);
282295
struct firmware_priv *fw_priv = to_firmware_priv(dev);
283-
struct firmware *fw;
296+
struct firmware_buf *buf;
284297
ssize_t ret_count;
285298

286299
mutex_lock(&fw_lock);
287-
fw = fw_priv->fw;
288-
if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
300+
buf = fw_priv->buf;
301+
if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) {
289302
ret_count = -ENODEV;
290303
goto out;
291304
}
292-
if (offset > fw_priv->size) {
305+
if (offset > buf->size) {
293306
ret_count = 0;
294307
goto out;
295308
}
296-
if (count > fw_priv->size - offset)
297-
count = fw_priv->size - offset;
309+
if (count > buf->size - offset)
310+
count = buf->size - offset;
298311

299312
ret_count = count;
300313

@@ -304,11 +317,11 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
304317
int page_ofs = offset & (PAGE_SIZE-1);
305318
int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
306319

307-
page_data = kmap(fw_priv->pages[page_nr]);
320+
page_data = kmap(buf->pages[page_nr]);
308321

309322
memcpy(buffer, page_data + page_ofs, page_cnt);
310323

311-
kunmap(fw_priv->pages[page_nr]);
324+
kunmap(buf->pages[page_nr]);
312325
buffer += page_cnt;
313326
offset += page_cnt;
314327
count -= page_cnt;
@@ -320,12 +333,13 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
320333

321334
static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
322335
{
336+
struct firmware_buf *buf = fw_priv->buf;
323337
int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
324338

325339
/* If the array of pages is too small, grow it... */
326-
if (fw_priv->page_array_size < pages_needed) {
340+
if (buf->page_array_size < pages_needed) {
327341
int new_array_size = max(pages_needed,
328-
fw_priv->page_array_size * 2);
342+
buf->page_array_size * 2);
329343
struct page **new_pages;
330344

331345
new_pages = kmalloc(new_array_size * sizeof(void *),
@@ -334,24 +348,24 @@ static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
334348
fw_load_abort(fw_priv);
335349
return -ENOMEM;
336350
}
337-
memcpy(new_pages, fw_priv->pages,
338-
fw_priv->page_array_size * sizeof(void *));
339-
memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
340-
(new_array_size - fw_priv->page_array_size));
341-
kfree(fw_priv->pages);
342-
fw_priv->pages = new_pages;
343-
fw_priv->page_array_size = new_array_size;
351+
memcpy(new_pages, buf->pages,
352+
buf->page_array_size * sizeof(void *));
353+
memset(&new_pages[buf->page_array_size], 0, sizeof(void *) *
354+
(new_array_size - buf->page_array_size));
355+
kfree(buf->pages);
356+
buf->pages = new_pages;
357+
buf->page_array_size = new_array_size;
344358
}
345359

346-
while (fw_priv->nr_pages < pages_needed) {
347-
fw_priv->pages[fw_priv->nr_pages] =
360+
while (buf->nr_pages < pages_needed) {
361+
buf->pages[buf->nr_pages] =
348362
alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
349363

350-
if (!fw_priv->pages[fw_priv->nr_pages]) {
364+
if (!buf->pages[buf->nr_pages]) {
351365
fw_load_abort(fw_priv);
352366
return -ENOMEM;
353367
}
354-
fw_priv->nr_pages++;
368+
buf->nr_pages++;
355369
}
356370
return 0;
357371
}
@@ -374,15 +388,15 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
374388
{
375389
struct device *dev = kobj_to_dev(kobj);
376390
struct firmware_priv *fw_priv = to_firmware_priv(dev);
377-
struct firmware *fw;
391+
struct firmware_buf *buf;
378392
ssize_t retval;
379393

380394
if (!capable(CAP_SYS_RAWIO))
381395
return -EPERM;
382396

383397
mutex_lock(&fw_lock);
384-
fw = fw_priv->fw;
385-
if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
398+
buf = fw_priv->buf;
399+
if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) {
386400
retval = -ENODEV;
387401
goto out;
388402
}
@@ -399,17 +413,17 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
399413
int page_ofs = offset & (PAGE_SIZE - 1);
400414
int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
401415

402-
page_data = kmap(fw_priv->pages[page_nr]);
416+
page_data = kmap(buf->pages[page_nr]);
403417

404418
memcpy(page_data + page_ofs, buffer, page_cnt);
405419

406-
kunmap(fw_priv->pages[page_nr]);
420+
kunmap(buf->pages[page_nr]);
407421
buffer += page_cnt;
408422
offset += page_cnt;
409423
count -= page_cnt;
410424
}
411425

412-
fw_priv->size = max_t(size_t, offset, fw_priv->size);
426+
buf->size = max_t(size_t, offset, buf->size);
413427
out:
414428
mutex_unlock(&fw_lock);
415429
return retval;
@@ -434,28 +448,39 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
434448
struct device *device, bool uevent, bool nowait)
435449
{
436450
struct firmware_priv *fw_priv;
451+
struct firmware_buf *buf;
437452
struct device *f_dev;
438453

439-
fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
454+
fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL);
440455
if (!fw_priv) {
441456
dev_err(device, "%s: kmalloc failed\n", __func__);
442-
return ERR_PTR(-ENOMEM);
457+
fw_priv = ERR_PTR(-ENOMEM);
458+
goto exit;
459+
}
460+
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;
443467
}
444468

445-
fw_priv->fw = firmware;
469+
buf->fw = firmware;
470+
fw_priv->buf = buf;
446471
fw_priv->nowait = nowait;
447-
strcpy(fw_priv->fw_id, fw_name);
448-
init_completion(&fw_priv->completion);
449472
setup_timer(&fw_priv->timeout,
450473
firmware_class_timeout, (u_long) fw_priv);
474+
strcpy(buf->fw_id, fw_name);
475+
init_completion(&buf->completion);
451476

452477
f_dev = &fw_priv->dev;
453478

454479
device_initialize(f_dev);
455480
dev_set_name(f_dev, "%s", fw_name);
456481
f_dev->parent = device;
457482
f_dev->class = &firmware_class;
458-
483+
exit:
459484
return fw_priv;
460485
}
461486

@@ -496,24 +521,18 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
496521
}
497522

498523
/* transfer the ownership of pages to firmware */
499-
static int fw_set_page_data(struct firmware_priv *fw_priv)
524+
static int fw_set_page_data(struct firmware_buf *buf)
500525
{
501-
struct firmware *fw = fw_priv->fw;
526+
struct firmware *fw = buf->fw;
502527

503-
fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages,
504-
0, PAGE_KERNEL_RO);
505-
if (!fw_priv->data)
528+
buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO);
529+
if (!buf->data)
506530
return -ENOMEM;
507531

508-
fw->data = fw_priv->data;
509-
fw->pages = fw_priv->pages;
510-
fw->size = fw_priv->size;
511-
512-
WARN_ON(PFN_UP(fw->size) != fw_priv->nr_pages);
513-
514-
fw_priv->nr_pages = 0;
515-
fw_priv->pages = NULL;
516-
fw_priv->data = NULL;
532+
fw->data = buf->data;
533+
fw->pages = buf->pages;
534+
fw->size = buf->size;
535+
WARN_ON(PFN_UP(fw->size) != buf->nr_pages);
517536

518537
return 0;
519538
}
@@ -523,6 +542,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
523542
{
524543
int retval = 0;
525544
struct device *f_dev = &fw_priv->dev;
545+
struct firmware_buf *buf = fw_priv->buf;
526546

527547
dev_set_uevent_suppress(f_dev, true);
528548

@@ -549,26 +569,30 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
549569

550570
if (uevent) {
551571
dev_set_uevent_suppress(f_dev, false);
552-
dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
572+
dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
553573
if (timeout != MAX_SCHEDULE_TIMEOUT)
554574
mod_timer(&fw_priv->timeout,
555575
round_jiffies_up(jiffies + timeout));
556576

557577
kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
558578
}
559579

560-
wait_for_completion(&fw_priv->completion);
580+
wait_for_completion(&buf->completion);
561581

562582
del_timer_sync(&fw_priv->timeout);
563583

564584
mutex_lock(&fw_lock);
565-
if (!fw_priv->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
585+
if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
566586
retval = -ENOENT;
567587

568588
/* transfer pages ownership at the last minute */
569589
if (!retval)
570-
retval = fw_set_page_data(fw_priv);
571-
fw_priv->fw = NULL;
590+
retval = fw_set_page_data(buf);
591+
if (retval)
592+
fw_free_buf(buf); /* free untransfered pages buffer */
593+
594+
kfree(buf);
595+
fw_priv->buf = NULL;
572596
mutex_unlock(&fw_lock);
573597

574598
device_remove_file(f_dev, &dev_attr_loading);

0 commit comments

Comments
 (0)