mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/7] CPER: Add Memory Error Section 2 support
@ 2026-11-04 11:03 Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits Pierre Gondois
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Rafael J. Wysocki,
	Len Brown, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Maciej Wieczor-Retman,
	Pawel Chmielewski, Dave Jiang, Jonathan Cameron,
	Fabio M. De Francesco, Breno Leitao, Terry Bowman, Dan Williams,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

The support is mostly duplicated from Memory Error Section handling.
Other than differences coming from the content of  Memory Error
Section 1 and 2, differences in the support are:

- v2 do not rely on a compact "struct cper_mem_err_compact" struct.
This structure was used to support older versions of the Memory
Error Section (1). This is not needed for the new structure.

- The compact version is also used by the tracing framework.
To avoid relying and propagating a non-standard record format,
through trace event (cf. extlog_mem event) the new trace event
prints each field individually.

The last patch of the serie was only build-tested due to the
absence of relevant hardware. apei_mce_report_mem_error() and
arch_apei_report_mem_error() implementations were also removed since
last version.

It will also require a proper handling from the rasdaemon. Applying
this last patch without rasdaemon support will silent the reports of
Memory Error Section 2 error, cf. ras_userspace_consumers() check.

Future:
- _OSC support
- Addition of arm64 tracepoints
https://lore.kernel.org/lkml/20261023170405.000060b8@oss.qualcomm.com/
- Emission of lossy CPER Mem error v1 tracepoints for legacy userspace
  tools
https://lore.kernel.org/lkml/at0rs4parlHFGI7k@hu-ashoraj-lv.qualcomm.com/


RFC: https://lore.kernel.org/all/20260929074659.2587216-1-pierre.gondois@arm.com/#t
V1:  https://lore.kernel.org/all/20261019145643.1877246-1-pierre.gondois@arm.com/
- Corrections from Jonathan's review
- New patch:
    [PATCH v2 4/6] EDAC/ghes: Extract error report initialization
- Last patch not in RFC as it has been reviewed by Jonathan@
    [PATCH v2 6/6] ACPI: extlog: add Memory Error Section 2 trace event
V2:
- Updated ghes_edac_init_error() to ghes_edac_init_error_desc(),
  which now only acts on the input "struct edac_raw_error_desc"
  + added lockdep_assert_held() to ghes_edac_init_error_desc()
- Accumulate failures with "queued |=" in ghes_do_proc()
- New PATCH:
  [PATCH v3 5/7] ACPI: APEI: Extract common memory failure handling

Pierre Gondois (7):
  cper: use BIT_ULL() for processor and memory validation bits
  cper: add Memory Error Section 2 structures
  cper: add helpers to handle Memory Error Section 2
  EDAC/ghes: Extract error report initialization
  ACPI: APEI: Extract common memory failure handling
  ACPI: APEI: add separate Memory Error Section 2 handlers
  ACPI: extlog: add Memory Error Section 2 trace event

 drivers/acpi/acpi_extlog.c  |   6 ++
 drivers/acpi/apei/ghes.c    |  58 +++++++++--
 drivers/edac/ghes_edac.c    | 189 +++++++++++++++++++++++++++++-------
 drivers/firmware/efi/cper.c | 109 +++++++++++++++++++++
 drivers/ras/ras.c           |   1 +
 include/acpi/ghes.h         |   2 +
 include/linux/cper.h        | 129 +++++++++++++++++-------
 include/ras/ras_event.h     | 102 +++++++++++++++++++
 8 files changed, 518 insertions(+), 78 deletions(-)

--
2.43.0

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 16:22   ` Mark Brown
  2026-11-04 11:03 ` [PATCH v3 2/7] cper: add Memory Error Section 2 structures Pierre Gondois
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Jonathan Cameron,
	Breno Leitao, Rafael J. Wysocki, Len Brown, Tony Luck,
	Borislav Petkov, Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue,
	Maciej Wieczor-Retman, Pawel Chmielewski, Dave Jiang,
	Fabio M. De Francesco, Dan Williams, Terry Bowman,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Use the BIT_ULL() macro to describe flag bits instead of
