* [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
* 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 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
* [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 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
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