diff options
author | Ming Lei <ming.lei@canonical.com> | 2012-08-04 00:01:20 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-16 16:15:08 -0400 |
commit | 1244691c73b250be522e77ac1a00ad53b601b4c4 (patch) | |
tree | 84547800970274ed513d60cec3751e17e8c080f3 /drivers/base/firmware_class.c | |
parent | 99c2aa72306079976369aad7fc62cc71931d692a (diff) |
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 <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.c | 180 |
1 files changed, 102 insertions, 78 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 04c75b56f4fc..5f2076e5d5b1 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -89,7 +89,7 @@ static inline long firmware_loading_timeout(void) | |||
89 | * guarding for corner cases a global lock should be OK */ | 89 | * guarding for corner cases a global lock should be OK */ |
90 | static DEFINE_MUTEX(fw_lock); | 90 | static DEFINE_MUTEX(fw_lock); |
91 | 91 | ||
92 | struct firmware_priv { | 92 | struct firmware_buf { |
93 | struct completion completion; | 93 | struct completion completion; |
94 | struct firmware *fw; | 94 | struct firmware *fw; |
95 | unsigned long status; | 95 | unsigned long status; |
@@ -98,10 +98,14 @@ struct firmware_priv { | |||
98 | struct page **pages; | 98 | struct page **pages; |
99 | int nr_pages; | 99 | int nr_pages; |
100 | int page_array_size; | 100 | int page_array_size; |
101 | char fw_id[]; | ||
102 | }; | ||
103 | |||
104 | struct firmware_priv { | ||
101 | struct timer_list timeout; | 105 | struct timer_list timeout; |
102 | struct device dev; | ||
103 | bool nowait; | 106 | bool nowait; |
104 | char fw_id[]; | 107 | struct device dev; |
108 | struct firmware_buf *buf; | ||
105 | }; | 109 | }; |
106 | 110 | ||
107 | static struct firmware_priv *to_firmware_priv(struct device *dev) | 111 | static struct firmware_priv *to_firmware_priv(struct device *dev) |
@@ -111,8 +115,10 @@ static struct firmware_priv *to_firmware_priv(struct device *dev) | |||
111 | 115 | ||
112 | static void fw_load_abort(struct firmware_priv *fw_priv) | 116 | static void fw_load_abort(struct firmware_priv *fw_priv) |
113 | { | 117 | { |
114 | set_bit(FW_STATUS_ABORT, &fw_priv->status); | 118 | struct firmware_buf *buf = fw_priv->buf; |
115 | complete(&fw_priv->completion); | 119 | |
120 | set_bit(FW_STATUS_ABORT, &buf->status); | ||
121 | complete(&buf->completion); | ||
116 | } | 122 | } |
117 | 123 | ||
118 | static ssize_t firmware_timeout_show(struct class *class, | 124 | static ssize_t firmware_timeout_show(struct class *class, |
@@ -152,15 +158,21 @@ static struct class_attribute firmware_class_attrs[] = { | |||
152 | __ATTR_NULL | 158 | __ATTR_NULL |
153 | }; | 159 | }; |
154 | 160 | ||
155 | static void fw_dev_release(struct device *dev) | 161 | static void fw_free_buf(struct firmware_buf *buf) |
156 | { | 162 | { |
157 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | ||
158 | int i; | 163 | int i; |
159 | 164 | ||
160 | /* free untransfered pages buffer */ | 165 | if (!buf) |
161 | for (i = 0; i < fw_priv->nr_pages; i++) | 166 | return; |
162 | __free_page(fw_priv->pages[i]); | 167 | |
163 | kfree(fw_priv->pages); | 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); | ||
164 | 176 | ||
165 | kfree(fw_priv); | 177 | kfree(fw_priv); |
166 | 178 | ||
@@ -171,7 +183,7 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
171 | { | 183 | { |
172 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | 184 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
173 | 185 | ||
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)) |
175 | return -ENOMEM; | 187 | return -ENOMEM; |
176 | if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) | 188 | if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) |
177 | return -ENOMEM; | 189 | return -ENOMEM; |
@@ -192,7 +204,7 @@ static ssize_t firmware_loading_show(struct device *dev, | |||
192 | struct device_attribute *attr, char *buf) | 204 | struct device_attribute *attr, char *buf) |
193 | { | 205 | { |
194 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | 206 | 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); |
196 | 208 | ||
197 | return sprintf(buf, "%d\n", loading); | 209 | return sprintf(buf, "%d\n", loading); |
198 | } | 210 | } |
@@ -231,32 +243,33 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
231 | const char *buf, size_t count) | 243 | const char *buf, size_t count) |
232 | { | 244 | { |
233 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | 245 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
246 | struct firmware_buf *fw_buf = fw_priv->buf; | ||
234 | int loading = simple_strtol(buf, NULL, 10); | 247 | int loading = simple_strtol(buf, NULL, 10); |
235 | int i; | 248 | int i; |
236 | 249 | ||
237 | mutex_lock(&fw_lock); | 250 | mutex_lock(&fw_lock); |
238 | 251 | ||
239 | if (!fw_priv->fw) | 252 | if (!fw_buf) |
240 | goto out; | 253 | goto out; |
241 | 254 | ||
242 | switch (loading) { | 255 | switch (loading) { |
243 | case 1: | 256 | case 1: |
244 | /* discarding any previous partial load */ | 257 | /* discarding any previous partial load */ |
245 | if (!test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 258 | if (!test_bit(FW_STATUS_DONE, &fw_buf->status)) { |
246 | for (i = 0; i < fw_priv->nr_pages; i++) | 259 | for (i = 0; i < fw_buf->nr_pages; i++) |
247 | __free_page(fw_priv->pages[i]); | 260 | __free_page(fw_buf->pages[i]); |
248 | kfree(fw_priv->pages); | 261 | kfree(fw_buf->pages); |
249 | fw_priv->pages = NULL; | 262 | fw_buf->pages = NULL; |
250 | fw_priv->page_array_size = 0; | 263 | fw_buf->page_array_size = 0; |
251 | fw_priv->nr_pages = 0; | 264 | fw_buf->nr_pages = 0; |
252 | set_bit(FW_STATUS_LOADING, &fw_priv->status); | 265 | set_bit(FW_STATUS_LOADING, &fw_buf->status); |
253 | } | 266 | } |
254 | break; | 267 | break; |
255 | case 0: | 268 | case 0: |
256 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { | 269 | if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { |
257 | set_bit(FW_STATUS_DONE, &fw_priv->status); | 270 | set_bit(FW_STATUS_DONE, &fw_buf->status); |
258 | clear_bit(FW_STATUS_LOADING, &fw_priv->status); | 271 | clear_bit(FW_STATUS_LOADING, &fw_buf->status); |
259 | complete(&fw_priv->completion); | 272 | complete(&fw_buf->completion); |
260 | break; | 273 | break; |
261 | } | 274 | } |
262 | /* fallthrough */ | 275 | /* fallthrough */ |
@@ -280,21 +293,21 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, | |||
280 | { | 293 | { |
281 | struct device *dev = kobj_to_dev(kobj); | 294 | struct device *dev = kobj_to_dev(kobj); |
282 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | 295 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
283 | struct firmware *fw; | 296 | struct firmware_buf *buf; |
284 | ssize_t ret_count; | 297 | ssize_t ret_count; |
285 | 298 | ||
286 | mutex_lock(&fw_lock); | 299 | mutex_lock(&fw_lock); |
287 | fw = fw_priv->fw; | 300 | buf = fw_priv->buf; |
288 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 301 | if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) { |
289 | ret_count = -ENODEV; | 302 | ret_count = -ENODEV; |
290 | goto out; | 303 | goto out; |
291 | } | 304 | } |
292 | if (offset > fw_priv->size) { | 305 | if (offset > buf->size) { |
293 | ret_count = 0; | 306 | ret_count = 0; |
294 | goto out; | 307 | goto out; |
295 | } | 308 | } |
296 | if (count > fw_priv->size - offset) | 309 | if (count > buf->size - offset) |
297 | count = fw_priv->size - offset; | 310 | count = buf->size - offset; |
298 | 311 | ||
299 | ret_count = count; | 312 | ret_count = count; |
300 | 313 | ||
@@ -304,11 +317,11 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, | |||
304 | int page_ofs = offset & (PAGE_SIZE-1); | 317 | int page_ofs = offset & (PAGE_SIZE-1); |
305 | int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); | 318 | int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); |
306 | 319 | ||
307 | page_data = kmap(fw_priv->pages[page_nr]); | 320 | page_data = kmap(buf->pages[page_nr]); |
308 | 321 | ||
309 | memcpy(buffer, page_data + page_ofs, page_cnt); | 322 | memcpy(buffer, page_data + page_ofs, page_cnt); |
310 | 323 | ||
311 | kunmap(fw_priv->pages[page_nr]); | 324 | kunmap(buf->pages[page_nr]); |
312 | buffer += page_cnt; | 325 | buffer += page_cnt; |
313 | offset += page_cnt; | 326 | offset += page_cnt; |
314 | count -= page_cnt; | 327 | count -= page_cnt; |
@@ -320,12 +333,13 @@ out: | |||
320 | 333 | ||
321 | static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) | 334 | static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) |
322 | { | 335 | { |
336 | struct firmware_buf *buf = fw_priv->buf; | ||
323 | int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT; | 337 | int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT; |
324 | 338 | ||
325 | /* If the array of pages is too small, grow it... */ | 339 | /* 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) { |
327 | int new_array_size = max(pages_needed, | 341 | int new_array_size = max(pages_needed, |
328 | fw_priv->page_array_size * 2); | 342 | buf->page_array_size * 2); |
329 | struct page **new_pages; | 343 | struct page **new_pages; |
330 | 344 | ||
331 | new_pages = kmalloc(new_array_size * sizeof(void *), | 345 | 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) | |||
334 | fw_load_abort(fw_priv); | 348 | fw_load_abort(fw_priv); |
335 | return -ENOMEM; | 349 | return -ENOMEM; |
336 | } | 350 | } |
337 | memcpy(new_pages, fw_priv->pages, | 351 | memcpy(new_pages, buf->pages, |
338 | fw_priv->page_array_size * sizeof(void *)); | 352 | buf->page_array_size * sizeof(void *)); |
339 | memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * | 353 | memset(&new_pages[buf->page_array_size], 0, sizeof(void *) * |
340 | (new_array_size - fw_priv->page_array_size)); | 354 | (new_array_size - buf->page_array_size)); |
341 | kfree(fw_priv->pages); | 355 | kfree(buf->pages); |
342 | fw_priv->pages = new_pages; | 356 | buf->pages = new_pages; |
343 | fw_priv->page_array_size = new_array_size; | 357 | buf->page_array_size = new_array_size; |
344 | } | 358 | } |
345 | 359 | ||
346 | while (fw_priv->nr_pages < pages_needed) { | 360 | while (buf->nr_pages < pages_needed) { |
347 | fw_priv->pages[fw_priv->nr_pages] = | 361 | buf->pages[buf->nr_pages] = |
348 | alloc_page(GFP_KERNEL | __GFP_HIGHMEM); | 362 | alloc_page(GFP_KERNEL | __GFP_HIGHMEM); |
349 | 363 | ||
350 | if (!fw_priv->pages[fw_priv->nr_pages]) { | 364 | if (!buf->pages[buf->nr_pages]) { |
351 | fw_load_abort(fw_priv); | 365 | fw_load_abort(fw_priv); |
352 | return -ENOMEM; | 366 | return -ENOMEM; |
353 | } | 367 | } |
354 | fw_priv->nr_pages++; | 368 | buf->nr_pages++; |
355 | } | 369 | } |
356 | return 0; | 370 | return 0; |
357 | } | 371 | } |
@@ -374,15 +388,15 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, | |||
374 | { | 388 | { |
375 | struct device *dev = kobj_to_dev(kobj); | 389 | struct device *dev = kobj_to_dev(kobj); |
376 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | 390 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
377 | struct firmware *fw; | 391 | struct firmware_buf *buf; |
378 | ssize_t retval; | 392 | ssize_t retval; |
379 | 393 | ||
380 | if (!capable(CAP_SYS_RAWIO)) | 394 | if (!capable(CAP_SYS_RAWIO)) |
381 | return -EPERM; | 395 | return -EPERM; |
382 | 396 | ||
383 | mutex_lock(&fw_lock); | 397 | mutex_lock(&fw_lock); |
384 | fw = fw_priv->fw; | 398 | buf = fw_priv->buf; |
385 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 399 | if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) { |
386 | retval = -ENODEV; | 400 | retval = -ENODEV; |
387 | goto out; | 401 | goto out; |
388 | } | 402 | } |
@@ -399,17 +413,17 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, | |||
399 | int page_ofs = offset & (PAGE_SIZE - 1); | 413 | int page_ofs = offset & (PAGE_SIZE - 1); |
400 | int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); | 414 | int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); |
401 | 415 | ||
402 | page_data = kmap(fw_priv->pages[page_nr]); | 416 | page_data = kmap(buf->pages[page_nr]); |
403 | 417 | ||
404 | memcpy(page_data + page_ofs, buffer, page_cnt); | 418 | memcpy(page_data + page_ofs, buffer, page_cnt); |
405 | 419 | ||
406 | kunmap(fw_priv->pages[page_nr]); | 420 | kunmap(buf->pages[page_nr]); |
407 | buffer += page_cnt; | 421 | buffer += page_cnt; |
408 | offset += page_cnt; | 422 | offset += page_cnt; |
409 | count -= page_cnt; | 423 | count -= page_cnt; |
410 | } | 424 | } |
411 | 425 | ||
412 | fw_priv->size = max_t(size_t, offset, fw_priv->size); | 426 | buf->size = max_t(size_t, offset, buf->size); |
413 | out: | 427 | out: |
414 | mutex_unlock(&fw_lock); | 428 | mutex_unlock(&fw_lock); |
415 | return retval; | 429 | return retval; |
@@ -434,20 +448,31 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, | |||
434 | struct device *device, bool uevent, bool nowait) | 448 | struct device *device, bool uevent, bool nowait) |
435 | { | 449 | { |
436 | struct firmware_priv *fw_priv; | 450 | struct firmware_priv *fw_priv; |
451 | struct firmware_buf *buf; | ||
437 | struct device *f_dev; | 452 | struct device *f_dev; |
438 | 453 | ||
439 | fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL); | 454 | fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL); |
440 | if (!fw_priv) { | 455 | if (!fw_priv) { |
441 | dev_err(device, "%s: kmalloc failed\n", __func__); | 456 | 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; | ||
443 | } | 467 | } |
444 | 468 | ||
445 | fw_priv->fw = firmware; | 469 | buf->fw = firmware; |
470 | fw_priv->buf = buf; | ||
446 | fw_priv->nowait = nowait; | 471 | fw_priv->nowait = nowait; |
447 | strcpy(fw_priv->fw_id, fw_name); | ||
448 | init_completion(&fw_priv->completion); | ||
449 | setup_timer(&fw_priv->timeout, | 472 | setup_timer(&fw_priv->timeout, |
450 | firmware_class_timeout, (u_long) fw_priv); | 473 | firmware_class_timeout, (u_long) fw_priv); |
474 | strcpy(buf->fw_id, fw_name); | ||
475 | init_completion(&buf->completion); | ||
451 | 476 | ||
452 | f_dev = &fw_priv->dev; | 477 | f_dev = &fw_priv->dev; |
453 | 478 | ||
@@ -455,7 +480,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, | |||
455 | dev_set_name(f_dev, "%s", fw_name); | 480 | dev_set_name(f_dev, "%s", fw_name); |
456 | f_dev->parent = device; | 481 | f_dev->parent = device; |
457 | f_dev->class = &firmware_class; | 482 | f_dev->class = &firmware_class; |
458 | 483 | exit: | |
459 | return fw_priv; | 484 | return fw_priv; |
460 | } | 485 | } |
461 | 486 | ||
@@ -496,24 +521,18 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p) | |||
496 | } | 521 | } |
497 | 522 | ||
498 | /* transfer the ownership of pages to firmware */ | 523 | /* 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) |
500 | { | 525 | { |
501 | struct firmware *fw = fw_priv->fw; | 526 | struct firmware *fw = buf->fw; |
502 | 527 | ||
503 | fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, | 528 | buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); |
504 | 0, PAGE_KERNEL_RO); | 529 | if (!buf->data) |
505 | if (!fw_priv->data) | ||
506 | return -ENOMEM; | 530 | return -ENOMEM; |
507 | 531 | ||
508 | fw->data = fw_priv->data; | 532 | fw->data = buf->data; |
509 | fw->pages = fw_priv->pages; | 533 | fw->pages = buf->pages; |
510 | fw->size = fw_priv->size; | 534 | fw->size = buf->size; |
511 | 535 | WARN_ON(PFN_UP(fw->size) != buf->nr_pages); | |
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; | ||
517 | 536 | ||
518 | return 0; | 537 | return 0; |
519 | } | 538 | } |
@@ -523,6 +542,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, | |||
523 | { | 542 | { |
524 | int retval = 0; | 543 | int retval = 0; |
525 | struct device *f_dev = &fw_priv->dev; | 544 | struct device *f_dev = &fw_priv->dev; |
545 | struct firmware_buf *buf = fw_priv->buf; | ||
526 | 546 | ||
527 | dev_set_uevent_suppress(f_dev, true); | 547 | dev_set_uevent_suppress(f_dev, true); |
528 | 548 | ||
@@ -549,7 +569,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, | |||
549 | 569 | ||
550 | if (uevent) { | 570 | if (uevent) { |
551 | dev_set_uevent_suppress(f_dev, false); | 571 | 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); |
553 | if (timeout != MAX_SCHEDULE_TIMEOUT) | 573 | if (timeout != MAX_SCHEDULE_TIMEOUT) |
554 | mod_timer(&fw_priv->timeout, | 574 | mod_timer(&fw_priv->timeout, |
555 | round_jiffies_up(jiffies + timeout)); | 575 | round_jiffies_up(jiffies + timeout)); |
@@ -557,18 +577,22 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, | |||
557 | kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); | 577 | kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); |
558 | } | 578 | } |
559 | 579 | ||
560 | wait_for_completion(&fw_priv->completion); | 580 | wait_for_completion(&buf->completion); |
561 | 581 | ||
562 | del_timer_sync(&fw_priv->timeout); | 582 | del_timer_sync(&fw_priv->timeout); |
563 | 583 | ||
564 | mutex_lock(&fw_lock); | 584 | 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)) |
566 | retval = -ENOENT; | 586 | retval = -ENOENT; |
567 | 587 | ||
568 | /* transfer pages ownership at the last minute */ | 588 | /* transfer pages ownership at the last minute */ |
569 | if (!retval) | 589 | if (!retval) |
570 | retval = fw_set_page_data(fw_priv); | 590 | retval = fw_set_page_data(buf); |
571 | fw_priv->fw = NULL; | 591 | if (retval) |
592 | fw_free_buf(buf); /* free untransfered pages buffer */ | ||
593 | |||
594 | kfree(buf); | ||
595 | fw_priv->buf = NULL; | ||
572 | mutex_unlock(&fw_lock); | 596 | mutex_unlock(&fw_lock); |
573 | 597 | ||
574 | device_remove_file(f_dev, &dev_attr_loading); | 598 | device_remove_file(f_dev, &dev_attr_loading); |