hexadecimal values which are harder to read.

Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 include/linux/cper.h | 72 ++++++++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/include/linux/cper.h b/include/linux/cper.h
index 440b35e459e5..81cda9874b25 100644
--- a/include/linux/cper.h
+++ b/include/linux/cper.h
@@ -225,42 +225,42 @@ enum {
 	GUID_INIT(0x036F84E1, 0x7F37, 0x428c, 0xA7, 0x9E, 0x57, 0x5F,	\
 		  0xDF, 0xAA, 0x84, 0xEC)
 
-#define CPER_PROC_VALID_TYPE			0x0001
-#define CPER_PROC_VALID_ISA			0x0002
-#define CPER_PROC_VALID_ERROR_TYPE		0x0004
-#define CPER_PROC_VALID_OPERATION		0x0008
-#define CPER_PROC_VALID_FLAGS			0x0010
-#define CPER_PROC_VALID_LEVEL			0x0020
-#define CPER_PROC_VALID_VERSION			0x0040
-#define CPER_PROC_VALID_BRAND_INFO		0x0080
-#define CPER_PROC_VALID_ID			0x0100
-#define CPER_PROC_VALID_TARGET_ADDRESS		0x0200
-#define CPER_PROC_VALID_REQUESTOR_ID		0x0400
-#define CPER_PROC_VALID_RESPONDER_ID		0x0800
-#define CPER_PROC_VALID_IP			0x1000
-
-#define CPER_MEM_VALID_ERROR_STATUS		0x0001
-#define CPER_MEM_VALID_PA			0x0002
-#define CPER_MEM_VALID_PA_MASK			0x0004
-#define CPER_MEM_VALID_NODE			0x0008
-#define CPER_MEM_VALID_CARD			0x0010
-#define CPER_MEM_VALID_MODULE			0x0020
-#define CPER_MEM_VALID_BANK			0x0040
-#define CPER_MEM_VALID_DEVICE			0x0080
-#define CPER_MEM_VALID_ROW			0x0100
-#define CPER_MEM_VALID_COLUMN			0x0200
-#define CPER_MEM_VALID_BIT_POSITION		0x0400
-#define CPER_MEM_VALID_REQUESTOR_ID		0x0800
-#define CPER_MEM_VALID_RESPONDER_ID		0x1000
-#define CPER_MEM_VALID_TARGET_ID		0x2000
-#define CPER_MEM_VALID_ERROR_TYPE		0x4000
-#define CPER_MEM_VALID_RANK_NUMBER		0x8000
-#define CPER_MEM_VALID_CARD_HANDLE		0x10000
-#define CPER_MEM_VALID_MODULE_HANDLE		0x20000
-#define CPER_MEM_VALID_ROW_EXT			0x40000
-#define CPER_MEM_VALID_BANK_GROUP		0x80000
-#define CPER_MEM_VALID_BANK_ADDRESS		0x100000
-#define CPER_MEM_VALID_CHIP_ID			0x200000
+#define CPER_PROC_VALID_TYPE			BIT_ULL(0)
+#define CPER_PROC_VALID_ISA			BIT_ULL(1)
+#define CPER_PROC_VALID_ERROR_TYPE		BIT_ULL(2)
+#define CPER_PROC_VALID_OPERATION		BIT_ULL(3)
+#define CPER_PROC_VALID_FLAGS			BIT_ULL(4)
+#define CPER_PROC_VALID_LEVEL			BIT_ULL(5)
+#define CPER_PROC_VALID_VERSION			BIT_ULL(6)
+#define CPER_PROC_VALID_BRAND_INFO		BIT_ULL(7)
+#define CPER_PROC_VALID_ID			BIT_ULL(8)
+#define CPER_PROC_VALID_TARGET_ADDRESS		BIT_ULL(9)
+#define CPER_PROC_VALID_REQUESTOR_ID		BIT_ULL(10)
+#define CPER_PROC_VALID_RESPONDER_ID		BIT_ULL(11)
+#define CPER_PROC_VALID_IP			BIT_ULL(12)
+
+#define CPER_MEM_VALID_ERROR_STATUS		BIT_ULL(0)
+#define CPER_MEM_VALID_PA			BIT_ULL(1)
+#define CPER_MEM_VALID_PA_MASK			BIT_ULL(2)
+#define CPER_MEM_VALID_NODE			BIT_ULL(3)
+#define CPER_MEM_VALID_CARD			BIT_ULL(4)
+#define CPER_MEM_VALID_MODULE			BIT_ULL(5)
+#define CPER_MEM_VALID_BANK			BIT_ULL(6)
+#define CPER_MEM_VALID_DEVICE			BIT_ULL(7)
+#define CPER_MEM_VALID_ROW			BIT_ULL(8)
+#define CPER_MEM_VALID_COLUMN			BIT_ULL(9)
+#define CPER_MEM_VALID_BIT_POSITION		BIT_ULL(10)
+#define CPER_MEM_VALID_REQUESTOR_ID		BIT_ULL(11)
+#define CPER_MEM_VALID_RESPONDER_ID		BIT_ULL(12)
+#define CPER_MEM_VALID_TARGET_ID		BIT_ULL(13)
+#define CPER_MEM_VALID_ERROR_TYPE		BIT_ULL(14)
+#define CPER_MEM_VALID_RANK_NUMBER		BIT_ULL(15)
+#define CPER_MEM_VALID_CARD_HANDLE		BIT_ULL(16)
+#define CPER_MEM_VALID_MODULE_HANDLE		BIT_ULL(17)
+#define CPER_MEM_VALID_ROW_EXT			BIT_ULL(18)
+#define CPER_MEM_VALID_BANK_GROUP		BIT_ULL(19)
+#define CPER_MEM_VALID_BANK_ADDRESS		BIT_ULL(20)
+#define CPER_MEM_VALID_CHIP_ID			BIT_ULL(21)
 
 #define CPER_MEM_EXT_ROW_MASK			0x3
 #define CPER_MEM_EXT_ROW_SHIFT			16
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 2/7] cper: add Memory Error Section 2 structures
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 3/7] cper: add helpers to handle Memory Error Section 2 Pierre Gondois
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Jonathan Cameron,
	Breno Leitao, Rafael J. Wysocki, Len Brown, Tony Luck,
	Borislav Petkov, Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue,
	Maciej Wieczor-Retman, Pawel Chmielewski, Dave Jiang,
	Fabio M. De Francesco, Dan Williams, Terry Bowman,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Add CPER Memory Error Section 2 definitions to the CPER headers.

Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 include/linux/cper.h | 54 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/include/linux/cper.h b/include/linux/cper.h
index 81cda9874b25..ed355b240685 100644
--- a/include/linux/cper.h
+++ b/include/linux/cper.h
@@ -198,6 +198,10 @@ enum {
 #define CPER_SEC_PLATFORM_MEM						\
 	GUID_INIT(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83,	\
 		  0xED, 0x7C, 0x83, 0xB1)
+/* Platform Memory 2 */
+#define CPER_SEC_PLATFORM_MEM2						\
+	GUID_INIT(0x61EC04FC, 0x48E6, 0xD813, 0x25, 0xC9, 0x8D, 0xAA,	\
+		  0x44, 0x75, 0x0B, 0x12)
 #define CPER_SEC_PCIE							\
 	GUID_INIT(0xD995E954, 0xBBC1, 0x430F, 0xAD, 0x91, 0xB4, 0x4D,	\
 		  0xCB, 0x3C, 0x6F, 0x35)
@@ -262,6 +266,30 @@ enum {
 #define CPER_MEM_VALID_BANK_ADDRESS		BIT_ULL(20)
 #define CPER_MEM_VALID_CHIP_ID			BIT_ULL(21)
 
+/* Memory Error Section 2 validation bits, UEFI v2.11 sec N.2.6. */
+#define CPER_MEM2_VALID_ERROR_STATUS		BIT_ULL(0)
+#define CPER_MEM2_VALID_PA			BIT_ULL(1)
+#define CPER_MEM2_VALID_PA_MASK			BIT_ULL(2)
+#define CPER_MEM2_VALID_NODE			BIT_ULL(3)
+#define CPER_MEM2_VALID_CARD			BIT_ULL(4)
+#define CPER_MEM2_VALID_MODULE			BIT_ULL(5)
+#define CPER_MEM2_VALID_BANK			BIT_ULL(6)
+#define CPER_MEM2_VALID_DEVICE			BIT_ULL(7)
+#define CPER_MEM2_VALID_ROW			BIT_ULL(8)
+#define CPER_MEM2_VALID_COLUMN			BIT_ULL(9)
+#define CPER_MEM2_VALID_RANK_NUMBER		BIT_ULL(10)
+#define CPER_MEM2_VALID_BIT_POSITION		BIT_ULL(11)
+#define CPER_MEM2_VALID_CHIP_ID			BIT_ULL(12)
+#define CPER_MEM2_VALID_ERROR_TYPE		BIT_ULL(13)
+#define CPER_MEM2_VALID_STATUS			BIT_ULL(14)
+#define CPER_MEM2_VALID_REQUESTOR_ID		BIT_ULL(15)
+#define CPER_MEM2_VALID_RESPONDER_ID		BIT_ULL(16)
+#define CPER_MEM2_VALID_TARGET_ID		BIT_ULL(17)
+#define CPER_MEM2_VALID_CARD_HANDLE		BIT_ULL(18)
+#define CPER_MEM2_VALID_MODULE_HANDLE		BIT_ULL(19)
+#define CPER_MEM2_VALID_BANK_GROUP		BIT_ULL(20)
+#define CPER_MEM2_VALID_BANK_ADDRESS		BIT_ULL(21)
+
 #define CPER_MEM_EXT_ROW_MASK			0x3
 #define CPER_MEM_EXT_ROW_SHIFT			16
 
@@ -506,6 +534,32 @@ struct cper_sec_mem_err {
 	u16	mem_dev_handle;		/* "module handle" in UEFI 2.4 */
 };
 
+/* Memory Error Section 2, UEFI v2.11 sec N.2.6 */
+struct cper_sec_mem_err2 {
+	u64	validation_bits;
+	u64	error_status;
+	u64	physical_addr;
+	u64	physical_addr_mask;
+	u16	node;
+	u16	card;
+	u16	module;
+	u16	bank;
+	u32	device;
+	u32	row;
+	u32	column;
+	u32	rank;
+	u32	bit_pos;
+	u8	chip_id;
+	u8	error_type;
+	u8	status;
+	u8	reserved;
+	u64	requestor_id;
+	u64	responder_id;
+	u64	target_id;
+	u32	mem_array_handle;	/* "card handle" */
+	u32	mem_dev_handle;		/* "module handle" */
+};
+
 struct cper_mem_err_compact {
 	u64	validation_bits;
 	u16	node;
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 3/7] cper: add helpers to handle Memory Error Section 2
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 2/7] cper: add Memory Error Section 2 structures Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 17:25   ` Mark Brown
  2026-11-04 11:03 ` [PATCH v3 4/7] EDAC/ghes: Extract error report initialization Pierre Gondois
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Jonathan Cameron,
	Rafael J. Wysocki, Len Brown, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue,
	Maciej Wieczor-Retman, Pawel Chmielewski, Dave Jiang,
	Fabio M. De Francesco, Breno Leitao, Terry Bowman, Dan Williams,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Add separate location and printing helpers for Memory Error
Section 2:
- cper_mem_err2_location()
- cper_dimm_err2_location()
- cper_print_mem2()

Similar functions/logic exists for Memory Error Section (1),
but require a compact version of the record. To avoid relying
and propagating a non-standard record format, the new functions
directly rely on struct cper_sec_mem_err2.

Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 drivers/firmware/efi/cper.c | 109 ++++++++++++++++++++++++++++++++++++
 include/linux/cper.h        |   3 +
 2 files changed, 112 insertions(+)

diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 13b3e72c3b62..6502afbedaf0 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -463,6 +463,107 @@ static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
 		printk("%s%s\n", pfx, rcd_decode_str);
 }
 
