| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * APEI Error INJection support |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 9 | 10 | * |
|---|
| 10 | 11 | * Copyright 2009-2010 Intel Corp. |
|---|
| 11 | 12 | * Author: Huang Ying <ying.huang@intel.com> |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is free software; you can redistribute it and/or |
|---|
| 14 | | - * modify it under the terms of the GNU General Public License version |
|---|
| 15 | | - * 2 as published by the Free Software Foundation. |
|---|
| 16 | | - * |
|---|
| 17 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 18 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 19 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 20 | | - * GNU General Public License for more details. |
|---|
| 21 | 13 | */ |
|---|
| 22 | 14 | |
|---|
| 23 | 15 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 180 | 172 | static int einj_timedout(u64 *t) |
|---|
| 181 | 173 | { |
|---|
| 182 | 174 | if ((s64)*t < SPIN_UNIT) { |
|---|
| 183 | | - pr_warning(FW_WARN "Firmware does not respond in time\n"); |
|---|
| 175 | + pr_warn(FW_WARN "Firmware does not respond in time\n"); |
|---|
| 184 | 176 | return 1; |
|---|
| 185 | 177 | } |
|---|
| 186 | 178 | *t -= SPIN_UNIT; |
|---|
| .. | .. |
|---|
| 320 | 312 | } |
|---|
| 321 | 313 | rc = einj_check_trigger_header(trigger_tab); |
|---|
| 322 | 314 | if (rc) { |
|---|
| 323 | | - pr_warning(FW_BUG "Invalid trigger error action table.\n"); |
|---|
| 315 | + pr_warn(FW_BUG "Invalid trigger error action table.\n"); |
|---|
| 324 | 316 | goto out_rel_header; |
|---|
| 325 | 317 | } |
|---|
| 326 | 318 | |
|---|
| .. | .. |
|---|
| 552 | 544 | ((region_intersects(base_addr, size, IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE) |
|---|
| 553 | 545 | != REGION_INTERSECTS) && |
|---|
| 554 | 546 | (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY) |
|---|
| 547 | + != REGION_INTERSECTS) && |
|---|
| 548 | + (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_SOFT_RESERVED) |
|---|
| 555 | 549 | != REGION_INTERSECTS))) |
|---|
| 556 | 550 | return -EINVAL; |
|---|
| 557 | 551 | |
|---|
| .. | .. |
|---|
| 607 | 601 | return 0; |
|---|
| 608 | 602 | } |
|---|
| 609 | 603 | |
|---|
| 610 | | -static int available_error_type_open(struct inode *inode, struct file *file) |
|---|
| 611 | | -{ |
|---|
| 612 | | - return single_open(file, available_error_type_show, NULL); |
|---|
| 613 | | -} |
|---|
| 614 | | - |
|---|
| 615 | | -static const struct file_operations available_error_type_fops = { |
|---|
| 616 | | - .open = available_error_type_open, |
|---|
| 617 | | - .read = seq_read, |
|---|
| 618 | | - .llseek = seq_lseek, |
|---|
| 619 | | - .release = single_release, |
|---|
| 620 | | -}; |
|---|
| 604 | +DEFINE_SHOW_ATTRIBUTE(available_error_type); |
|---|
| 621 | 605 | |
|---|
| 622 | 606 | static int error_type_get(void *data, u64 *val) |
|---|
| 623 | 607 | { |
|---|
| .. | .. |
|---|
| 654 | 638 | return 0; |
|---|
| 655 | 639 | } |
|---|
| 656 | 640 | |
|---|
| 657 | | -DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get, |
|---|
| 658 | | - error_type_set, "0x%llx\n"); |
|---|
| 641 | +DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set, |
|---|
| 642 | + "0x%llx\n"); |
|---|
| 659 | 643 | |
|---|
| 660 | 644 | static int error_inject_set(void *data, u64 val) |
|---|
| 661 | 645 | { |
|---|
| .. | .. |
|---|
| 666 | 650 | error_param3, error_param4); |
|---|
| 667 | 651 | } |
|---|
| 668 | 652 | |
|---|
| 669 | | -DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, |
|---|
| 670 | | - error_inject_set, "%llu\n"); |
|---|
| 653 | +DEFINE_DEBUGFS_ATTRIBUTE(error_inject_fops, NULL, error_inject_set, "%llu\n"); |
|---|
| 671 | 654 | |
|---|
| 672 | 655 | static int einj_check_table(struct acpi_table_einj *einj_tab) |
|---|
| 673 | 656 | { |
|---|
| .. | .. |
|---|
| 689 | 672 | { |
|---|
| 690 | 673 | int rc; |
|---|
| 691 | 674 | acpi_status status; |
|---|
| 692 | | - struct dentry *fentry; |
|---|
| 693 | 675 | struct apei_exec_context ctx; |
|---|
| 694 | 676 | |
|---|
| 695 | 677 | if (acpi_disabled) { |
|---|
| .. | .. |
|---|
| 712 | 694 | rc = einj_check_table(einj_tab); |
|---|
| 713 | 695 | if (rc) { |
|---|
| 714 | 696 | pr_warn(FW_BUG "Invalid EINJ table.\n"); |
|---|
| 715 | | - return -EINVAL; |
|---|
| 697 | + goto err_put_table; |
|---|
| 716 | 698 | } |
|---|
| 717 | 699 | |
|---|
| 718 | 700 | rc = -ENOMEM; |
|---|
| 719 | 701 | einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir()); |
|---|
| 720 | | - if (!einj_debug_dir) { |
|---|
| 721 | | - pr_err("Error creating debugfs node.\n"); |
|---|
| 722 | | - goto err_cleanup; |
|---|
| 723 | | - } |
|---|
| 724 | 702 | |
|---|
| 725 | | - fentry = debugfs_create_file("available_error_type", S_IRUSR, |
|---|
| 726 | | - einj_debug_dir, NULL, |
|---|
| 727 | | - &available_error_type_fops); |
|---|
| 728 | | - if (!fentry) |
|---|
| 729 | | - goto err_cleanup; |
|---|
| 730 | | - |
|---|
| 731 | | - fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR, |
|---|
| 732 | | - einj_debug_dir, NULL, &error_type_fops); |
|---|
| 733 | | - if (!fentry) |
|---|
| 734 | | - goto err_cleanup; |
|---|
| 735 | | - fentry = debugfs_create_file("error_inject", S_IWUSR, |
|---|
| 736 | | - einj_debug_dir, NULL, &error_inject_fops); |
|---|
| 737 | | - if (!fentry) |
|---|
| 738 | | - goto err_cleanup; |
|---|
| 703 | + debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir, |
|---|
| 704 | + NULL, &available_error_type_fops); |
|---|
| 705 | + debugfs_create_file_unsafe("error_type", 0600, einj_debug_dir, |
|---|
| 706 | + NULL, &error_type_fops); |
|---|
| 707 | + debugfs_create_file_unsafe("error_inject", 0200, einj_debug_dir, |
|---|
| 708 | + NULL, &error_inject_fops); |
|---|
| 739 | 709 | |
|---|
| 740 | 710 | apei_resources_init(&einj_resources); |
|---|
| 741 | 711 | einj_exec_ctx_init(&ctx); |
|---|
| .. | .. |
|---|
| 760 | 730 | rc = -ENOMEM; |
|---|
| 761 | 731 | einj_param = einj_get_parameter_address(); |
|---|
| 762 | 732 | if ((param_extension || acpi5) && einj_param) { |
|---|
| 763 | | - fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR, |
|---|
| 764 | | - einj_debug_dir, &error_flags); |
|---|
| 765 | | - if (!fentry) |
|---|
| 766 | | - goto err_unmap; |
|---|
| 767 | | - fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, |
|---|
| 768 | | - einj_debug_dir, &error_param1); |
|---|
| 769 | | - if (!fentry) |
|---|
| 770 | | - goto err_unmap; |
|---|
| 771 | | - fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, |
|---|
| 772 | | - einj_debug_dir, &error_param2); |
|---|
| 773 | | - if (!fentry) |
|---|
| 774 | | - goto err_unmap; |
|---|
| 775 | | - fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR, |
|---|
| 776 | | - einj_debug_dir, &error_param3); |
|---|
| 777 | | - if (!fentry) |
|---|
| 778 | | - goto err_unmap; |
|---|
| 779 | | - fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR, |
|---|
| 780 | | - einj_debug_dir, &error_param4); |
|---|
| 781 | | - if (!fentry) |
|---|
| 782 | | - goto err_unmap; |
|---|
| 783 | | - |
|---|
| 784 | | - fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, |
|---|
| 785 | | - einj_debug_dir, ¬rigger); |
|---|
| 786 | | - if (!fentry) |
|---|
| 787 | | - goto err_unmap; |
|---|
| 733 | + debugfs_create_x32("flags", S_IRUSR | S_IWUSR, einj_debug_dir, |
|---|
| 734 | + &error_flags); |
|---|
| 735 | + debugfs_create_x64("param1", S_IRUSR | S_IWUSR, einj_debug_dir, |
|---|
| 736 | + &error_param1); |
|---|
| 737 | + debugfs_create_x64("param2", S_IRUSR | S_IWUSR, einj_debug_dir, |
|---|
| 738 | + &error_param2); |
|---|
| 739 | + debugfs_create_x64("param3", S_IRUSR | S_IWUSR, einj_debug_dir, |
|---|
| 740 | + &error_param3); |
|---|
| 741 | + debugfs_create_x64("param4", S_IRUSR | S_IWUSR, einj_debug_dir, |
|---|
| 742 | + &error_param4); |
|---|
| 743 | + debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, |
|---|
| 744 | + einj_debug_dir, ¬rigger); |
|---|
| 788 | 745 | } |
|---|
| 789 | 746 | |
|---|
| 790 | 747 | if (vendor_dev[0]) { |
|---|
| 791 | 748 | vendor_blob.data = vendor_dev; |
|---|
| 792 | 749 | vendor_blob.size = strlen(vendor_dev); |
|---|
| 793 | | - fentry = debugfs_create_blob("vendor", S_IRUSR, |
|---|
| 794 | | - einj_debug_dir, &vendor_blob); |
|---|
| 795 | | - if (!fentry) |
|---|
| 796 | | - goto err_unmap; |
|---|
| 797 | | - fentry = debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR, |
|---|
| 798 | | - einj_debug_dir, &vendor_flags); |
|---|
| 799 | | - if (!fentry) |
|---|
| 800 | | - goto err_unmap; |
|---|
| 750 | + debugfs_create_blob("vendor", S_IRUSR, einj_debug_dir, |
|---|
| 751 | + &vendor_blob); |
|---|
| 752 | + debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR, |
|---|
| 753 | + einj_debug_dir, &vendor_flags); |
|---|
| 801 | 754 | } |
|---|
| 802 | 755 | |
|---|
| 803 | 756 | pr_info("Error INJection is initialized.\n"); |
|---|
| 804 | 757 | |
|---|
| 805 | 758 | return 0; |
|---|
| 806 | 759 | |
|---|
| 807 | | -err_unmap: |
|---|
| 808 | | - if (einj_param) { |
|---|
| 809 | | - acpi_size size = (acpi5) ? |
|---|
| 810 | | - sizeof(struct set_error_type_with_address) : |
|---|
| 811 | | - sizeof(struct einj_parameter); |
|---|
| 812 | | - |
|---|
| 813 | | - acpi_os_unmap_iomem(einj_param, size); |
|---|
| 814 | | - pr_err("Error creating param extension debugfs nodes.\n"); |
|---|
| 815 | | - } |
|---|
| 816 | | - apei_exec_post_unmap_gars(&ctx); |
|---|
| 817 | 760 | err_release: |
|---|
| 818 | 761 | apei_resources_release(&einj_resources); |
|---|
| 819 | 762 | err_fini: |
|---|
| 820 | 763 | apei_resources_fini(&einj_resources); |
|---|
| 821 | | -err_cleanup: |
|---|
| 822 | | - pr_err("Error creating primary debugfs nodes.\n"); |
|---|
| 823 | 764 | debugfs_remove_recursive(einj_debug_dir); |
|---|
| 765 | +err_put_table: |
|---|
| 766 | + acpi_put_table((struct acpi_table_header *)einj_tab); |
|---|
| 824 | 767 | |
|---|
| 825 | 768 | return rc; |
|---|
| 826 | 769 | } |
|---|
| .. | .. |
|---|
| 841 | 784 | apei_resources_release(&einj_resources); |
|---|
| 842 | 785 | apei_resources_fini(&einj_resources); |
|---|
| 843 | 786 | debugfs_remove_recursive(einj_debug_dir); |
|---|
| 787 | + acpi_put_table((struct acpi_table_header *)einj_tab); |
|---|
| 844 | 788 | } |
|---|
| 845 | 789 | |
|---|
| 846 | 790 | module_init(einj_init); |
|---|