Skip to content

Commit 3b2fedc

Browse files
AlisonSchofielddavejiang
authored andcommitted
cxl: Restore XOR'd position bits during address translation
When a device reports a DPA in events like poison, general_media, and dram, the driver translates that DPA back to an HPA. Presently, the CXL driver translation only considers the Modulo position and will report the wrong HPA for XOR configured root decoders. Add a helper function that restores the XOR'd bits during DPA->HPA address translation. Plumb a root decoder callback to the new helper when XOR interleave arithmetic is in use. For Modulo arithmetic, just let the callback be NULL - as in no extra work required. Upon completion of a DPA->HPA translation a couple of checks are performed on the result. One simply confirms that the calculated HPA is within the address range of the region. That test is useful for both Modulo and XOR interleave arithmetic decodes. A second check confirms that the HPA is within an expected chunk based on the endpoints position in the region and the region granularity. An XOR decode disrupts the Modulo pattern making the chunk check useless. To align the checks with the proper decode, pull the region range check inline and use the helper to do the chunk check for Modulo decodes only. A cxl-test unit test is posted for upstream review here: https://lore.kernel.org/20240624210644.495563-1-alison.schofield@intel.com/ Fixes: 28a3ae4 ("cxl/trace: Add an HPA to cxl_poison trace events") Signed-off-by: Alison Schofield <alison.schofield@intel.com> Tested-by: Diego Garcia Rodriguez <diego.garcia.rodriguez@intel.com> Reviewed-by: Dan Williams <dan.j.williams@intel.com> Link: https://patch.msgid.link/1a1ac880d9f889bd6384e657e810431b9a0a72e5.1719980933.git.alison.schofield@intel.com Signed-off-by: Dave Jiang <dave.jiang@intel.com>
1 parent 9aa5f62 commit 3b2fedc

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

drivers/cxl/acpi.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,43 @@ static struct cxl_dport *cxl_hb_xor(struct cxl_root_decoder *cxlrd, int pos)
7474
return cxlrd->cxlsd.target[n];
7575
}
7676

77+
static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa)
78+
{
79+
struct cxl_cxims_data *cximsd = cxlrd->platform_data;
80+
int hbiw = cxlrd->cxlsd.nr_targets;
81+
u64 val;
82+
int pos;
83+
84+
/* No xormaps for host bridge interleave ways of 1 or 3 */
85+
if (hbiw == 1 || hbiw == 3)
86+
return hpa;
87+
88+
/*
89+
* For root decoders using xormaps (hbiw: 2,4,6,8,12,16) restore
90+
* the position bit to its value before the xormap was applied at
91+
* HPA->DPA translation.
92+
*
93+
* pos is the lowest set bit in an XORMAP
94+
* val is the XORALLBITS(HPA & XORMAP)
95+
*
96+
* XORALLBITS: The CXL spec (3.1 Table 9-22) defines XORALLBITS
97+
* as an operation that outputs a single bit by XORing all the
98+
* bits in the input (hpa & xormap). Implement XORALLBITS using
99+
* hweight64(). If the hamming weight is even the XOR of those
100+
* bits results in val==0, if odd the XOR result is val==1.
101+
*/
102+
103+
for (int i = 0; i < cximsd->nr_maps; i++) {
104+
if (!cximsd->xormaps[i])
105+
continue;
106+
pos = __ffs(cximsd->xormaps[i]);
107+
val = (hweight64(hpa & cximsd->xormaps[i]) & 1);
108+
hpa = (hpa & ~(1ULL << pos)) | (val << pos);
109+
}
110+
111+
return hpa;
112+
}
113+
77114
struct cxl_cxims_context {
78115
struct device *dev;
79116
struct cxl_root_decoder *cxlrd;
@@ -434,6 +471,9 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
434471

435472
cxlrd->qos_class = cfmws->qtg_id;
436473

474+
if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR)
475+
cxlrd->hpa_to_spa = cxl_xor_hpa_to_spa;
476+
437477
rc = cxl_decoder_add(cxld, target_map);
438478
if (rc)
439479
return rc;

drivers/cxl/core/region.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2723,20 +2723,13 @@ struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa)
27232723
return ctx.cxlr;
27242724
}
27252725

2726-
static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos)
2726+
static bool cxl_is_hpa_in_chunk(u64 hpa, struct cxl_region *cxlr, int pos)
27272727
{
27282728
struct cxl_region_params *p = &cxlr->params;
27292729
int gran = p->interleave_granularity;
27302730
int ways = p->interleave_ways;
27312731
u64 offset;
27322732

2733-
/* Is the hpa within this region at all */
2734-
if (hpa < p->res->start || hpa > p->res->end) {
2735-
dev_dbg(&cxlr->dev,
2736-
"Addr trans fail: hpa 0x%llx not in region\n", hpa);
2737-
return false;
2738-
}
2739-
27402733
/* Is the hpa in an expected chunk for its pos(-ition) */
27412734
offset = hpa - p->res->start;
27422735
offset = do_div(offset, gran * ways);
@@ -2752,6 +2745,7 @@ static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos)
27522745
u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
27532746
u64 dpa)
27542747
{
2748+
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
27552749
u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa;
27562750
struct cxl_region_params *p = &cxlr->params;
27572751
struct cxl_endpoint_decoder *cxled = NULL;
@@ -2801,7 +2795,18 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
28012795
/* Apply the hpa_offset to the region base address */
28022796
hpa = hpa_offset + p->res->start;
28032797

2804-
if (!cxl_is_hpa_in_range(hpa, cxlr, cxled->pos))
2798+
/* Root decoder translation overrides typical modulo decode */
2799+
if (cxlrd->hpa_to_spa)
2800+
hpa = cxlrd->hpa_to_spa(cxlrd, hpa);
2801+
2802+
if (hpa < p->res->start || hpa > p->res->end) {
2803+
dev_dbg(&cxlr->dev,
2804+
"Addr trans fail: hpa 0x%llx not in region\n", hpa);
2805+
return ULLONG_MAX;
2806+
}
2807+
2808+
/* Simple chunk check, by pos & gran, only applies to modulo decodes */
2809+
if (!cxlrd->hpa_to_spa && (!cxl_is_hpa_in_chunk(hpa, cxlr, pos)))
28052810
return ULLONG_MAX;
28062811

28072812
return hpa;

drivers/cxl/cxl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,12 +434,14 @@ struct cxl_switch_decoder {
434434
struct cxl_root_decoder;
435435
typedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd,
436436
int pos);
437+
typedef u64 (*cxl_hpa_to_spa_fn)(struct cxl_root_decoder *cxlrd, u64 hpa);
437438

438439
/**
439440
* struct cxl_root_decoder - Static platform CXL address decoder
440441
* @res: host / parent resource for region allocations
441442
* @region_id: region id for next region provisioning event
442443
* @calc_hb: which host bridge covers the n'th position by granularity
444+
* @hpa_to_spa: translate CXL host-physical-address to Platform system-physical-address
443445
* @platform_data: platform specific configuration data
444446
* @range_lock: sync region autodiscovery by address range
445447
* @qos_class: QoS performance class cookie
@@ -449,6 +451,7 @@ struct cxl_root_decoder {
449451
struct resource *res;
450452
atomic_t region_id;
451453
cxl_calc_hb_fn calc_hb;
454+
cxl_hpa_to_spa_fn hpa_to_spa;
452455
void *platform_data;
453456
struct mutex range_lock;
454457
int qos_class;

0 commit comments

Comments
 (0)