diff options
author | Ingo Molnar <mingo@kernel.org> | 2013-06-19 07:54:04 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-06-19 07:54:04 -0400 |
commit | d908e1ebbc66a4a44469f27dcfb1f2f46144c4bf (patch) | |
tree | 8a7bc06b20147379cd3f4dcf26abda4afad6101d | |
parent | 2e7e98b85d2b4a085296cad42d0247d4dd3d5778 (diff) | |
parent | ace3647afb3eca214f6da5d653ad116ff77545b6 (diff) |
Merge tag 'please-pull-einj' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras into x86/ras
Pull miscellaneous fixes for ACPI EINJ (error injection) code, from Tony Luck.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | Documentation/acpi/apei/einj.txt | 9 | ||||
-rw-r--r-- | drivers/acpi/apei/einj.c | 39 | ||||
-rw-r--r-- | kernel/resource.c | 1 |
3 files changed, 44 insertions, 5 deletions
diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt index e20b6daaced4..a58b63da1a36 100644 --- a/Documentation/acpi/apei/einj.txt +++ b/Documentation/acpi/apei/einj.txt | |||
@@ -47,11 +47,16 @@ directory apei/einj. The following files are provided. | |||
47 | 47 | ||
48 | - param1 | 48 | - param1 |
49 | This file is used to set the first error parameter value. Effect of | 49 | This file is used to set the first error parameter value. Effect of |
50 | parameter depends on error_type specified. | 50 | parameter depends on error_type specified. For example, if error |
51 | type is memory related type, the param1 should be a valid physical | ||
52 | memory address. | ||
51 | 53 | ||
52 | - param2 | 54 | - param2 |
53 | This file is used to set the second error parameter value. Effect of | 55 | This file is used to set the second error parameter value. Effect of |
54 | parameter depends on error_type specified. | 56 | parameter depends on error_type specified. For example, if error |
57 | type is memory related type, the param2 should be a physical memory | ||
58 | address mask. Linux requires page or narrower granularity, say, | ||
59 | 0xfffffffffffff000. | ||
55 | 60 | ||
56 | - notrigger | 61 | - notrigger |
57 | The EINJ mechanism is a two step process. First inject the error, then | 62 | The EINJ mechanism is a two step process. First inject the error, then |
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 8d457b55c55a..fb57d03e698b 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include <linux/nmi.h> | 33 | #include <linux/nmi.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/mm.h> | ||
35 | #include <acpi/acpi.h> | 36 | #include <acpi/acpi.h> |
36 | 37 | ||
37 | #include "apei-internal.h" | 38 | #include "apei-internal.h" |
@@ -41,6 +42,10 @@ | |||
41 | #define SPIN_UNIT 100 /* 100ns */ | 42 | #define SPIN_UNIT 100 /* 100ns */ |
42 | /* Firmware should respond within 1 milliseconds */ | 43 | /* Firmware should respond within 1 milliseconds */ |
43 | #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) | 44 | #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) |
45 | #define ACPI5_VENDOR_BIT BIT(31) | ||
46 | #define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \ | ||
47 | ACPI_EINJ_MEMORY_UNCORRECTABLE | \ | ||
48 | ACPI_EINJ_MEMORY_FATAL) | ||
44 | 49 | ||
45 | /* | 50 | /* |
46 | * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action. | 51 | * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action. |
@@ -367,7 +372,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
367 | * This will cause resource conflict with regular memory. So | 372 | * This will cause resource conflict with regular memory. So |
368 | * remove it from trigger table resources. | 373 | * remove it from trigger table resources. |
369 | */ | 374 | */ |
370 | if ((param_extension || acpi5) && (type & 0x0038) && param2) { | 375 | if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) { |
371 | struct apei_resources addr_resources; | 376 | struct apei_resources addr_resources; |
372 | apei_resources_init(&addr_resources); | 377 | apei_resources_init(&addr_resources); |
373 | trigger_param_region = einj_get_trigger_parameter_region( | 378 | trigger_param_region = einj_get_trigger_parameter_region( |
@@ -427,7 +432,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) | |||
427 | struct set_error_type_with_address *v5param = einj_param; | 432 | struct set_error_type_with_address *v5param = einj_param; |
428 | 433 | ||
429 | v5param->type = type; | 434 | v5param->type = type; |
430 | if (type & 0x80000000) { | 435 | if (type & ACPI5_VENDOR_BIT) { |
431 | switch (vendor_flags) { | 436 | switch (vendor_flags) { |
432 | case SETWA_FLAGS_APICID: | 437 | case SETWA_FLAGS_APICID: |
433 | v5param->apicid = param1; | 438 | v5param->apicid = param1; |
@@ -512,7 +517,34 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) | |||
512 | static int einj_error_inject(u32 type, u64 param1, u64 param2) | 517 | static int einj_error_inject(u32 type, u64 param1, u64 param2) |
513 | { | 518 | { |
514 | int rc; | 519 | int rc; |
520 | unsigned long pfn; | ||
515 | 521 | ||
522 | /* | ||
523 | * We need extra sanity checks for memory errors. | ||
524 | * Other types leap directly to injection. | ||
525 | */ | ||
526 | |||
527 | /* ensure param1/param2 existed */ | ||
528 | if (!(param_extension || acpi5)) | ||
529 | goto inject; | ||
530 | |||
531 | /* ensure injection is memory related */ | ||
532 | if (type & ACPI5_VENDOR_BIT) { | ||
533 | if (vendor_flags != SETWA_FLAGS_MEM) | ||
534 | goto inject; | ||
535 | } else if (!(type & MEM_ERROR_MASK)) | ||
536 | goto inject; | ||
537 | |||
538 | /* | ||
539 | * Disallow crazy address masks that give BIOS leeway to pick | ||
540 | * injection address almost anywhere. Insist on page or | ||
541 | * better granularity and that target address is normal RAM. | ||
542 | */ | ||
543 | pfn = PFN_DOWN(param1 & param2); | ||
544 | if (!page_is_ram(pfn) || ((param2 & PAGE_MASK) != PAGE_MASK)) | ||
545 | return -EINVAL; | ||
546 | |||
547 | inject: | ||
516 | mutex_lock(&einj_mutex); | 548 | mutex_lock(&einj_mutex); |
517 | rc = __einj_error_inject(type, param1, param2); | 549 | rc = __einj_error_inject(type, param1, param2); |
518 | mutex_unlock(&einj_mutex); | 550 | mutex_unlock(&einj_mutex); |
@@ -590,7 +622,7 @@ static int error_type_set(void *data, u64 val) | |||
590 | * Vendor defined types have 0x80000000 bit set, and | 622 | * Vendor defined types have 0x80000000 bit set, and |
591 | * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE | 623 | * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE |
592 | */ | 624 | */ |
593 | vendor = val & 0x80000000; | 625 | vendor = val & ACPI5_VENDOR_BIT; |
594 | tval = val & 0x7fffffff; | 626 | tval = val & 0x7fffffff; |
595 | 627 | ||
596 | /* Only one error type can be specified */ | 628 | /* Only one error type can be specified */ |
@@ -694,6 +726,7 @@ static int __init einj_init(void) | |||
694 | if (rc) | 726 | if (rc) |
695 | goto err_release; | 727 | goto err_release; |
696 | 728 | ||
729 | rc = -ENOMEM; | ||
697 | einj_param = einj_get_parameter_address(); | 730 | einj_param = einj_get_parameter_address(); |
698 | if ((param_extension || acpi5) && einj_param) { | 731 | if ((param_extension || acpi5) && einj_param) { |
699 | fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, | 732 | fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, |
diff --git a/kernel/resource.c b/kernel/resource.c index d7386986e10e..77bf11a86c7d 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -409,6 +409,7 @@ int __weak page_is_ram(unsigned long pfn) | |||
409 | { | 409 | { |
410 | return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; | 410 | return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; |
411 | } | 411 | } |
412 | EXPORT_SYMBOL_GPL(page_is_ram); | ||
412 | 413 | ||
413 | void __weak arch_remove_reservations(struct resource *avail) | 414 | void __weak arch_remove_reservations(struct resource *avail) |
414 | { | 415 | { |