Linux CXL
 help / color / mirror / Atom feed
From: Alison Schofield <alison.schofield@intel.com>
To: Robert Richter <rrichter@amd.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>,
	Jonathan Cameron <jic23@kernel.org>,
	Dave Jiang <dave.jiang@intel.com>,
	Vishal Verma <vishal.l.verma@intel.com>,
	Ira Weiny <iweiny@kernel.org>, Li Ming <ming.li@zohomail.com>,
	<linux-cxl@vger.kernel.org>
Subject: Re: [PATCH v3 1/9] cxl/region: Factor port target calculations
Date: Thu, 20 Aug 2026 14:58:04 -0700	[thread overview]
Message-ID: <aod4bFCBtVhUwOAd@aschofie-mobl2.lan> (raw)
In-Reply-To: <aoQV0mEURRUwZJmh@rric.localdomain>

On Tue, Aug 18, 2026 at 10:20:34AM +0200, Robert Richter wrote:
> On 30.07.26 15:20:21, Alison Schofield wrote:
> > cxl_port_setup_targets() calculates the interleave fan-out above a
> > port, the port decoder granularity, and the distance between
> > endpoints routed through the same downstream port.
> > 
> > Factor those calculations into helpers so the target setup path can
> > be extended. Validation of parent decoder values is dropped since
> > those values are validated where they are set, before this port's
> > setup runs. A configuration that is invalid in more than one way may
> > report a different error first.
> > 
> > Suggested-by: Originally-by: Robert Richter <rrichter@amd.com>
> > Signed-off-by: Alison Schofield <alison.schofield@intel.com>
> > ---
> >  drivers/cxl/core/region.c | 197 +++++++++++++++++++-------------------
> 
> Please split patch and move out changes in error handling, see also
> below.

Thanks for the reviews Robert!

I took another pass at this, including the broader complexity concern
you raised here and in the collab mtg.

Rather than further splitting the refactoring here, I reworked the
the series around the existing region setup flow. The selector walk
and the helper machinery introduced here are gone in v4, along with
the unrelated error-handling movement.

more below

> 
> >  1 file changed, 96 insertions(+), 101 deletions(-)
> > 
> > diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> > index 1e211542b6b6..1082db7b2cca 100644
> > --- a/drivers/cxl/core/region.c
> > +++ b/drivers/cxl/core/region.c
> > @@ -1350,6 +1350,19 @@ static void cxl_port_detach_region(struct cxl_port *port,
> >  		free_region_ref(cxl_rr);
> >  }
> >  
> > +/**
> > + * check_last_peer() - Verify the previous endpoint routed to this dport
> > + * @cxled: endpoint decoder being placed
> > + * @ep: this endpoint's entry for the port
> > + * @cxl_rr: region reference for the port
> > + * @distance: distance to the previous endpoint routed to this dport
> > + *
> > + * Endpoints routed through the same dport recur at @distance intervals in
> > + * region-position order. Verify that the endpoint at ``pos - distance`` used
> > + * the same dport.
> > + *
> > + * Return: 0 on success, -ENXIO on a routing mismatch.
> > + */
> >  static int check_last_peer(struct cxl_endpoint_decoder *cxled,
> >  			   struct cxl_ep *ep, struct cxl_region_ref *cxl_rr,
> >  			   int distance)
> > @@ -1434,60 +1447,106 @@ static int check_interleave_cap(struct cxl_decoder *cxld, int iw, int ig)
> >  	return 0;
> >  }
> >  
> > +/**
> > + * get_parent_fanout() - Calculate the switch fan-out above a port
> > + * @parent_port: first ancestor port
> > + * @cxlr: region under construction
> > + * @fanout: filled with the product of the ancestor switch ways
> > + *
> > + * Walk from @parent_port to the root and multiply the interleave ways of
> > + * each switch decoder. Root decoder ways are not included.
> > + *
> > + * Return: 0 on success.
> > + */
> 
> I don't think that static functions should be documented. They do not
> describe an interface, are short and also called only once. Instead,
> the function's purpose should be understandable from reading the code
> with small comments only where really helpful.
> 

These helpers are gone in v4. I also took your larger point here and
tried to make the resulting code readable without needing comments
to explain the implementation.


