Re: [PATCH v2 1/2] cxl/hdm: Allow zero sized HDM decoders

From: Alison Schofield

Date: Wed Jun 03 2026 - 22:59:51 EST


On Tue, Jun 02, 2026 at 01:40:52PM +0800, Richard Cheng wrote:
> CXL r3.2 §8.2.4.20.12 and §14.13.10 permit committing an HDM decoder
> with size 0. BIOS commits and LOCKs such decoders to burn slots,
> preventing the OS from programming new regions through them, e.g. for a
> Type 3 device in a Trusted Computing Base (TCB) established via the
> Trusted Security Protocol (TSP).
>
> init_hdm_decoder() rejects these with -ENXIO and aborts port
> enumeration, so "cxl list" shows nothing for the affected port.
>
> Set port->commit_end before the size check so later contiguous decoders
> pass the out-of-order check, and skip devm_cxl_dpa_reserve() since
> zero-size decoder wouldn't need to reserve DPA ranges.
>
> The decoder is added to topology normally, LOCK is read from the HW
> control register so "cxl list" reflects the slot's real state.
>
> Signed-off-by: Vishal Aslot <vaslot@xxxxxxxxxx>
> Signed-off-by: Richard Cheng <icheng@xxxxxxxxxx>
> ---
> Changelog
>
> v1->v2:
> - Add zero-size committed decoders to the topology instead of
> skipping them. Drop v1's -ENOSPC sentinel and the matching
> "continue" in devm_cxl_enumerate_decoders(); fall through so
> add_hdm_decoder() registers the decoder.
> - Set port->commit_end unconditionally for any committed decoder,
> not only non-zero-size ones, so subsequent decoders satisfy the
> out-of-order check.
> - Add an explicit early-return before devm_cxl_dpa_reserve() in the
> endpoint-decoder path. __cxl_dpa reserve() rejects zero-size
> decoders
> - Spell out TSP and TCB and cite spec sections in commit message
> - Reorder series, implementation first
> ---
> drivers/cxl/core/hdm.c | 15 +++++++++------
> 1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
> index 0c80b76a5f9b..467ac45bee55 100644
> --- a/drivers/cxl/core/hdm.c
> +++ b/drivers/cxl/core/hdm.c
> @@ -1031,13 +1031,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
> return -ENXIO;
> }
>
> - if (size == 0) {
> - dev_warn(&port->dev,
> - "decoder%d.%d: Committed with zero size\n",
> - port->id, cxld->id);
> - return -ENXIO;
> - }
> port->commit_end = cxld->id;
> +
> + if (size == 0)
> + dev_dbg(&port->dev,
> + "decoder%d.%d: Committed with zero size\n",
> + port->id, cxld->id);

I suspect this leads to the poison count mismatch.
Previously every committed endpoint decoder reached
devm_cxl_dpa_reserve(). That meant the highest committed decoder always
had a dpa_res. poison_by_decoder() depends on that. If it gets skipped
poison in the unmapped DPA 'tail' is not collected.


> } else {
> if (cxled) {
> struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
> @@ -1096,6 +1095,10 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
> if (!committed)
> return 0;
>
> + /* Committed zero-size decoder has nothing to reserve in DPA. */
> + if (size == 0)
> + return 0;
> +

This is the early return that Sashiko called out. Leave dpa_res NULL
but port->commit_end already is set to this decoders id, cxld->id.
Previously commit_end only marked a 'fully' reserved decoder, now
it is marking this one w dpa_res == NULL. That is different. ???



> dpa_size = div_u64_rem(size, cxld->interleave_ways, &remainder);
> if (remainder) {
> dev_err(&port->dev,
> --
> 2.43.0
>