Linux CXL
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Support zero-sized HDM decoders
@ 2026-06-02  5:40 Richard Cheng
  2026-06-02  5:40 ` [PATCH v2 1/2] cxl/hdm: Allow zero sized " Richard Cheng
  2026-06-02  5:40 ` [PATCH v2 2/2] tools/testing/cxl: Enable zero sized decoders under hb0 Richard Cheng
  0 siblings, 2 replies; 6+ messages in thread
From: Richard Cheng @ 2026-06-02  5:40 UTC (permalink / raw)
  To: dave, jonathan.cameron, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams
  Cc: linux-cxl, linux-kernel, newtonl, kristinc, kaihengf, kobak,
	vaslot, smadhavan, Richard Cheng

Hello,

This v2 picks up Vishal Aslot's "Support zero-sized decoders" series [1]
and addresses the review feedback, if any SoB or credits have mistake,
please let me know, I'll correct them.

CXL r3.2 §8.2.4.20.12 and §14.13.10 permit committing an HDM decoder
with size 0. BIOS uses this together with LOCK to burn decoder slots so
the OS cannot program 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() today rejects committed zero-size decoders with
-ENXIO during port enumeration, which aborts the whole port — affected
systems show nothing under 'cxl list'. Patch 1 lets these decoders be
enumerated normally so they appear in topology with their HW-reported
LOCK state. Patch 2 extends cxl_test to inject zero-size + locked
decoders under host-bridge 0 so the new code path has in-tree coverage.

A note on Alison's v1 concern about autoregion teardown being blocked
by locked zero-size decoders sitting above the autoregion: this does
not actually fire with v2's "add to topology" approach. The existing
cxl_decoder_reset() already returns early on CXL_DECODER_F_LOCK and
tolerates out-of-order reset of the unlocked autoregion.
port->commit_end staying at its watermark after teardown
maps to physical reality — the slots above are permanently burned by
the locked decoders. No reset-path patch is therefore needed in v2.

Changes since v1:
    - Reorder: implementation patch first, cxl_test patch second
    - Patch 1: drop -ENOSPC sentinel and the matching "continue"
      in devm_cxl_enumerate_decoders(). The decoder is now added
      to the topology so "cxl list" shows it.
      Move port->commit_end assignment before the size check so
      later contiguous decoders pass the out-of-order check. Add
      an early return before devm_cxl_dpa_reserve().
    - Patch 2: replace second_decoder() / third_decoder() with a single
      match_decoder_by_index() helper. Use CXL_DECODER_STATE_MANUAL 
      instead of STATE_AUTO. Set CXL_DECODER_F_LOCK on the mock zero-size
      decoders to model the BIOS-burns-slots case.

[1]:
https://lore.kernel.org/all/20251015024019.1189713-1-vaslot@nvidia.com/T/#u

Richard Cheng (2):
  cxl/hdm: Allow zero sized HDM decoders
  tools/testing/cxl: Enable zero sized decoders under hb0

 drivers/cxl/core/hdm.c       | 15 ++++---
 tools/testing/cxl/test/cxl.c | 79 +++++++++++++++++++++++++++++++-----
 2 files changed, 78 insertions(+), 16 deletions(-)


base-commit: eb3f4b7426cfd2b79d65b7d37155480b32259a11
-- 
2.43.0


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

* [PATCH v2 1/2] cxl/hdm: Allow zero sized HDM decoders
  2026-06-02  5:40 [PATCH v2 0/2] Support zero-sized HDM decoders Richard Cheng
@ 2026-06-02  5:40 ` Richard Cheng
  2026-06-02  5:57   ` sashiko-bot
  2026-06-04  2:56   ` Alison Schofield
  2026-06-02  5:40 ` [PATCH v2 2/2] tools/testing/cxl: Enable zero sized decoders under hb0 Richard Cheng
  1 sibling, 2 replies; 6+ messages in thread