+int cper_mem_err2_location(const struct cper_sec_mem_err2 *mem, char *msg)
+{
+	u32 len, n;
+
+	if (!msg)
+		return 0;
+
+	n = 0;
+	len = CPER_REC_LEN;
+	if (mem->validation_bits & CPER_MEM2_VALID_NODE)
+		n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
+	if (mem->validation_bits & CPER_MEM2_VALID_CARD)
+		n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
+	if (mem->validation_bits & CPER_MEM2_VALID_MODULE)
+		n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
+	if (mem->validation_bits & CPER_MEM2_VALID_RANK_NUMBER)
+		n += scnprintf(msg + n, len - n, "rank:%u ", mem->rank);
+	if (mem->validation_bits & CPER_MEM2_VALID_BANK)
+		n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
+	if (mem->validation_bits & CPER_MEM2_VALID_BANK_GROUP)
+		n += scnprintf(msg + n, len - n, "bank_group:%d ",
+			       mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
+	if (mem->validation_bits & CPER_MEM2_VALID_BANK_ADDRESS)
+		n += scnprintf(msg + n, len - n, "bank_address:%d ",
+			       mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
+	if (mem->validation_bits & CPER_MEM2_VALID_DEVICE)
+		n += scnprintf(msg + n, len - n, "device:%u ", mem->device);
+	if (mem->validation_bits & CPER_MEM2_VALID_ROW)
+		n += scnprintf(msg + n, len - n, "row:%u ", mem->row);
+	if (mem->validation_bits & CPER_MEM2_VALID_COLUMN)
+		n += scnprintf(msg + n, len - n, "column:%u ", mem->column);
+	if (mem->validation_bits & CPER_MEM2_VALID_BIT_POSITION)
+		n += scnprintf(msg + n, len - n, "bit_position:%u ",
+			       mem->bit_pos);
+	if (mem->validation_bits & CPER_MEM2_VALID_REQUESTOR_ID)
+		n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
+			       mem->requestor_id);
+	if (mem->validation_bits & CPER_MEM2_VALID_RESPONDER_ID)
+		n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
+			       mem->responder_id);
+	if (mem->validation_bits & CPER_MEM2_VALID_TARGET_ID)
+		n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
+			       mem->target_id);
+	if (mem->validation_bits & CPER_MEM2_VALID_CHIP_ID)
+		n += scnprintf(msg + n, len - n, "chip_id:%d ",
+			       mem->chip_id);
+
+	return n;
+}
+EXPORT_SYMBOL_GPL(cper_mem_err2_location);
+
+int cper_dimm_err2_location(const struct cper_sec_mem_err2 *mem, char *msg)
+{
+	u32 len, n;
+	const char *bank = NULL, *device = NULL;
+
+	if (!msg || !(mem->validation_bits & CPER_MEM2_VALID_MODULE_HANDLE))
+		return 0;
+
+	/* SMBIOS handles are 16 bits; never truncate a Section 2 handle. */
+	if (mem->mem_dev_handle <= U16_MAX)
+		dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
+	else
+		pr_warn(FW_WARN "Memory Error Section 2 module handle 0x%x exceeds SMBIOS range\n",
+			mem->mem_dev_handle);
+
+	len = CPER_REC_LEN;
+	if (bank && device)
+		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
+	else
+		n = snprintf(msg, len,
+			     "DIMM location: not present. DMI handle: 0x%.8x ",
+			     mem->mem_dev_handle);
+
+	return n;
+}
+EXPORT_SYMBOL_GPL(cper_dimm_err2_location);
+
+static void cper_print_mem2(const char *pfx, const struct cper_sec_mem_err2 *mem)
+{
+	char rcd_decode_str[CPER_REC_LEN];
+
+	if (mem->validation_bits & CPER_MEM2_VALID_ERROR_STATUS)
+		printk("%serror_status: %s (0x%016llx)\n", pfx,
+		       cper_mem_err_status_str(mem->error_status), mem->error_status);
+	if (mem->validation_bits & CPER_MEM2_VALID_PA)
+		printk("%sphysical_address: 0x%016llx\n", pfx, mem->physical_addr);
+	if (mem->validation_bits & CPER_MEM2_VALID_PA_MASK)
+		printk("%sphysical_address_mask: 0x%016llx\n", pfx,
+		       mem->physical_addr_mask);
+	if (cper_mem_err2_location(mem, rcd_decode_str))
+		printk("%s%s\n", pfx, rcd_decode_str);
+	if (mem->validation_bits & CPER_MEM2_VALID_ERROR_TYPE)
+		printk("%serror_type: %u, %s\n", pfx, mem->error_type,
+		       cper_mem_err_type_str(mem->error_type));
+	if (mem->validation_bits & CPER_MEM2_VALID_STATUS)
+		printk("%sstatus: 0x%02x\n", pfx, mem->status);
+	if (cper_dimm_err2_location(mem, rcd_decode_str))
+		printk("%s%s\n", pfx, rcd_decode_str);
+}
+
 static const char * const pcie_port_type_strs[] = {
 	"PCIe end point",
 	"legacy PCI end point",
@@ -668,6 +769,14 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
 				       gdata->error_data_length);
 		else
 			goto err_section_too_small;
