Skip to content

Commit b51792f

Browse files
AlisonSchofielddavejiang
authored andcommitted
cxl/region: Translate HPA to DPA and memdev in unaligned regions
The CXL driver supports an expert user debugfs interface to inject and clear poison by a region offset. That feature requires translating a HPA (the region address) to a DPA and a memdev to perform the poison operation. Unaligned regions do not have an algebraically invertible mapping from HPA to DPA due to the region offset skew. The region base is not aligned to a full interleave. Add a helper to perform the unaligned translations that first calculates the DPA offset and then tests it against each candidate endpoint decoder. Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Signed-off-by: Alison Schofield <alison.schofield@intel.com> Link: https://patch.msgid.link/f338b7aff7e4574fcc525b1a0d4f09786bfb6489.1768538962.git.alison.schofield@intel.com Signed-off-by: Dave Jiang <dave.jiang@intel.com>
1 parent e639055 commit b51792f

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

drivers/cxl/core/region.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,6 +3314,48 @@ struct dpa_result {
33143314
u64 dpa;
33153315
};
33163316

3317+
static int unaligned_region_offset_to_dpa_result(struct cxl_region *cxlr,
3318+
u64 offset,
3319+
struct dpa_result *result)
3320+
{
3321+
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
3322+
struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
3323+
struct cxl_region_params *p = &cxlr->params;
3324+
u64 interleave_width, interleave_index;
3325+
u64 gran, gran_offset, dpa_offset;
3326+
u64 hpa = p->res->start + offset;
3327+
3328+
/*
3329+
* Unaligned addresses are not algebraically invertible. Calculate
3330+
* a dpa_offset independent of the target device and then enumerate
3331+
* and test that dpa_offset against each candidate endpoint decoder.
3332+
*/
3333+
gran = cxld->interleave_granularity;
3334+
interleave_width = gran * cxld->interleave_ways;
3335+
interleave_index = div64_u64(offset, interleave_width);
3336+
gran_offset = div64_u64_rem(offset, gran, NULL);
3337+
3338+
dpa_offset = interleave_index * gran + gran_offset;
3339+
3340+
for (int i = 0; i < p->nr_targets; i++) {
3341+
struct cxl_endpoint_decoder *cxled = p->targets[i];
3342+
int pos = cxled->pos;
3343+
u64 test_hpa;
3344+
3345+
test_hpa = unaligned_dpa_to_hpa(cxld, p, pos, dpa_offset);
3346+
if (test_hpa == hpa) {
3347+
result->cxlmd = cxled_to_memdev(cxled);
3348+
result->dpa =
3349+
cxl_dpa_resource_start(cxled) + dpa_offset;
3350+
return 0;
3351+
}
3352+
}
3353+
dev_err(&cxlr->dev,
3354+
"failed to resolve HPA %#llx in unaligned MOD3 region\n", hpa);
3355+
3356+
return -ENXIO;
3357+
}
3358+
33173359
static int region_offset_to_dpa_result(struct cxl_region *cxlr, u64 offset,
33183360
struct dpa_result *result)
33193361
{
@@ -3343,6 +3385,10 @@ static int region_offset_to_dpa_result(struct cxl_region *cxlr, u64 offset,
33433385
hpa_offset = offset;
33443386
}
33453387

3388+
if (region_is_unaligned_mod3(cxlr))
3389+
return unaligned_region_offset_to_dpa_result(cxlr, offset,
3390+
result);
3391+
33463392
pos = cxl_calculate_position(hpa_offset, eiw, eig);
33473393
if (pos < 0 || pos >= p->nr_targets) {
33483394
dev_dbg(&cxlr->dev, "Invalid position %d for %d targets\n",

0 commit comments

Comments
 (0)