* [RFC PATCH] cxl/region: Translate DPA->HPA in unaligned MOD3 regions
@ 2025-03-06 19:43 alison.schofield
2025-03-07 2:15 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: alison.schofield @ 2025-03-06 19:43 UTC (permalink / raw)
To: Davidlohr Bueso, Jonathan Cameron, Dave Jiang, Alison Schofield,
Vishal Verma, Ira Weiny, Dan Williams
Cc: linux-cxl, Qing Huang
From: Alison Schofield <alison.schofield@intel.com>
Posting as an RFC because this adds support for a configuration that
is not CXL spec compliant.
The CXL driver implementation of DPA->HPA address translation depends
upon the spec defined requirement[1] that a regions starting address
will always be a multiple of the host bridge interleave ways. The CXL
driver implementation follows the decode methods defined in the CXL
Spec[2] and expanded upon in the CXL Driver Writers Guide[3].
A platform has presented with a CFMWS defined 3-way Host Bridge inter-
leave that breaks alignment in order to avoid gaps in the platform
memory layout and requires a new DPA->HPA decode.
This unaligned decode takes little from the existing method because
without alignment, bit manipulations cannot restore the position bits
to the correct location. Instead it reconstructs the HPA by breaking
the process into two steps: restore the address at the port level and
then at the host bridge level. (See in code comments)
Support is limited to 3,6,12 way region interleaves built upon 3-way
Host Bridge interleaves without switches. ie: 1+1+1 2+2+2 4+4+4+4
This method could be made to work for all configs, aligned or not.
Expanding for all configs at least requires rework of decode_pos()
and support for switches.
[1] CXL Spec 3.2 9-22 Interleave Target List Description
[2] CXL Spec 3.2 8.2.4.20.13 Implementation Note Device Decoder Logic
[3] CXL Type 3 Memory Software Guide 1.1 2.13.25 DPA to HPA Translation
Suggested-by: Qing Huang <qing.huang@intel.com>
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
---
This patch is built upon cxl/next and is not dependent upon
cxl/region: Allow 6 & 12 way regions on 3-way HB interleaves
that is also in review on this list.
With this patch alone, 3-way unaligned regions can be translated.
cxl/test: Define a CFMWS capable of a 3 way HB interleave is also
on cxl/next and provides and unaligned 3-way CMFWS.
drivers/cxl/core/region.c | 113 +++++++++++++++++++++++++++++++++++++-
1 file changed, 111 insertions(+), 2 deletions(-)
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 8537b6a9ca18..411a108e87ad 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2883,13 +2883,112 @@ static bool cxl_is_hpa_in_chunk(u64 hpa, struct cxl_region *cxlr, int pos)
return false;
}
+static int decode_pos(int region_ways, int pos, int *pos_port, int *pos_hb)
+{
+ switch (region_ways) {
+ /*
+ * Extract the port and hb positions from an endpoint position.
+ * Knowing there is only one possible decode** for each of these
+ * regions, decode logic is:
+ * 3-way: port always 0, hb is pos
+ * 6-way: port cycles thru 0,1, hb increments every 2
+ * 12-way: port cycles thru 0,1,2,3, hb increments every 4
+ *
+ * **CXL Spec 3.2 9.13.1.1 Legal Interleaving Configurations
+ */
+ case 3:
+ *pos_port = 0;
+ *pos_hb = pos;
+ break;
+ case 6:
+ *pos_port = pos % 2;
+ *pos_hb = pos / 2;
+ break;
+ case 12:
+ *pos_port = pos % 4;
+ *pos_hb = pos / 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * restore_parent() reconstructs the address in parent
+ *
+ * [mask] isolate the offset with the granularity
+ * [addr & ~mask] remove the offset leaving the aligned portion
+ * [* ways] distribute across all interleave ways
+ * [+ (pos * gran)] add the positional offset
+ * [+ (addr & mask)] restore the masked offset
+ */
+static u64 restore_parent(u64 addr, u64 pos, u64 gran, u64 ways)
+{
+ u64 mask = gran - 1;
+
+ return ((addr & ~mask) * ways) + (pos * gran) + (addr & mask);
+}
+
+/*
+ * unaligned_dpa_to_hpa() translates a DPA to HPA when the region resource
+ * start address is not a multiple of the Host Bridge interleave ways.
+ *
+ * Unaligned address translation is only supported for regions built upon
+ * 3-way HB interleaves, 1+1+1 2+2+2 4+4+4+4, and will fail on any other
+ * unaligned regions. ie. if a 4-way region appears with an unaligned start
+ * address it fails at the decode_pos().
+ */
+static u64 unaligned_dpa_to_hpa(struct cxl_decoder *cxld,
+ struct cxl_region_params *p, int pos, u64 dpa)
+{
+ int ways_port = p->interleave_ways / cxld->interleave_ways;
+ int gran_port = p->interleave_granularity;
+ int gran_hb = cxld->interleave_granularity;
+ int ways_hb = cxld->interleave_ways;
+ u64 hpa, hpa_port = 0;
+ int pos_port, pos_hb;
+
+ /* Decode an endpoint 'pos' into port and host-bridge components */
+ if (decode_pos(p->interleave_ways, pos, &pos_port, &pos_hb)) {
+ dev_dbg(&cxld->dev, "not supported for region ways:%d\n",
+ p->interleave_ways);
+ return ULLONG_MAX;
+ }
+ /* Restore the port parent address if needed */
+ /* This could also be 'if (region ways > 3)' for this limited soln */
+ if (gran_hb != gran_port)
+ hpa_port = restore_parent(dpa, pos_port, gran_port, ways_port);
+
+ /*
+ * Complete the HPA reconstruction by restoring the address as if
+ * each HB position is a candidate. Test against expected pos_hb
+ * to confirm match.
+ */
+ for (int index = 0; index < ways_hb; index++) {
+ hpa = restore_parent(hpa_port, index, gran_hb, ways_hb);
+ hpa += p->res->start;
+ if ((hpa / gran_hb) % ways_hb == pos_hb)
+ return hpa;
+ }
+
+ dev_dbg(&cxld->dev, "fail dpa:%#llx start:%#llx pos:%d\n", dpa,
+ p->res->start, pos);
+ dev_dbg(&cxld->dev, " port-w/g/p:%d/%d/%d hb-w/g/p:%d/%d/%d\n",
+ ways_port, gran_port, pos_port, ways_hb, gran_hb, pos_hb);
+
+ return ULLONG_MAX;
+}
+
u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
u64 dpa)
{
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa;
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
struct cxl_region_params *p = &cxlr->params;
struct cxl_endpoint_decoder *cxled = NULL;
+ bool aligned;
u16 eig = 0;
u8 eiw = 0;
int pos;
@@ -2902,6 +3001,14 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
if (!cxled || cxlmd != cxled_to_memdev(cxled))
return ULLONG_MAX;
+ aligned = (p->res->start % cxld->interleave_ways == 0);
+ if (!aligned) {
+ hpa = unaligned_dpa_to_hpa(cxld, p, cxled->pos, dpa);
+ if (hpa == ULLONG_MAX)
+ return ULLONG_MAX;
+
+ goto to_spa;
+ }
pos = cxled->pos;
ways_to_eiw(p->interleave_ways, &eiw);
granularity_to_eig(p->interleave_granularity, &eig);
@@ -2936,6 +3043,7 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
/* Apply the hpa_offset to the region base address */
hpa = hpa_offset + p->res->start + p->cache_size;
+to_spa:
/* Root decoder translation overrides typical modulo decode */
if (cxlrd->hpa_to_spa)
hpa = cxlrd->hpa_to_spa(cxlrd, hpa);
@@ -2946,8 +3054,9 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
return ULLONG_MAX;
}
- /* Simple chunk check, by pos & gran, only applies to modulo decodes */
- if (!cxlrd->hpa_to_spa && (!cxl_is_hpa_in_chunk(hpa, cxlr, pos)))
+ /* Chunk check applies to aligned modulo decodes only */
+ if (aligned && !cxlrd->hpa_to_spa &&
+ !cxl_is_hpa_in_chunk(hpa, cxlr, pos))
return ULLONG_MAX;
return hpa;
base-commit: 26600bf10173beda5358d194ec425a1cfafa2fe2
--
2.37.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [RFC PATCH] cxl/region: Translate DPA->HPA in unaligned MOD3 regions
2025-03-06 19:43 [RFC PATCH] cxl/region: Translate DPA->HPA in unaligned MOD3 regions alison.schofield
@ 2025-03-07 2:15 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2025-03-07 2:15 UTC (permalink / raw)
To: alison.schofield; +Cc: llvm, oe-kbuild-all
Hi,
[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:
[auto build test WARNING on 26600bf10173beda5358d194ec425a1cfafa2fe2]
url: https://github.com/intel-lab-lkp/linux/commits/alison-schofield-intel-com/cxl-region-Translate-DPA-HPA-in-unaligned-MOD3-regions/20250307-034424
base: 26600bf10173beda5358d194ec425a1cfafa2fe2
patch link: https://lore.kernel.org/r/20250306194328.2600429-1-alison.schofield%40intel.com
patch subject: [RFC PATCH] cxl/region: Translate DPA->HPA in unaligned MOD3 regions
config: arm-randconfig-001-20250307 (https://download.01.org/0day-ci/archive/20250307/202503070931.7aNcyFaJ-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project 14170b16028c087ca154878f5ed93d3089a965c6)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250307/202503070931.7aNcyFaJ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503070931.7aNcyFaJ-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/cxl/core/region.c:2976:3: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
2975 | dev_dbg(&cxld->dev, "fail dpa:%#llx start:%#llx pos:%d\n", dpa,
| ~~~~~
| %#x
2976 | p->res->start, pos);
| ^~~~~~~~~~~~~
include/linux/dev_printk.h:165:39: note: expanded from macro 'dev_dbg'
165 | dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dynamic_debug.h:274:19: note: expanded from macro 'dynamic_dev_dbg'
274 | dev, fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dynamic_debug.h:250:59: note: expanded from macro '_dynamic_func_call'
250 | _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
| ^~~~~~~~~~~
include/linux/dynamic_debug.h:248:65: note: expanded from macro '_dynamic_func_call_cls'
248 | __dynamic_func_call_cls(__UNIQUE_ID(ddebug), cls, fmt, func, ##__VA_ARGS__)
| ^~~~~~~~~~~
include/linux/dynamic_debug.h:224:15: note: expanded from macro '__dynamic_func_call_cls'
224 | func(&id, ##__VA_ARGS__); \
| ^~~~~~~~~~~
1 warning generated.
vim +2976 drivers/cxl/core/region.c
2932
2933 /*
2934 * unaligned_dpa_to_hpa() translates a DPA to HPA when the region resource
2935 * start address is not a multiple of the Host Bridge interleave ways.
2936 *
2937 * Unaligned address translation is only supported for regions built upon
2938 * 3-way HB interleaves, 1+1+1 2+2+2 4+4+4+4, and will fail on any other
2939 * unaligned regions. ie. if a 4-way region appears with an unaligned start
2940 * address it fails at the decode_pos().
2941 */
2942 static u64 unaligned_dpa_to_hpa(struct cxl_decoder *cxld,
2943 struct cxl_region_params *p, int pos, u64 dpa)
2944 {
2945 int ways_port = p->interleave_ways / cxld->interleave_ways;
2946 int gran_port = p->interleave_granularity;
2947 int gran_hb = cxld->interleave_granularity;
2948 int ways_hb = cxld->interleave_ways;
2949 u64 hpa, hpa_port = 0;
2950 int pos_port, pos_hb;
2951
2952 /* Decode an endpoint 'pos' into port and host-bridge components */
2953 if (decode_pos(p->interleave_ways, pos, &pos_port, &pos_hb)) {
2954 dev_dbg(&cxld->dev, "not supported for region ways:%d\n",
2955 p->interleave_ways);
2956 return ULLONG_MAX;
2957 }
2958 /* Restore the port parent address if needed */
2959 /* This could also be 'if (region ways > 3)' for this limited soln */
2960 if (gran_hb != gran_port)
2961 hpa_port = restore_parent(dpa, pos_port, gran_port, ways_port);
2962
2963 /*
2964 * Complete the HPA reconstruction by restoring the address as if
2965 * each HB position is a candidate. Test against expected pos_hb
2966 * to confirm match.
2967 */
2968 for (int index = 0; index < ways_hb; index++) {
2969 hpa = restore_parent(hpa_port, index, gran_hb, ways_hb);
2970 hpa += p->res->start;
2971 if ((hpa / gran_hb) % ways_hb == pos_hb)
2972 return hpa;
2973 }
2974
2975 dev_dbg(&cxld->dev, "fail dpa:%#llx start:%#llx pos:%d\n", dpa,
> 2976 p->res->start, pos);
2977 dev_dbg(&cxld->dev, " port-w/g/p:%d/%d/%d hb-w/g/p:%d/%d/%d\n",
2978 ways_port, gran_port, pos_port, ways_hb, gran_hb, pos_hb);
2979
2980 return ULLONG_MAX;
2981 }
2982
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-03-07 2:16 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-06 19:43 [RFC PATCH] cxl/region: Translate DPA->HPA in unaligned MOD3 regions alison.schofield
2025-03-07 2:15 ` kernel test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.