> > +static int get_parent_fanout(struct cxl_port *parent_port,
> > +			     struct cxl_region *cxlr, int *fanout)
> > +{
> > +	int distance = 1;
> > +	struct cxl_port *iter;
> > +
> > +	for (iter = parent_port; !is_cxl_root(iter);
> > +	     iter = to_cxl_port(iter->dev.parent)) {
> > +		struct cxl_region_ref *cxl_rr_iter = cxl_rr_load(iter, cxlr);
> > +
> > +		distance *= cxl_rr_iter->nr_targets;
> > +	}
> > +
> > +	*fanout = distance;
> > +	return 0;
> > +}
> > +
> > +/**
> > + * derive_port_granularity() - Calculate the granularity for a port decoder
> > + * @cxlr: region under construction
> > + * @fanout: product of the ancestor switch ways
> > + * @ig: filled with the port decoder granularity
> > + *
> > + * Preserve the existing parent-granularity times parent-ways recurrence in
> > + * terms of the region granularity and the fan-out above this port.
> > + *
> > + * Return: 0 on success.
> > + */
> > +static int derive_port_granularity(struct cxl_region *cxlr, int fanout,
> > +				   int *ig)
> > +{
> > +	struct cxl_root_decoder *cxlrd = cxlr->cxlrd;
> > +	int root_iw = cxlrd->cxlsd.cxld.interleave_ways;
> > +	struct cxl_region_params *p = &cxlr->params;
> > +	int sel_distance;
> > +
> > +	sel_distance = is_power_of_2(root_iw) ? root_iw : root_iw / 3;
> > +	sel_distance *= fanout;
> > +	*ig = p->interleave_granularity * sel_distance;
> > +
> > +	return 0;
> 
> Always succeeds. Should directly return ig.

Agree. This helper is gone in v4.

> 
> > +}
> 
> I will review both functions again after reading the rest of the
> series.
> 
> > +
> >  static int cxl_port_setup_targets(struct cxl_port *port,
> >  				  struct cxl_region *cxlr,
> >  				  struct cxl_endpoint_decoder *cxled)
> >  {
> >  	struct cxl_root_decoder *cxlrd = cxlr->cxlrd;
> > -	int parent_iw, parent_ig, ig, iw, rc, pos = cxled->pos;
> > +	int root_iw = cxlrd->cxlsd.cxld.interleave_ways;
> >  	struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
> >  	struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr);
> >  	struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
> >  	struct cxl_ep *ep = cxl_ep_load(port, cxlmd);
> >  	struct cxl_region_params *p = &cxlr->params;
> >  	struct cxl_decoder *cxld = cxl_rr->decoder;
> > -	struct cxl_switch_decoder *cxlsd;
> > -	struct cxl_port *iter = port;
> > -	u16 eig, peig;
> > -	u8 eiw, peiw;
> > +	struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(&cxld->dev);
> > +	int ig, iw = cxl_rr->nr_targets;
> 
> The changes around here should be a separate patch only containing
> error handling changes and other related reworks.
> 

Agree. I dropped this unrelated rework rather than carrying as
part of this series.


> > +	int fanout, rc;
> > +	int pos = cxled->pos;
> > +	u16 eig;
> > +	u8 eiw;
> >  
> >  	/*
> >  	 * While root level decoders support x3, x6, x12, switch level
> >  	 * decoders only support powers of 2 up to x16.
> >  	 */
> > -	if (!is_power_of_2(cxl_rr->nr_targets)) {
> > +	if (!is_power_of_2(iw)) {
> >  		dev_dbg(&cxlr->dev, "%s:%s: invalid target count %d\n",
> > -			dev_name(port->uport_dev), dev_name(&port->dev),
> > -			cxl_rr->nr_targets);
> > +			dev_name(port->uport_dev), dev_name(&port->dev), iw);
> >  		return -EINVAL;
> >  	}
> >  
> > -	cxlsd = to_cxl_switch_decoder(&cxld->dev);
> > +	if (iw > 8 || iw > cxlsd->nr_targets) {
> > +		dev_dbg(&cxlr->dev,
> > +			"%s:%s:%s: ways: %d overflows targets: %d\n",
> > +			dev_name(port->uport_dev), dev_name(&port->dev),
> > +			dev_name(&cxld->dev), iw, cxlsd->nr_targets);
> > +		return -ENXIO;
> > +	}
> 
> Split patch: Moving of this check and other changes above should be in
> a separate patch.

Agree. This movement is gone in v4.

> 
> > +
> > +	rc = get_parent_fanout(parent_port, cxlr, &fanout);
> 
> I am not a "fan" of that term. :-) IMO, target_count or target_total
> would fit better here.

:) No more fanout in v4.

