[PATCH v5 3/3] cxl/edac: Mask DPA flags in the event record cache key

From: Jongwon Lee

Date: Sat Nov 07 2026 - 21:21:34 EST


The low bits of the DPA field in General Media and DRAM event records
are flags. Bit 0 is VOLATILE and bit 1 is NOT_REPAIRABLE. The trace
events print the DPA with CXL_DPA_MASK applied, while
cxl_store_rec_gen_media() and cxl_store_rec_dram() use the raw value as
the xarray key.

User space takes the DPA from the trace event and writes it to the
mem_repair dpa attribute. If the record has any flag set, xa_load() does
not find it and the repair fails with -EINVAL.

Use the masked DPA as the key. Records marked NOT_REPAIRABLE are still
rejected, because the lookup skips them.

Fixes: 0b5ccb0de1e2 ("cxl/edac: Support for finding memory operation attributes from the current boot")
Signed-off-by: Jongwon Lee <ai@xxxxxxxxx>
---
drivers/cxl/core/edac.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/cxl/core/edac.c b/drivers/cxl/core/edac.c
index 42683b7c54..f627c73ff6 100644
--- a/drivers/cxl/core/edac.c
+++ b/drivers/cxl/core/edac.c
@@ -918,6 +918,16 @@ struct cxl_mem_repair_attrbs {
enum cxl_mem_repair_type repair_type;
};

+/*
+ * The low bits of the event record DPA are flags (VOLATILE, NOT_REPAIRABLE).
+ * Records are looked up by the DPA user space writes back, which comes from
+ * the trace event and has the flags masked off, so key them the same way.
+ */
+static inline unsigned long cxl_rec_dpa(const struct cxl_event_media_hdr *hdr)
+{
+ return le64_to_cpu(hdr->phys_addr) & CXL_DPA_MASK;
+}
+
static inline bool cxl_rec_not_repairable(const struct cxl_event_media_hdr *hdr)
{
return le64_to_cpu(hdr->phys_addr) & CXL_DPA_NOT_REPAIRABLE;
@@ -1131,8 +1141,7 @@ int cxl_store_rec_gen_media(struct cxl_memdev *cxlmd, union cxl_event *evt)
return -ENOMEM;

old_rec = xa_store(&array_rec->rec_gen_media,
- le64_to_cpu(rec->media_hdr.phys_addr), rec,
- GFP_KERNEL);
+ cxl_rec_dpa(&rec->media_hdr), rec, GFP_KERNEL);
if (xa_is_err(old_rec)) {
kfree(rec);
return xa_err(old_rec);
@@ -1161,8 +1170,7 @@ int cxl_store_rec_dram(struct cxl_memdev *cxlmd, union cxl_event *evt)
return -ENOMEM;

old_rec = xa_store(&array_rec->rec_dram,
- le64_to_cpu(rec->media_hdr.phys_addr), rec,
- GFP_KERNEL);
+ cxl_rec_dpa(&rec->media_hdr), rec, GFP_KERNEL);
if (xa_is_err(old_rec)) {
kfree(rec);
return xa_err(old_rec);
--
2.55.0