Add an alignment gate to cxl_add_pending(): every extent in a tag group must have its start_dpa and length aligned to CXL_DCD_EXTENT_ALIGN (SZ_2M, the minimum device-dax mapping granularity on every architecture that enables CXL DCD). A misaligned extent makes the resulting dax device unusable, so drop the whole group rather than accept a partial allocation that would surface a broken dax_resource.
Based on patches by John Groves. Signed-off-by: Ira Weiny <[email protected]> Signed-off-by: John Groves <[email protected]> Signed-off-by: Anisa Su <[email protected]> --- Changes: [anisa: split out as a separate validation step] --- drivers/cxl/core/mbox.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index e5edc3975e8f..421bd716a273 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -7,6 +7,7 @@ #include <linux/unaligned.h> #include <linux/list.h> #include <linux/list_sort.h> +#include <linux/sizes.h> #include <cxlpci.h> #include <cxlmem.h> #include <cxl.h> @@ -1280,6 +1281,24 @@ static int add_to_pending_list(struct list_head *pending_list, return 0; } +/* + * Device-dax requires extent boundaries aligned to its mapping granularity. + * Use SZ_2M as a conservative default; a tighter check that queries the + * cxl_dax_region / cxl_endpoint_decoder for its actual alignment would be + * strictly more correct, but SZ_2M is the minimum device-dax supports on + * every architecture that enables CXL DCD today. + */ +#define CXL_DCD_EXTENT_ALIGN SZ_2M + +static bool cxl_extent_dcd_aligned(const struct cxl_extent *extent) +{ + u64 start = le64_to_cpu(extent->start_dpa); + u64 len = le64_to_cpu(extent->length); + + return IS_ALIGNED(start, CXL_DCD_EXTENT_ALIGN) && + IS_ALIGNED(len, CXL_DCD_EXTENT_ALIGN); +} + /* * Compare two extents by shared_extn_seq (ascending). list_sort is * stable so when shared_extn_seq is 0 for every entry (non-sharable @@ -1352,6 +1371,26 @@ static int cxl_add_pending(struct cxl_memdev_state *mds) extract_tag_group(pending, &tag, &group); list_sort(NULL, &group, extent_seq_compare); + /* Alignment gate — abort the group if any member fails */ + bool aligned = true; + list_for_each_entry(pos, &group, list) { + if (!cxl_extent_dcd_aligned(pos->extent)) { + dev_warn(dev, + "Tag %pUb: dropping group, extent DPA:%#llx LEN:%#llx not %u-aligned\n", + &tag, + le64_to_cpu(pos->extent->start_dpa), + le64_to_cpu(pos->extent->length), + CXL_DCD_EXTENT_ALIGN); + aligned = false; + break; + } + } + if (!aligned) { + list_for_each_entry_safe(pos, tmp, &group, list) + delete_extent_node(pos); + continue; + } + u16 logical_seq = 1; list_for_each_entry_safe(pos, tmp, &group, list) { u16 raw = le16_to_cpu(pos->extent->shared_extn_seq); -- 2.43.0