+	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM2)) {
+		struct cper_sec_mem_err2 *mem_err = acpi_hest_get_payload(gdata);
+
+		printk("%ssection_type: memory error 2\n", newpfx);
+		if (gdata->error_data_length >= sizeof(*mem_err))
+			cper_print_mem2(newpfx, mem_err);
+		else
+			goto err_section_too_small;
 	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
 		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
 
diff --git a/include/linux/cper.h b/include/linux/cper.h
index ed355b240685..a466cba4fd61 100644
--- a/include/linux/cper.h
+++ b/include/linux/cper.h
@@ -656,6 +656,9 @@ void cper_print_proc_ia(const char *pfx,
 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg);
 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg);
 
+int cper_mem_err2_location(const struct cper_sec_mem_err2 *mem, char *msg);
+int cper_dimm_err2_location(const struct cper_sec_mem_err2 *mem, char *msg);
+
 struct acpi_hest_generic_status;
 void cper_estatus_print(const char *pfx,
 			const struct acpi_hest_generic_status *estatus);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 4/7] EDAC/ghes: Extract error report initialization
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
                   ` (2 preceding siblings ...)
  2026-11-04 11:03 ` [PATCH v3 3/7] cper: add helpers to handle Memory Error Section 2 Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 5/7] ACPI: APEI: Extract common memory failure handling Pierre Gondois
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Rafael J. Wysocki,
	Len Brown, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Maciej Wieczor-Retman,
	Pawel Chmielewski, Dave Jiang, Jonathan Cameron,
	Fabio M. De Francesco, Breno Leitao, Terry Bowman, Dan Williams,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Extract a ghes_edac_init_error_desc() function to prepare for
Memory Error Section 2 support (and re-usage).

Also use a guard in the caller ghes_edac_report_mem_error()
function for code simplification.

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 drivers/edac/ghes_edac.c | 70 +++++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 34 deletions(-)

diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index d80c88818691..f1cf4d640d68 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -267,6 +267,39 @@ static int print_mem_error_other_detail(const struct cper_sec_mem_err *mem, char
 	return n;
 }
 
+static void ghes_edac_init_error_desc(struct edac_raw_error_desc *e,
+				      unsigned long sev, char *msg, char *other_detail)
+{
+	lockdep_assert_held(&ghes_lock);
+
+	/* Cleans the error report buffer */
+	memset(e, 0, sizeof(*e));
+	e->error_count = 1;
+	e->grain = 1;
+	e->msg = msg;
+	e->other_detail = other_detail;
+	e->top_layer = -1;
+	e->mid_layer = -1;
+	e->low_layer = -1;
+	*msg = '\0';
+	*other_detail = '\0';
+
+	switch (sev) {
+	case GHES_SEV_CORRECTED:
+		e->type = HW_EVENT_ERR_CORRECTED;
+		break;
+	case GHES_SEV_RECOVERABLE:
+		e->type = HW_EVENT_ERR_UNCORRECTED;
+		break;
+	case GHES_SEV_PANIC:
+		e->type = HW_EVENT_ERR_FATAL;
+		break;
+	default:
+	case GHES_SEV_NO:
+		e->type = HW_EVENT_ERR_INFO;
+	}
+}
+
 static int ghes_edac_report_mem_error(struct notifier_block *nb,
 				      unsigned long val, void *data)
 {
@@ -274,9 +307,7 @@ static int ghes_edac_report_mem_error(struct notifier_block *nb,
 	struct cper_mem_err_compact cmem;
 	struct edac_raw_error_desc *e;
 	struct mem_ctl_info *mci;
-	unsigned long sev = val;
 	struct ghes_pvt *pvt;
-	unsigned long flags;
 	char *p;
 
 	/*
@@ -287,41 +318,15 @@ static int ghes_edac_report_mem_error(struct notifier_block *nb,
 	if (WARN_ON_ONCE(in_nmi()))
 		return NOTIFY_OK;
 
-	spin_lock_irqsave(&ghes_lock, flags);
+	guard(spinlock_irqsave)(&ghes_lock);
 
 	pvt = ghes_pvt;
 	if (!pvt)
-		goto unlock;
+		return NOTIFY_OK;
 
 	mci = pvt->mci;
 	e = &mci->error_desc;
-
-	/* Cleans the error report buffer */
-	memset(e, 0, sizeof (*e));
-	e->error_count = 1;
-	e->grain = 1;
-	e->msg = pvt->msg;
-	e->other_detail = pvt->other_detail;
-	e->top_layer = -1;
-	e->mid_layer = -1;
-	e->low_layer = -1;
-	*pvt->other_detail = '\0';
-	*pvt->msg = '\0';
-
-	switch (sev) {
-	case GHES_SEV_CORRECTED:
-		e->type = HW_EVENT_ERR_CORRECTED;
-		break;
-	case GHES_SEV_RECOVERABLE:
-		e->type = HW_EVENT_ERR_UNCORRECTED;
-		break;
-	case GHES_SEV_PANIC:
-		e->type = HW_EVENT_ERR_FATAL;
-		break;
-	default:
-	case GHES_SEV_NO:
-		e->type = HW_EVENT_ERR_INFO;
-	}
+	ghes_edac_init_error_desc(e, val, pvt->msg, pvt->other_detail);
 
 	edac_dbg(1, "error validation_bits: 0x%08llx\n",
 		 (long long)mem_err->validation_bits);
@@ -375,9 +380,6 @@ static int ghes_edac_report_mem_error(struct notifier_block *nb,
 
 	edac_raw_mc_handle_error(e);
 
-unlock:
-	spin_unlock_irqrestore(&ghes_lock, flags);
-
 	return NOTIFY_OK;
 }
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 5/7] ACPI: APEI: Extract common memory failure handling
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
                   ` (3 preceding siblings ...)
  2026-11-04 11:03 ` [PATCH v3 4/7] EDAC/ghes: Extract error report initialization Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 11:03 ` [PATCH v3 6/7] ACPI: APEI: add separate Memory Error Section 2 handlers Pierre Gondois
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Rafael J. Wysocki,
	Len Brown, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Maciej Wieczor-Retman,
	Pawel Chmielewski, Dave Jiang, Jonathan Cameron,
	Fabio M. De Francesco, Breno Leitao, Terry Bowman, Dan Williams,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Extract ghes_handle_memory_failure_common() to share the severity checks
and memory failure dispatch with the upcoming Memory Error Section 2
handler.

No functional change.

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 drivers/acpi/apei/ghes.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 663dc2e601cf..d6bbee466b48 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -528,15 +528,11 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags)
 	return true;
 }
 
-static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
-				       int sev, bool sync)
+static bool ghes_handle_memory_failure_common(struct acpi_hest_generic_data *gdata,
+					      int sev, bool sync, u64 physical_addr)
 {
 	int flags = -1;
 	int sec_sev = ghes_severity(gdata->error_severity);
-	struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
-
-	if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
-		return false;
 
 	/* iff following two events can be handled properly by now */
 	if (sec_sev == GHES_SEV_CORRECTED &&
@@ -546,11 +542,22 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
 		flags = sync ? MF_ACTION_REQUIRED : 0;
 
 	if (flags != -1)
-		return ghes_do_memory_failure(mem_err->physical_addr, flags);
+		return ghes_do_memory_failure(physical_addr, flags);
 
 	return false;
 }
 
+static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
+				       int sev, bool sync)
+{
+	struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
+
+	if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
+		return false;
+
+	return ghes_handle_memory_failure_common(gdata, sev, sync, mem_err->physical_addr);
+}
+
 static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
 				     int sev, bool sync)
 {
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 6/7] ACPI: APEI: add separate Memory Error Section 2 handlers
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
                   ` (4 preceding siblings ...)
  2026-11-04 11:03 ` [PATCH v3 5/7] ACPI: APEI: Extract common memory failure handling Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 17:51   ` Mark Brown
  2026-11-04 11:03 ` [PATCH v3 7/7] ACPI: extlog: add Memory Error Section 2 trace event Pierre Gondois
  2026-11-04 11:07 ` [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
  7 siblings, 1 reply; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Jonathan Cameron,
	Rafael J. Wysocki, Len Brown, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue,
	Maciej Wieczor-Retman, Pawel Chmielewski, Dave Jiang,
	Fabio M. De Francesco, Breno Leitao, Dan Williams, Terry Bowman,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Add dedicated GHES and EDAC callbacks for Memory Error Section 2
records. Use a separate GHES notifier chain so existing consumers
continue to receive legacy memory error sections.

Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 drivers/acpi/apei/ghes.c |  37 +++++++++++-
 drivers/edac/ghes_edac.c | 119 +++++++++++++++++++++++++++++++++++++++
 include/acpi/ghes.h      |   2 +
 3 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index d6bbee466b48..ae1990429e12 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -101,6 +101,7 @@
 #endif
 
 static ATOMIC_NOTIFIER_HEAD(ghes_report_chain);
+static ATOMIC_NOTIFIER_HEAD(ghes_report_mem2_chain);
 
 static inline bool is_hest_type_generic_v2(struct ghes *ghes)
 {
@@ -558,6 +559,17 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
 	return ghes_handle_memory_failure_common(gdata, sev, sync, mem_err->physical_addr);
 }
 
+static bool ghes_handle_memory_failure2(struct acpi_hest_generic_data *gdata,
+					int sev, bool sync)
+{
+	struct cper_sec_mem_err2 *mem_err = acpi_hest_get_payload(gdata);
+
+	if (!(mem_err->validation_bits & CPER_MEM2_VALID_PA))
+		return false;
+
+	return ghes_handle_memory_failure_common(gdata, sev, sync, mem_err->physical_addr);
+}
+
 static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
 				     int sev, bool sync)
 {
@@ -930,7 +942,8 @@ static void ghes_log_hwerr(int sev, guid_t *sec_type)
 		return;
 	}
 
-	if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
+	if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM) ||
+	    guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM2)) {
 		hwerr_log_error_type(HWERR_RECOV_MEMORY);
 		return;
 	}
