Browse Source

Merge tag 'please-pull-einj' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras into x86/ras

Pull error injection update from Tony Luck:

 * Add more flexibility to the error injection (EINJ) debugfs interface

Signed-off-by: Ingo Molnar <mingo@kernel.org>
Ingo Molnar 11 years ago
parent
commit
cc131eef1c
2 changed files with 52 additions and 6 deletions
  1. 18 1
      Documentation/acpi/apei/einj.txt
  2. 34 5
      drivers/acpi/apei/einj.c

+ 18 - 1
Documentation/acpi/apei/einj.txt

@@ -45,11 +45,22 @@ directory apei/einj. The following files are provided.
   injection. Before this, please specify all necessary error
   injection. Before this, please specify all necessary error
   parameters.
   parameters.
 
 
+- flags
+  Present for kernel version 3.13 and above. Used to specify which
+  of param{1..4} are valid and should be used by BIOS during injection.
+  Value is a bitmask as specified in ACPI5.0 spec for the
+  SET_ERROR_TYPE_WITH_ADDRESS data structure:
+	Bit 0 - Processor APIC field valid (see param3 below)
+	Bit 1 - Memory address and mask valid (param1 and param2)
+	Bit 2 - PCIe (seg,bus,dev,fn) valid (param4 below)
+  If set to zero, legacy behaviour is used where the type of injection
+  specifies just one bit set, and param1 is multiplexed.
+
 - param1
 - param1
   This file is used to set the first error parameter value. Effect of
   This file is used to set the first error parameter value. Effect of
   parameter depends on error_type specified. For example, if error
   parameter depends on error_type specified. For example, if error
   type is memory related type, the param1 should be a valid physical
   type is memory related type, the param1 should be a valid physical
-  memory address.
+  memory address. [Unless "flag" is set - see above]
 
 
 - param2
 - param2
   This file is used to set the second error parameter value. Effect of
   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.
   address mask. Linux requires page or narrower granularity, say,
   address mask. Linux requires page or narrower granularity, say,
   0xfffffffffffff000.
   0xfffffffffffff000.
 
 
+- param3
+  Used when the 0x1 bit is set in "flag" to specify the APIC id
+
+- param4
+  Used when the 0x4 bit is set in "flag" to specify target PCIe device
+
 - notrigger
 - notrigger
   The EINJ mechanism is a two step process. First inject the error, then
   The EINJ mechanism is a two step process. First inject the error, then
   perform some actions to trigger it. Setting "notrigger" to 1 skips the
   perform some actions to trigger it. Setting "notrigger" to 1 skips the

+ 34 - 5
drivers/acpi/apei/einj.c

@@ -416,7 +416,8 @@ out:
 	return rc;
 	return rc;
 }
 }
 
 
-static int __einj_error_inject(u32 type, u64 param1, u64 param2)
+static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
+			       u64 param3, u64 param4)
 {
 {
 	struct apei_exec_context ctx;
 	struct apei_exec_context ctx;
 	u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
 	u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
@@ -446,6 +447,12 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
 				break;
 				break;
 			}
 			}
 			v5param->flags = vendor_flags;
 			v5param->flags = vendor_flags;
+		} else if (flags) {
+				v5param->flags = flags;
+				v5param->memory_address = param1;
+				v5param->memory_address_range = param2;
+				v5param->apicid = param3;
+				v5param->pcie_sbdf = param4;
 		} else {
 		} else {
 			switch (type) {
 			switch (type) {
 			case ACPI_EINJ_PROCESSOR_CORRECTABLE:
 			case ACPI_EINJ_PROCESSOR_CORRECTABLE:
@@ -514,11 +521,17 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
 }
 }
 
 
 /* Inject the specified hardware error */
 /* Inject the specified hardware error */
-static int einj_error_inject(u32 type, u64 param1, u64 param2)
+static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
+			     u64 param3, u64 param4)
 {
 {
 	int rc;
 	int rc;
 	unsigned long pfn;
 	unsigned long pfn;
 
 
+	/* If user manually set "flags", make sure it is legal */
+	if (flags && (flags &
+		~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF)))
+		return -EINVAL;
+
 	/*
 	/*
 	 * We need extra sanity checks for memory errors.
 	 * We need extra sanity checks for memory errors.
 	 * Other types leap directly to injection.
 	 * Other types leap directly to injection.
@@ -532,7 +545,7 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2)
 	if (type & ACPI5_VENDOR_BIT) {
 	if (type & ACPI5_VENDOR_BIT) {
 		if (vendor_flags != SETWA_FLAGS_MEM)
 		if (vendor_flags != SETWA_FLAGS_MEM)
 			goto inject;
 			goto inject;
-	} else if (!(type & MEM_ERROR_MASK))
+	} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM))
 		goto inject;
 		goto inject;
 
 
 	/*
 	/*
@@ -546,15 +559,18 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2)
 
 
 inject:
 inject:
 	mutex_lock(&einj_mutex);
 	mutex_lock(&einj_mutex);
-	rc = __einj_error_inject(type, param1, param2);
+	rc = __einj_error_inject(type, flags, param1, param2, param3, param4);
 	mutex_unlock(&einj_mutex);
 	mutex_unlock(&einj_mutex);
 
 
 	return rc;
 	return rc;
 }
 }
 
 
 static u32 error_type;
 static u32 error_type;
+static u32 error_flags;
 static u64 error_param1;
 static u64 error_param1;
 static u64 error_param2;
 static u64 error_param2;
+static u64 error_param3;
+static u64 error_param4;
 static struct dentry *einj_debug_dir;
 static struct dentry *einj_debug_dir;
 
 
 static int available_error_type_show(struct seq_file *m, void *v)
 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)
 	if (!error_type)
 	if (!error_type)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	return einj_error_inject(error_type, error_param1, error_param2);
+	return einj_error_inject(error_type, error_flags, error_param1, error_param2,
+		error_param3, error_param4);
 }
 }
 
 
 DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
 DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
@@ -729,6 +746,10 @@ static int __init einj_init(void)
 	rc = -ENOMEM;
 	rc = -ENOMEM;
 	einj_param = einj_get_parameter_address();
 	einj_param = einj_get_parameter_address();
 	if ((param_extension || acpi5) && einj_param) {
 	if ((param_extension || acpi5) && einj_param) {
+		fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR,
+					    einj_debug_dir, &error_flags);
+		if (!fentry)
+			goto err_unmap;
 		fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
 		fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
 					    einj_debug_dir, &error_param1);
 					    einj_debug_dir, &error_param1);
 		if (!fentry)
 		if (!fentry)
@@ -737,6 +758,14 @@ static int __init einj_init(void)
 					    einj_debug_dir, &error_param2);
 					    einj_debug_dir, &error_param2);
 		if (!fentry)
 		if (!fentry)
 			goto err_unmap;
 			goto err_unmap;
+		fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR,
+					    einj_debug_dir, &error_param3);
+		if (!fentry)
+			goto err_unmap;
+		fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR,
+					    einj_debug_dir, &error_param4);
+		if (!fentry)
+			goto err_unmap;
 
 
 		fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
 		fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
 					    einj_debug_dir, &notrigger);
 					    einj_debug_dir, &notrigger);