1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 4 #include <cxl.h> 5 #include "core.h" 6 7 #define CREATE_TRACE_POINTS 8 #include "trace.h" 9 10 static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos) 11 { 12 struct cxl_region_params *p = &cxlr->params; 13 int gran = p->interleave_granularity; 14 int ways = p->interleave_ways; 15 u64 offset; 16 17 /* Is the hpa within this region at all */ 18 if (hpa < p->res->start || hpa > p->res->end) { 19 dev_dbg(&cxlr->dev, 20 "Addr trans fail: hpa 0x%llx not in region\n", hpa); 21 return false; 22 } 23 24 /* Is the hpa in an expected chunk for its pos(-ition) */ 25 offset = hpa - p->res->start; 26 offset = do_div(offset, gran * ways); 27 if ((offset >= pos * gran) && (offset < (pos + 1) * gran)) 28 return true; 29 30 dev_dbg(&cxlr->dev, 31 "Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa); 32 33 return false; 34 } 35 36 static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, 37 struct cxl_endpoint_decoder *cxled) 38 { 39 u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; 40 struct cxl_region_params *p = &cxlr->params; 41 int pos = cxled->pos; 42 u16 eig = 0; 43 u8 eiw = 0; 44 45 ways_to_eiw(p->interleave_ways, &eiw); 46 granularity_to_eig(p->interleave_granularity, &eig); 47 48 /* 49 * The device position in the region interleave set was removed 50 * from the offset at HPA->DPA translation. To reconstruct the 51 * HPA, place the 'pos' in the offset. 52 * 53 * The placement of 'pos' in the HPA is determined by interleave 54 * ways and granularity and is defined in the CXL Spec 3.0 Section 55 * 8.2.4.19.13 Implementation Note: Device Decode Logic 56 */ 57 58 /* Remove the dpa base */ 59 dpa_offset = dpa - cxl_dpa_resource_start(cxled); 60 61 mask_upper = GENMASK_ULL(51, eig + 8); 62 63 if (eiw < 8) { 64 hpa_offset = (dpa_offset & mask_upper) << eiw; 65 hpa_offset |= pos << (eig + 8); 66 } else { 67 bits_upper = (dpa_offset & mask_upper) >> (eig + 8); 68 bits_upper = bits_upper * 3; 69 hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8); 70 } 71 72 /* The lower bits remain unchanged */ 73 hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0); 74 75 /* Apply the hpa_offset to the region base address */ 76 hpa = hpa_offset + p->res->start; 77 78 if (!cxl_is_hpa_in_range(hpa, cxlr, cxled->pos)) 79 return ULLONG_MAX; 80 81 return hpa; 82 } 83 84 u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *cxlmd, 85 u64 dpa) 86 { 87 struct cxl_region_params *p = &cxlr->params; 88 struct cxl_endpoint_decoder *cxled = NULL; 89 90 for (int i = 0; i < p->nr_targets; i++) { 91 cxled = p->targets[i]; 92 if (cxlmd == cxled_to_memdev(cxled)) 93 break; 94 } 95 if (!cxled || cxlmd != cxled_to_memdev(cxled)) 96 return ULLONG_MAX; 97 98 return cxl_dpa_to_hpa(dpa, cxlr, cxled); 99 } 100