@@ -1008,6 +1021,16 @@ static void ghes_do_proc(struct ghes *ghes,
 
 			arch_apei_report_mem_error(sev, mem_err);
 			queued |= ghes_handle_memory_failure(gdata, sev, sync);
+		} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM2)) {
+			struct cper_sec_mem_err2 *mem_err = acpi_hest_get_payload(gdata);
+
+			if (gdata->error_data_length < sizeof(*mem_err)) {
+				pr_warn(FW_WARN "Memory Error Section 2 length is too small\n");
+				continue;
+			}
+
+			atomic_notifier_call_chain(&ghes_report_mem2_chain, sev, mem_err);
+			queued |= ghes_handle_memory_failure2(gdata, sev, sync);
 		} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
 			ghes_handle_aer(gdata);
 		} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
@@ -2033,3 +2056,15 @@ void ghes_unregister_report_chain(struct notifier_block *nb)
 	atomic_notifier_chain_unregister(&ghes_report_chain, nb);
 }
 EXPORT_SYMBOL_GPL(ghes_unregister_report_chain);
+
+void ghes_register_report_mem2_chain(struct notifier_block *nb)
+{
+	atomic_notifier_chain_register(&ghes_report_mem2_chain, nb);
+}
+EXPORT_SYMBOL_GPL(ghes_register_report_mem2_chain);
+
+void ghes_unregister_report_mem2_chain(struct notifier_block *nb)
+{
+	atomic_notifier_chain_unregister(&ghes_report_mem2_chain, nb);
+}
+EXPORT_SYMBOL_GPL(ghes_unregister_report_mem2_chain);
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index f1cf4d640d68..dfa8276884f6 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -388,6 +388,123 @@ static struct notifier_block ghes_edac_mem_err_nb = {
 	.priority	= 0,
 };
 
