diff options
| -rw-r--r-- | Documentation/acpi/apei/einj.txt | 19 | ||||
| -rw-r--r-- | drivers/acpi/apei/einj.c | 39 |
2 files changed, 52 insertions, 6 deletions
diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt index a58b63da1a36..f51861bcb07b 100644 --- a/Documentation/acpi/apei/einj.txt +++ b/Documentation/acpi/apei/einj.txt | |||
| @@ -45,11 +45,22 @@ directory apei/einj. The following files are provided. | |||
| 45 | injection. Before this, please specify all necessary error | 45 | injection. Before this, please specify all necessary error |
| 46 | parameters. | 46 | parameters. |
| 47 | 47 | ||
| 48 | - flags | ||
| 49 | Present for kernel version 3.13 and above. Used to specify which | ||
| 50 | of param{1..4} are valid and should be used by BIOS during injection. | ||
| 51 | Value is a bitmask as specified in ACPI5.0 spec for the | ||
| 52 | SET_ERROR_TYPE_WITH_ADDRESS data structure: | ||
| 53 | Bit 0 - Processor APIC field valid (see param3 below) | ||
| 54 | Bit 1 - Memory address and mask valid (param1 and param2) | ||
| 55 | Bit 2 - PCIe (seg,bus,dev,fn) valid (param4 below) | ||
| 56 | If set to zero, legacy behaviour is used where the type of injection | ||
| 57 | specifies just one bit set, and param1 is multiplexed. | ||
| 58 | |||
| 48 | - param1 | 59 | - param1 |
| 49 | This file is used to set the first error parameter value. Effect of | 60 | This file is used to set the first error parameter value. Effect of |
| 50 | parameter depends on error_type specified. For example, if error | 61 | parameter depends on error_type specified. For example, if error |
| 51 | type is memory related type, the param1 should be a valid physical | 62 | type is memory related type, the param1 should be a valid physical |
| 52 | memory address. | 63 | memory address. [Unless "flag" is set - see above] |
| 53 | 64 | ||
| 54 | - param2 | 65 | - param2 |
| 55 | This file is used to set the second error parameter value. Effect of | 66 | This file is used to set the second error parameter value. Effect of |
| @@ -58,6 +69,12 @@ directory apei/einj. The following files are provided. | |||
| 58 | address mask. Linux requires page or narrower granularity, say, | 69 | address mask. Linux requires page or narrower granularity, say, |
| 59 | 0xfffffffffffff000. | 70 | 0xfffffffffffff000. |
| 60 | 71 | ||
| 72 | - param3 | ||
| 73 | Used when the 0x1 bit is set in "flag" to specify the APIC id | ||
| 74 | |||
| 75 | - param4 | ||
| 76 | Used when the 0x4 bit is set in "flag" to specify target PCIe device | ||
| 77 | |||
| 61 | - notrigger | 78 | - notrigger |
| 62 | The EINJ mechanism is a two step process. First inject the error, then | 79 | The EINJ mechanism is a two step process. First inject the error, then |
| 63 | perform some actions to trigger it. Setting "notrigger" to 1 skips the | 80 | perform some actions to trigger it. Setting "notrigger" to 1 skips the |
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fb57d03e698b..c76674e2a01f 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c | |||
| @@ -416,7 +416,8 @@ out: | |||
| 416 | return rc; | 416 | return rc; |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | static int __einj_error_inject(u32 type, u64 param1, u64 param2) | 419 | static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, |
| 420 | u64 param3, u64 param4) | ||
| 420 | { | 421 | { |
| 421 | struct apei_exec_context ctx; | 422 | struct apei_exec_context ctx; |
| 422 | u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT; | 423 | u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT; |
| @@ -446,6 +447,12 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) | |||
| 446 | break; | 447 | break; |
| 447 | } | 448 | } |
| 448 | v5param->flags = vendor_flags; | 449 | v5param->flags = vendor_flags; |
| 450 | } else if (flags) { | ||
| 451 | v5param->flags = flags; | ||
| 452 | v5param->memory_address = param1; | ||
| 453 | v5param->memory_address_range = param2; | ||
| 454 | v5param->apicid = param3; | ||
| 455 | v5param->pcie_sbdf = param4; | ||
| 449 | } else { | 456 | } else { |
| 450 | switch (type) { | 457 | switch (type) { |
| 451 | case ACPI_EINJ_PROCESSOR_CORRECTABLE: | 458 | case ACPI_EINJ_PROCESSOR_CORRECTABLE: |
| @@ -514,11 +521,17 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) | |||
| 514 | } | 521 | } |
| 515 | 522 | ||
| 516 | /* Inject the specified hardware error */ | 523 | /* Inject the specified hardware error */ |
| 517 | static int einj_error_inject(u32 type, u64 param1, u64 param2) | 524 | static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, |
| 525 | u64 param3, u64 param4) | ||
| 518 | { | 526 | { |
| 519 | int rc; | 527 | int rc; |
| 520 | unsigned long pfn; | 528 | unsigned long pfn; |
| 521 | 529 | ||
| 530 | /* If user manually set "flags", make sure it is legal */ | ||
| 531 | if (flags && (flags & | ||
| 532 | ~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF))) | ||
| 533 | return -EINVAL; | ||
| 534 | |||
| 522 | /* | 535 | /* |
| 523 | * We need extra sanity checks for memory errors. | 536 | * We need extra sanity checks for memory errors. |
| 524 | * Other types leap directly to injection. | 537 | * Other types leap directly to injection. |
| @@ -532,7 +545,7 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2) | |||
| 532 | if (type & ACPI5_VENDOR_BIT) { | 545 | if (type & ACPI5_VENDOR_BIT) { |
| 533 | if (vendor_flags != SETWA_FLAGS_MEM) | 546 | if (vendor_flags != SETWA_FLAGS_MEM) |
| 534 | goto inject; | 547 | goto inject; |
| 535 | } else if (!(type & MEM_ERROR_MASK)) | 548 | } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) |
| 536 | goto inject; | 549 | goto inject; |
| 537 | 550 | ||
| 538 | /* | 551 | /* |
| @@ -546,15 +559,18 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2) | |||
| 546 | 559 | ||
| 547 | inject: | 560 | inject: |
| 548 | mutex_lock(&einj_mutex); | 561 | mutex_lock(&einj_mutex); |
| 549 | rc = __einj_error_inject(type, param1, param2); | 562 | rc = __einj_error_inject(type, flags, param1, param2, param3, param4); |
| 550 | mutex_unlock(&einj_mutex); | 563 | mutex_unlock(&einj_mutex); |
| 551 | 564 | ||
| 552 | return rc; | 565 | return rc; |
| 553 | } | 566 | } |
| 554 | 567 | ||
| 555 | static u32 error_type; | 568 | static u32 error_type; |
| 569 | static u32 error_flags; | ||
| 556 | static u64 error_param1; | 570 | static u64 error_param1; |
| 557 | static u64 error_param2; | 571 | static u64 error_param2; |
| 572 | static u64 error_param3; | ||
| 573 | static u64 error_param4; | ||
| 558 | static struct dentry *einj_debug_dir; | 574 | static struct dentry *einj_debug_dir; |
| 559 | 575 | ||
| 560 | static int available_error_type_show(struct seq_file *m, void *v) | 576 | static int available_error_type_show(struct seq_file *m, void *v) |
| @@ -648,7 +664,8 @@ static int error_inject_set(void *data, u64 val) | |||
| 648 | if (!error_type) | 664 | if (!error_type) |
| 649 | return -EINVAL; | 665 | return -EINVAL; |
| 650 | 666 | ||
| 651 | return einj_error_inject(error_type, error_param1, error_param2); | 667 | return einj_error_inject(error_type, error_flags, error_param1, error_param2, |
| 668 | error_param3, error_param4); | ||
| 652 | } | 669 | } |
| 653 | 670 | ||
| 654 | DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, | 671 | DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, |
| @@ -729,6 +746,10 @@ static int __init einj_init(void) | |||
| 729 | rc = -ENOMEM; | 746 | rc = -ENOMEM; |
| 730 | einj_param = einj_get_parameter_address(); | 747 | einj_param = einj_get_parameter_address(); |
| 731 | if ((param_extension || acpi5) && einj_param) { | 748 | if ((param_extension || acpi5) && einj_param) { |
| 749 | fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR, | ||
| 750 | einj_debug_dir, &error_flags); | ||
| 751 | if (!fentry) | ||
| 752 | goto err_unmap; | ||
| 732 | fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, | 753 | fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, |
| 733 | einj_debug_dir, &error_param1); | 754 | einj_debug_dir, &error_param1); |
| 734 | if (!fentry) | 755 | if (!fentry) |
| @@ -737,6 +758,14 @@ static int __init einj_init(void) | |||
| 737 | einj_debug_dir, &error_param2); | 758 | einj_debug_dir, &error_param2); |
| 738 | if (!fentry) | 759 | if (!fentry) |
| 739 | goto err_unmap; | 760 | goto err_unmap; |
| 761 | fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR, | ||
| 762 | einj_debug_dir, &error_param3); | ||
| 763 | if (!fentry) | ||
| 764 | goto err_unmap; | ||
| 765 | fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR, | ||
| 766 | einj_debug_dir, &error_param4); | ||
| 767 | if (!fentry) | ||
| 768 | goto err_unmap; | ||
| 740 | 769 | ||
| 741 | fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, | 770 | fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, |
| 742 | einj_debug_dir, ¬rigger); | 771 | einj_debug_dir, ¬rigger); |
