aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-06-19 07:54:04 -0400
committerIngo Molnar <mingo@kernel.org>2013-06-19 07:54:04 -0400
commitd908e1ebbc66a4a44469f27dcfb1f2f46144c4bf (patch)
tree8a7bc06b20147379cd3f4dcf26abda4afad6101d
parent2e7e98b85d2b4a085296cad42d0247d4dd3d5778 (diff)
parentace3647afb3eca214f6da5d653ad116ff77545b6 (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.txt9
-rw-r--r--drivers/acpi/apei/einj.c39
-rw-r--r--kernel/resource.c1
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)
512static int einj_error_inject(u32 type, u64 param1, u64 param2) 517static 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
547inject:
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}
412EXPORT_SYMBOL_GPL(page_is_ram);
412 413
413void __weak arch_remove_reservations(struct resource *avail) 414void __weak arch_remove_reservations(struct resource *avail)
414{ 415{