+static int print_mem_error2_other_detail(const struct cper_sec_mem_err2 *mem, char *msg,
+					 const char *location, unsigned int len)
+{
+	u32 n;
+
+	if (!msg)
+		return 0;
+
+	n = 0;
+	len -= 1;
+
+	n += scnprintf(msg + n, len - n, "APEI location: %s ", location);
+
+	if (mem->validation_bits & CPER_MEM2_VALID_ERROR_STATUS) {
+		n += scnprintf(msg + n, len - n, "status(0x%016llx): ", mem->error_status);
+		n += scnprintf(msg + n, len - n, "%s ",
+			       cper_mem_err_status_str(mem->error_status));
+	}
+	if (mem->validation_bits & CPER_MEM2_VALID_STATUS)
+		n += scnprintf(msg + n, len - n, "section_status:0x%02x ",
+			       mem->status);
+
+	msg[n] = '\0';
+
+	return n;
+}
+
+static int ghes_edac_report_mem_error2(struct notifier_block *nb,
+				       unsigned long val, void *data)
+{
+	struct cper_sec_mem_err2 *mem_err = data;
+	struct edac_raw_error_desc *e;
+	struct mem_ctl_info *mci;
+	struct ghes_pvt *pvt;
+	char *p;
+
+	/*
+	 * We can do the locking below because GHES defers error processing
+	 * from NMI to IRQ context. Whenever that changes, we'd at least
+	 * know.
+	 */
+	if (WARN_ON_ONCE(in_nmi()))
+		return NOTIFY_OK;
+
+	guard(spinlock_irqsave)(&ghes_lock);
+
+	pvt = ghes_pvt;
+	if (!pvt)
+		return NOTIFY_OK;
+
+	mci = pvt->mci;
+	e = &mci->error_desc;
+	ghes_edac_init_error_desc(e, val, pvt->msg, pvt->other_detail);
+
+	edac_dbg(1, "error validation_bits: 0x%08llx\n",
+		 (long long)mem_err->validation_bits);
+
+	/* Error type, mapped on e->msg */
+	if (mem_err->validation_bits & CPER_MEM2_VALID_ERROR_TYPE) {
+		u8 etype = mem_err->error_type;
+
+		p = pvt->msg;
+		p += snprintf(p, sizeof(pvt->msg), "%s", cper_mem_err_type_str(etype));
+	} else {
+		strscpy(pvt->msg, "unknown error");
+	}
+
+	/* Error address */
+	if (mem_err->validation_bits & CPER_MEM2_VALID_PA) {
+		e->page_frame_number = PHYS_PFN(mem_err->physical_addr);
+		e->offset_in_page = offset_in_page(mem_err->physical_addr);
+	}
+
+	/* Error grain */
+	if (mem_err->validation_bits & CPER_MEM2_VALID_PA_MASK)
+		e->grain = ~mem_err->physical_addr_mask + 1;
+
+	/* Memory error location, mapped on e->location */
+	p = e->location;
+	p += cper_mem_err2_location(mem_err, p);
+
+	if (mem_err->validation_bits & CPER_MEM2_VALID_MODULE_HANDLE) {
+		struct dimm_info *dimm = NULL;
+
+		p += cper_dimm_err2_location(mem_err, p);
+		if (mem_err->mem_dev_handle <= U16_MAX)
+			dimm = find_dimm_by_handle(mci, mem_err->mem_dev_handle);
+		else
+			pr_warn(FW_WARN "Memory Error Section 2 module handle 0x%x exceeds SMBIOS range\n",
+				mem_err->mem_dev_handle);
+		if (dimm) {
+			e->top_layer = dimm->idx;
+			strscpy(e->label, dimm->label);
+		}
+	}
+	if (p > e->location)
+		*(p - 1) = '\0';
+
+	if (!*e->label)
+		strscpy(e->label, "unknown memory");
+
+	/* All other fields are mapped on e->other_detail */
+	p = pvt->other_detail;
+	p += print_mem_error2_other_detail(mem_err, p, e->location, OTHER_DETAIL_LEN);
+	if (p > pvt->other_detail)
+		*(p - 1) = '\0';
+
+	edac_raw_mc_handle_error(e);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ghes_edac_mem_err2_nb = {
+	.notifier_call	= ghes_edac_report_mem_error2,
+	.priority	= 0,
+};
+
 static int ghes_edac_register(struct device *dev)
 {
 	bool fake = false;
@@ -492,6 +609,7 @@ static int ghes_edac_register(struct device *dev)
 	spin_unlock_irqrestore(&ghes_lock, flags);
 
 	ghes_register_report_chain(&ghes_edac_mem_err_nb);
+	ghes_register_report_mem2_chain(&ghes_edac_mem_err2_nb);
 
 	/* only set on success */
 	refcount_set(&ghes_refcount, 1);
@@ -535,6 +653,7 @@ static void ghes_edac_unregister(struct ghes *ghes)
 	if (mci)
 		edac_mc_free(mci);
 
+	ghes_unregister_report_mem2_chain(&ghes_edac_mem_err2_nb);
 	ghes_unregister_report_chain(&ghes_edac_mem_err_nb);
 
 unlock:
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 7acf209061ea..3fdb7ea59f9c 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -147,4 +147,6 @@ static inline int ghes_notify_sea(void) { return -ENOENT; }
 struct notifier_block;
 extern void ghes_register_report_chain(struct notifier_block *nb);
 extern void ghes_unregister_report_chain(struct notifier_block *nb);
+extern void ghes_register_report_mem2_chain(struct notifier_block *nb);
+extern void ghes_unregister_report_mem2_chain(struct notifier_block *nb);
 #endif /* GHES_H */
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 7/7] ACPI: extlog: add Memory Error Section 2 trace event
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
                   ` (5 preceding siblings ...)
  2026-11-04 11:03 ` [PATCH v3 6/7] ACPI: APEI: add separate Memory Error Section 2 handlers Pierre Gondois
@ 2026-11-04 11:03 ` Pierre Gondois
  2026-11-04 11:07 ` [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
  7 siblings, 0 replies; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Morse, Mark Brown, Pierre Gondois, Jonathan Cameron,
	Rafael J. Wysocki, Len Brown, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue,
	Maciej Wieczor-Retman, Pawel Chmielewski, Dave Jiang,
	Fabio M. De Francesco, Breno Leitao, Terry Bowman, Dan Williams,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

Add a separate handling for Memory Error Section 2 trace events.
The fields of the record are individually printed so userspace
can discover the layout more dynamically if a new field is added.

Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
---
 drivers/acpi/acpi_extlog.c |   6 +++
 drivers/ras/ras.c          |   1 +
 include/ras/ras_event.h    | 102 +++++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+)

diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c
index bf5f7b1a9aea..5565177be328 100644
--- a/drivers/acpi/acpi_extlog.c
+++ b/drivers/acpi/acpi_extlog.c
@@ -231,6 +231,12 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
 			if (gdata->error_data_length >= sizeof(*mem))
 				trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
 						       (u8)gdata->error_severity);
+		} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM2)) {
+			struct cper_sec_mem_err2 *mem = acpi_hest_get_payload(gdata);
+
+			if (gdata->error_data_length >= sizeof(*mem))
+				trace_extlog_mem2_event(mem, err_seq, fru_id, fru_text,
+							(u8)gdata->error_severity);
 		} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
 			struct cxl_cper_sec_prot_err *prot_err =
 				acpi_hest_get_payload(gdata);
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 03df3db62334..c6b14202a5e9 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -111,6 +111,7 @@ subsys_initcall(ras_init);
 
 #if defined(CONFIG_ACPI_EXTLOG) || defined(CONFIG_ACPI_EXTLOG_MODULE)
 EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event);
+EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem2_event);
 #endif
 EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(non_standard_event);
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index fdb785fa4613..0c0dbe068dc8 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -74,6 +74,108 @@ TRACE_EVENT(extlog_mem_event,
 		  &__entry->fru_id,
 		  __get_str(fru_text))
 );