From: Richard Cheng @ 2026-06-02  5:40 UTC (permalink / raw)
  To: dave, jonathan.cameron, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams
  Cc: linux-cxl, linux-kernel, newtonl, kristinc, kaihengf, kobak,
	vaslot, smadhavan, Richard Cheng

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@nvidia.com>
Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
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);
 	} 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;
+
 	dpa_size = div_u64_rem(size, cxld->interleave_ways, &remainder);
 	if (remainder) {
 		dev_err(&port->dev,
-- 
2.43.0


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

* [PATCH v2 2/2] tools/testing/cxl: Enable zero sized decoders under hb0
  2026-06-02  5:40 [PATCH v2 0/2] Support zero-sized HDM decoders Richard Cheng
  2026-06-02  5:40 ` [PATCH v2 1/2] cxl/hdm: Allow zero sized " Richard Cheng
@ 2026-06-02  5:40 ` Richard Cheng
  2026-06-04  2:44   ` Alison Schofield
  1 sibling, 1 reply; 6+ messages in thread
From: Richard Cheng @ 2026-06-02  5:40 UTC (permalink / raw)
  To: dave, jonathan.cameron, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams
  Cc: linux-cxl, linux-kernel, newtonl, kristinc, kaihengf, kobak,
	vaslot, smadhavan, Richard Cheng

The kernel now allows committed HDM decoders of zero size so BIOS can
burn slots with LOCK. Without cxl_test coverage the new path goes
unexercised.

For the special endpoints under host-bridge 0, e.g. cxl_mem.0 and
cxl_mem.4, commit decoders 1 and 2 as zero-size + locked alongside the
existing autoregion at decoder[0]. Mirro the same shape on the parent
switch and host bridge via the walk-up that already builds the
autoregion path.

Signed-off-by: Vishal Aslot <vaslot@nvidia.com>
Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
Changelog:

v1->v2:
    - Replace second_decoder(), third_decoder() with a single
      match_decoder_by_index() helper, so all lookups share one matcher.
    - Use DEFINE_RANGE() for the empty range instread of an open-coded
      struct
    - Set cxled->state = CXL_DECODER_STATE_MANUAL rather than STATE_AUTO
    - Set CXL_DECODER_F_LOCK on the mock zero-size decoders to model the
      BIOS-burns-slots case
---
 tools/testing/cxl/test/cxl.c | 79 +++++++++++++++++++++++++++++++-----
 1 file changed, 69 insertions(+), 10 deletions(-)

diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c
index 418669927fb0..1ae0290a9221 100644
--- a/tools/testing/cxl/test/cxl.c
+++ b/tools/testing/cxl/test/cxl.c
@@ -1041,16 +1041,41 @@ static void default_mock_decoder(struct cxl_decoder *cxld)
 	WARN_ON_ONCE(!cxld_registry_new(cxld));
 }
 
-static int first_decoder(struct device *dev, const void *data)
+static int match_decoder_by_index(struct device *dev, const void *data)
 {
+	int target_id = *(const int *)data;
 	struct cxl_decoder *cxld;
 
 	if (!is_switch_decoder(dev))
 		return 0;
 	cxld = to_cxl_decoder(dev);
-	if (cxld->id == 0)
-		return 1;
-	return 0;
+	return cxld->id == target_id;
+}
+
+static void size_zero_mock_decoder_ep(struct cxl_decoder *cxld, u64 base)
+{
+	struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(&cxld->dev);
+
+	cxld->hpa_range = DEFINE_RANGE(base, base - 1);
+	cxld->interleave_ways = 2;
+	cxld->interleave_granularity = 4096;
+	cxld->target_type = CXL_DECODER_HOSTONLYMEM;
+	cxld->flags = CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
+	cxled->state = CXL_DECODER_STATE_MANUAL;
+	cxld->commit = mock_decoder_commit;
+	cxld->reset = mock_decoder_reset;
+}
+
+static void size_zero_mock_decoder_sw(struct cxl_decoder *cxld, u64 base,
+				      int level)
+{
+	cxld->flags = CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
+	cxld->target_type = CXL_DECODER_HOSTONLYMEM;
+	cxld->interleave_ways = level == 0 ? 2 : 1;
+	cxld->interleave_granularity = 4096;
+	cxld->hpa_range = DEFINE_RANGE(base, base - 1);
+	cxld->commit = mock_decoder_commit;
+	cxld->reset = mock_decoder_reset;
 }
 
 /*
@@ -1123,15 +1148,17 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
 	}
 
 	/*
-	 * The first decoder on the first 2 devices on the first switch
-	 * attached to host-bridge0 mock a fake / static RAM region. All
-	 * other decoders are default disabled. Given the round robin
-	 * assignment those devices are named cxl_mem.0, and cxl_mem.4.
+	 * On the first 2 devices on the first switch attached to
+	 * host-bridge0, decoder[0] mocks a fake / static RAM region and
+	 * decoders 1 and 2 mock BIOS-burnt zero-size + locked slots
+	 * (CXL r3.2 §8.2.4.20.12, §14.13.10). All other decoders are
+	 * default disabled. Given the round robin assignment those
+	 * devices are named cxl_mem.0 and cxl_mem.4.
 	 *
 	 * See 'cxl list -BMPu -m cxl_mem.0,cxl_mem.4'
 	 */
 	if (!is_endpoint_decoder(&cxld->dev) || !hb0 || pdev->id % 4 ||
-	    pdev->id > 4 || cxld->id > 0) {
+	    pdev->id > 4 || cxld->id > 2) {
 		default_mock_decoder(cxld);
 		return false;
 	}
@@ -1145,6 +1172,18 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
 	base = window->base_hpa;
 	if (extended_linear_cache)
 		base += mock_auto_region_size;
+
+	/*
+	 * Decoders 1 and 2 of the special endpoints under host-bridge0
+	 * are committed as zero-size + locked to mock BIOS burning
+	 * decoder slots (CXL r3.2 §8.2.4.20.12, §14.13.10).
+	 */
+	if (cxld->id == 1 || cxld->id == 2) {
+		size_zero_mock_decoder_ep(cxld, base);
+		port->commit_end = cxld->id;
+		WARN_ON_ONCE(!cxld_registry_new(cxld));
+		return false;
+	}
 	cxld->hpa_range = (struct range) {
 		.start = base,
 		.end = base + mock_auto_region_size - 1,
@@ -1168,9 +1207,12 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
 	 */
 	iter = port;
 	for (i = 0; i < 2; i++) {
+		int id;
+
 		dport = iter->parent_dport;
 		iter = dport->port;
-		dev = device_find_child(&iter->dev, NULL, first_decoder);
+		id = 0;
+		dev = device_find_child(&iter->dev, &id, match_decoder_by_index);
 		/*
 		 * Ancestor ports are guaranteed to be enumerated before
 		 * @port, and all ports have at least one decoder.
@@ -1214,6 +1256,23 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
 
 		cxld_registry_update(cxld);
 		put_device(dev);
+
+		/*
+		 * Mirror the endpoint: also commit the next two switch
+		 * decoders as zero-size + locked so the hierarchy looks
+		 * like a BIOS post-lock layout end-to-end.
+		 */
+		for (id = 1; id <= 2; id++) {
+			dev = device_find_child(&iter->dev, &id,
+						match_decoder_by_index);
+			if (WARN_ON(!dev))
+				continue;
+			cxld = to_cxl_decoder(dev);
+			size_zero_mock_decoder_sw(cxld, base, i);
+			iter->commit_end = id;
+			cxld_registry_update(cxld);
+			put_device(dev);
+		}
 	}
 
 	return false;
-- 
2.43.0


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

* Re: [PATCH v2 1/2] cxl/hdm: Allow zero sized HDM decoders
  2026-06-02  5:40 ` [PATCH v2 1/2] cxl/hdm: Allow zero sized " Richard Cheng
@ 2026-06-02  5:57   ` sashiko-bot
  2026-06-04  2:56   ` Alison Schofield
  1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-06-02  5:57 UTC (permalink / raw)
  To: Richard Cheng; +Cc: linux-cxl

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Skipping devm_cxl_dpa_reserve() for zero-size decoders leaves port->hdm_end un-incremented, causing the out-of-order DPA allocation check to fail unconditionally for subsequent decoders.
--

commit 413b72f0366d77ee154e5fec85ab5deab385b5af
Author: Richard Cheng <icheng@nvidia.com>

cxl/hdm: Allow zero sized HDM decoders
    
This commit allows committing an HDM decoder with a size of 0 to support BIOS
configurations that burn slots for Trusted Computing Base devices. It sets
port->commit_end before checking for a zero size and skips
devm_cxl_dpa_reserve() for these decoders since they have no DPA range to
reserve.

> diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
> index 0c80b76a5f9b4..467ac45bee553 100644
> --- a/drivers/cxl/core/hdm.c
> +++ b/drivers/cxl/core/hdm.c

[ ... ]

> @@ -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;
> +

[Severity: High]
Does skipping devm_cxl_dpa_reserve() here prevent port->hdm_end from being
incremented for the zero-size decoder?

If port->hdm_end is not updated, won't subsequent decoders fail the DPA
reservation path?

drivers/cxl/core/hdm.c:__cxl_dpa_reserve() {
    ...
	if (port->hdm_end + 1 != cxled->cxld.id) {
		/*
		 * Assumes alloc and commit order is always in hardware instance
		 * order...
		 */
		dev_dbg(dev, "decoder%d.%d: expected decoder%d.%d\n", port->id,
			cxled->cxld.id, port->id, port->hdm_end + 1);
		return -EBUSY;
	}
    ...
}

If a zero-size decoder (e.g. ID N) skips the reserve step, port->hdm_end stays
at N-1. When decoder N+1 tries to reserve DPA, port->hdm_end + 1 is N, which
does not match N+1, causing an unconditional -EBUSY.

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

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1779957270.git.icheng@nvidia.com?part=1

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

* Re: [PATCH v2 2/2] tools/testing/cxl: Enable zero sized decoders under hb0
  2026-06-02  5:40 ` [PATCH v2 2/2] tools/testing/cxl: Enable zero sized decoders under hb0 Richard Cheng
@ 2026-06-04  2:44   ` Alison Schofield
  0 siblings, 0 replies; 6+ messages in thread
From: Alison Schofield @ 2026-06-04  2:44 UTC (permalink / raw)
  To: Richard Cheng
  Cc: dave, jonathan.cameron, dave.jiang, vishal.l.verma, ira.weiny,
	dan.j.williams, linux-cxl, linux-kernel, newtonl, kristinc,
	kaihengf, kobak, vaslot, smadhavan

On Tue, Jun 02, 2026 at 01:40:53PM +0800, Richard Cheng wrote:
> The kernel now allows committed HDM decoders of zero size so BIOS can
> burn slots with LOCK. Without cxl_test coverage the new path goes
> unexercised.
> 
> For the special endpoints under host-bridge 0, e.g. cxl_mem.0 and
> cxl_mem.4, commit decoders 1 and 2 as zero-size + locked alongside the
> existing autoregion at decoder[0]. Mirro the same shape on the parent
> switch and host bridge via the walk-up that already builds the
> autoregion path.
> 

With these patches I've got 7 of 17 cxl unit tests failing.
cxl-region-sysfs, cxl-create-region, cxl-xor-region,
cxl-destroy-region, cxl-qos-class, cxl-region-replay,
cxl-poison

I think all of them are failing for the at least one reason, the 'burned'
slots sit on the auto region endpoints that the suite reuses. So how we test
this needs to be reconsidered.

cxl-poison is actually failing for a second reason, and that
is an issue in patch 1. It gets to a point where 4 poison records
are expected and only 2 are found. That is because commit_end
points at a decoder wihtout a dpa_resource so cxl_get_poison_unmapped()
gets skipped, meaning we don't get the tail end of the possible poison.

I'll jump back to patch 1 and point that out next.


> Signed-off-by: Vishal Aslot <vaslot@nvidia.com>
> Signed-off-by: Richard Cheng <icheng@nvidia.com>
> ---
> Changelog:
> 
> v1->v2:
>     - Replace second_decoder(), third_decoder() with a single
>       match_decoder_by_index() helper, so all lookups share one matcher.
>     - Use DEFINE_RANGE() for the empty range instread of an open-coded
>       struct
>     - Set cxled->state = CXL_DECODER_STATE_MANUAL rather than STATE_AUTO
>     - Set CXL_DECODER_F_LOCK on the mock zero-size decoders to model the
>       BIOS-burns-slots case
> ---
>  tools/testing/cxl/test/cxl.c | 79 +++++++++++++++++++++++++++++++-----
>  1 file changed, 69 insertions(+), 10 deletions(-)
> 
> diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c
> index 418669927fb0..1ae0290a9221 100644
> --- a/tools/testing/cxl/test/cxl.c
> +++ b/tools/testing/cxl/test/cxl.c
> @@ -1041,16 +1041,41 @@ static void default_mock_decoder(struct cxl_decoder *cxld)
>  	WARN_ON_ONCE(!cxld_registry_new(cxld));
>  }
>  
> -static int first_decoder(struct device *dev, const void *data)
> +static int match_decoder_by_index(struct device *dev, const void *data)
>  {
> +	int target_id = *(const int *)data;
>  	struct cxl_decoder *cxld;
>  
>  	if (!is_switch_decoder(dev))
>  		return 0;
>  	cxld = to_cxl_decoder(dev);
> -	if (cxld->id == 0)
> -		return 1;
> -	return 0;
> +	return cxld->id == target_id;
> +}
> +
> +static void size_zero_mock_decoder_ep(struct cxl_decoder *cxld, u64 base)
> +{
> +	struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(&cxld->dev);
> +
> +	cxld->hpa_range = DEFINE_RANGE(base, base - 1);
> +	cxld->interleave_ways = 2;
> +	cxld->interleave_granularity = 4096;
> +	cxld->target_type = CXL_DECODER_HOSTONLYMEM;
> +	cxld->flags = CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
> +	cxled->state = CXL_DECODER_STATE_MANUAL;
> +	cxld->commit = mock_decoder_commit;
> +	cxld->reset = mock_decoder_reset;
> +}
> +
> +static void size_zero_mock_decoder_sw(struct cxl_decoder *cxld, u64 base,
> +				      int level)
> +{
> +	cxld->flags = CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
> +	cxld->target_type = CXL_DECODER_HOSTONLYMEM;
> +	cxld->interleave_ways = level == 0 ? 2 : 1;
> +	cxld->interleave_granularity = 4096;
> +	cxld->hpa_range = DEFINE_RANGE(base, base - 1);
> +	cxld->commit = mock_decoder_commit;
> +	cxld->reset = mock_decoder_reset;
>  }
>  
>  /*
> @@ -1123,15 +1148,17 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
>  	}
>  
>  	/*
> -	 * The first decoder on the first 2 devices on the first switch
> -	 * attached to host-bridge0 mock a fake / static RAM region. All
> -	 * other decoders are default disabled. Given the round robin
> -	 * assignment those devices are named cxl_mem.0, and cxl_mem.4.
> +	 * On the first 2 devices on the first switch attached to
> +	 * host-bridge0, decoder[0] mocks a fake / static RAM region and
> +	 * decoders 1 and 2 mock BIOS-burnt zero-size + locked slots
> +	 * (CXL r3.2 §8.2.4.20.12, §14.13.10). All other decoders are
> +	 * default disabled. Given the round robin assignment those
> +	 * devices are named cxl_mem.0 and cxl_mem.4.
>  	 *
>  	 * See 'cxl list -BMPu -m cxl_mem.0,cxl_mem.4'
>  	 */
>  	if (!is_endpoint_decoder(&cxld->dev) || !hb0 || pdev->id % 4 ||
> -	    pdev->id > 4 || cxld->id > 0) {
> +	    pdev->id > 4 || cxld->id > 2) {
>  		default_mock_decoder(cxld);
>  		return false;
>  	}
> @@ -1145,6 +1172,18 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
>  	base = window->base_hpa;
>  	if (extended_linear_cache)
>  		base += mock_auto_region_size;
> +
> +	/*
> +	 * Decoders 1 and 2 of the special endpoints under host-bridge0
> +	 * are committed as zero-size + locked to mock BIOS burning
> +	 * decoder slots (CXL r3.2 §8.2.4.20.12, §14.13.10).
> +	 */
> +	if (cxld->id == 1 || cxld->id == 2) {
> +		size_zero_mock_decoder_ep(cxld, base);
> +		port->commit_end = cxld->id;
> +		WARN_ON_ONCE(!cxld_registry_new(cxld));
> +		return false;
> +	}
>  	cxld->hpa_range = (struct range) {
>  		.start = base,
>  		.end = base + mock_auto_region_size - 1,
> @@ -1168,9 +1207,12 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
>  	 */
>  	iter = port;
>  	for (i = 0; i < 2; i++) {
> +		int id;
> +
>  		dport = iter->parent_dport;
>  		iter = dport->port;
> -		dev = device_find_child(&iter->dev, NULL, first_decoder);
> +		id = 0;
> +		dev = device_find_child(&iter->dev, &id, match_decoder_by_index);
>  		/*
>  		 * Ancestor ports are guaranteed to be enumerated before
>  		 * @port, and all ports have at least one decoder.
> @@ -1214,6 +1256,23 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
>  
>  		cxld_registry_update(cxld);
>  		put_device(dev);
> +
> +		/*
> +		 * Mirror the endpoint: also commit the next two switch
> +		 * decoders as zero-size + locked so the hierarchy looks
> +		 * like a BIOS post-lock layout end-to-end.
> +		 */
> +		for (id = 1; id <= 2; id++) {
> +			dev = device_find_child(&iter->dev, &id,
> +						match_decoder_by_index);
> +			if (WARN_ON(!dev))
> +				continue;
> +			cxld = to_cxl_decoder(dev);
> +			size_zero_mock_decoder_sw(cxld, base, i);
> +			iter->commit_end = id;
> +			cxld_registry_update(cxld);
> +			put_device(dev);
> +		}
>  	}
>  
>  	return false;
> -- 
> 2.43.0
> 

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

* Re: [PATCH v2 1/2] cxl/hdm: Allow zero sized HDM decoders
  2026-06-02  5:40 ` [PATCH v2 1/2] cxl/hdm: Allow zero sized " Richard Cheng
  2026-06-02  5:57   ` sashiko-bot
@ 2026-06-04  2:56   ` Alison Schofield
  1 sibling, 0 replies; 6+ messages in thread
From: Alison Schofield @ 2026-06-04  2:56 UTC (permalink / raw)
  To: Richard Cheng
  Cc: dave, jonathan.cameron, dave.jiang, vishal.l.verma, ira.weiny,
	dan.j.williams, linux-cxl, linux-kernel, newtonl, kristinc,
	kaihengf, kobak, vaslot, smadhavan

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@nvidia.com>
> Signed-off-by: Richard Cheng <icheng@nvidia.com>
> ---
> 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
> 

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

end of thread, other threads:[~2026-06-04  2:56 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02  5:40 [PATCH v2 0/2] Support zero-sized HDM decoders Richard Cheng
2026-06-02  5:40 ` [PATCH v2 1/2] cxl/hdm: Allow zero sized " Richard Cheng
2026-06-02  5:57   ` sashiko-bot
2026-06-04  2:56   ` Alison Schofield
2026-06-02  5:40 ` [PATCH v2 2/2] tools/testing/cxl: Enable zero sized decoders under hb0 Richard Cheng
2026-06-04  2:44   ` Alison Schofield

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