From: alison.schofield@intel.com
To: Davidlohr Bueso <dave@stgolabs.net>,
Jonathan Cameron <jonathan.cameron@huawei.com>,
Dave Jiang <dave.jiang@intel.com>,
Alison Schofield <alison.schofield@intel.com>,
Vishal Verma <vishal.l.verma@intel.com>,
Ira Weiny <ira.weiny@intel.com>,
Dan Williams <dan.j.williams@intel.com>
Cc: linux-cxl@vger.kernel.org, Dmytro Adamenko <dmytro.adamenko@intel.com>
Subject: [PATCH v2 2/3] cxl/region: Calculate a target position in a region interleave
Date: Sun, 15 Oct 2023 23:02:27 -0700 [thread overview]
Message-ID: <80f80f0d26e73cd6941d8530163a4bbd731d50ec.1697433770.git.alison.schofield@intel.com> (raw)
In-Reply-To: <cover.1697433770.git.alison.schofield@intel.com>
From: Alison Schofield <alison.schofield@intel.com>
Introduce a calculation that determines a targets position in a region
interleave. Perform a selftest of the calculation on user-defined
regions.
The region driver uses the kernel sort() function to put region
targets in relative order. Positions are assigned based on each
targets index in that sorted list. That relative sort doesn't
consider the offset of a port into its parent port which causes
some auto-discovered regions to fail creation. In one failure case,
a 2 + 2 config (2 host bridges each with 2 endpoints), the sort
puts all the targets of one port ahead of another port when they
were expected to be interleaved.
In preparation for repairing the autodiscovery region assembly,
introduce a new method for discovering a target position in the
region interleave.
cxl_interleave_pos() offers a method to determine a targets position
by ascending from an endpoint to a root decoder. The calculation starts
with the endpoints local position and its position in its parents port.
It traverses towards the root decoder and examines both position and
ways in order to allow the position to be refined all the way to the
root decoder.
This calculation, applied iteratively, yields the correct position:
position = position * parent_ways + parent_pos;
...with these rules:
Rule #1 - When (parent_ways == region_ways), Stop!
position = parent_position;
This rule is applied in calc_interleave_pos()
Rule #2 - Skip over siblings that come before this memdev in
the decoder list when searching for the parent position.
This rule is applied in the helper find_pos_and_ways().
Include a selftest that exercises this new position calculation against
every successfully configured user-defined region.
Fixes: a32320b71f08 ("cxl/region: Add region autodiscovery")
Reported-by: Dmytro Adamenko <dmytro.adamenko@intel.com>
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
---
drivers/cxl/core/region.c | 102 ++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 64206fc4d99b..b451d215c3c5 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1500,6 +1500,93 @@ static int match_switch_decoder_by_range(struct device *dev, void *data)
return range_contains(r1, r2);
}
+/* Find the position of a port in it's parent and the parents ways */
+static int find_pos_and_ways(struct cxl_port *port, struct range *range,
+ int *pos, int *ways)
+{
+ struct cxl_switch_decoder *cxlsd;
+ struct cxl_port *parent;
+ int child_ways = *ways;
+ int child_pos = *pos;
+ struct device *dev;
+ int skip = 0;
+ int rc = -1;
+
+ parent = next_port(port);
+ if (!parent)
+ return rc;
+
+ dev = device_find_child(&parent->dev, range,
+ match_switch_decoder_by_range);
+ if (!dev) {
+ dev_err(port->uport_dev,
+ "failed to find decoder mapping %#llx-%#llx\n",
+ range->start, range->end);
+ return rc;
+ }
+ cxlsd = to_cxl_switch_decoder(dev);
+ *ways = cxlsd->cxld.interleave_ways;
+
+ /* Skip over this many siblings in the target list */
+ if (*ways > child_ways)
+ skip = child_pos;
+
+ for (int i = 0; i < *ways; i++) {
+ if (cxlsd->target[i] == port->parent_dport) {
+ if (skip--)
+ continue;
+ *pos = i;
+ rc = 0;
+ break;
+ }
+ }
+ put_device(dev);
+
+ return rc;
+}
+
+static int calc_interleave_pos(struct cxl_endpoint_decoder *cxled,
+ int region_ways)
+{
+ struct cxl_port *iter, *port = cxled_to_port(cxled);
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct range *range = &cxled->cxld.hpa_range;
+ int parent_ways = 0;
+ int parent_pos = 0;
+ int rc, pos;
+
+ /* Initialize pos to its local position */
+ rc = find_pos_and_ways(port, range, &parent_pos, &parent_ways);
+ if (rc)
+ return -ENXIO;
+
+ pos = parent_pos;
+
+ if (parent_ways == region_ways)
+ goto out;
+
+ /* Iterate up the ancestral tree refining the position */
+ for (iter = next_port(port); iter; iter = next_port(iter)) {
+ if (is_cxl_root(iter))
+ break;
+
+ rc = find_pos_and_ways(iter, range, &parent_pos, &parent_ways);
+ if (rc)
+ return -ENXIO;
+
+ if (parent_ways == region_ways) {
+ pos = parent_pos;
+ break;
+ }
+ pos = pos * parent_ways + parent_pos;
+ }
+out:
+ dev_dbg(&cxlmd->dev,
+ "decoder:%s parent:%s port:%s range:%#llx-%#llx pos:%d\n",
+ dev_name(&cxled->cxld.dev), dev_name(cxlmd->dev.parent),
+ dev_name(&port->dev), range->start, range->end, pos);
+
+ return pos;
}
static void find_positions(const struct cxl_switch_decoder *cxlsd,
@@ -1765,6 +1852,21 @@ static int cxl_region_attach(struct cxl_region *cxlr,
.end = p->res->end,
};
+ if (p->nr_targets != p->interleave_ways)
+ return 0;
+
+ /* Exercise position calculator on user-defined regions */
+ for (int i = 0; i < p->nr_targets; i++) {
+ struct cxl_endpoint_decoder *cxled = p->targets[i];
+ int test_pos;
+
+ test_pos = calc_interleave_pos(cxled, p->interleave_ways);
+ dev_dbg(&cxled->cxld.dev,
+ "Interleave calc match %s test_pos:%d cxled->pos:%d\n",
+ (test_pos == cxled->pos) ? "Success" : "Fail",
+ test_pos, cxled->pos);
+ }
+
return 0;
err_decrement:
--
2.37.3
next prev parent reply other threads:[~2023-10-16 6:02 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-16 6:02 [PATCH v2 0/3] cxl/region: Autodiscovery position repair alison.schofield
2023-10-16 6:02 ` [PATCH v2 1/3] cxl/region: Prepare the decoder match range helper for reuse alison.schofield
2023-10-17 16:21 ` Jim Harris
2023-10-17 17:24 ` Jim Harris
2023-10-23 23:22 ` Alison Schofield
2023-10-17 20:43 ` Alison Schofield
2023-10-17 22:59 ` Jim Harris
2023-10-23 17:51 ` Alison Schofield
2023-10-23 20:54 ` Dan Williams
2023-10-23 23:30 ` Alison Schofield
2023-10-16 6:02 ` alison.schofield [this message]
2023-10-17 17:33 ` [PATCH v2 2/3] cxl/region: Calculate a target position in a region interleave Jim Harris
2023-10-23 18:10 ` Alison Schofield
2023-10-23 18:34 ` Jim Harris
2023-10-23 21:47 ` Dan Williams
2023-10-16 6:02 ` [PATCH v2 3/3] cxl/region: Use calc_interleave_pos() with autodiscovered regions alison.schofield
2023-10-17 17:40 ` Jim Harris
2023-10-23 21:58 ` Dan Williams
2023-10-24 0:42 ` 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=80f80f0d26e73cd6941d8530163a4bbd731d50ec.1697433770.git.alison.schofield@intel.com \
--to=alison.schofield@intel.com \
--cc=dan.j.williams@intel.com \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=dmytro.adamenko@intel.com \
--cc=ira.weiny@intel.com \
--cc=jonathan.cameron@huawei.com \
--cc=linux-cxl@vger.kernel.org \
--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