.. | .. |
---|
22 | 22 | #include <linux/slab.h> |
---|
23 | 23 | #include <linux/uaccess.h> |
---|
24 | 24 | #include <linux/delay.h> |
---|
| 25 | +#include <linux/kstrtox.h> |
---|
25 | 26 | #include <linux/kthread.h> |
---|
26 | 27 | #include <linux/vmalloc.h> |
---|
27 | 28 | #include <linux/efi_embedded_fw.h> |
---|
.. | .. |
---|
41 | 42 | bool sent; |
---|
42 | 43 | const struct firmware *fw; |
---|
43 | 44 | const char *name; |
---|
| 45 | + const char *fw_buf; |
---|
44 | 46 | struct completion completion; |
---|
45 | 47 | struct task_struct *task; |
---|
46 | 48 | struct device *dev; |
---|
.. | .. |
---|
143 | 145 | |
---|
144 | 146 | for (i = 0; i < test_fw_config->num_requests; i++) { |
---|
145 | 147 | req = &test_fw_config->reqs[i]; |
---|
146 | | - if (req->fw) |
---|
| 148 | + if (req->fw) { |
---|
| 149 | + if (req->fw_buf) { |
---|
| 150 | + kfree_const(req->fw_buf); |
---|
| 151 | + req->fw_buf = NULL; |
---|
| 152 | + } |
---|
147 | 153 | release_firmware(req->fw); |
---|
| 154 | + req->fw = NULL; |
---|
| 155 | + } |
---|
148 | 156 | } |
---|
149 | 157 | |
---|
150 | 158 | vfree(test_fw_config->reqs); |
---|
.. | .. |
---|
175 | 183 | { |
---|
176 | 184 | *dst = kstrndup(name, count, gfp); |
---|
177 | 185 | if (!*dst) |
---|
178 | | - return -ENOSPC; |
---|
| 186 | + return -ENOMEM; |
---|
179 | 187 | return count; |
---|
180 | 188 | } |
---|
181 | 189 | |
---|
.. | .. |
---|
313 | 321 | return len; |
---|
314 | 322 | } |
---|
315 | 323 | |
---|
| 324 | +static inline int __test_dev_config_update_bool(const char *buf, size_t size, |
---|
| 325 | + bool *cfg) |
---|
| 326 | +{ |
---|
| 327 | + int ret; |
---|
| 328 | + |
---|
| 329 | + if (kstrtobool(buf, cfg) < 0) |
---|
| 330 | + ret = -EINVAL; |
---|
| 331 | + else |
---|
| 332 | + ret = size; |
---|
| 333 | + |
---|
| 334 | + return ret; |
---|
| 335 | +} |
---|
| 336 | + |
---|
316 | 337 | static int test_dev_config_update_bool(const char *buf, size_t size, |
---|
317 | 338 | bool *cfg) |
---|
318 | 339 | { |
---|
319 | 340 | int ret; |
---|
320 | 341 | |
---|
321 | 342 | mutex_lock(&test_fw_mutex); |
---|
322 | | - if (strtobool(buf, cfg) < 0) |
---|
323 | | - ret = -EINVAL; |
---|
324 | | - else |
---|
325 | | - ret = size; |
---|
| 343 | + ret = __test_dev_config_update_bool(buf, size, cfg); |
---|
326 | 344 | mutex_unlock(&test_fw_mutex); |
---|
327 | 345 | |
---|
328 | 346 | return ret; |
---|
.. | .. |
---|
333 | 351 | return snprintf(buf, PAGE_SIZE, "%d\n", val); |
---|
334 | 352 | } |
---|
335 | 353 | |
---|
336 | | -static int test_dev_config_update_size_t(const char *buf, |
---|
| 354 | +static int __test_dev_config_update_size_t( |
---|
| 355 | + const char *buf, |
---|
337 | 356 | size_t size, |
---|
338 | 357 | size_t *cfg) |
---|
339 | 358 | { |
---|
.. | .. |
---|
344 | 363 | if (ret) |
---|
345 | 364 | return ret; |
---|
346 | 365 | |
---|
347 | | - mutex_lock(&test_fw_mutex); |
---|
348 | 366 | *(size_t *)cfg = new; |
---|
349 | | - mutex_unlock(&test_fw_mutex); |
---|
350 | 367 | |
---|
351 | 368 | /* Always return full write size even if we didn't consume all */ |
---|
352 | 369 | return size; |
---|
.. | .. |
---|
362 | 379 | return snprintf(buf, PAGE_SIZE, "%d\n", val); |
---|
363 | 380 | } |
---|
364 | 381 | |
---|
365 | | -static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) |
---|
| 382 | +static int __test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) |
---|
366 | 383 | { |
---|
| 384 | + u8 val; |
---|
367 | 385 | int ret; |
---|
368 | | - long new; |
---|
369 | 386 | |
---|
370 | | - ret = kstrtol(buf, 10, &new); |
---|
| 387 | + ret = kstrtou8(buf, 10, &val); |
---|
371 | 388 | if (ret) |
---|
372 | 389 | return ret; |
---|
373 | 390 | |
---|
374 | | - if (new > U8_MAX) |
---|
375 | | - return -EINVAL; |
---|
376 | | - |
---|
377 | | - mutex_lock(&test_fw_mutex); |
---|
378 | | - *(u8 *)cfg = new; |
---|
379 | | - mutex_unlock(&test_fw_mutex); |
---|
| 391 | + *(u8 *)cfg = val; |
---|
380 | 392 | |
---|
381 | 393 | /* Always return full write size even if we didn't consume all */ |
---|
382 | 394 | return size; |
---|
| 395 | +} |
---|
| 396 | + |
---|
| 397 | +static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) |
---|
| 398 | +{ |
---|
| 399 | + int ret; |
---|
| 400 | + |
---|
| 401 | + mutex_lock(&test_fw_mutex); |
---|
| 402 | + ret = __test_dev_config_update_u8(buf, size, cfg); |
---|
| 403 | + mutex_unlock(&test_fw_mutex); |
---|
| 404 | + |
---|
| 405 | + return ret; |
---|
383 | 406 | } |
---|
384 | 407 | |
---|
385 | 408 | static ssize_t test_dev_config_show_u8(char *buf, u8 val) |
---|
.. | .. |
---|
408 | 431 | mutex_unlock(&test_fw_mutex); |
---|
409 | 432 | goto out; |
---|
410 | 433 | } |
---|
411 | | - mutex_unlock(&test_fw_mutex); |
---|
412 | 434 | |
---|
413 | | - rc = test_dev_config_update_u8(buf, count, |
---|
414 | | - &test_fw_config->num_requests); |
---|
| 435 | + rc = __test_dev_config_update_u8(buf, count, |
---|
| 436 | + &test_fw_config->num_requests); |
---|
| 437 | + mutex_unlock(&test_fw_mutex); |
---|
415 | 438 | |
---|
416 | 439 | out: |
---|
417 | 440 | return rc; |
---|
.. | .. |
---|
455 | 478 | mutex_unlock(&test_fw_mutex); |
---|
456 | 479 | goto out; |
---|
457 | 480 | } |
---|
458 | | - mutex_unlock(&test_fw_mutex); |
---|
459 | 481 | |
---|
460 | | - rc = test_dev_config_update_size_t(buf, count, |
---|
461 | | - &test_fw_config->buf_size); |
---|
| 482 | + rc = __test_dev_config_update_size_t(buf, count, |
---|
| 483 | + &test_fw_config->buf_size); |
---|
| 484 | + mutex_unlock(&test_fw_mutex); |
---|
462 | 485 | |
---|
463 | 486 | out: |
---|
464 | 487 | return rc; |
---|
.. | .. |
---|
485 | 508 | mutex_unlock(&test_fw_mutex); |
---|
486 | 509 | goto out; |
---|
487 | 510 | } |
---|
488 | | - mutex_unlock(&test_fw_mutex); |
---|
489 | 511 | |
---|
490 | | - rc = test_dev_config_update_size_t(buf, count, |
---|
491 | | - &test_fw_config->file_offset); |
---|
| 512 | + rc = __test_dev_config_update_size_t(buf, count, |
---|
| 513 | + &test_fw_config->file_offset); |
---|
| 514 | + mutex_unlock(&test_fw_mutex); |
---|
492 | 515 | |
---|
493 | 516 | out: |
---|
494 | 517 | return rc; |
---|
.. | .. |
---|
583 | 606 | |
---|
584 | 607 | name = kstrndup(buf, count, GFP_KERNEL); |
---|
585 | 608 | if (!name) |
---|
586 | | - return -ENOSPC; |
---|
| 609 | + return -ENOMEM; |
---|
587 | 610 | |
---|
588 | 611 | pr_info("loading '%s'\n", name); |
---|
589 | 612 | |
---|
590 | 613 | mutex_lock(&test_fw_mutex); |
---|
591 | 614 | release_firmware(test_firmware); |
---|
| 615 | + if (test_fw_config->reqs) |
---|
| 616 | + __test_release_all_firmware(); |
---|
592 | 617 | test_firmware = NULL; |
---|
593 | 618 | rc = request_firmware(&test_firmware, name, dev); |
---|
594 | 619 | if (rc) { |
---|
.. | .. |
---|
629 | 654 | |
---|
630 | 655 | name = kstrndup(buf, count, GFP_KERNEL); |
---|
631 | 656 | if (!name) |
---|
632 | | - return -ENOSPC; |
---|
| 657 | + return -ENOMEM; |
---|
633 | 658 | |
---|
634 | 659 | pr_info("inserting test platform fw '%s'\n", name); |
---|
635 | 660 | efi_embedded_fw.name = name; |
---|
.. | .. |
---|
682 | 707 | |
---|
683 | 708 | name = kstrndup(buf, count, GFP_KERNEL); |
---|
684 | 709 | if (!name) |
---|
685 | | - return -ENOSPC; |
---|
| 710 | + return -ENOMEM; |
---|
686 | 711 | |
---|
687 | 712 | pr_info("loading '%s'\n", name); |
---|
688 | 713 | |
---|
689 | 714 | mutex_lock(&test_fw_mutex); |
---|
690 | 715 | release_firmware(test_firmware); |
---|
691 | 716 | test_firmware = NULL; |
---|
| 717 | + if (test_fw_config->reqs) |
---|
| 718 | + __test_release_all_firmware(); |
---|
692 | 719 | rc = request_firmware_nowait(THIS_MODULE, 1, name, dev, GFP_KERNEL, |
---|
693 | 720 | NULL, trigger_async_request_cb); |
---|
694 | 721 | if (rc) { |
---|
.. | .. |
---|
725 | 752 | |
---|
726 | 753 | name = kstrndup(buf, count, GFP_KERNEL); |
---|
727 | 754 | if (!name) |
---|
728 | | - return -ENOSPC; |
---|
| 755 | + return -ENOMEM; |
---|
729 | 756 | |
---|
730 | 757 | pr_info("loading '%s' using custom fallback mechanism\n", name); |
---|
731 | 758 | |
---|
732 | 759 | mutex_lock(&test_fw_mutex); |
---|
733 | 760 | release_firmware(test_firmware); |
---|
| 761 | + if (test_fw_config->reqs) |
---|
| 762 | + __test_release_all_firmware(); |
---|
734 | 763 | test_firmware = NULL; |
---|
735 | 764 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, name, |
---|
736 | 765 | dev, GFP_KERNEL, NULL, |
---|
.. | .. |
---|
774 | 803 | |
---|
775 | 804 | test_buf = kzalloc(TEST_FIRMWARE_BUF_SIZE, GFP_KERNEL); |
---|
776 | 805 | if (!test_buf) |
---|
777 | | - return -ENOSPC; |
---|
| 806 | + return -ENOMEM; |
---|
778 | 807 | |
---|
779 | 808 | if (test_fw_config->partial) |
---|
780 | 809 | req->rc = request_partial_firmware_into_buf |
---|
.. | .. |
---|
793 | 822 | test_fw_config->buf_size); |
---|
794 | 823 | if (!req->fw) |
---|
795 | 824 | kfree(test_buf); |
---|
| 825 | + else |
---|
| 826 | + req->fw_buf = test_buf; |
---|
796 | 827 | } else { |
---|
797 | 828 | req->rc = test_fw_config->req_firmware(&req->fw, |
---|
798 | 829 | req->name, |
---|
.. | .. |
---|
832 | 863 | |
---|
833 | 864 | mutex_lock(&test_fw_mutex); |
---|
834 | 865 | |
---|
| 866 | + if (test_fw_config->reqs) { |
---|
| 867 | + rc = -EBUSY; |
---|
| 868 | + goto out_bail; |
---|
| 869 | + } |
---|
| 870 | + |
---|
835 | 871 | test_fw_config->reqs = |
---|
836 | 872 | vzalloc(array3_size(sizeof(struct test_batched_req), |
---|
837 | 873 | test_fw_config->num_requests, 2)); |
---|
.. | .. |
---|
848 | 884 | req->fw = NULL; |
---|
849 | 885 | req->idx = i; |
---|
850 | 886 | req->name = test_fw_config->name; |
---|
| 887 | + req->fw_buf = NULL; |
---|
851 | 888 | req->dev = dev; |
---|
852 | 889 | init_completion(&req->completion); |
---|
853 | 890 | req->task = kthread_run(test_fw_run_batch_request, req, |
---|
.. | .. |
---|
930 | 967 | |
---|
931 | 968 | mutex_lock(&test_fw_mutex); |
---|
932 | 969 | |
---|
| 970 | + if (test_fw_config->reqs) { |
---|
| 971 | + rc = -EBUSY; |
---|
| 972 | + goto out_bail; |
---|
| 973 | + } |
---|
| 974 | + |
---|
933 | 975 | test_fw_config->reqs = |
---|
934 | 976 | vzalloc(array3_size(sizeof(struct test_batched_req), |
---|
935 | 977 | test_fw_config->num_requests, 2)); |
---|
.. | .. |
---|
947 | 989 | for (i = 0; i < test_fw_config->num_requests; i++) { |
---|
948 | 990 | req = &test_fw_config->reqs[i]; |
---|
949 | 991 | req->name = test_fw_config->name; |
---|
| 992 | + req->fw_buf = NULL; |
---|
950 | 993 | req->fw = NULL; |
---|
951 | 994 | req->idx = i; |
---|
952 | 995 | init_completion(&req->completion); |
---|
.. | .. |
---|
1114 | 1157 | |
---|
1115 | 1158 | rc = misc_register(&test_fw_misc_device); |
---|
1116 | 1159 | if (rc) { |
---|
| 1160 | + __test_firmware_config_free(); |
---|
1117 | 1161 | kfree(test_fw_config); |
---|
1118 | 1162 | pr_err("could not register misc device: %d\n", rc); |
---|
1119 | 1163 | return rc; |
---|