+
+/*
+ * Memory Error Section 2 exposes each field separately so userspace can
+ * discover its layout. Validation bits use the UEFI Section 2 assignments.
+ */
+TRACE_EVENT(extlog_mem2_event,
+	TP_PROTO(const struct cper_sec_mem_err2 *mem,
+		 u32 err_seq,
+		 const guid_t *fru_id,
+		 const char *fru_text,
+		 u8 sev),
+
+	TP_ARGS(mem, err_seq, fru_id, fru_text, sev),
+
+	TP_STRUCT__entry(
+		__field(u32, err_seq)
+		__field(u8, sev)
+		__field_struct(guid_t, fru_id)
+		__string(fru_text, fru_text)
+		__field(u64, validation_bits)
+		__field(u64, error_status)
+		__field(u64, physical_addr)
+		__field(u64, physical_addr_mask)
+		__field(u16, node)
+		__field(u16, card)
+		__field(u16, module)
+		__field(u16, bank)
+		__field(u32, device)
+		__field(u32, row)
+		__field(u32, column)
+		__field(u32, rank)
+		__field(u32, bit_pos)
+		__field(u8, chip_id)
+		__field(u8, error_type)
+		__field(u8, status)
+		__field(u64, requestor_id)
+		__field(u64, responder_id)
+		__field(u64, target_id)
+		__field(u32, mem_array_handle)
+		__field(u32, mem_dev_handle)
+	),
+
+	TP_fast_assign(
+		__entry->err_seq = err_seq;
+		__entry->sev = sev;
+		__entry->fru_id = *fru_id;
+		__assign_str(fru_text);
+		__entry->validation_bits = mem->validation_bits;
+		__entry->error_status = mem->error_status;
+		__entry->physical_addr = mem->physical_addr;
+		__entry->physical_addr_mask = mem->physical_addr_mask;
+		__entry->node = mem->node;
+		__entry->card = mem->card;
+		__entry->module = mem->module;
+		__entry->bank = mem->bank;
+		__entry->device = mem->device;
+		__entry->row = mem->row;
+		__entry->column = mem->column;
+		__entry->rank = mem->rank;
+		__entry->bit_pos = mem->bit_pos;
+		__entry->chip_id = mem->chip_id;
+		__entry->error_type = mem->error_type;
+		__entry->status = mem->status;
+		__entry->requestor_id = mem->requestor_id;
+		__entry->responder_id = mem->responder_id;
+		__entry->target_id = mem->target_id;
+		__entry->mem_array_handle = mem->mem_array_handle;
+		__entry->mem_dev_handle = mem->mem_dev_handle;
+	),
+
+	TP_printk("{%u} %s error: validation_bits: 0x%llx "
+		  "error_status: 0x%llx physical_addr: 0x%llx "
+		  "physical_addr_mask: 0x%llx node: %u card: %u "
+		  "module: %u bank: %u device: %u row: %u column: %u "
+		  "rank: %u bit_pos: %u chip_id: %u error_type: %u "
+		  "status: 0x%x requestor_id: 0x%llx responder_id: 0x%llx "
+		  "target_id: 0x%llx mem_array_handle: 0x%x "
+		  "mem_dev_handle: 0x%x FRU: %pUl %.20s",
+		  __entry->err_seq, cper_severity_str(__entry->sev),
+		  __entry->validation_bits,
+		  __entry->error_status,
+		  __entry->physical_addr,
+		  __entry->physical_addr_mask,
+		  __entry->node,
+		  __entry->card,
+		  __entry->module,
+		  __entry->bank,
+		  __entry->device,
+		  __entry->row,
+		  __entry->column,
+		  __entry->rank,
+		  __entry->bit_pos,
+		  __entry->chip_id,
+		  __entry->error_type,
+		  __entry->status,
+		  __entry->requestor_id,
+		  __entry->responder_id,
+		  __entry->target_id,
+		  __entry->mem_array_handle,
+		  __entry->mem_dev_handle,
+		  &__entry->fru_id, __get_str(fru_text))
+);
 #endif
 
 /*
-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 0/7] CPER: Add Memory Error Section 2 support
  2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
                   ` (6 preceding siblings ...)
  2026-11-04 11:03 ` [PATCH v3 7/7] ACPI: extlog: add Memory Error Section 2 trace event Pierre Gondois
@ 2026-11-04 11:07 ` Pierre Gondois
  7 siblings, 0 replies; 12+ messages in thread
From: Pierre Gondois @ 2026-11-04 11:07 UTC (permalink / raw)
  To: Ashok Raj
  Cc: linux-kernel, James Morse, Mark Brown, Rafael J. Wysocki,
	Len Brown, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Maciej Wieczor-Retman,
	Pawel Chmielewski, Dave Jiang, Jonathan Cameron,
	Fabio M. De Francesco, Breno Leitao, Terry Bowman, Dan Williams,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

+ Ashok

On 11/4/26 12:03, Pierre Gondois wrote:
> The support is mostly duplicated from Memory Error Section handling.
> Other than differences coming from the content of  Memory Error
> Section 1 and 2, differences in the support are:
>
> - v2 do not rely on a compact "struct cper_mem_err_compact" struct.
> This structure was used to support older versions of the Memory
> Error Section (1). This is not needed for the new structure.
>
> - The compact version is also used by the tracing framework.
> To avoid relying and propagating a non-standard record format,
> through trace event (cf. extlog_mem event) the new trace event
> prints each field individually.
>
> The last patch of the serie was only build-tested due to the
> absence of relevant hardware. apei_mce_report_mem_error() and
> arch_apei_report_mem_error() implementations were also removed since
> last version.
>
> It will also require a proper handling from the rasdaemon. Applying
> this last patch without rasdaemon support will silent the reports of
> Memory Error Section 2 error, cf. ras_userspace_consumers() check.
>
> Future:
> - _OSC support
> - Addition of arm64 tracepoints
> https://lore.kernel.org/lkml/20261023170405.000060b8@oss.qualcomm.com/
> - Emission of lossy CPER Mem error v1 tracepoints for legacy userspace
>    tools
> https://lore.kernel.org/lkml/at0rs4parlHFGI7k@hu-ashoraj-lv.qualcomm.com/
>
>
> RFC: https://lore.kernel.org/all/20260929074659.2587216-1-pierre.gondois@arm.com/#t
> V1:  https://lore.kernel.org/all/20261019145643.1877246-1-pierre.gondois@arm.com/
> - Corrections from Jonathan's review
> - New patch:
>      [PATCH v2 4/6] EDAC/ghes: Extract error report initialization
> - Last patch not in RFC as it has been reviewed by Jonathan@
>      [PATCH v2 6/6] ACPI: extlog: add Memory Error Section 2 trace event
> V2:
> - Updated ghes_edac_init_error() to ghes_edac_init_error_desc(),
>    which now only acts on the input "struct edac_raw_error_desc"
>    + added lockdep_assert_held() to ghes_edac_init_error_desc()
> - Accumulate failures with "queued |=" in ghes_do_proc()
> - New PATCH:
>    [PATCH v3 5/7] ACPI: APEI: Extract common memory failure handling
>
> Pierre Gondois (7):
>    cper: use BIT_ULL() for processor and memory validation bits
>    cper: add Memory Error Section 2 structures
>    cper: add helpers to handle Memory Error Section 2
>    EDAC/ghes: Extract error report initialization
>    ACPI: APEI: Extract common memory failure handling
>    ACPI: APEI: add separate Memory Error Section 2 handlers
>    ACPI: extlog: add Memory Error Section 2 trace event
>
>   drivers/acpi/acpi_extlog.c  |   6 ++
>   drivers/acpi/apei/ghes.c    |  58 +++++++++--
>   drivers/edac/ghes_edac.c    | 189 +++++++++++++++++++++++++++++-------
>   drivers/firmware/efi/cper.c | 109 +++++++++++++++++++++
>   drivers/ras/ras.c           |   1 +
>   include/acpi/ghes.h         |   2 +
>   include/linux/cper.h        | 129 +++++++++++++++++-------
>   include/ras/ras_event.h     | 102 +++++++++++++++++++
>   8 files changed, 518 insertions(+), 78 deletions(-)
>
> --
> 2.43.0

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits
  2026-11-04 11:03 ` [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits Pierre Gondois
@ 2026-11-04 16:22   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2026-11-04 16:22 UTC (permalink / raw)
  To: Pierre Gondois
  Cc: linux-kernel, James Morse, Jonathan Cameron, Breno Leitao,
	Rafael J. Wysocki, Len Brown, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue,
	Maciej Wieczor-Retman, Pawel Chmielewski, Dave Jiang,
	Fabio M. De Francesco, Dan Williams, Terry Bowman,
	Ard Biesheuvel, Morduan Zang, linux-acpi, linux-edac,
	acpica-devel

[-- Attachment #1: Type: text/plain, Size: 272 bytes --]

On Wed, Nov 04, 2026 at 12:03:09PM +0100, Pierre Gondois wrote:
> Use the BIT_ULL() macro to describe flag bits instead of
> hexadecimal values which are harder to read.

This should explicitly incldue linux/bits.h - we're getting it via
implicit inclusion at the minute.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/7] cper: add helpers to handle Memory Error Section 2
  2026-11-04 11:03 ` [PATCH v3 3/7] cper: add helpers to handle Memory Error Section 2 Pierre Gondois
@ 2026-11-04 17:25   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2026-11-04 17:25 UTC (permalink / raw)
  To: Pierre Gondois
  Cc: linux-kernel, James Morse, Jonathan Cameron, Rafael J. Wysocki,
	Len Brown, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Maciej Wieczor-Retman,
	Pawel Chmielewski, Dave Jiang, Fabio M. De Francesco,
	Breno Leitao, Terry Bowman, Dan Williams, Ard Biesheuvel,
	Morduan Zang, linux-acpi, linux-edac, acpica-devel

[-- Attachment #1: Type: text/plain, Size: 1142 bytes --]

On Wed, Nov 04, 2026 at 12:03:11PM +0100, Pierre Gondois wrote:
> Add separate location and printing helpers for Memory Error
> Section 2:
> - cper_mem_err2_location()
> - cper_dimm_err2_location()
> - cper_print_mem2()

> +int cper_dimm_err2_location(const struct cper_sec_mem_err2 *mem, char *msg)
> +{
> +	u32 len, n;
> +	const char *bank = NULL, *device = NULL;
> +
> +	if (!msg || !(mem->validation_bits & CPER_MEM2_VALID_MODULE_HANDLE))
> +		return 0;
> +
> +	/* SMBIOS handles are 16 bits; never truncate a Section 2 handle. */
> +	if (mem->mem_dev_handle <= U16_MAX)
> +		dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
> +	else
> +		pr_warn(FW_WARN "Memory Error Section 2 module handle 0x%x exceeds SMBIOS range\n",
> +			mem->mem_dev_handle);

