#include "cxlpci.h"
#include "cxl.h"
+#define CXL_RCRB_SIZE SZ_8K
+
+ struct cxl_cxims_data {
+ int nr_maps;
+ u64 xormaps[];
+ };
+
+ /*
+ * Find a targets entry (n) in the host bridge interleave list.
+ * CXL Specfication 3.0 Table 9-22
+ */
+ static int cxl_xor_calc_n(u64 hpa, struct cxl_cxims_data *cximsd, int iw,
+ int ig)
+ {
+ int i = 0, n = 0;
+ u8 eiw;
+
+ /* IW: 2,4,6,8,12,16 begin building 'n' using xormaps */
+ if (iw != 3) {
+ for (i = 0; i < cximsd->nr_maps; i++)
+ n |= (hweight64(hpa & cximsd->xormaps[i]) & 1) << i;
+ }
+ /* IW: 3,6,12 add a modulo calculation to 'n' */
+ if (!is_power_of_2(iw)) {
+ if (ways_to_cxl(iw, &eiw))
+ return -1;
+ hpa &= GENMASK_ULL(51, eiw + ig);
+ n |= do_div(hpa, 3) << i;
+ }
+ return n;
+ }
+
+ static struct cxl_dport *cxl_hb_xor(struct cxl_root_decoder *cxlrd, int pos)
+ {
+ struct cxl_cxims_data *cximsd = cxlrd->platform_data;
+ struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
+ struct cxl_decoder *cxld = &cxlsd->cxld;
+ int ig = cxld->interleave_granularity;
+ int iw = cxld->interleave_ways;
+ int n = 0;
+ u64 hpa;
+
+ if (dev_WARN_ONCE(&cxld->dev,
+ cxld->interleave_ways != cxlsd->nr_targets,
+ "misconfigured root decoder\n"))
+ return NULL;
+
+ hpa = cxlrd->res->start + pos * ig;
+
+ /* Entry (n) is 0 for no interleave (iw == 1) */
+ if (iw != 1)
+ n = cxl_xor_calc_n(hpa, cximsd, iw, ig);
+
+ if (n < 0)
+ return NULL;
+
+ return cxlrd->cxlsd.target[n];
+ }
+
+ struct cxl_cxims_context {
+ struct device *dev;
+ struct cxl_root_decoder *cxlrd;
+ };
+
+ static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg,
+ const unsigned long end)
+ {
+ struct acpi_cedt_cxims *cxims = (struct acpi_cedt_cxims *)header;
+ struct cxl_cxims_context *ctx = arg;
+ struct cxl_root_decoder *cxlrd = ctx->cxlrd;
+ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
+ struct device *dev = ctx->dev;
+ struct cxl_cxims_data *cximsd;
+ unsigned int hbig, nr_maps;
+ int rc;
+
+ rc = cxl_to_granularity(cxims->hbig, &hbig);
+ if (rc)
+ return rc;
+
+ /* Does this CXIMS entry apply to the given CXL Window? */
+ if (hbig != cxld->interleave_granularity)
+ return 0;
+
+ /* IW 1,3 do not use xormaps and skip this parsing entirely */
+ if (is_power_of_2(cxld->interleave_ways))
+ /* 2, 4, 8, 16 way */
+ nr_maps = ilog2(cxld->interleave_ways);
+ else
+ /* 6, 12 way */
+ nr_maps = ilog2(cxld->interleave_ways / 3);
+
+ if (cxims->nr_xormaps < nr_maps) {
+ dev_dbg(dev, "CXIMS nr_xormaps[%d] expected[%d]\n",
+ cxims->nr_xormaps, nr_maps);
+ return -ENXIO;
+ }
+
+ cximsd = devm_kzalloc(dev, struct_size(cximsd, xormaps, nr_maps),
+ GFP_KERNEL);
+ if (!cximsd)
+ return -ENOMEM;
+ memcpy(cximsd->xormaps, cxims->xormap_list,
+ nr_maps * sizeof(*cximsd->xormaps));
+ cximsd->nr_maps = nr_maps;
+ cxlrd->platform_data = cximsd;
+
+ return 0;
+ }
+
static unsigned long cfmws_to_decoder_flags(int restrictions)
{
unsigned long flags = CXL_DECODER_F_ENABLE;
#include <cxlmem.h>
#include "mock.h"
+ static int interleave_arithmetic;
+
#define NR_CXL_HOST_BRIDGES 2
#define NR_CXL_SINGLE_HOST 1
+#define NR_CXL_RCH 1
#define NR_CXL_ROOT_PORTS 2
#define NR_CXL_SWITCH_PORTS 2
#define NR_CXL_PORT_DECODERS 8
struct acpi_cedt_cfmws cfmws;
u32 target[1];
} cfmws5;
- u32 target[2];
+ struct {
+ struct acpi_cedt_cfmws cfmws;
- u32 target[4];
++ u32 target[1];
+ } cfmws6;
+ struct {
+ struct acpi_cedt_cfmws cfmws;
++ u32 target[2];
+ } cfmws7;
+ struct {
++ struct acpi_cedt_cfmws cfmws;
++ u32 target[4];
++ } cfmws8;
++ struct {
+ struct acpi_cedt_cxims cxims;
+ u64 xormap_list[2];
+ } cxims0;
} __packed mock_cedt = {
.cedt = {
.header = {
.type = ACPI_CEDT_TYPE_CFMWS,
.length = sizeof(mock_cedt.cfmws5),
},
- .cfmws6 = {
+ .interleave_ways = 0,
+ .granularity = 4,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
+ .qtg_id = 5,
+ .window_size = SZ_256M,
+ },
+ .target = { 3 },
+ },
++ /* .cfmws6,7,8 use ACPI_CEDT_CFMWS_ARITHMETIC_XOR */
++ .cfmws6 = {
++ .cfmws = {
++ .header = {
++ .type = ACPI_CEDT_TYPE_CFMWS,
++ .length = sizeof(mock_cedt.cfmws6),
++ },
+ .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
+ .interleave_ways = 0,
+ .granularity = 4,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_PMEM,
+ .qtg_id = 0,
+ .window_size = SZ_256M * 8UL,
+ },
+ .target = { 0, },
+ },
- .length = sizeof(mock_cedt.cfmws6),
++ .cfmws7 = {
+ .cfmws = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CFMWS,
- .cfmws7 = {
++ .length = sizeof(mock_cedt.cfmws7),
+ },
+ .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
+ .interleave_ways = 1,
+ .granularity = 0,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_PMEM,
+ .qtg_id = 1,
+ .window_size = SZ_256M * 8UL,
+ },
+ .target = { 0, 1, },
+ },
- .length = sizeof(mock_cedt.cfmws7),
++ .cfmws8 = {
+ .cfmws = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CFMWS,
++ .length = sizeof(mock_cedt.cfmws8),
+ },
+ .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
+ .interleave_ways = 2,
+ .granularity = 0,
+ .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
+ ACPI_CEDT_CFMWS_RESTRICT_PMEM,
+ .qtg_id = 0,
+ .window_size = SZ_256M * 16UL,
+ },
+ .target = { 0, 1, 0, 1, },
+ },
+ .cxims0 = {
+ .cxims = {
+ .header = {
+ .type = ACPI_CEDT_TYPE_CXIMS,
+ .length = sizeof(mock_cedt.cxims0),
+ },
+ .hbig = 0,
+ .nr_xormaps = 2,
+ },
+ .xormap_list = { 0x404100, 0x808200, },
+ },
};
-struct acpi_cedt_cfmws *mock_cfmws[8] = {
+struct acpi_cedt_cfmws *mock_cfmws[] = {
[0] = &mock_cedt.cfmws0.cfmws,
[1] = &mock_cedt.cfmws1.cfmws,
[2] = &mock_cedt.cfmws2.cfmws,
[3] = &mock_cedt.cfmws3.cfmws,
[4] = &mock_cedt.cfmws4.cfmws,
- /* Modulo Math above, XOR Math below */
[5] = &mock_cedt.cfmws5.cfmws,
-#define CFMWS_MOD_ARRAY_END 4
-#define CFMWS_XOR_ARRAY_START 5
-#define CFMWS_XOR_ARRAY_END 7
++ /* Modulo Math above, XOR Math below */
+ [6] = &mock_cedt.cfmws6.cfmws,
+ [7] = &mock_cedt.cfmws7.cfmws,
++ [8] = &mock_cedt.cfmws8.cfmws,
+ };
+
+ static int cfmws_start;
+ static int cfmws_end;
+ #define CFMWS_MOD_ARRAY_START 0
++#define CFMWS_MOD_ARRAY_END 5
++#define CFMWS_XOR_ARRAY_START 6
++#define CFMWS_XOR_ARRAY_END 8
+
+ struct acpi_cedt_cxims *mock_cxims[1] = {
+ [0] = &mock_cedt.cxims0.cxims,
};
struct cxl_mock_res {
chbs->length = size;
}
- for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
+ for (i = cfmws_start; i <= cfmws_end; i++) {
struct acpi_cedt_cfmws *window = mock_cfmws[i];
- res = alloc_mock_res(window->window_size);
+ res = alloc_mock_res(window->window_size, SZ_256M);
if (!res)
return -ENOMEM;
window->base_hpa = res->range.start;