Re: [PATCH v3 1/2] cxl/region: Allow passthrough decoders with >16K granularity
Richard Cheng <[email protected]> Fri, 31 Jul 2026 15:41:54 +0800
| Newsgroups | org.kernel.vger.linux-cxl |
|---|---|
| Message-ID | <amxHLqcwROvNP6Mz@MWDK4CY14F> |
On Fri, Jul 24, 2026 at 06:08:54PM +0800, Alison Schofield wrote:
> Region configuration rejects valid topologies that contain a
> passthrough decoder beneath a wide parent interleave.
>
> For example, a passthrough switch below an 8-way root decoder with
> 4K granularity computes a 32K granularity. That exceeds the maximum
> encodable value of the HDM Decoder Control IG field, causing region
> setup to fail even though a non-interleaving decoder does not consume
> the IG field.
>
> Only require the granularity to be encodable for interleaving decoders,
> both where it is inherited from the parent and where it is computed for
> the current decoder. Keep the computed value for passthrough decoders so
> it can seed descendant decoder setup.
>
> When committing a non-interleaving decoder, still program the granularity
> if it is encodable; use a don't-care IG encoding only when it is not. This
> preserves an encodable passthrough granularity across re-enumeration, so
> descendants do not inherit a stale value.
>
> As a consequence, the interleave_granularity attribute of a decoder
> whose interleave_ways is 1 may report a value above 16K. Document that
> the reported granularity for non-interleaving decoders is a don't-care
> value that may exceed the maximum encodable in hardware.
>
> Fixes: 18f35dc9314d ("cxl/region: Refactor granularity select in cxl_port_setup_targets()")
> Suggested-by: Sashiko AI Review <[email protected]>
> Assisted-by: Claude:Opus-4-8
> Signed-off-by: Alison Schofield <[email protected]>
> ---
> Documentation/ABI/testing/sysfs-bus-cxl | 5 ++-
> drivers/cxl/core/hdm.c | 8 ++++-
> drivers/cxl/core/region.c | 47 +++++++++++++++----------
> 3 files changed, 39 insertions(+), 21 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 16a9b3d2e2c0..3f96e5bf1fd3 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -407,7 +407,10 @@ Description:
> space this decoder claims at address N before the decode rotates
> to the next target in the interleave at address N +
> interleave_granularity (assuming N is aligned to
> - interleave_granularity).
> + interleave_granularity). When 'interleave_ways' is 1, the
> + decoder does not interleave and the reported granularity is
> + a don't-care value that may exceed the maximum encodable in
> + hardware.
>
>
> What: /sys/bus/cxl/devices/decoderX.Y/create_{pmem,ram}_region
> diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
> index 0c80b76a5f9b..d2ada82fe3c7 100644
> --- a/drivers/cxl/core/hdm.c
> +++ b/drivers/cxl/core/hdm.c
> @@ -691,7 +691,13 @@ static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
> if (WARN_ONCE(ways_to_eiw(cxld->interleave_ways, &eiw),
> "invalid interleave_ways: %d\n", cxld->interleave_ways))
> return;
> - if (WARN_ONCE(granularity_to_eig(cxld->interleave_granularity, &eig),
> +
> + /*
> + * A non-interleaving decoder ignores the IG field, so an
> + * unencodable granularity is a don't-care rather than a failure.
> + */
> + if (granularity_to_eig(cxld->interleave_granularity, &eig) &&
> + WARN_ONCE(cxld->interleave_ways > 1,
> "invalid interleave_granularity: %d\n",
> cxld->interleave_granularity))
> return;
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index 1e211542b6b6..5a443551288c 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -1521,12 +1521,20 @@ static int cxl_port_setup_targets(struct cxl_port *port,
> parent_iw = parent_cxld->interleave_ways;
> }
>
> - rc = granularity_to_eig(parent_ig, &peig);
> - if (rc) {
> - dev_dbg(&cxlr->dev, "%s:%s: invalid parent granularity: %d\n",
> - dev_name(parent_port->uport_dev),
> - dev_name(&parent_port->dev), parent_ig);
> - return rc;
> + /*
> + * A non-interleaving parent does not encode its granularity, so its
> + * stored value may exceed the maximum encodable and need not be
> + * validated here.
> + */
> + if (parent_iw > 1) {
> + rc = granularity_to_eig(parent_ig, &peig);
> + if (rc) {
> + dev_dbg(&cxlr->dev,
> + "%s:%s: invalid parent granularity: %d\n",
> + dev_name(parent_port->uport_dev),
> + dev_name(&parent_port->dev), parent_ig);
> + return rc;
> + }
> }
>
> rc = ways_to_eiw(parent_iw, &peiw);
> @@ -1549,20 +1557,21 @@ static int cxl_port_setup_targets(struct cxl_port *port,
> * Interleave granularity is a multiple of @parent_port granularity.
> * Multiplier is the parent port interleave ways.
> */
> - rc = granularity_to_eig(parent_ig * parent_iw, &eig);
> - if (rc) {
> - dev_dbg(&cxlr->dev,
> - "%s: invalid granularity calculation (%d * %d)\n",
> - dev_name(&parent_port->dev), parent_ig, parent_iw);
> - return rc;
> - }
> + ig = parent_ig * parent_iw;
>
> - rc = eig_to_granularity(eig, &ig);
> - if (rc) {
> - dev_dbg(&cxlr->dev, "%s:%s: invalid interleave: %d\n",
> - dev_name(port->uport_dev), dev_name(&port->dev),
> - 256 << eig);
> - return rc;
> + /*
> + * Keep the computed granularity for descendant setup. Only
> + * interleaving decoders require an encodable granularity.
> + */
> + if (iw > 1) {
> + rc = granularity_to_eig(ig, &eig);
> + if (rc) {
> + dev_dbg(&cxlr->dev,
> + "%s: invalid granularity calculation (%d * %d)\n",
> + dev_name(&parent_port->dev), parent_ig,
> + parent_iw);
> + return rc;
> + }
> }
>
Hi Alison,
Looks sane to me, just that this check pattern appears twice and peig
and eig are both write-only afterwards.
Could they be formed into a helper or macro ?
Something like the following might do ?
"""
static bool granularity_is_encodable(int ways, int granularity)
{
u16 eig;
if (ways <= 1)
return true;
return granularity_to_eig(granularity, &eig) == 0;
}
if (!granularity_is_encodable(parent_iw, parent_ig) {
dev_dbg();
return -EINVAL;
}
"""
Reviewed-by: Richard Cheng <[email protected]>
Best regards,
Richard Cheng.
> if (iw > 8 || iw > cxlsd->nr_targets) {
> --
> 2.37.3
>
>