Re: [PATCH v12 3/8] cxl/cdat: Gather DSMAS data for DCD partitions

Anisa Su <[email protected]>
Newsgroups dev.linux.lists.nvdimm,org.kernel.vger.linux-cxl,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On Mon, Aug 03, 2026 at 03:56:36PM -0700, Alison Schofield wrote:
> On Fri, Jul 31, 2026 at 01:48:08AM -0700, Anisa Su wrote:
> > From: Ira Weiny <[email protected]>
> > 
> > Additional DCD partition (AKA region) information is contained in the
> > DSMAS CDAT tables, including performance, read only, and shareable
> > attributes.
> > 
> > Match DCD partitions with DSMAS tables and store the meta data.
> > 
> > Signed-off-by: Ira Weiny <[email protected]>
> > Co-developed-by: Anisa Su <[email protected]>
> > Signed-off-by: Anisa Su <[email protected]>
> > Tested-by: Wonjae Lee <[email protected]>
> > Tested-by: Junhee Park <[email protected]>
> > Tested-by: Heesoo Kim <[email protected]>
> > Reviewed-by: Dave Jiang <[email protected]>
> > ---
> >  drivers/cxl/core/cdat.c | 13 +++++++++++++
> >  drivers/cxl/core/hdm.c  |  1 +
> >  drivers/cxl/core/mbox.c | 22 ++++++++++++++++------
> >  drivers/cxl/cxlmem.h    |  2 ++
> >  include/cxl/cxl.h       |  4 ++++
> >  5 files changed, 36 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> > index 5c9f07262513..37136b2cf7e4 100644
> > --- a/drivers/cxl/core/cdat.c
> > +++ b/drivers/cxl/core/cdat.c
> > @@ -17,6 +17,7 @@ struct dsmas_entry {
> >  	struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
> >  	int entries;
> >  	int qos_class;
> > +	bool shareable;
> >  };
> >  
> >  static u32 cdat_normalize(u16 entry, u64 base, u8 type)
> > @@ -74,6 +75,7 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
> >  		return -ENOMEM;
> >  
> >  	dent->handle = dsmas->dsmad_handle;
> > +	dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE;
> >  	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
> >  	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
> >  			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
> > @@ -266,15 +268,26 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
> >  		bool found = false;
> >  
> >  		for (int i = 0; i < cxlds->nr_partitions; i++) {
> > +			enum cxl_partition_mode mode = cxlds->part[i].mode;
> >  			struct resource *res = &cxlds->part[i].res;
> > +			u8 handle = cxlds->part[i].handle;
> >  			struct range range = {
> >  				.start = res->start,
> >  				.end = res->end,
> >  			};
> >  
> >  			if (range_contains(&range, &dent->dpa_range)) {
> > +				if (mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
> > +				    dent->handle != handle) {
> > +					dev_warn(dev,
> > +						 "Dynamic RAM perf mismatch; %pra (%u) vs %pra (%u)\n",
> > +						 &range, handle, &dent->dpa_range,
> > +						 dent->handle);
> > +					continue;
> 
> Seems like the above message needs to say that the DSMAD handle from
> mbox disagrees w CDAT DSMAS handle. Those (%u) that are handles have
> no description.

Reworded to:

	dev_warn(dev,
		 "DSMAD handle mismatch: mailbox %u %pra, CDAT %u %pra\n",
		 part->handle, &range,
		 dent->handle, &dent->dpa_range);

which for example would read as:

	DSMAD handle mismatch: [range 0x100000000-0x1ffffffff] has 3, DSMAS [range 0x100000000-0x17fffffff] has 7

I applied it with your suggestion below to invert the range_contains()
and use a 'part' local pointer to reduce nesting and repeated indexing,
but the line is still quite long (99 chars), since it's still within the
xa_for_each(dsmas_xa...){} and the for loop. The message could
be clearer, but I wasn't sure how to do so without going over
100 chars, so I added a comment:

		/*
		 * part->handle is from Get DC Config, dent->handle
		 * from the CDAT DSMAS entry.
		 */
		if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
		    dent->handle != part->handle) {
			dev_warn(dev,
				 "DSMAD handle mismatch: %pra has %u, DSMAS %pra has %u\n",
				 &range, part->handle,
				 &dent->dpa_range, dent->handle);
			break;
		}


> With the above mismatch and continue, the loop exits w found still
> false. Is that really true?
> 
Good point. found is now set to true before the above check. So with the
inverted range_contains() suggestion:

	if (!range_contains(&range, &dent->dpa_range))
		continue;

	found = true;
	if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
	    dent->handle != part->handle) {
		dev_warn(...);
		break;
	}


> 
> > +				}
> >  				update_perf_entry(dev, dent,
> >  						  &cxlds->part[i].perf);
> > +				cxlds->part[i].shareable = dent->shareable;
> 
> 
> why is shareable assigned for every node, and not only DYNAMIC_RAM_1
> 
Fixed to only be assigned if the mode is DYNAMIC_RAM_1 now:

	update_perf_entry(dev, dent, &part->perf);
	if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1)
		part->shareable = dent->shareable;

