From: Alison Schofield <alison.schofield@intel.com>
To: Davidlohr Bueso <dave@stgolabs.net>,
Jonathan Cameron <jic23@kernel.org>,
Dave Jiang <dave.jiang@intel.com>,
Alison Schofield <alison.schofield@intel.com>,
Vishal Verma <vishal.l.verma@intel.com>,
Ira Weiny <iweiny@kernel.org>, Li Ming <ming.li@zohomail.com>,
Robert Richter <rrichter@amd.com>
Cc: linux-cxl@vger.kernel.org
Subject: [PATCH v5 3/7] cxl/region: Generalize endpoint position mapping
Date: Thu, 3 Sep 2026 16:23:45 -0700 [thread overview]
Message-ID: <16d749d4eef2f6f142bbf6c48e4210e0587e466c.1788475206.git.alison.schofield@intel.com> (raw)
In-Reply-To: <cover.1788475206.git.alison.schofield@intel.com>
Endpoint position calculation currently relies on the requirement that an
interleaving root have the same granularity as the region. Auto region
creation builds the position by multiplying by the parent decoders' ways,
while user region creation selects the root target with 'pos % ways'. Those
calculations are sufficient under the current granularity restriction.
In order to support mixed-granularity regions, that granularity restriction
will need to be removed so decoder granularity can change between levels of
the interleave hierarchy. The position calculation needs to account for
those changes to produce the correct endpoint ordering.
Change the position calculation so each decoder's contribution is weighted
by its granularity relative to the region granularity:
position += target_pos *
(decoder_granularity / region_granularity)
Use the same relationship to select the root target during user region
creation.
Weight each level by the region granularity, passed in by the caller,
rather than by the granularity programmed in the endpoint decoder. The two
are equal for most configurations, but not when Normalized Addressing
leaves the endpoint decoder programmed passthrough while the region
interleaves.
For currently supported regions, the new weighted calculation reduces to
the existing position calculation and produces identical endpoint
positions. The exception is a region wider than a same-granularity Mod3
root, where address bit routing programs the level below the root at the
region granularity, so the ratio derives a weight of one rather than three.
A later patch in this series rejects that layout.
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
---
drivers/cxl/core/region.c | 69 ++++++++++++++++++++++++---------------
1 file changed, 42 insertions(+), 27 deletions(-)
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 6a698f36aa6d..506b1cba1a92 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1806,9 +1806,15 @@ static int cxl_region_attach_position(struct cxl_region *cxlr,
struct cxl_decoder *cxld = &cxlsd->cxld;
int iw = cxld->interleave_ways;
struct cxl_port *iter;
+ int root_pos = pos;
int rc;
- if (dport != cxlrd->cxlsd.target[pos % iw]) {
+ /* Root target selection advances at root-granularity intervals */
+ if (iw > 1)
+ root_pos = pos * cxlr->params.interleave_granularity /
+ cxld->interleave_granularity;
+
+ if (dport != cxlrd->cxlsd.target[root_pos % iw]) {
dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n",
dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
dev_name(&cxlrd->cxlsd.cxld.dev));
@@ -1909,12 +1915,13 @@ static int match_switch_decoder_by_range(struct device *dev,
return (r1->start == r2->start && r1->end == r2->end);
}
-static int find_pos_and_ways(struct cxl_port *port, struct range *range,
- int *pos, int *ways)
+static int find_pos_and_gran(struct cxl_port *port, struct range *range,
+ int *pos, int *gran)
{
struct cxl_switch_decoder *cxlsd;
struct cxl_port *parent;
int rc = -ENXIO;
+ int ways;
parent = parent_port_of(port);
if (!parent)
@@ -1929,9 +1936,10 @@ static int find_pos_and_ways(struct cxl_port *port, struct range *range,
return rc;
}
cxlsd = to_cxl_switch_decoder(dev);
- *ways = cxlsd->cxld.interleave_ways;
+ ways = cxlsd->cxld.interleave_ways;
+ *gran = cxlsd->cxld.interleave_granularity;
- for (int i = 0; i < *ways; i++) {
+ for (int i = 0; i < ways; i++) {
if (cxlsd->target[i] == port->parent_dport) {
*pos = i;
rc = 0;
@@ -1951,24 +1959,29 @@ static int find_pos_and_ways(struct cxl_port *port, struct range *range,
* cxl_calc_interleave_pos() - calculate an endpoint position in a region
* @cxled: endpoint decoder member of given region
* @hpa_range: translated HPA range of the endpoint
+ * @region_gran: interleave granularity of the region
*
- * The endpoint position is calculated by traversing the topology from
- * the endpoint to the root decoder and iteratively applying this
- * calculation:
+ * A region position is the index of a region-granularity chunk within one full
+ * pass of the region interleave. The position is calculated by traversing the
+ * topology from the endpoint to the root decoder and accumulating the
+ * contribution of each decoder level:
*
- * position = position * parent_ways + parent_pos;
+ * position += parent_pos * (parent_granularity / region_gran);
*
- * ...where @position is inferred from switch and root decoder target lists.
+ * ...where @parent_pos is inferred from switch and root decoder target lists.
+ * The multiplier is the weight of that level: how many region positions pass
+ * between successive advances of the level's target index. A level that selects
+ * a single target contributes nothing.
*
* Return: position >= 0 on success
* -ENXIO on failure
*/
static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled,
- struct range *hpa_range)
+ struct range *hpa_range, int region_gran)
{
struct cxl_port *iter, *port = cxled_to_port(cxled);
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
- int parent_ways = 0, parent_pos = 0, pos = 0;
+ int parent_gran = 0, parent_pos = 0, pos = 0;
int rc;
/*
@@ -1981,20 +1994,20 @@ static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled,
* | | | |
* mem0 mem1 mem2 mem3
*
- * In the example the calculator will iterate twice. The first iteration
- * uses the mem position in the host-bridge and the ways of the host-
- * bridge to generate the first, or local, position. The second
- * iteration uses the host-bridge position in the root_port and the ways
- * of the root_port to refine the position.
+ * The region and the root decoder interleave at the region
+ * granularity, so each host-bridge decoder interleaves at twice that.
+ * The host-bridge decoders advance one target every two region
+ * positions, weight 2, and the root decoder advances one target every
+ * region position, weight 1.
*
* A trace of the calculation per endpoint looks like this:
- * mem0: pos = 0 * 2 + 0 mem2: pos = 0 * 2 + 0
- * pos = 0 * 2 + 0 pos = 0 * 2 + 1
+ * mem0: pos += 0 * 2 mem2: pos += 0 * 2
+ * pos += 0 * 1 pos += 1 * 1
* pos: 0 pos: 1
*
- * mem1: pos = 0 * 2 + 1 mem3: pos = 0 * 2 + 1
- * pos = 1 * 2 + 0 pos = 1 * 2 + 1
- * pos: 2 pos = 3
+ * mem1: pos += 1 * 2 mem3: pos += 1 * 2
+ * pos += 0 * 1 pos += 1 * 1
+ * pos: 2 pos: 3
*
* Note that while this example is simple, the method applies to more
* complex topologies, including those with switches.
@@ -2005,12 +2018,12 @@ static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled,
if (is_cxl_root(iter))
break;
- rc = find_pos_and_ways(iter, hpa_range, &parent_pos,
- &parent_ways);
+ rc = find_pos_and_gran(iter, hpa_range, &parent_pos,
+ &parent_gran);
if (rc)
return rc;
- pos = pos * parent_ways + parent_pos;
+ pos += parent_pos * (parent_gran / region_gran);
}
dev_dbg(&cxlmd->dev,
@@ -2029,7 +2042,8 @@ static int cxl_region_sort_targets(struct cxl_region *cxlr)
for (i = 0; i < p->nr_targets; i++) {
struct cxl_endpoint_decoder *cxled = p->targets[i];
- cxled->pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range);
+ cxled->pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range,
+ p->interleave_granularity);
/*
* Record that sorting failed, but still continue to calc
* cxled->pos so that cxl_calc_interleave_pos() emits its
@@ -2214,7 +2228,8 @@ static int cxl_region_attach(struct cxl_region *cxlr,
struct cxl_endpoint_decoder *target = p->targets[i];
int test_pos;
- test_pos = cxl_calc_interleave_pos(target, &cxlr->hpa_range);
+ test_pos = cxl_calc_interleave_pos(target, &cxlr->hpa_range,
+ p->interleave_granularity);
if (test_pos != target->pos)
dev_warn(&cxlr->dev,
"%s: position mismatch: calculated:%d assigned:%d\n",
--
2.37.3
next prev parent reply other threads:[~2026-09-03 23:24 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-03 23:23 [PATCH v5 0/7] cxl: Support mixed-granularity region interleaves Alison Schofield
2026-09-03 23:23 ` [PATCH v5 1/7] Documentation/cxl: Describe mixed-granularity regions Alison Schofield
2026-09-03 23:23 ` [PATCH v5 2/7] cxl/region: Warn on user region position mismatch Alison Schofield
2026-09-03 23:23 ` Alison Schofield [this message]
2026-09-03 23:23 ` [PATCH v5 4/7] cxl/region: Name the interleave locals in cxl_port_setup_targets() Alison Schofield
2026-09-03 23:23 ` [PATCH v5 5/7] cxl/region: Support mixed-granularity auto regions Alison Schofield
2026-09-03 23:23 ` [PATCH v5 6/7] cxl/region: Support mixed-granularity user created regions Alison Schofield
2026-09-03 23:23 ` [PATCH v5 7/7] cxl/test: Add a topology to test mixed-granularity regions 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=16d749d4eef2f6f142bbf6c48e4210e0587e466c.1788475206.git.alison.schofield@intel.com \
--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