> 
> > +	if (rc)
> > +		return rc;
> > +
> >  	if (cxl_rr->nr_targets_set) {
> 
> The check can be dropped now as it is done with the for loop already.

Agree. This rework is gone in v4 as well.

snip

> > @@ -1495,84 +1554,20 @@ static int cxl_port_setup_targets(struct cxl_port *port,
> >  		goto add_target;
> >  	}
> >  
> > -	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;
> > -		/*
> > -		 * For purposes of address bit routing, use power-of-2 math for
> > -		 * switch ports.
> > -		 */
> > -		if (!is_power_of_2(parent_iw))
> > -			parent_iw /= 3;
> > -	} else {
> > -		struct cxl_region_ref *parent_rr;
> > -		struct cxl_decoder *parent_cxld;
> > -
> > -		parent_rr = cxl_rr_load(parent_port, cxlr);
> > -		parent_cxld = parent_rr->decoder;
> > -		parent_ig = parent_cxld->interleave_granularity;
> > -		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;
> > -	}
> > -
> > -	rc = ways_to_eiw(parent_iw, &peiw);
> > -	if (rc) {
> > -		dev_dbg(&cxlr->dev, "%s:%s: invalid parent interleave: %d\n",
> > -			dev_name(parent_port->uport_dev),
> > -			dev_name(&parent_port->dev), parent_iw);
> > +	rc = derive_port_granularity(cxlr, fanout, &ig);
> 
> I still think, the granularity should be determined just by
> calculating the bit position of the ways bit within the HPA. But let's
> see next patches.


Agree with the direction here. I ended up dropping the selector walk as
well, though, and deriving the decoder granularity directly from the parent
interleave geometry. More on that in the following patches.


> 
> > +	if (rc)
> >  		return rc;
> > -	}
> >  
> > -	iw = cxl_rr->nr_targets;
> >  	rc = ways_to_eiw(iw, &eiw);
> > -	if (rc) {
> > -		dev_dbg(&cxlr->dev, "%s:%s: invalid port interleave: %d\n",
> > -			dev_name(port->uport_dev), dev_name(&port->dev), iw);
> > -		return rc;
> > -	}
> > -
> > -	/*
> > -	 * 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)
> > +		rc = granularity_to_eig(ig, &eig);
> 
> Same here, separate the combination of those two checks in a separate
> patch.
> 
> With a patch split the actual change will be much better readable.


Agree. Rather than splitting this version further, I dropped this rework
and substantially simplified the target setup in v4.


> 
> Thanks,
> 
> -Robert
> 

snip

  reply	other threads:[~2026-08-20 21:58 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-30 22:20 [PATCH v3 0/9] cxl: Support mixed-granularity region interleaves Alison Schofield
2026-07-30 22:20 ` [PATCH v3 1/9] cxl/region: Factor port target calculations Alison Schofield
2026-07-30 22:36   ` sashiko-bot
2026-08-18  8:20   ` Robert Richter
2026-08-20 21:58     ` Alison Schofield [this message]
2026-07-30 22:20 ` [PATCH v3 2/9] cxl/region: Validate interleave selector bits Alison Schofield
2026-08-18  9:13   ` Robert Richter
2026-08-20 22:14     ` Alison Schofield
2026-07-30 22:20 ` [PATCH v3 3/9] cxl/region: Derive port granularity from " Alison Schofield
2026-08-18 10:01   ` Robert Richter
2026-08-20 22:48     ` Alison Schofield
2026-07-30 22:20 ` [PATCH v3 4/9] cxl/region: Account for mixed-granularity in position calculations Alison Schofield
2026-07-30 22:20 ` [PATCH v3 5/9] cxl/region: Allow mixed-granularity regions Alison Schofield
2026-07-30 22:20 ` [PATCH v3 6/9] cxl/region: Enforce coarse-to-fine ordering for " Alison Schofield
2026-07-30 22:20 ` [PATCH v3 7/9] cxl/region: Fail region creation on position check mismatch Alison Schofield
2026-07-30 22:40   ` sashiko-bot
2026-07-30 22:20 ` [PATCH v3 8/9] cxl/test: Add a topology to test mixed-granularity regions Alison Schofield
2026-07-30 22:20 ` [PATCH v3 9/9] Documentation/cxl: Describe multi-level interleave validation 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=aod4bFCBtVhUwOAd@aschofie-mobl2.lan \
    --to=alison.schofield@intel.com \
    --cc=dave.jiang@intel.com \
    --cc=dave@stgolabs.net \
    --cc=iweiny@kernel.org \
    --cc=jic23@kernel.org \
    --cc=linux-cxl@vger.kernel.org \
    --cc=ming.li@zohomail.com \
    --cc=rrichter@amd.com \
    --cc=vishal.l.verma@intel.com \
    /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