Skip to contentSkip to conversation

ACPI: APEI: EINJ: Fix EINJV2 memory error injection

PATCH In review Tony Luck 4 participants 6 messages Apr 21 – Apr 27

Subsystems (3)
lore
Share & tools
lore

Tony Luck

author reviewer
#0 lore raw

v4 cover ACPI: APEI: EINJ: Fix EINJV2 memory error injection

EINJV2 (introduced in version 6.5 of the ACPI specification) uses different values for the "type" of injection. Two places in the Linux driver need patching to take account of the new type values.

Changes since V3:

* Moved the #defines for EINV2 types to <acpi/actbl1.h> [Change submitted through ACPICA tree with duplicate in patch 1 of this series]

* Sashiko noted that I'd dropped the test for "flags & SETWA_FLAGS_MEM" from my is_memory_injection() helper.

Tony Luck (2):
ACPICA: Provide #defines for EINJV2 error types
ACPI: APEI: EINJ: Fix EINJV2 memory error injection

 include/acpi/actbl1.h         |  6 +++++
 drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++----------------
 2 files changed, 31 insertions(+), 20 deletions(-)

base-commit: 028ef9c96e96197026887c0f092424679298aae8

Signature · 1 line
2.53.0
author reviewer
#1 lore raw

PATCH v4 1/2 ACPICA: Provide #defines for EINJV2 error types

EINJV2 defined new error types by moving the severity (correctable, uncorrectable non-fatal, uncorrectable fatal) out of the "type".

ACPI 6.5 introduced EINJV2 and defined a vendor defined error type using bit 31. This was dropped in ACPI 6.6.

---
Already applied to https://github.com/acpica/acpica.git as commit e82d2d2fd145 ("Provide #defines for EINJV2 error types")

 include/acpi/actbl1.h | 6 ++++++
 1 file changed, 6 insertions(+)
