From patchwork Wed Oct 25 17:31:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 13436498 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1445B1C683 for ; Wed, 25 Oct 2023 17:31:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="DnTqTNr9" Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D778F184 for ; Wed, 25 Oct 2023 10:31:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1698255099; x=1729791099; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qF+NcbypEjhRR4/i6wuDTLB5fVJIkgYKMoJr4J6AHy0=; b=DnTqTNr9s4SpJw7lQ7ZlFm/HtXxobaQxCIfJl/NPu8yXEyuDs+TZSgUI x5V7145Zct3To3vlR74rDOXivbWIt+iJpBXNdx3ZpduNRp9yy4TY6Wp7S te/P4ItESR8v7s7Ja3n/Apevb4zBS6e88aJ2oN3CW3BF6A6ksf/YAgA5T xFoRU3VmdF94OkAm114o3nTjRB4VUaik3OybHOFQ/KbIc5RuHqIzBguwW nEYX82WpN/9LoXYbQ+31CWbQ+0z7bg4RuV0bijkOEh2U62SGYn8ErBITn TVZNR+Ov5fknGbdZvhXtdJRvvskZOgmdlaQBM1yyBgGAwxnzmXP6zsc5E w==; X-IronPort-AV: E=McAfee;i="6600,9927,10874"; a="141114" X-IronPort-AV: E=Sophos;i="6.03,250,1694761200"; d="scan'208";a="141114" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2023 10:31:33 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10874"; a="902608456" X-IronPort-AV: E=Sophos;i="6.03,250,1694761200"; d="scan'208";a="902608456" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.212.181.198]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2023 10:29:08 -0700 From: alison.schofield@intel.com To: Davidlohr Bueso , Jonathan Cameron , Dave Jiang , Alison Schofield , Vishal Verma , Ira Weiny , Dan Williams Cc: linux-cxl@vger.kernel.org, Jonathan Cameron , Jim Harris Subject: [PATCH v3 1/3] cxl/region: Prepare the decoder match range helper for reuse Date: Wed, 25 Oct 2023 10:31:27 -0700 Message-Id: <011b1f498e1758bb8df17c5951be00bd8d489e3b.1698254338.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Alison Schofield match_decoder_by_range() and decoder_match_range() both determine if an HPA range matches a decoder. The first does it for root decoders and the second one operates on switch decoders. Tidy these up with clear naming and make the switch helper more like the root decoder helper in style and functionality. Make it take the actual range, rather than an endpoint decoder from which it extracts the range. Require an exact match on switch decoders, because unlike a root decoder that maps an entire region, Linux only supports 1:1 mapping of switch to endpoint decoders. Aside from aesthetics and maintainability, this is in preparation for reuse. Signed-off-by: Alison Schofield Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Reviewed-by: Jim Harris --- drivers/cxl/core/region.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 6d63b8798c29..eea8e89a6860 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1487,16 +1487,18 @@ static struct cxl_port *next_port(struct cxl_port *port) return port->parent_dport->port; } -static int decoder_match_range(struct device *dev, void *data) +static int match_switch_decoder_by_range(struct device *dev, void *data) { - struct cxl_endpoint_decoder *cxled = data; struct cxl_switch_decoder *cxlsd; + struct range *r1, *r2 = data; if (!is_switch_decoder(dev)) return 0; cxlsd = to_cxl_switch_decoder(dev); - return range_contains(&cxlsd->cxld.hpa_range, &cxled->cxld.hpa_range); + r1 = &cxlsd->cxld.hpa_range; + + return (r1->start == r2->start && r1->end == r2->end); } static void find_positions(const struct cxl_switch_decoder *cxlsd, @@ -1565,7 +1567,8 @@ static int cmp_decode_pos(const void *a, const void *b) goto err; } - dev = device_find_child(&port->dev, cxled_a, decoder_match_range); + dev = device_find_child(&port->dev, &cxled_a->cxld.hpa_range, + match_switch_decoder_by_range); if (!dev) { struct range *range = &cxled_a->cxld.hpa_range; @@ -2696,7 +2699,7 @@ static int devm_cxl_add_dax_region(struct cxl_region *cxlr) return rc; } -static int match_decoder_by_range(struct device *dev, void *data) +static int match_root_decoder_by_range(struct device *dev, void *data) { struct range *r1, *r2 = data; struct cxl_root_decoder *cxlrd; @@ -2827,7 +2830,7 @@ int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled) int rc; cxlrd_dev = device_find_child(&root->dev, &cxld->hpa_range, - match_decoder_by_range); + match_root_decoder_by_range); if (!cxlrd_dev) { dev_err(cxlmd->dev.parent, "%s:%s no CXL window for range %#llx:%#llx\n", From patchwork Wed Oct 25 17:31:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 13436499 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4EB5C30CFB for ; Wed, 25 Oct 2023 17:31:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="k6vusoka" Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E24DC186 for ; Wed, 25 Oct 2023 10:31:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1698255100; x=1729791100; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=PMEowbj4ZchUah/GgbyOx/F2D2QdG2iALsRsDzXbR9o=; b=k6vusokajrrjOOBS6ENUQ3zoT7H+DKta8q6Z2Ty0loj5D6UDRRG/1ory lJ2PAJpr7AhHMKht0PpX7B0Zjv4glrv6KTcwqtYPKkGPmVqJXfhevPayp Dcx8ldMctXlhVrb8/1JcYElK0SbOUJ54HsCLuvcI/mxuRtL6qHczG3THl 5A7LR619gmaIC9S/j0LJulbl2waM5qSaIbKYT2+TriDUD7mrn5U+paq1U GsGgDcYY32rEjDomnrl7bDOdQqXcE3dlEgY+O4Nu/IPbdqYI7gCauFk/s wHwEF0+1HSnsyxx1ziaExuImP7QGTEcm5ZvGqt5nJqoVzPeF0CNuAzenb g==; X-IronPort-AV: E=McAfee;i="6600,9927,10874"; a="141118" X-IronPort-AV: E=Sophos;i="6.03,250,1694761200"; d="scan'208";a="141118" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2023 10:31:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10874"; a="902608470" X-IronPort-AV: E=Sophos;i="6.03,250,1694761200"; d="scan'208";a="902608470" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.212.181.198]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2023 10:29:10 -0700 From: alison.schofield@intel.com To: Davidlohr Bueso , Jonathan Cameron , Dave Jiang , Alison Schofield , Vishal Verma , Ira Weiny , Dan Williams Cc: linux-cxl@vger.kernel.org Subject: [PATCH v3 2/3] cxl/region: Calculate a target position in a region interleave Date: Wed, 25 Oct 2023 10:31:28 -0700 Message-Id: <7709896423244c523e810d9f5d2ef625e7babf3b.1698254338.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Alison Schofield Introduce a calculation to find a target's position in a region interleave. Perform a self-test 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 target's 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_calc_interleave_pos() adds a method to find the target position by ascending from an endpoint to a root decoder. The calculation starts with the endpoint's local position and position in the parent 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: position = position * parent_ways + parent_pos; applied iteratively yields the correct position. Include a self-test that exercises this new position calculation against every successfully configured user-defined region. Signed-off-by: Alison Schofield --- drivers/cxl/core/region.c | 142 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index eea8e89a6860..bea43da7e8f2 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1501,6 +1501,128 @@ static int match_switch_decoder_by_range(struct device *dev, void *data) return (r1->start == r2->start && r1->end == r2->end); } +/** + * cxl_find_pos_and_ways() - find the position of a port in a parent + * and the parent interleave ways + * + * @port: the port in search of parent info + * @range: the hpa range that the parent must map + * @pos: the position of @port in the parent decoder target list + * @ways: the interleave ways of the parent decoder + * + * This helper function for cxl_calc_interleave_pos() provides the + * @pos and @ways used to calculate the endpoint position in a region + * interleave. + * + * Use @range to find @port's parent port and follow that to the + * parent switch decoder. Extract @ways from the switch decoder and + * lookup the @port @pos in the switch decoder target list. + * + * Returns: 0: success, @pos and @ways are updated + * -ENXIO: failed to find @pos or @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; + struct device *dev; + int rc = -ENXIO; + + 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; + + for (int i = 0; i < *ways; i++) { + if (cxlsd->target[i] == port->parent_dport) { + *pos = i; + rc = 0; + break; + } + } + put_device(dev); + + return rc; +} + +/** + * cxl_calc_interleave_pos() - calculate an endpoint position in a region + * @cxled: the endpoint decoder + * + * The endpoint position is calculated by traversing from the endpoint to + * the root decoder and iteratively applying this calculation: + * position = position * parent_ways + parent_pos; + * + * For example, the expected interleave order of the 4-way region shown + * below is: mem0, mem2, mem1, mem3 + * + * root_port + * / \ + * host_bridge_0 host_bridge_1 + * | | | | + * 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. + * + * 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 + * 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 + * + * Note that while this example is simple, the method applies to more + * complex topologies, including those with switches. + * + * Return: position >= 0 on success + * -ENXIO on failure + */ + +static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled) +{ + 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, parent_pos = 0, pos = 0; + int rc; + + /* Iterate from endpoint to root_port refining the position */ + for (iter = 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 rc; + + pos = pos * parent_ways + parent_pos; + } + + 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, const struct cxl_port *iter_a, const struct cxl_port *iter_b, int *a_pos, @@ -1764,6 +1886,26 @@ static int cxl_region_attach(struct cxl_region *cxlr, .end = p->res->end, }; + if (p->nr_targets != p->interleave_ways) + return 0; + + /* + * Test the auto-discovery position calculator function + * against this successfully created user-defined region. + * A fail message here means that this interleave config + * will fail when presented as CXL_REGION_F_AUTO. + */ + for (int i = 0; i < p->nr_targets; i++) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + int test_pos; + + test_pos = cxl_calc_interleave_pos(cxled); + dev_dbg(&cxled->cxld.dev, + "Test cxl_calc_interleave_pos(): %s test_pos:%d cxled->pos:%d\n", + (test_pos == cxled->pos) ? "success" : "fail", + test_pos, cxled->pos); + } + return 0; err_decrement: From patchwork Wed Oct 25 17:31:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 13436500 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 32D301C683 for ; Wed, 25 Oct 2023 17:31:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="H48eOPR+" Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0284C187 for ; Wed, 25 Oct 2023 10:31:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1698255100; x=1729791100; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=J26Z3u/lu7taVdjJ0dlnJwrcRhpBawqj4/DN03ICql0=; b=H48eOPR+c47HclZh8aRVoC1Tp7aVEA+YbC2WAtJRZ9aqv1bigVfdEUS+ YPfFbZYw7oD/ubkwlggSPgYCHyjH1Hv8ANOP6blT0G4wTS/0ByKHdceUn d0p5mkgJu414B1uaeLT6oGqTqaMsn9LiifVUH2t47POoSwh7yw/MPOQ59 K74Beds3//xfpBQm2+OEAqAuubc9R63eFTDSwA+7DvZuFlCj25yz+u92e CnGwHuSwVSo+JauKKr/MphAco+98jvz2SrtsCT38qKKsQm5qWw5WjffgW Ay+FE3bThH1fcSk4oLo0e7JeWxuL01Kqxzs1aFcITOmIMZ6HJ9A6zpm/l A==; X-IronPort-AV: E=McAfee;i="6600,9927,10874"; a="141124" X-IronPort-AV: E=Sophos;i="6.03,250,1694761200"; d="scan'208";a="141124" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2023 10:31:36 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10874"; a="902608484" X-IronPort-AV: E=Sophos;i="6.03,250,1694761200"; d="scan'208";a="902608484" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.212.181.198]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2023 10:29:11 -0700 From: alison.schofield@intel.com To: Davidlohr Bueso , Jonathan Cameron , Dave Jiang , Alison Schofield , Vishal Verma , Ira Weiny , Dan Williams Cc: linux-cxl@vger.kernel.org, Dmytro Adamenko , Jim Harris Subject: [PATCH v3 3/3] cxl/region: Use cxl_calc_interleave_pos() for auto-discovery Date: Wed, 25 Oct 2023 10:31:29 -0700 Message-Id: <843f38822178791cfe7b49d53e143b69fabfa530.1698254338.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Alison Schofield For auto-discovered regions the driver must assign each target to a valid position in the region interleave set based on the decoder topology. The current implementation fails to parse valid decode topologies, as it does not consider the child offset into a parent port. The sort put all targets of one port ahead of another port when an interleave was expected, causing the region assembly to fail. Replace the existing relative sort with cxl_calc_interleave_pos() that finds the exact position in a region interleave for an endpoint based on a walk up the ancestral tree from endpoint to root decoder. cxl_calc_interleave_pos() was introduced in a prior patch, so the work here is to use it in cxl_region_sort_targets(). Remove the obsoleted helper functions from the prior sort. Testing passes on pre-production hardware with BIOS defined regions that natively trigger this autodiscovery path of the region driver. Testing passes a CXL unit test using the dev_dbg() calculation test (see cxl_region_attach()) across an expanded set of region configs: 1, 1, 1+1, 1+1+1, 2, 2+2, 2+2+2, 2+2+2+2, 4, 4+4, where each number represents the count of endpoints per host bridge. Fixes: a32320b71f08 ("cxl/region: Add region autodiscovery") Reported-by: Dmytro Adamenko Signed-off-by: Alison Schofield Reviewed-by: Dave Jiang Reviewed-by: Jim Harris --- drivers/cxl/core/region.c | 127 +++++--------------------------------- 1 file changed, 15 insertions(+), 112 deletions(-) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index bea43da7e8f2..55836fddb494 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1480,6 +1480,14 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr, return 0; } +static int cmp_interleave_pos(const void *a, const void *b) +{ + struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a; + struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b; + + return cxled_a->pos - cxled_b->pos; +} + static struct cxl_port *next_port(struct cxl_port *port) { if (!port->parent_dport) @@ -1623,131 +1631,26 @@ static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled) return pos; } -static void find_positions(const struct cxl_switch_decoder *cxlsd, - const struct cxl_port *iter_a, - const struct cxl_port *iter_b, int *a_pos, - int *b_pos) -{ - int i; - - for (i = 0, *a_pos = -1, *b_pos = -1; i < cxlsd->nr_targets; i++) { - if (cxlsd->target[i] == iter_a->parent_dport) - *a_pos = i; - else if (cxlsd->target[i] == iter_b->parent_dport) - *b_pos = i; - if (*a_pos >= 0 && *b_pos >= 0) - break; - } -} - -static int cmp_decode_pos(const void *a, const void *b) -{ - struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a; - struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b; - struct cxl_memdev *cxlmd_a = cxled_to_memdev(cxled_a); - struct cxl_memdev *cxlmd_b = cxled_to_memdev(cxled_b); - struct cxl_port *port_a = cxled_to_port(cxled_a); - struct cxl_port *port_b = cxled_to_port(cxled_b); - struct cxl_port *iter_a, *iter_b, *port = NULL; - struct cxl_switch_decoder *cxlsd; - struct device *dev; - int a_pos, b_pos; - unsigned int seq; - - /* Exit early if any prior sorting failed */ - if (cxled_a->pos < 0 || cxled_b->pos < 0) - return 0; - - /* - * Walk up the hierarchy to find a shared port, find the decoder that - * maps the range, compare the relative position of those dport - * mappings. - */ - for (iter_a = port_a; iter_a; iter_a = next_port(iter_a)) { - struct cxl_port *next_a, *next_b; - - next_a = next_port(iter_a); - if (!next_a) - break; - - for (iter_b = port_b; iter_b; iter_b = next_port(iter_b)) { - next_b = next_port(iter_b); - if (next_a != next_b) - continue; - port = next_a; - break; - } - - if (port) - break; - } - - if (!port) { - dev_err(cxlmd_a->dev.parent, - "failed to find shared port with %s\n", - dev_name(cxlmd_b->dev.parent)); - goto err; - } - - dev = device_find_child(&port->dev, &cxled_a->cxld.hpa_range, - match_switch_decoder_by_range); - if (!dev) { - struct range *range = &cxled_a->cxld.hpa_range; - - dev_err(port->uport_dev, - "failed to find decoder that maps %#llx-%#llx\n", - range->start, range->end); - goto err; - } - - cxlsd = to_cxl_switch_decoder(dev); - do { - seq = read_seqbegin(&cxlsd->target_lock); - find_positions(cxlsd, iter_a, iter_b, &a_pos, &b_pos); - } while (read_seqretry(&cxlsd->target_lock, seq)); - - put_device(dev); - - if (a_pos < 0 || b_pos < 0) { - dev_err(port->uport_dev, - "failed to find shared decoder for %s and %s\n", - dev_name(cxlmd_a->dev.parent), - dev_name(cxlmd_b->dev.parent)); - goto err; - } - - dev_dbg(port->uport_dev, "%s comes %s %s\n", - dev_name(cxlmd_a->dev.parent), - a_pos - b_pos < 0 ? "before" : "after", - dev_name(cxlmd_b->dev.parent)); - - return a_pos - b_pos; -err: - cxled_a->pos = -1; - return 0; -} - static int cxl_region_sort_targets(struct cxl_region *cxlr) { struct cxl_region_params *p = &cxlr->params; int i, rc = 0; - sort(p->targets, p->nr_targets, sizeof(p->targets[0]), cmp_decode_pos, - NULL); - for (i = 0; i < p->nr_targets; i++) { struct cxl_endpoint_decoder *cxled = p->targets[i]; + cxled->pos = cxl_calc_interleave_pos(cxled); /* - * Record that sorting failed, but still continue to restore - * cxled->pos with its ->targets[] position so that follow-on - * code paths can reliably do p->targets[cxled->pos] to - * self-reference their entry. + * Record that sorting failed, but still continue to calc + * cxled->pos so that follow-on code paths can reliably + * do p->targets[cxled->pos] to self-reference their entry. */ if (cxled->pos < 0) rc = -ENXIO; - cxled->pos = i; } + /* Keep the cxlr target list in interleave position order */ + sort(p->targets, p->nr_targets, sizeof(p->targets[0]), + cmp_interleave_pos, NULL); dev_dbg(&cxlr->dev, "region sort %s\n", rc ? "failed" : "successful"); return rc;