aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei
diff options
context:
space:
mode:
authorChen Gong <gong.chen@linux.intel.com>2013-06-06 18:20:51 -0400
committerTony Luck <tony.luck@intel.com>2013-06-06 18:20:51 -0400
commitc5a130325f13b219438cb100e2da71a3e31199f3 (patch)
treea57ee8ac08e1e479078d3e773a87eea3eccae130 /drivers/acpi/apei
parentb8edb64119b4e8158f268e250dcb9919a3b7ccea (diff)
ACPI/APEI: Add parameter check before error injection
When param1 is enabled in EINJ but not assigned with a valid value, sometimes it will cause the error like below: APEI: Can not request [mem 0x7aaa7000-0x7aaa7007] for APEI EINJ Trigger registers It is because some firmware will access target address specified in param1 to trigger the error when injecting memory error. This will cause resource conflict with regular memory. So It must be removed from trigger table resources, but incorrect param1/param2 combination will stop this action. Add extra check to avoid this kind of error. Signed-off-by: Chen Gong <gong.chen@linux.intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r--drivers/acpi/apei/einj.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 2cc8e034a3c0..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 */