Linux CXL
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Alison Schofield" <alison.schofield@intel.com>
Cc: linux-cxl@vger.kernel.org
Subject: Re: [PATCH v7 3/5] cxl/region: Support auto region granularity finer than the root
Date: Fri, 06 Nov 2026 22:22:37 +0000	[thread overview]
Message-ID: <sashiko-outbox-202327@kernel.org> (raw)
In-Reply-To: <15338cf5f174c87f414e4518b24edb3c1f8371bd.1794000806.git.alison.schofield@intel.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] cxl/region: passthrough parent granularity used in
  cxl_port_calc_interleave()
- [Medium] cxl/region: unvalidated endpoint positions in
  cxl_region_sort_targets()
--

commit d69ce1cc3e00f111d2894f426382e5b9afaa5815
Author: Alison Schofield <alison.schofield@intel.com>

cxl/region: Support auto region granularity finer than the root

This commit adds support for assembling auto-discovered CXL regions whose
interleave granularity is finer than the interleaving root decoder, and
updates unaligned region offset-to-DPA translation to use the region
granularity and ways.

> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index 1594bec3930bf..0a39e634b4b0a 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c

[ ... ]

> @@ -1449,6 +1495,14 @@ static int cxl_port_peer_distance(struct cxl_port *port, struct cxl_region *cxlr
>  	struct cxl_port *iter = port;
>  	int distance = 1;
>  
> +	/*
> +	 * A finer-than-root region refines toward the endpoints, so peer
> +	 * targets at the finest interleaving level occupy consecutive region
> +	 * positions.
> +	 */
> +	if (cxl_region_is_finer_than_root(cxlr))
> +		return 1;
> +
>  	do {
>  		cxl_rr_iter = cxl_rr_load(iter, cxlr);
>  		distance *= cxl_rr_iter->nr_targets;

[Severity: Medium]
Can check_last_peer() index out of bounds or dereference NULL in
p->targets[] when cxl_port_peer_distance() returns 1?

During auto-region assembly in cxl_region_attach(),
cxl_region_sort_targets() runs before cxl_region_setup_targets() validates
intermediate decoder granularities.  cxl_port_interleave_pos() scales pos
by gran / region_gran using the unvalidated decoder granularity, and
cxl_region_sort_targets() only checks cxled->pos < 0 without verifying
that the sorted positions match 0 .. p->nr_targets - 1:

drivers/cxl/core/region.c:cxl_region_sort_targets() {
	for (i = 0; i < p->nr_targets; i++) {
		struct cxl_endpoint_decoder *cxled = p->targets[i];

		cxled->pos = cxl_calc_interleave_pos(cxled, cxlr);
		...
		if (cxled->pos < 0)
			rc = -ENXIO;
	}
	/* Keep the cxlr target list in interleave position order */
	sort(p->targets, p->nr_targets, sizeof(p->targets[0]),
	     cmp_interleave_pos, NULL);
}

If firmware programs a bogus granularity on an intermediate decoder,
cxled->pos can exceed p->nr_targets or CXL_DECODER_MAX_INTERLEAVE (or
produce duplicate positions).  When cxl_region_setup_targets() then calls
check_last_peer() with distance == 1 at an upper port, pos < distance only
rejects pos < 1 before indexing p->targets[pos - 1] and dereferencing
cxled_peer.  Because cxl_region_attach_position() attaches endpoints using
the loop index i while cxled->pos != i, later teardown in
__cxl_decoder_detach() also hits dev_WARN_ONCE() and fails to detach the
endpoint.

Validating that p->targets[i]->pos == i for all targets after sort() in
cxl_region_sort_targets() would catch both out-of-range and duplicate
positions before attachment and target setup proceed.

> @@ -1476,15 +1530,17 @@ static int cxl_port_parent_interleave(struct cxl_port *port,
>  	int parent_iw, parent_ig;
>  
>  	if (is_cxl_root(parent_port)) {
> -		/*
> -		 * Root decoder IG is always set to value in CFMWS which
> -		 * may be different than this region's IG.  We can use the
> -		 * region's IG here since interleave_granularity_store()
> -		 * does not allow interleaved host-bridges with
> -		 * root IG != region IG.
> -		 */
> -		parent_ig = p->interleave_granularity;
>  		parent_iw = cxlrd->cxlsd.cxld.interleave_ways;
> +		if (parent_iw > 1) {
> +			parent_ig = cxlrd->cxlsd.cxld.interleave_granularity;
> +		} else {
> +			/*
> +			 * A single-way root does not interleave, so its
> +			 * granularity does not constrain the region interleave.
> +			 * Use the region granularity instead.
> +			 */
> +			parent_ig = p->interleave_granularity;
> +		}
>  		if (!is_power_of_2(parent_iw))
>  			parent_iw /= 3;
>  	} else {
> @@ -1521,7 +1577,7 @@ static int cxl_port_calc_interleave(struct cxl_port *port, struct cxl_region *cx
>  				    struct cxl_region_ref *cxl_rr, int *out_iw,
>  				    int *out_ig)
>  {
> -	struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
> +	struct cxl_region_params *p = &cxlr->params;
>  	struct cxl_decoder *cxld = cxl_rr->decoder;
>  	int parent_iw, parent_ig, iw, ig, rc;
>  	struct cxl_switch_decoder *cxlsd;
> @@ -1537,16 +1593,24 @@ static int cxl_port_calc_interleave(struct cxl_port *port, struct cxl_region *cx
>  		return -EINVAL;
>  	}
>  
> -	/*
> -	 * Interleave granularity is a multiple of @parent_port granularity.
> -	 * Multiplier is the parent port interleave ways.
> -	 */
> -	ig = parent_ig * parent_iw;
> +	/* Finer-than-root regions refine granularity toward the endpoints */
> +	if (cxl_region_is_finer_than_root(cxlr)) {
> +		ig = parent_ig / iw;
> +
> +		if (ig < p->interleave_granularity) {
> +			dev_dbg(&cxlr->dev,
> +				"%s:%s: granularity %d is finer than region granularity %d\n",
> +				dev_name(port->uport_dev), dev_name(&port->dev),
> +				ig, p->interleave_granularity);
> +			return -ENXIO;
> +		}
> +	} else {
> +		ig = parent_ig * parent_iw;
> +	}
>  
>  	if (!granularity_valid(ig)) {
> -		dev_dbg(&cxlr->dev,
> -			"%s: invalid granularity calculation (%d * %d)\n",
> -			dev_name(&parent_port->dev), parent_ig, parent_iw);
> +		dev_dbg(&cxlr->dev, "%s:%s: invalid granularity: %d\n",
> +			dev_name(port->uport_dev), dev_name(&port->dev), ig);
>  		return -EINVAL;
>  	}

[Severity: High]
Does cxl_port_calc_interleave() use an unvalidated passthrough decoder
granularity when an interleaving switch sits below a 1-way host bridge or
parent switch?

In cxl_port_setup_decoder(), an auto-region passthrough decoder (iw == 1)
is exempted from matching ig and its cxld->interleave_granularity is left
at whatever raw value firmware programmed in the hardware register (such
as 256B):

drivers/cxl/core/region.c:cxl_port_setup_decoder() {
	if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) {
		if (cxld->interleave_ways != iw ||
		    (iw > 1 && cxld->interleave_granularity != ig) ||
		    !spa_maps_hpa(p, &cxld->hpa_range) ||
		    ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)) {
			...
			return -ENXIO;
		}
	}
}

When cxl_region_setup_targets() then descends to a downstream interleaving
switch port (for example, a 3-way root at 2 * IGB -> 1-way host bridge ->
2-way switch at IGB), the non-root branch of cxl_port_parent_interleave()
reads parent_ig = parent_cxld->interleave_granularity directly from that
passthrough host bridge decoder.  cxl_port_calc_interleave() then divides
that raw passthrough granularity by iw instead of using the granularity
from the nearest upstream interleaving decoder, causing auto-region
assembly to fail with -ENXIO.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1794000806.git.alison.schofield@intel.com?part=3

  reply	other threads:[~2026-11-06 22:22 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06 21:57 [PATCH v7 0/5] CXL: Support region granularities finer than the root Alison Schofield
2026-11-06 21:57 ` [PATCH v7 1/5] Documentation/cxl: Describe region granularity " Alison Schofield
2026-11-06 21:57 ` [PATCH v7 2/5] cxl/region: Generalize endpoint position mapping Alison Schofield
2026-11-06 21:57 ` [PATCH v7 3/5] cxl/region: Support auto region granularity finer than the root Alison Schofield
2026-11-06 22:22   ` sashiko-bot [this message]
2026-11-07  0:59     ` Alison Schofield
2026-11-06 21:57 ` [PATCH v7 4/5] cxl/region: Support user " Alison Schofield
2026-11-06 21:57 ` [PATCH v7 5/5] cxl/test: Add a topology for " Alison Schofield

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-202327@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=alison.schofield@intel.com \
    --cc=linux-cxl@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox