Commit 9ebfbd45f9d4ee9cd72529cf99e5f300eb398e67
Committed by
Greg Kroah-Hartman
1 parent
03d673e6af
Exists in
master
and in
39 other branches
firmware_class: make request_firmware_nowait more useful
Unfortunately, one cannot hold on to the struct firmware that request_firmware_nowait() hands off, which is needed in some cases. Allow this by requiring the callback to free it (via release_firmware). Additionally, give it a gfp_t parameter -- all the current users call it from a GFP_KERNEL context so the GFP_ATOMIC isn't necessary. This also marks an API break which is useful in a sense, although that is obviously not the primary purpose of this change. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Marcel Holtmann <marcel@holtmann.org> Cc: Ming Lei <tom.leiming@gmail.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: David Woodhouse <David.Woodhouse@intel.com> Cc: Pavel Roskin <proski@gnu.org> Cc: Abhay Salunke <abhay_salunke@dell.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 7 changed files with 33 additions and 20 deletions Side-by-side Diff
drivers/base/firmware_class.c
... | ... | @@ -601,12 +601,9 @@ |
601 | 601 | } |
602 | 602 | ret = _request_firmware(&fw, fw_work->name, fw_work->device, |
603 | 603 | fw_work->uevent); |
604 | - if (ret < 0) | |
605 | - fw_work->cont(NULL, fw_work->context); | |
606 | - else { | |
607 | - fw_work->cont(fw, fw_work->context); | |
608 | - release_firmware(fw); | |
609 | - } | |
604 | + | |
605 | + fw_work->cont(fw, fw_work->context); | |
606 | + | |
610 | 607 | module_put(fw_work->module); |
611 | 608 | kfree(fw_work); |
612 | 609 | return ret; |
... | ... | @@ -619,6 +616,7 @@ |
619 | 616 | * is non-zero else the firmware copy must be done manually. |
620 | 617 | * @name: name of firmware file |
621 | 618 | * @device: device for which firmware is being loaded |
619 | + * @gfp: allocation flags | |
622 | 620 | * @context: will be passed over to @cont, and |
623 | 621 | * @fw may be %NULL if firmware request fails. |
624 | 622 | * @cont: function will be called asynchronously when the firmware |
625 | 623 | |
... | ... | @@ -631,12 +629,12 @@ |
631 | 629 | int |
632 | 630 | request_firmware_nowait( |
633 | 631 | struct module *module, int uevent, |
634 | - const char *name, struct device *device, void *context, | |
632 | + const char *name, struct device *device, gfp_t gfp, void *context, | |
635 | 633 | void (*cont)(const struct firmware *fw, void *context)) |
636 | 634 | { |
637 | 635 | struct task_struct *task; |
638 | 636 | struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), |
639 | - GFP_ATOMIC); | |
637 | + gfp); | |
640 | 638 | |
641 | 639 | if (!fw_work) |
642 | 640 | return -ENOMEM; |
drivers/firmware/dell_rbu.c
... | ... | @@ -544,9 +544,12 @@ |
544 | 544 | { |
545 | 545 | rbu_data.entry_created = 0; |
546 | 546 | |
547 | - if (!fw || !fw->size) | |
547 | + if (!fw) | |
548 | 548 | return; |
549 | 549 | |
550 | + if (!fw->size) | |
551 | + goto out; | |
552 | + | |
550 | 553 | spin_lock(&rbu_data.lock); |
551 | 554 | if (!strcmp(image_type, "mono")) { |
552 | 555 | if (!img_update_realloc(fw->size)) |
... | ... | @@ -568,6 +571,8 @@ |
568 | 571 | } else |
569 | 572 | pr_debug("invalid image type specified.\n"); |
570 | 573 | spin_unlock(&rbu_data.lock); |
574 | + out: | |
575 | + release_firmware(fw); | |
571 | 576 | } |
572 | 577 | |
573 | 578 | static ssize_t read_rbu_image_type(struct kobject *kobj, |
... | ... | @@ -615,7 +620,7 @@ |
615 | 620 | spin_unlock(&rbu_data.lock); |
616 | 621 | req_firm_rc = request_firmware_nowait(THIS_MODULE, |
617 | 622 | FW_ACTION_NOHOTPLUG, "dell_rbu", |
618 | - &rbu_device->dev, &context, | |
623 | + &rbu_device->dev, GFP_KERNEL, &context, | |
619 | 624 | callbackfn_rbu); |
620 | 625 | if (req_firm_rc) { |
621 | 626 | printk(KERN_ERR |
drivers/serial/ucc_uart.c
... | ... | @@ -1179,16 +1179,18 @@ |
1179 | 1179 | |
1180 | 1180 | if (firmware->header.length != fw->size) { |
1181 | 1181 | dev_err(dev, "invalid firmware\n"); |
1182 | - return; | |
1182 | + goto out; | |
1183 | 1183 | } |
1184 | 1184 | |
1185 | 1185 | ret = qe_upload_firmware(firmware); |
1186 | 1186 | if (ret) { |
1187 | 1187 | dev_err(dev, "could not load firmware\n"); |
1188 | - return; | |
1188 | + goto out; | |
1189 | 1189 | } |
1190 | 1190 | |
1191 | 1191 | firmware_loaded = 1; |
1192 | + out: | |
1193 | + release_firmware(fw); | |
1192 | 1194 | } |
1193 | 1195 | |
1194 | 1196 | static int ucc_uart_probe(struct of_device *ofdev, |
... | ... | @@ -1247,7 +1249,7 @@ |
1247 | 1249 | */ |
1248 | 1250 | ret = request_firmware_nowait(THIS_MODULE, |
1249 | 1251 | FW_ACTION_HOTPLUG, filename, &ofdev->dev, |
1250 | - &ofdev->dev, uart_firmware_cont); | |
1252 | + GFP_KERNEL, &ofdev->dev, uart_firmware_cont); | |
1251 | 1253 | if (ret) { |
1252 | 1254 | dev_err(&ofdev->dev, |
1253 | 1255 | "could not load firmware %s\n", |
drivers/staging/comedi/drivers/usbdux.c
... | ... | @@ -2327,9 +2327,11 @@ |
2327 | 2327 | if (ret) { |
2328 | 2328 | dev_err(&usbdev->dev, |
2329 | 2329 | "Could not upload firmware (err=%d)\n", ret); |
2330 | - return; | |
2330 | + goto out; | |
2331 | 2331 | } |
2332 | 2332 | comedi_usb_auto_config(usbdev, BOARDNAME); |
2333 | + out: | |
2334 | + release_firmware(fw); | |
2333 | 2335 | } |
2334 | 2336 | |
2335 | 2337 | /* allocate memory for the urbs and initialise them */ |
... | ... | @@ -2580,6 +2582,7 @@ |
2580 | 2582 | FW_ACTION_HOTPLUG, |
2581 | 2583 | "usbdux_firmware.bin", |
2582 | 2584 | &udev->dev, |
2585 | + GFP_KERNEL, | |
2583 | 2586 | usbduxsub + index, |
2584 | 2587 | usbdux_firmware_request_complete_handler); |
2585 | 2588 |
drivers/staging/comedi/drivers/usbduxfast.c
... | ... | @@ -1451,10 +1451,12 @@ |
1451 | 1451 | if (ret) { |
1452 | 1452 | dev_err(&usbdev->dev, |
1453 | 1453 | "Could not upload firmware (err=%d)\n", ret); |
1454 | - return; | |
1454 | + goto out; | |
1455 | 1455 | } |
1456 | 1456 | |
1457 | 1457 | comedi_usb_auto_config(usbdev, BOARDNAME); |
1458 | + out: | |
1459 | + release_firmware(fw); | |
1458 | 1460 | } |
1459 | 1461 | |
1460 | 1462 | /* |
... | ... | @@ -1569,6 +1571,7 @@ |
1569 | 1571 | FW_ACTION_HOTPLUG, |
1570 | 1572 | "usbduxfast_firmware.bin", |
1571 | 1573 | &udev->dev, |
1574 | + GFP_KERNEL, | |
1572 | 1575 | usbduxfastsub + index, |
1573 | 1576 | usbduxfast_firmware_request_complete_handler); |
1574 | 1577 |
drivers/usb/atm/ueagle-atm.c
... | ... | @@ -667,12 +667,12 @@ |
667 | 667 | else |
668 | 668 | uea_info(usb, "firmware uploaded\n"); |
669 | 669 | |
670 | - uea_leaves(usb); | |
671 | - return; | |
670 | + goto err; | |
672 | 671 | |
673 | 672 | err_fw_corrupted: |
674 | 673 | uea_err(usb, "firmware is corrupted\n"); |
675 | 674 | err: |
675 | + release_firmware(fw_entry); | |
676 | 676 | uea_leaves(usb); |
677 | 677 | } |
678 | 678 | |
... | ... | @@ -705,7 +705,8 @@ |
705 | 705 | break; |
706 | 706 | } |
707 | 707 | |
708 | - ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); | |
708 | + ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, | |
709 | + GFP_KERNEL, usb, uea_upload_pre_firmware); | |
709 | 710 | if (ret) |
710 | 711 | uea_err(usb, "firmware %s is not available\n", fw_name); |
711 | 712 | else |
include/linux/firmware.h
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 | #include <linux/module.h> |
5 | 5 | #include <linux/types.h> |
6 | 6 | #include <linux/compiler.h> |
7 | +#include <linux/gfp.h> | |
7 | 8 | |
8 | 9 | #define FW_ACTION_NOHOTPLUG 0 |
9 | 10 | #define FW_ACTION_HOTPLUG 1 |
... | ... | @@ -38,7 +39,7 @@ |
38 | 39 | struct device *device); |
39 | 40 | int request_firmware_nowait( |
40 | 41 | struct module *module, int uevent, |
41 | - const char *name, struct device *device, void *context, | |
42 | + const char *name, struct device *device, gfp_t gfp, void *context, | |
42 | 43 | void (*cont)(const struct firmware *fw, void *context)); |
43 | 44 | |
44 | 45 | void release_firmware(const struct firmware *fw); |
... | ... | @@ -51,7 +52,7 @@ |
51 | 52 | } |
52 | 53 | static inline int request_firmware_nowait( |
53 | 54 | struct module *module, int uevent, |
54 | - const char *name, struct device *device, void *context, | |
55 | + const char *name, struct device *device, gfp_t gfp, void *context, | |
55 | 56 | void (*cont)(const struct firmware *fw, void *context)) |
56 | 57 | { |
57 | 58 | return -EINVAL; |