include/acpi/actbl1.h +6 -0
index 4e15583e0d25..f72e00517eb3 100644
@@ -1386,6 +1386,12 @@ enum acpi_einj_command_status {
 #define ACPI_EINJ_CXL_MEM_FATAL             (1<<17)
 #define ACPI_EINJ_VENDOR_DEFINED            (1<<31)
 
+/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */
+
+#define ACPI_EINJV2_PROCESSOR               (1)
+#define ACPI_EINJV2_MEMORY                  (1<<1)
+#define ACPI_EINJV2_PCIE                    (1<<2)
+
 /*******************************************************************************
  *
  * ERST - Error Record Serialization Table (ACPI 4.0)
Signature · 1 line
2.53.0
#2 lore raw

Re: [PATCH v4 1/2] ACPICA: Provide #defines for EINJV2 error types

Quoted 4 lines · Tony Luck

EINJV2 defined new error types by moving the severity (correctable, uncorrectable non-fatal, uncorrectable fatal) out of the "type".

Quoted 8 lines

ACPI 6.5 introduced EINJV2 and defined a vendor defined error type using bit 31. This was dropped in ACPI 6.6.

---
Already applied to https://github.com/acpica/acpica.git as commit e82d2d2fd145 ("Provide #defines for EINJV2 error types")

So you do

which I've done already for this one and applied it as 7.1-rc material along with the [2/2].

Thanks!

Quoted 26 lines

 include/acpi/actbl1.h | 6 ++++++
 1 file changed, 6 insertions(+)
include/acpi/actbl1.h +6 -1
index 4e15583e0d25..f72e00517eb3 100644
@@ -1386,6 +1386,12 @@ enum acpi_einj_command_status {
 #define ACPI_EINJ_CXL_MEM_FATAL             (1<<17)
 #define ACPI_EINJ_VENDOR_DEFINED            (1<<31)
 
+/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */
+
+#define ACPI_EINJV2_PROCESSOR               (1)
+#define ACPI_EINJV2_MEMORY                  (1<<1)
+#define ACPI_EINJV2_PCIE                    (1<<2)
+
 /*******************************************************************************
  *
  * ERST - Error Record Serialization Table (ACPI 4.0)
--

2.53.0

author reviewer
#3 lore raw

PATCH v4 2/2 ACPI: APEI: EINJ: Fix EINJV2 memory error injection

In reply to Tony Luck

Error types in EINJV2 use different bit positions for each flavor of injection from legacy EINJ.

Two issues:

1) The address sanity checks in einj_error_inject() were skipped for EINJV2 injections. Noted by sashiko[1]
2) __einj_error_trigger() failed to drop the entry of the target physical address from the list of resources that need to be requested.

Add a helper function that checks if an injection is to memory and use it to solve each of these issues.

Note that the old test in __einj_error_trigger() checked that param2 was not zero. This isn't needed because the sanity checks in einj_error_inject() reject memory injections with param2 == 0.

Fixes b47610296d17 ("ACPI: APEI: EINJ: Enable EINJv2 error injections")

#Reported-by: sashiko <[email protected]>

---
 drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 20 deletions(-)
drivers/acpi/apei/einj-core.c +25 -20
index a9248af078f6..1f3fa2278584 100644
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
 
 	return NULL;
 }
+
+static bool is_memory_injection(u32 type, u32 flags)
+{
+	if (flags & SETWA_FLAGS_EINJV2)
+		return !!(type & ACPI_EINJV2_MEMORY);
+	if (type & ACPI5_VENDOR_BIT)
+		return !!(vendor_flags & SETWA_FLAGS_MEM);
+	return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM);
+}
+
 /* Execute instructions in trigger error action table */
-static int __einj_error_trigger(u64 trigger_paddr, u32 type,
+static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags,
 				u64 param1, u64 param2)
 {
 	struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
 	 * This will cause resource conflict with regular memory.  So
 	 * remove it from trigger table resources.
 	 */
-	if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
+	if ((param_extension || acpi5) && is_memory_injection(type, flags)) {
 		struct apei_resources addr_resources;
 
 		apei_resources_init(&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
 		return rc;
 	trigger_paddr = apei_exec_ctx_get_output(&ctx);
 	if (notrigger == 0) {
-		rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
+		rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2);
 		if (rc)
 			return rc;
 	}
@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
 		      SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
 		return -EINVAL;
 
+	/*
+	 * Injections targeting a CXL 1.0/1.1 port have to be injected
+	 * via the einj_cxl_rch_error_inject() path as that does the proper
+	 * validation of the given RCRB base (MMIO) address.
+	 */
+	if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
+		return -EINVAL;
+
 	/* check if type is a valid EINJv2 error type */
 	if (is_v2) {
 		if (!(type & available_error_type_v2))
 			return -EINVAL;
 	}
-	/*
-	 * We need extra sanity checks for memory errors.
-	 * Other types leap directly to injection.
-	 */
 
 	/* ensure param1/param2 existed */
 	if (!(param_extension || acpi5))
 		goto inject;
 
-	/* ensure injection is memory related */
-	if (type & ACPI5_VENDOR_BIT) {
-		if (vendor_flags != SETWA_FLAGS_MEM)
-			goto inject;
-	} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
-		goto inject;
-	}
-
 	/*
-	 * Injections targeting a CXL 1.0/1.1 port have to be injected
-	 * via the einj_cxl_rch_error_inject() path as that does the proper
-	 * validation of the given RCRB base (MMIO) address.
+	 * We need extra sanity checks for memory errors.
+	 * Other types leap directly to injection.
 	 */
-	if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
-		return -EINVAL;
+	if (!is_memory_injection(type, flags))
+		goto inject;
 
 	/*
 	 * Disallow crazy address masks that give BIOS leeway to pick
Signature · 1 line
2.53.0
Reviewed-by on v4 2/2
#4 lore raw
Quoted 120 lines · Tony Luck

Error types in EINJV2 use different bit positions for each flavor of injection from legacy EINJ.

Two issues:

1) The address sanity checks in einj_error_inject() were skipped for EINJV2 injections. Noted by sashiko[1]
2) __einj_error_trigger() failed to drop the entry of the target physical address from the list of resources that need to be requested.

Add a helper function that checks if an injection is to memory and use it to solve each of these issues.

Note that the old test in __einj_error_trigger() checked that param2 was not zero. This isn't needed because the sanity checks in einj_error_inject() reject memory injections with param2 == 0.

Fixes b47610296d17 ("ACPI: APEI: EINJ: Enable EINJv2 error injections")

#Reported-by: sashiko <[email protected]>

---
 drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 20 deletions(-)
drivers/acpi/apei/einj-core.c +25 -21
index a9248af078f6..1f3fa2278584 100644
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
 
        return NULL;
 }
+
+static bool is_memory_injection(u32 type, u32 flags)
+{
+       if (flags & SETWA_FLAGS_EINJV2)
+               return !!(type & ACPI_EINJV2_MEMORY);
+       if (type & ACPI5_VENDOR_BIT)
+               return !!(vendor_flags & SETWA_FLAGS_MEM);
+       return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM);
+}
+
 /* Execute instructions in trigger error action table */
-static int __einj_error_trigger(u64 trigger_paddr, u32 type,
+static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags,
                                u64 param1, u64 param2)
 {
        struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
         * This will cause resource conflict with regular memory.  So
         * remove it from trigger table resources.
         */
-       if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
+       if ((param_extension || acpi5) && is_memory_injection(type, flags)) {
                struct apei_resources addr_resources;
 
                apei_resources_init(&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
                return rc;
        trigger_paddr = apei_exec_ctx_get_output(&ctx);
        if (notrigger == 0) {
-               rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
+               rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2);
                if (rc)
                        return rc;
        }
@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
                      SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
                return -EINVAL;
 
+       /*
+        * Injections targeting a CXL 1.0/1.1 port have to be injected
+        * via the einj_cxl_rch_error_inject() path as that does the proper
+        * validation of the given RCRB base (MMIO) address.
+        */
+       if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
+               return -EINVAL;
+
        /* check if type is a valid EINJv2 error type */
        if (is_v2) {
                if (!(type & available_error_type_v2))
                        return -EINVAL;
        }
-       /*
-        * We need extra sanity checks for memory errors.
-        * Other types leap directly to injection.
-        */
 
        /* ensure param1/param2 existed */
        if (!(param_extension || acpi5))
                goto inject;
 
-       /* ensure injection is memory related */
-       if (type & ACPI5_VENDOR_BIT) {
-               if (vendor_flags != SETWA_FLAGS_MEM)
-                       goto inject;
-       } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
-               goto inject;
-       }
-
        /*
-        * Injections targeting a CXL 1.0/1.1 port have to be injected
-        * via the einj_cxl_rch_error_inject() path as that does the proper
-        * validation of the given RCRB base (MMIO) address.
+        * We need extra sanity checks for memory errors.
+        * Other types leap directly to injection.
         */
-       if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
-               return -EINVAL;
+       if (!is_memory_injection(type, flags))
+               goto inject;
 
        /*
         * Disallow crazy address masks that give BIOS leeway to pick
--
Quoted 2 lines

2.53.0

Reviewed-by on v4 2/2
#5 lore raw
In reply to Tony Luck
Quoted 121 lines · Tony Luck

Error types in EINJV2 use different bit positions for each flavor of injection from legacy EINJ.

Two issues:

1) The address sanity checks in einj_error_inject() were skipped for EINJV2 injections. Noted by sashiko[1]
2) __einj_error_trigger() failed to drop the entry of the target physical address from the list of resources that need to be requested.

Add a helper function that checks if an injection is to memory and use it to solve each of these issues.

Note that the old test in __einj_error_trigger() checked that param2 was not zero. This isn't needed because the sanity checks in einj_error_inject() reject memory injections with param2 == 0.

Fixes b47610296d17 ("ACPI: APEI: EINJ: Enable EINJv2 error injections")

#Reported-by: sashiko <[email protected]>

---
 drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 20 deletions(-)
drivers/acpi/apei/einj-core.c +25 -20
index a9248af078f6..1f3fa2278584 100644
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
 
 	return NULL;
 }
+
+static bool is_memory_injection(u32 type, u32 flags)
+{
+	if (flags & SETWA_FLAGS_EINJV2)
+		return !!(type & ACPI_EINJV2_MEMORY);
+	if (type & ACPI5_VENDOR_BIT)
+		return !!(vendor_flags & SETWA_FLAGS_MEM);
+	return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM);
+}
+
 /* Execute instructions in trigger error action table */
-static int __einj_error_trigger(u64 trigger_paddr, u32 type,
+static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags,
 				u64 param1, u64 param2)
 {
 	struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
 	 * This will cause resource conflict with regular memory.  So
 	 * remove it from trigger table resources.
 	 */
-	if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
+	if ((param_extension || acpi5) && is_memory_injection(type, flags)) {
 		struct apei_resources addr_resources;
 
 		apei_resources_init(&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
 		return rc;
 	trigger_paddr = apei_exec_ctx_get_output(&ctx);
 	if (notrigger == 0) {
-		rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
+		rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2);
 		if (rc)
 			return rc;
 	}
@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
 		      SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
 		return -EINVAL;
 
+	/*
+	 * Injections targeting a CXL 1.0/1.1 port have to be injected
+	 * via the einj_cxl_rch_error_inject() path as that does the proper
+	 * validation of the given RCRB base (MMIO) address.
+	 */
+	if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
+		return -EINVAL;
+
 	/* check if type is a valid EINJv2 error type */
 	if (is_v2) {
 		if (!(type & available_error_type_v2))
 			return -EINVAL;
 	}
-	/*
-	 * We need extra sanity checks for memory errors.
-	 * Other types leap directly to injection.
-	 */
 
 	/* ensure param1/param2 existed */
 	if (!(param_extension || acpi5))
 		goto inject;
 
-	/* ensure injection is memory related */
-	if (type & ACPI5_VENDOR_BIT) {
-		if (vendor_flags != SETWA_FLAGS_MEM)
-			goto inject;
-	} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
-		goto inject;
-	}
-
 	/*
-	 * Injections targeting a CXL 1.0/1.1 port have to be injected
-	 * via the einj_cxl_rch_error_inject() path as that does the proper
-	 * validation of the given RCRB base (MMIO) address.
+	 * We need extra sanity checks for memory errors.
+	 * Other types leap directly to injection.
 	 */
-	if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
-		return -EINVAL;
+	if (!is_memory_injection(type, flags))
+		goto inject;
 
 	/*
 	 * Disallow crazy address masks that give BIOS leeway to pick
Signature · 1 line
2.53.0