|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-only
|
2 | 2 | /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
|
3 | 3 |
|
| 4 | +#include <cxl.h> |
| 5 | +#include "core.h" |
| 6 | + |
4 | 7 | #define CREATE_TRACE_POINTS
|
5 | 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 | +} |
0 commit comments