Although we now have 2 places that gate on if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1),
I chose to keep this as a separate check. If we consolidate this with
the above part->handle != dent->handle check, it would add another level
of nesting and make the dev_warn message from above to over 100 cols.

> >  				found = true;
> >  				break;
> >  			}
> 
> Above nesting can be improved. Inverting range_contains() to unindent
> the main body. A 'part' local pointer would reduce repeated indexing.
> 
Done.

> 
> > diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
> > index 0ef076c08ed2..7f63b86887f4 100644
> > --- a/drivers/cxl/core/hdm.c
> > +++ b/drivers/cxl/core/hdm.c
> > @@ -477,6 +477,7 @@ int cxl_dpa_setup(struct cxl_dev_state *cxlds, const struct cxl_dpa_info *info)
> >  
> >  		cxlds->part[i].perf.qos_class = CXL_QOS_CLASS_INVALID;
> >  		cxlds->part[i].mode = part->mode;
> > +		cxlds->part[i].handle = part->handle;
> >  
> >  		/* Require ordered + contiguous partitions */
> >  		if (i) {
> > diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
> > index d79019fbd790..a6cdea9f4080 100644
> > --- a/drivers/cxl/core/mbox.c
> > +++ b/drivers/cxl/core/mbox.c
> > @@ -1357,10 +1357,16 @@ static int cxl_dc_check(struct device *dev, struct cxl_dc_partition_info *part_a
> >  {
> >  	u64 blk_size = le64_to_cpu(dev_part->block_size);
> >  	u64 len = le64_to_cpu(dev_part->length);
> > +	u32 handle = le32_to_cpu(dev_part->dsmad_handle);
> >  
> >  	part_array[index].start = le64_to_cpu(dev_part->base);
> >  	part_array[index].size = le64_to_cpu(dev_part->decode_length);
> >  	part_array[index].size *= CXL_CAPACITY_MULTIPLIER;
> > +	if (handle & ~0xFF) {
> > +		dev_warn(dev, "DSMAD handle 0x%x has non-zero reserved bits\n", handle);
> 
> I don't see reserve bits for a DSMAD handle. I think this check is valid
> but the message has the wrong constraint. Expect it is a CDAT constraint.
> 
Yes, thank you for point it out. CXL r4.0 Table 8-347 gives DSMADHandle a
full 4 bytes and declares no reserved bits; the table's Reserved field
is the 3 bytes at 0x25, after Flags. The 8 bit limit comes from CDAT,
where struct acpi_cdat_dsmas has a u8 dsmad_handle, so a value above
0xFF cannot name a DSMAS entry that exists.

The driver stores the handle as u8 in cxl_dpa_partition, cxl_dc_partition_info and cdat.c's
dsmas_entry, so 0x100 would narrow to 0x00 and silently match whichever
DSMAS entry has handle 0. The mssage now reads:

	/* The CDAT DSMAD handle this refers to is 8 bits */
	if (handle & ~0xFF) {
		dev_warn(dev, "DSMAD handle 0x%x exceeds the 8 bit CDAT DSMAD handle\n",
			 handle);

> 
> > +		return -EINVAL;
> > +	}
> > +	part_array[index].handle = handle;
> >  
> >  	/* Check partitions are in increasing DPA order */
> >  	if (index > 0) {
> > @@ -1536,6 +1542,7 @@ int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
> >  	/* Return 1st partition */
> >  	dc_info->start = partitions[0].start;
> >  	dc_info->size = partitions[0].size;
> > +	dc_info->handle = partitions[0].handle;
> >  	dev_dbg(dev, "Returning partition 0 %llu size %llu\n",
> >  		dc_info->start, dc_info->size);
> >  
> > @@ -1543,7 +1550,8 @@ int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
> >  }
> >  EXPORT_SYMBOL_NS_GPL(cxl_dev_dc_identify, "CXL");
> >  
> > -static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
> > +static void add_part(struct cxl_dpa_info *info, u64 start, u64 size,
> > +		     enum cxl_partition_mode mode, u8 handle)
> >  {
> >  	int i = info->nr_partitions;
> >  
> > @@ -1555,6 +1563,7 @@ static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_pa
> >  		.end = start + size - 1,
> >  	};
> >  	info->part[i].mode = mode;
> > +	info->part[i].handle = handle;
> >  	info->nr_partitions++;
> >  }
> >  
> > @@ -1572,9 +1581,9 @@ int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
> >  	info->size = mds->total_bytes;
> >  
> >  	if (mds->partition_align_bytes == 0) {
> > -		add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
> > +		add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM, 0);
> >  		add_part(info, mds->volatile_only_bytes,
> > -			 mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
> > +			 mds->persistent_only_bytes, CXL_PARTMODE_PMEM, 0);
> >  		return 0;
> >  	}
> >  
> > @@ -1584,9 +1593,9 @@ int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
> >  		return rc;
> >  	}
> >  
> > -	add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
> > +	add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM, 0);
> >  	add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
> > -		 CXL_PARTMODE_PMEM);
> > +		 CXL_PARTMODE_PMEM, 0);
> >  
> >  	return 0;
> >  }
> > @@ -1638,7 +1647,8 @@ void cxl_configure_dcd(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
> >  	info->size += dc_info.size;
> >  	dev_dbg(dev, "Adding dynamic ram partition 1; %llu size %llu\n",
> >  		dc_info.start, dc_info.size);
> > -	add_part(info, dc_info.start, dc_info.size, CXL_PARTMODE_DYNAMIC_RAM_1);
> > +	add_part(info, dc_info.start, dc_info.size, CXL_PARTMODE_DYNAMIC_RAM_1,
> > +		 dc_info.handle);
> >  }
> >  EXPORT_SYMBOL_NS_GPL(cxl_configure_dcd, "CXL");
> >  
> > diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> > index a9782939d82b..eb1e6f7a2038 100644
> > --- a/drivers/cxl/cxlmem.h
> > +++ b/drivers/cxl/cxlmem.h
> > @@ -140,6 +140,7 @@ struct cxl_dpa_info {
> >  	struct cxl_dpa_part_info {
> >  		struct range range;
> >  		enum cxl_partition_mode mode;
> > +		u8 handle;
> >  	} part[CXL_NR_PARTITIONS_MAX];
> >  	int nr_partitions;
> >  };
> > @@ -853,6 +854,7 @@ int cxl_dev_state_identify(struct cxl_memdev_state *mds);
> >  struct cxl_dc_partition_info {
> >  	u64 start;
> >  	u64 size;
> > +	u8 handle;
> >  };
> >  
> >  int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
> > diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
> > index 87c2bd73df21..baf0132c70a3 100644
> > --- a/include/cxl/cxl.h
> > +++ b/include/cxl/cxl.h
> > @@ -141,11 +141,15 @@ enum cxl_partition_mode {
> >   * @res: shortcut to the partition in the DPA resource tree (cxlds->dpa_res)
> >   * @perf: performance attributes of the partition from CDAT
> >   * @mode: operation mode for the DPA capacity, e.g. ram, pmem, dynamic...
> > + * @handle: DSMAS handle intended to represent this partition
> 
> What is with the 'intended'? Either it represents the partition
> or the match failed.
> 
Dropped, now says "DSMAS handle that represents this partition".

> 
> > + * @shareable: Is the partition sharable (from its CDAT DSMAS entry)
>                                    ^
> 				   shareable
> 
Fixed.

Thanks,
Anisa
> 
> >   */
> >  struct cxl_dpa_partition {
> >  	struct resource res;
> >  	struct cxl_dpa_perf perf;
> >  	enum cxl_partition_mode mode;
> > +	u8 handle;
> > +	bool shareable;
> >  };
> >  
> >  #define CXL_NR_PARTITIONS_MAX 3
> > -- 
> > 2.43.0
> >
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.