Should this be rate limited?

> +	len = CPER_REC_LEN;
> +	if (bank && device)
> +		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
> +	else
> +		n = snprintf(msg, len,
> +			     "DIMM location: not present. DMI handle: 0x%.8x ",
> +			     mem->mem_dev_handle);

Shouldn't this be scnprintf(), especially in the first case where the
strings come from the firmware?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 6/7] ACPI: APEI: add separate Memory Error Section 2 handlers
  2026-11-04 11:03 ` [PATCH v3 6/7] ACPI: APEI: add separate Memory Error Section 2 handlers Pierre Gondois
@ 2026-11-04 17:51   ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2026-11-04 17:51 UTC (permalink / raw)
  To: Pierre Gondois
  Cc: linux-kernel, James Morse, Jonathan Cameron, Rafael J. Wysocki,
	Len Brown, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Maciej Wieczor-Retman,
	Pawel Chmielewski, Dave Jiang, Fabio M. De Francesco,
	Breno Leitao, Dan Williams, Terry Bowman, Ard Biesheuvel,
	Morduan Zang, linux-acpi, linux-edac, acpica-devel

[-- Attachment #1: Type: text/plain, Size: 1832 bytes --]

On Wed, Nov 04, 2026 at 12:03:14PM +0100, Pierre Gondois wrote:
> Add dedicated GHES and EDAC callbacks for Memory Error Section 2
> records. Use a separate GHES notifier chain so existing consumers
> continue to receive legacy memory error sections.

> @@ -1008,6 +1021,16 @@ static void ghes_do_proc(struct ghes *ghes,
>  
>  			arch_apei_report_mem_error(sev, mem_err);
>  			queued |= ghes_handle_memory_failure(gdata, sev, sync);
> +		} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM2)) {
> +			struct cper_sec_mem_err2 *mem_err = acpi_hest_get_payload(gdata);
> +
> +			if (gdata->error_data_length < sizeof(*mem_err)) {
> +				pr_warn(FW_WARN "Memory Error Section 2 length is too small\n");

The v1 code uses pr_warn_ratelimited() which seems sensible.

> +static int ghes_edac_report_mem_error2(struct notifier_block *nb,
> +				       unsigned long val, void *data)
> +{
> +	struct cper_sec_mem_err2 *mem_err = data;
> +	struct edac_raw_error_desc *e;
> +	struct mem_ctl_info *mci;
> +	struct ghes_pvt *pvt;
> +	char *p;

> +	/* Memory error location, mapped on e->location */
> +	p = e->location;
> +	p += cper_mem_err2_location(mem_err, p);
> +
> +	if (mem_err->validation_bits & CPER_MEM2_VALID_MODULE_HANDLE) {
> +		struct dimm_info *dimm = NULL;
> +
> +		p += cper_dimm_err2_location(mem_err, p);

Do we need to raise the size of e->location?  It's 256 bytes and
there's an awful ot of potential fields that could be decoded here,
including some with 64 bit IDs.

> +		if (mem_err->mem_dev_handle <= U16_MAX)
> +			dimm = find_dimm_by_handle(mci, mem_err->mem_dev_handle);
> +		else
> +			pr_warn(FW_WARN "Memory Error Section 2 module handle 0x%x exceeds SMBIOS range\n",
> +				mem_err->mem_dev_handle);

There's an equivalent print in cper_dimm_err2_location().

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-11-04 17:52 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 11:03 [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois
2026-11-04 11:03 ` [PATCH v3 1/7] cper: use BIT_ULL() for processor and memory validation bits Pierre Gondois
2026-11-04 16:22   ` Mark Brown
2026-11-04 11:03 ` [PATCH v3 2/7] cper: add Memory Error Section 2 structures Pierre Gondois
2026-11-04 11:03 ` [PATCH v3 3/7] cper: add helpers to handle Memory Error Section 2 Pierre Gondois
2026-11-04 17:25   ` Mark Brown
2026-11-04 11:03 ` [PATCH v3 4/7] EDAC/ghes: Extract error report initialization Pierre Gondois
2026-11-04 11:03 ` [PATCH v3 5/7] ACPI: APEI: Extract common memory failure handling Pierre Gondois
2026-11-04 11:03 ` [PATCH v3 6/7] ACPI: APEI: add separate Memory Error Section 2 handlers Pierre Gondois
2026-11-04 17:51   ` Mark Brown
2026-11-04 11:03 ` [PATCH v3 7/7] ACPI: extlog: add Memory Error Section 2 trace event Pierre Gondois
2026-11-04 11:07 ` [PATCH v3 0/7] CPER: Add Memory Error Section 2 support Pierre Gondois

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®