167dcdd4dSDan Williams // SPDX-License-Identifier: GPL-2.0-only
267dcdd4dSDan Williams // Copyright(c) 2021 Intel Corporation. All rights reserved.
367dcdd4dSDan Williams
467dcdd4dSDan Williams #include <linux/platform_device.h>
567dcdd4dSDan Williams #include <linux/genalloc.h>
667dcdd4dSDan Williams #include <linux/module.h>
767dcdd4dSDan Williams #include <linux/mutex.h>
867dcdd4dSDan Williams #include <linux/acpi.h>
967dcdd4dSDan Williams #include <linux/pci.h>
1067dcdd4dSDan Williams #include <linux/mm.h>
11d17d0540SDan Williams #include <cxlmem.h>
128c149eb0SDan Williams
138c149eb0SDan Williams #include "../watermark.h"
1467dcdd4dSDan Williams #include "mock.h"
1567dcdd4dSDan Williams
167a7e6edfSAlison Schofield static int interleave_arithmetic;
177a7e6edfSAlison Schofield
18c1915142SDan Williams #define NR_CXL_HOST_BRIDGES 2
19e41c8452SDan Williams #define NR_CXL_SINGLE_HOST 1
20c9435dbeSDan Williams #define NR_CXL_RCH 1
2167dcdd4dSDan Williams #define NR_CXL_ROOT_PORTS 2
22c1915142SDan Williams #define NR_CXL_SWITCH_PORTS 2
23855c90d3SDan Williams #define NR_CXL_PORT_DECODERS 8
24c9435dbeSDan Williams #define NR_BRIDGES (NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + NR_CXL_RCH)
2567dcdd4dSDan Williams
2667dcdd4dSDan Williams static struct platform_device *cxl_acpi;
2767dcdd4dSDan Williams static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
28e41c8452SDan Williams #define NR_MULTI_ROOT (NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS)
29e41c8452SDan Williams static struct platform_device *cxl_root_port[NR_MULTI_ROOT];
30e41c8452SDan Williams static struct platform_device *cxl_switch_uport[NR_MULTI_ROOT];
31e41c8452SDan Williams #define NR_MEM_MULTI \
32e41c8452SDan Williams (NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS * NR_CXL_SWITCH_PORTS)
33e41c8452SDan Williams static struct platform_device *cxl_switch_dport[NR_MEM_MULTI];
34e41c8452SDan Williams
35e41c8452SDan Williams static struct platform_device *cxl_hb_single[NR_CXL_SINGLE_HOST];
36e41c8452SDan Williams static struct platform_device *cxl_root_single[NR_CXL_SINGLE_HOST];
37e41c8452SDan Williams static struct platform_device *cxl_swu_single[NR_CXL_SINGLE_HOST];
38e41c8452SDan Williams #define NR_MEM_SINGLE (NR_CXL_SINGLE_HOST * NR_CXL_SWITCH_PORTS)
39e41c8452SDan Williams static struct platform_device *cxl_swd_single[NR_MEM_SINGLE];
40e41c8452SDan Williams
41e41c8452SDan Williams struct platform_device *cxl_mem[NR_MEM_MULTI];
42e41c8452SDan Williams struct platform_device *cxl_mem_single[NR_MEM_SINGLE];
43e41c8452SDan Williams
44c9435dbeSDan Williams static struct platform_device *cxl_rch[NR_CXL_RCH];
45c9435dbeSDan Williams static struct platform_device *cxl_rcd[NR_CXL_RCH];
46e41c8452SDan Williams
is_multi_bridge(struct device * dev)47e41c8452SDan Williams static inline bool is_multi_bridge(struct device *dev)
48e41c8452SDan Williams {
49e41c8452SDan Williams int i;
50e41c8452SDan Williams
51e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
52e41c8452SDan Williams if (&cxl_host_bridge[i]->dev == dev)
53e41c8452SDan Williams return true;
54e41c8452SDan Williams return false;
55e41c8452SDan Williams }
56e41c8452SDan Williams
is_single_bridge(struct device * dev)57e41c8452SDan Williams static inline bool is_single_bridge(struct device *dev)
58e41c8452SDan Williams {
59e41c8452SDan Williams int i;
60e41c8452SDan Williams
61e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
62e41c8452SDan Williams if (&cxl_hb_single[i]->dev == dev)
63e41c8452SDan Williams return true;
64e41c8452SDan Williams return false;
65e41c8452SDan Williams }
6667dcdd4dSDan Williams
6767dcdd4dSDan Williams static struct acpi_device acpi0017_mock;
68c9435dbeSDan Williams static struct acpi_device host_bridge[NR_BRIDGES] = {
6967dcdd4dSDan Williams [0] = {
7067dcdd4dSDan Williams .handle = &host_bridge[0],
7167dcdd4dSDan Williams },
7267dcdd4dSDan Williams [1] = {
7367dcdd4dSDan Williams .handle = &host_bridge[1],
7467dcdd4dSDan Williams },
75e41c8452SDan Williams [2] = {
76e41c8452SDan Williams .handle = &host_bridge[2],
77e41c8452SDan Williams },
78c9435dbeSDan Williams [3] = {
79c9435dbeSDan Williams .handle = &host_bridge[3],
80c9435dbeSDan Williams },
8167dcdd4dSDan Williams };
8267dcdd4dSDan Williams
is_mock_dev(struct device * dev)8367dcdd4dSDan Williams static bool is_mock_dev(struct device *dev)
8467dcdd4dSDan Williams {
857d3eb23cSDan Williams int i;
867d3eb23cSDan Williams
877d3eb23cSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_mem); i++)
887d3eb23cSDan Williams if (dev == &cxl_mem[i]->dev)
897d3eb23cSDan Williams return true;
90e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++)
91e41c8452SDan Williams if (dev == &cxl_mem_single[i]->dev)
92e41c8452SDan Williams return true;
93c9435dbeSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++)
94c9435dbeSDan Williams if (dev == &cxl_rcd[i]->dev)
95c9435dbeSDan Williams return true;
9667dcdd4dSDan Williams if (dev == &cxl_acpi->dev)
9767dcdd4dSDan Williams return true;
9867dcdd4dSDan Williams return false;
9967dcdd4dSDan Williams }
10067dcdd4dSDan Williams
is_mock_adev(struct acpi_device * adev)10167dcdd4dSDan Williams static bool is_mock_adev(struct acpi_device *adev)
10267dcdd4dSDan Williams {
10367dcdd4dSDan Williams int i;
10467dcdd4dSDan Williams
10567dcdd4dSDan Williams if (adev == &acpi0017_mock)
10667dcdd4dSDan Williams return true;
10767dcdd4dSDan Williams
10867dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
10967dcdd4dSDan Williams if (adev == &host_bridge[i])
11067dcdd4dSDan Williams return true;
11167dcdd4dSDan Williams
11267dcdd4dSDan Williams return false;
11367dcdd4dSDan Williams }
11467dcdd4dSDan Williams
11567dcdd4dSDan Williams static struct {
11667dcdd4dSDan Williams struct acpi_table_cedt cedt;
117c9435dbeSDan Williams struct acpi_cedt_chbs chbs[NR_BRIDGES];
11867dcdd4dSDan Williams struct {
11967dcdd4dSDan Williams struct acpi_cedt_cfmws cfmws;
12067dcdd4dSDan Williams u32 target[1];
12167dcdd4dSDan Williams } cfmws0;
12267dcdd4dSDan Williams struct {
12367dcdd4dSDan Williams struct acpi_cedt_cfmws cfmws;
124c1915142SDan Williams u32 target[2];
12567dcdd4dSDan Williams } cfmws1;
12667dcdd4dSDan Williams struct {
12767dcdd4dSDan Williams struct acpi_cedt_cfmws cfmws;
12867dcdd4dSDan Williams u32 target[1];
12967dcdd4dSDan Williams } cfmws2;
13067dcdd4dSDan Williams struct {
13167dcdd4dSDan Williams struct acpi_cedt_cfmws cfmws;
132c1915142SDan Williams u32 target[2];
13367dcdd4dSDan Williams } cfmws3;
134e41c8452SDan Williams struct {
135e41c8452SDan Williams struct acpi_cedt_cfmws cfmws;
136e41c8452SDan Williams u32 target[1];
137e41c8452SDan Williams } cfmws4;
138c9435dbeSDan Williams struct {
139c9435dbeSDan Williams struct acpi_cedt_cfmws cfmws;
140c9435dbeSDan Williams u32 target[1];
141c9435dbeSDan Williams } cfmws5;
1427a7e6edfSAlison Schofield struct {
1437a7e6edfSAlison Schofield struct acpi_cedt_cfmws cfmws;
14402fedf14SDan Williams u32 target[1];
1457a7e6edfSAlison Schofield } cfmws6;
1467a7e6edfSAlison Schofield struct {
1477a7e6edfSAlison Schofield struct acpi_cedt_cfmws cfmws;
14802fedf14SDan Williams u32 target[2];
1497a7e6edfSAlison Schofield } cfmws7;
1507a7e6edfSAlison Schofield struct {
15102fedf14SDan Williams struct acpi_cedt_cfmws cfmws;
15202fedf14SDan Williams u32 target[4];
15302fedf14SDan Williams } cfmws8;
15402fedf14SDan Williams struct {
1557a7e6edfSAlison Schofield struct acpi_cedt_cxims cxims;
1567a7e6edfSAlison Schofield u64 xormap_list[2];
1577a7e6edfSAlison Schofield } cxims0;
15867dcdd4dSDan Williams } __packed mock_cedt = {
15967dcdd4dSDan Williams .cedt = {
16067dcdd4dSDan Williams .header = {
16167dcdd4dSDan Williams .signature = "CEDT",
16267dcdd4dSDan Williams .length = sizeof(mock_cedt),
16367dcdd4dSDan Williams .revision = 1,
16467dcdd4dSDan Williams },
16567dcdd4dSDan Williams },
16667dcdd4dSDan Williams .chbs[0] = {
16767dcdd4dSDan Williams .header = {
16867dcdd4dSDan Williams .type = ACPI_CEDT_TYPE_CHBS,
16967dcdd4dSDan Williams .length = sizeof(mock_cedt.chbs[0]),
17067dcdd4dSDan Williams },
17167dcdd4dSDan Williams .uid = 0,
17267dcdd4dSDan Williams .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
17367dcdd4dSDan Williams },
17467dcdd4dSDan Williams .chbs[1] = {
17567dcdd4dSDan Williams .header = {
17667dcdd4dSDan Williams .type = ACPI_CEDT_TYPE_CHBS,
17767dcdd4dSDan Williams .length = sizeof(mock_cedt.chbs[0]),
17867dcdd4dSDan Williams },
17967dcdd4dSDan Williams .uid = 1,
18067dcdd4dSDan Williams .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
18167dcdd4dSDan Williams },
182e41c8452SDan Williams .chbs[2] = {
183e41c8452SDan Williams .header = {
184e41c8452SDan Williams .type = ACPI_CEDT_TYPE_CHBS,
185e41c8452SDan Williams .length = sizeof(mock_cedt.chbs[0]),
186e41c8452SDan Williams },
187e41c8452SDan Williams .uid = 2,
188e41c8452SDan Williams .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
189e41c8452SDan Williams },
190c9435dbeSDan Williams .chbs[3] = {
191c9435dbeSDan Williams .header = {
192c9435dbeSDan Williams .type = ACPI_CEDT_TYPE_CHBS,
193c9435dbeSDan Williams .length = sizeof(mock_cedt.chbs[0]),
194c9435dbeSDan Williams },
195c9435dbeSDan Williams .uid = 3,
196c9435dbeSDan Williams .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL11,
197c9435dbeSDan Williams },
19867dcdd4dSDan Williams .cfmws0 = {
19967dcdd4dSDan Williams .cfmws = {
20067dcdd4dSDan Williams .header = {
20167dcdd4dSDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
20267dcdd4dSDan Williams .length = sizeof(mock_cedt.cfmws0),
20367dcdd4dSDan Williams },
20467dcdd4dSDan Williams .interleave_ways = 0,
20567dcdd4dSDan Williams .granularity = 4,
20667dcdd4dSDan Williams .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
20767dcdd4dSDan Williams ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
20867dcdd4dSDan Williams .qtg_id = 0,
209855c90d3SDan Williams .window_size = SZ_256M * 4UL,
21067dcdd4dSDan Williams },
21167dcdd4dSDan Williams .target = { 0 },
21267dcdd4dSDan Williams },
21367dcdd4dSDan Williams .cfmws1 = {
21467dcdd4dSDan Williams .cfmws = {
21567dcdd4dSDan Williams .header = {
21667dcdd4dSDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
21767dcdd4dSDan Williams .length = sizeof(mock_cedt.cfmws1),
21867dcdd4dSDan Williams },
219c1915142SDan Williams .interleave_ways = 1,
22067dcdd4dSDan Williams .granularity = 4,
22167dcdd4dSDan Williams .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
22267dcdd4dSDan Williams ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
22367dcdd4dSDan Williams .qtg_id = 1,
224855c90d3SDan Williams .window_size = SZ_256M * 8UL,
22567dcdd4dSDan Williams },
226c1915142SDan Williams .target = { 0, 1, },
22767dcdd4dSDan Williams },
22867dcdd4dSDan Williams .cfmws2 = {
22967dcdd4dSDan Williams .cfmws = {
23067dcdd4dSDan Williams .header = {
23167dcdd4dSDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
23267dcdd4dSDan Williams .length = sizeof(mock_cedt.cfmws2),
23367dcdd4dSDan Williams },
23467dcdd4dSDan Williams .interleave_ways = 0,
23567dcdd4dSDan Williams .granularity = 4,
23667dcdd4dSDan Williams .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
23767dcdd4dSDan Williams ACPI_CEDT_CFMWS_RESTRICT_PMEM,
23867dcdd4dSDan Williams .qtg_id = 2,
239855c90d3SDan Williams .window_size = SZ_256M * 4UL,
24067dcdd4dSDan Williams },
24167dcdd4dSDan Williams .target = { 0 },
24267dcdd4dSDan Williams },
24367dcdd4dSDan Williams .cfmws3 = {
24467dcdd4dSDan Williams .cfmws = {
24567dcdd4dSDan Williams .header = {
24667dcdd4dSDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
24767dcdd4dSDan Williams .length = sizeof(mock_cedt.cfmws3),
24867dcdd4dSDan Williams },
249c1915142SDan Williams .interleave_ways = 1,
25067dcdd4dSDan Williams .granularity = 4,
25167dcdd4dSDan Williams .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
25267dcdd4dSDan Williams ACPI_CEDT_CFMWS_RESTRICT_PMEM,
25367dcdd4dSDan Williams .qtg_id = 3,
254855c90d3SDan Williams .window_size = SZ_256M * 8UL,
25567dcdd4dSDan Williams },
256c1915142SDan Williams .target = { 0, 1, },
25767dcdd4dSDan Williams },
258e41c8452SDan Williams .cfmws4 = {
259e41c8452SDan Williams .cfmws = {
260e41c8452SDan Williams .header = {
261e41c8452SDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
262e41c8452SDan Williams .length = sizeof(mock_cedt.cfmws4),
263e41c8452SDan Williams },
264e41c8452SDan Williams .interleave_ways = 0,
265e41c8452SDan Williams .granularity = 4,
266e41c8452SDan Williams .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
267e41c8452SDan Williams ACPI_CEDT_CFMWS_RESTRICT_PMEM,
268e41c8452SDan Williams .qtg_id = 4,
269e41c8452SDan Williams .window_size = SZ_256M * 4UL,
270e41c8452SDan Williams },
271e41c8452SDan Williams .target = { 2 },
272e41c8452SDan Williams },
273c9435dbeSDan Williams .cfmws5 = {
274c9435dbeSDan Williams .cfmws = {
275c9435dbeSDan Williams .header = {
276c9435dbeSDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
277c9435dbeSDan Williams .length = sizeof(mock_cedt.cfmws5),
278c9435dbeSDan Williams },
279c9435dbeSDan Williams .interleave_ways = 0,
280c9435dbeSDan Williams .granularity = 4,
281c9435dbeSDan Williams .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
282c9435dbeSDan Williams ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
283c9435dbeSDan Williams .qtg_id = 5,
284c9435dbeSDan Williams .window_size = SZ_256M,
285c9435dbeSDan Williams },
286c9435dbeSDan Williams .target = { 3 },
287c9435dbeSDan Williams },
28802fedf14SDan Williams /* .cfmws6,7,8 use ACPI_CEDT_CFMWS_ARITHMETIC_XOR */
28902fedf14SDan Williams .cfmws6 = {
29002fedf14SDan Williams .cfmws = {
29102fedf14SDan Williams .header = {
29202fedf14SDan Williams .type = ACPI_CEDT_TYPE_CFMWS,
29302fedf14SDan Williams .length = sizeof(mock_cedt.cfmws6),
29402fedf14SDan Williams },
2957a7e6edfSAlison Schofield .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
2967a7e6edfSAlison Schofield .interleave_ways = 0,
2977a7e6edfSAlison Schofield .granularity = 4,
2987a7e6edfSAlison Schofield .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
2997a7e6edfSAlison Schofield ACPI_CEDT_CFMWS_RESTRICT_PMEM,
3007a7e6edfSAlison Schofield .qtg_id = 0,
3017a7e6edfSAlison Schofield .window_size = SZ_256M * 8UL,
3027a7e6edfSAlison Schofield },
3037a7e6edfSAlison Schofield .target = { 0, },
3047a7e6edfSAlison Schofield },
30502fedf14SDan Williams .cfmws7 = {
3067a7e6edfSAlison Schofield .cfmws = {
3077a7e6edfSAlison Schofield .header = {
3087a7e6edfSAlison Schofield .type = ACPI_CEDT_TYPE_CFMWS,
30902fedf14SDan Williams .length = sizeof(mock_cedt.cfmws7),
3107a7e6edfSAlison Schofield },
3117a7e6edfSAlison Schofield .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
3127a7e6edfSAlison Schofield .interleave_ways = 1,
3137a7e6edfSAlison Schofield .granularity = 0,
3147a7e6edfSAlison Schofield .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
3157a7e6edfSAlison Schofield ACPI_CEDT_CFMWS_RESTRICT_PMEM,
3167a7e6edfSAlison Schofield .qtg_id = 1,
3177a7e6edfSAlison Schofield .window_size = SZ_256M * 8UL,
3187a7e6edfSAlison Schofield },
3197a7e6edfSAlison Schofield .target = { 0, 1, },
3207a7e6edfSAlison Schofield },
32102fedf14SDan Williams .cfmws8 = {
3227a7e6edfSAlison Schofield .cfmws = {
3237a7e6edfSAlison Schofield .header = {
3247a7e6edfSAlison Schofield .type = ACPI_CEDT_TYPE_CFMWS,
32502fedf14SDan Williams .length = sizeof(mock_cedt.cfmws8),
3267a7e6edfSAlison Schofield },
3277a7e6edfSAlison Schofield .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
3287a7e6edfSAlison Schofield .interleave_ways = 2,
3297a7e6edfSAlison Schofield .granularity = 0,
3307a7e6edfSAlison Schofield .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
3317a7e6edfSAlison Schofield ACPI_CEDT_CFMWS_RESTRICT_PMEM,
3327a7e6edfSAlison Schofield .qtg_id = 0,
3337a7e6edfSAlison Schofield .window_size = SZ_256M * 16UL,
3347a7e6edfSAlison Schofield },
3357a7e6edfSAlison Schofield .target = { 0, 1, 0, 1, },
3367a7e6edfSAlison Schofield },
3377a7e6edfSAlison Schofield .cxims0 = {
3387a7e6edfSAlison Schofield .cxims = {
3397a7e6edfSAlison Schofield .header = {
3407a7e6edfSAlison Schofield .type = ACPI_CEDT_TYPE_CXIMS,
3417a7e6edfSAlison Schofield .length = sizeof(mock_cedt.cxims0),
3427a7e6edfSAlison Schofield },
3437a7e6edfSAlison Schofield .hbig = 0,
3447a7e6edfSAlison Schofield .nr_xormaps = 2,
3457a7e6edfSAlison Schofield },
3467a7e6edfSAlison Schofield .xormap_list = { 0x404100, 0x808200, },
3477a7e6edfSAlison Schofield },
34867dcdd4dSDan Williams };
34967dcdd4dSDan Williams
350e41c8452SDan Williams struct acpi_cedt_cfmws *mock_cfmws[] = {
351814dff9aSDan Williams [0] = &mock_cedt.cfmws0.cfmws,
352814dff9aSDan Williams [1] = &mock_cedt.cfmws1.cfmws,
353814dff9aSDan Williams [2] = &mock_cedt.cfmws2.cfmws,
354814dff9aSDan Williams [3] = &mock_cedt.cfmws3.cfmws,
355e41c8452SDan Williams [4] = &mock_cedt.cfmws4.cfmws,
356c9435dbeSDan Williams [5] = &mock_cedt.cfmws5.cfmws,
35702fedf14SDan Williams /* Modulo Math above, XOR Math below */
3587a7e6edfSAlison Schofield [6] = &mock_cedt.cfmws6.cfmws,
3597a7e6edfSAlison Schofield [7] = &mock_cedt.cfmws7.cfmws,
36002fedf14SDan Williams [8] = &mock_cedt.cfmws8.cfmws,
3617a7e6edfSAlison Schofield };
3627a7e6edfSAlison Schofield
3637a7e6edfSAlison Schofield static int cfmws_start;
3647a7e6edfSAlison Schofield static int cfmws_end;
3657a7e6edfSAlison Schofield #define CFMWS_MOD_ARRAY_START 0
36602fedf14SDan Williams #define CFMWS_MOD_ARRAY_END 5
36702fedf14SDan Williams #define CFMWS_XOR_ARRAY_START 6
36802fedf14SDan Williams #define CFMWS_XOR_ARRAY_END 8
3697a7e6edfSAlison Schofield
3707a7e6edfSAlison Schofield struct acpi_cedt_cxims *mock_cxims[1] = {
3717a7e6edfSAlison Schofield [0] = &mock_cedt.cxims0.cxims,
372814dff9aSDan Williams };
373814dff9aSDan Williams
37467dcdd4dSDan Williams struct cxl_mock_res {
37567dcdd4dSDan Williams struct list_head list;
37667dcdd4dSDan Williams struct range range;
37767dcdd4dSDan Williams };
37867dcdd4dSDan Williams
37967dcdd4dSDan Williams static LIST_HEAD(mock_res);
38067dcdd4dSDan Williams static DEFINE_MUTEX(mock_res_lock);
38167dcdd4dSDan Williams static struct gen_pool *cxl_mock_pool;
38267dcdd4dSDan Williams
depopulate_all_mock_resources(void)38367dcdd4dSDan Williams static void depopulate_all_mock_resources(void)
38467dcdd4dSDan Williams {
38567dcdd4dSDan Williams struct cxl_mock_res *res, *_res;
38667dcdd4dSDan Williams
38767dcdd4dSDan Williams mutex_lock(&mock_res_lock);
38867dcdd4dSDan Williams list_for_each_entry_safe(res, _res, &mock_res, list) {
38967dcdd4dSDan Williams gen_pool_free(cxl_mock_pool, res->range.start,
39067dcdd4dSDan Williams range_len(&res->range));
39167dcdd4dSDan Williams list_del(&res->list);
39267dcdd4dSDan Williams kfree(res);
39367dcdd4dSDan Williams }
39467dcdd4dSDan Williams mutex_unlock(&mock_res_lock);
39567dcdd4dSDan Williams }
39667dcdd4dSDan Williams
alloc_mock_res(resource_size_t size,int align)397c9435dbeSDan Williams static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
39867dcdd4dSDan Williams {
39967dcdd4dSDan Williams struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
40067dcdd4dSDan Williams struct genpool_data_align data = {
401c9435dbeSDan Williams .align = align,
40267dcdd4dSDan Williams };
40367dcdd4dSDan Williams unsigned long phys;
40467dcdd4dSDan Williams
40567dcdd4dSDan Williams INIT_LIST_HEAD(&res->list);
40667dcdd4dSDan Williams phys = gen_pool_alloc_algo(cxl_mock_pool, size,
40767dcdd4dSDan Williams gen_pool_first_fit_align, &data);
40867dcdd4dSDan Williams if (!phys)
40967dcdd4dSDan Williams return NULL;
41067dcdd4dSDan Williams
41167dcdd4dSDan Williams res->range = (struct range) {
41267dcdd4dSDan Williams .start = phys,
41367dcdd4dSDan Williams .end = phys + size - 1,
41467dcdd4dSDan Williams };
41567dcdd4dSDan Williams mutex_lock(&mock_res_lock);
41667dcdd4dSDan Williams list_add(&res->list, &mock_res);
41767dcdd4dSDan Williams mutex_unlock(&mock_res_lock);
41867dcdd4dSDan Williams
41967dcdd4dSDan Williams return res;
42067dcdd4dSDan Williams }
42167dcdd4dSDan Williams
populate_cedt(void)42267dcdd4dSDan Williams static int populate_cedt(void)
42367dcdd4dSDan Williams {
42467dcdd4dSDan Williams struct cxl_mock_res *res;
42567dcdd4dSDan Williams int i;
42667dcdd4dSDan Williams
42767dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
42867dcdd4dSDan Williams struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i];
42967dcdd4dSDan Williams resource_size_t size;
43067dcdd4dSDan Williams
43167dcdd4dSDan Williams if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20)
43267dcdd4dSDan Williams size = ACPI_CEDT_CHBS_LENGTH_CXL20;
43367dcdd4dSDan Williams else
43467dcdd4dSDan Williams size = ACPI_CEDT_CHBS_LENGTH_CXL11;
43567dcdd4dSDan Williams
436c9435dbeSDan Williams res = alloc_mock_res(size, size);
43767dcdd4dSDan Williams if (!res)
43867dcdd4dSDan Williams return -ENOMEM;
43967dcdd4dSDan Williams chbs->base = res->range.start;
44067dcdd4dSDan Williams chbs->length = size;
44167dcdd4dSDan Williams }
44267dcdd4dSDan Williams
4437a7e6edfSAlison Schofield for (i = cfmws_start; i <= cfmws_end; i++) {
444814dff9aSDan Williams struct acpi_cedt_cfmws *window = mock_cfmws[i];
44567dcdd4dSDan Williams
446c9435dbeSDan Williams res = alloc_mock_res(window->window_size, SZ_256M);
44767dcdd4dSDan Williams if (!res)
44867dcdd4dSDan Williams return -ENOMEM;
44967dcdd4dSDan Williams window->base_hpa = res->range.start;
45067dcdd4dSDan Williams }
45167dcdd4dSDan Williams
45267dcdd4dSDan Williams return 0;
45367dcdd4dSDan Williams }
45467dcdd4dSDan Williams
4558b3b1c0dSDan Williams static bool is_mock_port(struct device *dev);
4568b3b1c0dSDan Williams
457814dff9aSDan Williams /*
4588b3b1c0dSDan Williams * WARNING, this hack assumes the format of 'struct cxl_cfmws_context'
4598b3b1c0dSDan Williams * and 'struct cxl_chbs_context' share the property that the first
4608b3b1c0dSDan Williams * struct member is a cxl_test device being probed by the cxl_acpi
461814dff9aSDan Williams * driver.
462814dff9aSDan Williams */
463814dff9aSDan Williams struct cxl_cedt_context {
464814dff9aSDan Williams struct device *dev;
465814dff9aSDan Williams };
46667dcdd4dSDan Williams
mock_acpi_table_parse_cedt(enum acpi_cedt_type id,acpi_tbl_entry_handler_arg handler_arg,void * arg)467814dff9aSDan Williams static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
468814dff9aSDan Williams acpi_tbl_entry_handler_arg handler_arg,
469814dff9aSDan Williams void *arg)
470814dff9aSDan Williams {
471814dff9aSDan Williams struct cxl_cedt_context *ctx = arg;
472814dff9aSDan Williams struct device *dev = ctx->dev;
473814dff9aSDan Williams union acpi_subtable_headers *h;
474814dff9aSDan Williams unsigned long end;
475814dff9aSDan Williams int i;
476814dff9aSDan Williams
4778b3b1c0dSDan Williams if (!is_mock_port(dev) && !is_mock_dev(dev))
478814dff9aSDan Williams return acpi_table_parse_cedt(id, handler_arg, arg);
479814dff9aSDan Williams
480814dff9aSDan Williams if (id == ACPI_CEDT_TYPE_CHBS)
481814dff9aSDan Williams for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
482814dff9aSDan Williams h = (union acpi_subtable_headers *)&mock_cedt.chbs[i];
483814dff9aSDan Williams end = (unsigned long)&mock_cedt.chbs[i + 1];
484814dff9aSDan Williams handler_arg(h, arg, end);
48567dcdd4dSDan Williams }
48667dcdd4dSDan Williams
487814dff9aSDan Williams if (id == ACPI_CEDT_TYPE_CFMWS)
4887a7e6edfSAlison Schofield for (i = cfmws_start; i <= cfmws_end; i++) {
489814dff9aSDan Williams h = (union acpi_subtable_headers *) mock_cfmws[i];
490814dff9aSDan Williams end = (unsigned long) h + mock_cfmws[i]->header.length;
491814dff9aSDan Williams handler_arg(h, arg, end);
492814dff9aSDan Williams }
493814dff9aSDan Williams
4947a7e6edfSAlison Schofield if (id == ACPI_CEDT_TYPE_CXIMS)
4957a7e6edfSAlison Schofield for (i = 0; i < ARRAY_SIZE(mock_cxims); i++) {
4967a7e6edfSAlison Schofield h = (union acpi_subtable_headers *)mock_cxims[i];
4977a7e6edfSAlison Schofield end = (unsigned long)h + mock_cxims[i]->header.length;
4987a7e6edfSAlison Schofield handler_arg(h, arg, end);
4997a7e6edfSAlison Schofield }
5007a7e6edfSAlison Schofield
501814dff9aSDan Williams return 0;
50267dcdd4dSDan Williams }
50367dcdd4dSDan Williams
is_mock_bridge(struct device * dev)50467dcdd4dSDan Williams static bool is_mock_bridge(struct device *dev)
50567dcdd4dSDan Williams {
50667dcdd4dSDan Williams int i;
50767dcdd4dSDan Williams
50867dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
50967dcdd4dSDan Williams if (dev == &cxl_host_bridge[i]->dev)
51067dcdd4dSDan Williams return true;
511e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
512e41c8452SDan Williams if (dev == &cxl_hb_single[i]->dev)
513e41c8452SDan Williams return true;
514c9435dbeSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_rch); i++)
515c9435dbeSDan Williams if (dev == &cxl_rch[i]->dev)
516c9435dbeSDan Williams return true;
517c9435dbeSDan Williams
51898d2d3a2SDan Williams return false;
51998d2d3a2SDan Williams }
52098d2d3a2SDan Williams
is_mock_port(struct device * dev)52198d2d3a2SDan Williams static bool is_mock_port(struct device *dev)
52298d2d3a2SDan Williams {
52398d2d3a2SDan Williams int i;
52498d2d3a2SDan Williams
52598d2d3a2SDan Williams if (is_mock_bridge(dev))
52698d2d3a2SDan Williams return true;
52798d2d3a2SDan Williams
52898d2d3a2SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++)
52998d2d3a2SDan Williams if (dev == &cxl_root_port[i]->dev)
53098d2d3a2SDan Williams return true;
53167dcdd4dSDan Williams
532c1915142SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++)
533c1915142SDan Williams if (dev == &cxl_switch_uport[i]->dev)
534c1915142SDan Williams return true;
535c1915142SDan Williams
536c1915142SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++)
537c1915142SDan Williams if (dev == &cxl_switch_dport[i]->dev)
538c1915142SDan Williams return true;
539c1915142SDan Williams
540e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++)
541e41c8452SDan Williams if (dev == &cxl_root_single[i]->dev)
542e41c8452SDan Williams return true;
543e41c8452SDan Williams
544e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++)
545e41c8452SDan Williams if (dev == &cxl_swu_single[i]->dev)
546e41c8452SDan Williams return true;
547e41c8452SDan Williams
548e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++)
549e41c8452SDan Williams if (dev == &cxl_swd_single[i]->dev)
550e41c8452SDan Williams return true;
551e41c8452SDan Williams
552c1915142SDan Williams if (is_cxl_memdev(dev))
553c1915142SDan Williams return is_mock_dev(dev->parent);
554c1915142SDan Williams
55567dcdd4dSDan Williams return false;
55667dcdd4dSDan Williams }
55767dcdd4dSDan Williams
host_bridge_index(struct acpi_device * adev)55867dcdd4dSDan Williams static int host_bridge_index(struct acpi_device *adev)
55967dcdd4dSDan Williams {
56067dcdd4dSDan Williams return adev - host_bridge;
56167dcdd4dSDan Williams }
56267dcdd4dSDan Williams
find_host_bridge(acpi_handle handle)56367dcdd4dSDan Williams static struct acpi_device *find_host_bridge(acpi_handle handle)
56467dcdd4dSDan Williams {
56567dcdd4dSDan Williams int i;
56667dcdd4dSDan Williams
56767dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
56867dcdd4dSDan Williams if (handle == host_bridge[i].handle)
56967dcdd4dSDan Williams return &host_bridge[i];
57067dcdd4dSDan Williams return NULL;
57167dcdd4dSDan Williams }
57267dcdd4dSDan Williams
57367dcdd4dSDan Williams static acpi_status
mock_acpi_evaluate_integer(acpi_handle handle,acpi_string pathname,struct acpi_object_list * arguments,unsigned long long * data)57467dcdd4dSDan Williams mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname,
57567dcdd4dSDan Williams struct acpi_object_list *arguments,
57667dcdd4dSDan Williams unsigned long long *data)
57767dcdd4dSDan Williams {
57867dcdd4dSDan Williams struct acpi_device *adev = find_host_bridge(handle);
57967dcdd4dSDan Williams
58067dcdd4dSDan Williams if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0)
58167dcdd4dSDan Williams return acpi_evaluate_integer(handle, pathname, arguments, data);
58267dcdd4dSDan Williams
58367dcdd4dSDan Williams *data = host_bridge_index(adev);
58467dcdd4dSDan Williams return AE_OK;
58567dcdd4dSDan Williams }
58667dcdd4dSDan Williams
587c9435dbeSDan Williams static struct pci_bus mock_pci_bus[NR_BRIDGES];
58876f19110SDan Williams static struct acpi_pci_root mock_pci_root[ARRAY_SIZE(mock_pci_bus)] = {
58967dcdd4dSDan Williams [0] = {
59067dcdd4dSDan Williams .bus = &mock_pci_bus[0],
59167dcdd4dSDan Williams },
59267dcdd4dSDan Williams [1] = {
59367dcdd4dSDan Williams .bus = &mock_pci_bus[1],
59467dcdd4dSDan Williams },
59576f19110SDan Williams [2] = {
59676f19110SDan Williams .bus = &mock_pci_bus[2],
59776f19110SDan Williams },
598c9435dbeSDan Williams [3] = {
599c9435dbeSDan Williams .bus = &mock_pci_bus[3],
600c9435dbeSDan Williams },
60176f19110SDan Williams
60267dcdd4dSDan Williams };
60367dcdd4dSDan Williams
is_mock_bus(struct pci_bus * bus)60467dcdd4dSDan Williams static bool is_mock_bus(struct pci_bus *bus)
60567dcdd4dSDan Williams {
60667dcdd4dSDan Williams int i;
60767dcdd4dSDan Williams
60867dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++)
60967dcdd4dSDan Williams if (bus == &mock_pci_bus[i])
61067dcdd4dSDan Williams return true;
61167dcdd4dSDan Williams return false;
61267dcdd4dSDan Williams }
61367dcdd4dSDan Williams
mock_acpi_pci_find_root(acpi_handle handle)61467dcdd4dSDan Williams static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle)
61567dcdd4dSDan Williams {
61667dcdd4dSDan Williams struct acpi_device *adev = find_host_bridge(handle);
61767dcdd4dSDan Williams
61867dcdd4dSDan Williams if (!adev)
61967dcdd4dSDan Williams return acpi_pci_find_root(handle);
62067dcdd4dSDan Williams return &mock_pci_root[host_bridge_index(adev)];
62167dcdd4dSDan Williams }
62267dcdd4dSDan Williams
mock_cxl_setup_hdm(struct cxl_port * port,struct cxl_endpoint_dvsec_info * info)6234474ce56SDave Jiang static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port,
6244474ce56SDave Jiang struct cxl_endpoint_dvsec_info *info)
625d17d0540SDan Williams {
626d17d0540SDan Williams struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL);
627843836bfSYao Xingtao struct device *dev = &port->dev;
628d17d0540SDan Williams
629d17d0540SDan Williams if (!cxlhdm)
630d17d0540SDan Williams return ERR_PTR(-ENOMEM);
631d17d0540SDan Williams
632d17d0540SDan Williams cxlhdm->port = port;
633843836bfSYao Xingtao cxlhdm->interleave_mask = ~0U;
634843836bfSYao Xingtao cxlhdm->iw_cap_mask = ~0UL;
635843836bfSYao Xingtao dev_set_drvdata(dev, cxlhdm);
636d17d0540SDan Williams return cxlhdm;
637d17d0540SDan Williams }
638d17d0540SDan Williams
mock_cxl_add_passthrough_decoder(struct cxl_port * port)639664bf115SDan Williams static int mock_cxl_add_passthrough_decoder(struct cxl_port *port)
640d17d0540SDan Williams {
641d17d0540SDan Williams dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n");
642d17d0540SDan Williams return -EOPNOTSUPP;
643d17d0540SDan Williams }
644d17d0540SDan Williams
6457c7d68dbSDan Williams
6467c7d68dbSDan Williams struct target_map_ctx {
6477c7d68dbSDan Williams int *target_map;
6487c7d68dbSDan Williams int index;
6497c7d68dbSDan Williams int target_count;
6507c7d68dbSDan Williams };
6517c7d68dbSDan Williams
map_targets(struct device * dev,void * data)6527c7d68dbSDan Williams static int map_targets(struct device *dev, void *data)
6537c7d68dbSDan Williams {
6547c7d68dbSDan Williams struct platform_device *pdev = to_platform_device(dev);
6557c7d68dbSDan Williams struct target_map_ctx *ctx = data;
6567c7d68dbSDan Williams
6577c7d68dbSDan Williams ctx->target_map[ctx->index++] = pdev->id;
6587c7d68dbSDan Williams
6597c7d68dbSDan Williams if (ctx->index > ctx->target_count) {
6607c7d68dbSDan Williams dev_WARN_ONCE(dev, 1, "too many targets found?\n");
6617c7d68dbSDan Williams return -ENXIO;
6627c7d68dbSDan Williams }
6637c7d68dbSDan Williams
6647c7d68dbSDan Williams return 0;
6657c7d68dbSDan Williams }
6667c7d68dbSDan Williams
mock_decoder_commit(struct cxl_decoder * cxld)667176baefbSDan Williams static int mock_decoder_commit(struct cxl_decoder *cxld)
668176baefbSDan Williams {
669176baefbSDan Williams struct cxl_port *port = to_cxl_port(cxld->dev.parent);
670176baefbSDan Williams int id = cxld->id;
671176baefbSDan Williams
672176baefbSDan Williams if (cxld->flags & CXL_DECODER_F_ENABLE)
673176baefbSDan Williams return 0;
674176baefbSDan Williams
675176baefbSDan Williams dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
676c56f610fSDave Jiang if (cxl_num_decoders_committed(port) != id) {
677176baefbSDan Williams dev_dbg(&port->dev,
678176baefbSDan Williams "%s: out of order commit, expected decoder%d.%d\n",
679c56f610fSDave Jiang dev_name(&cxld->dev), port->id,
680c56f610fSDave Jiang cxl_num_decoders_committed(port));
681176baefbSDan Williams return -EBUSY;
682176baefbSDan Williams }
683176baefbSDan Williams
684176baefbSDan Williams port->commit_end++;
685176baefbSDan Williams cxld->flags |= CXL_DECODER_F_ENABLE;
686176baefbSDan Williams
687176baefbSDan Williams return 0;
688176baefbSDan Williams }
689176baefbSDan Williams
mock_decoder_reset(struct cxl_decoder * cxld)690*8e1b52c1SDan Williams static void mock_decoder_reset(struct cxl_decoder *cxld)
691176baefbSDan Williams {
692176baefbSDan Williams struct cxl_port *port = to_cxl_port(cxld->dev.parent);
693176baefbSDan Williams int id = cxld->id;
694176baefbSDan Williams
695176baefbSDan Williams if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
696*8e1b52c1SDan Williams return;
697176baefbSDan Williams
698176baefbSDan Williams dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
699*8e1b52c1SDan Williams if (port->commit_end == id)
700*8e1b52c1SDan Williams cxl_port_commit_reap(cxld);
701*8e1b52c1SDan Williams else
702176baefbSDan Williams dev_dbg(&port->dev,
703176baefbSDan Williams "%s: out of order reset, expected decoder%d.%d\n",
704176baefbSDan Williams dev_name(&cxld->dev), port->id, port->commit_end);
705176baefbSDan Williams cxld->flags &= ~CXL_DECODER_F_ENABLE;
706176baefbSDan Williams }
707176baefbSDan Williams
default_mock_decoder(struct cxl_decoder * cxld)7083d8f7ccaSDan Williams static void default_mock_decoder(struct cxl_decoder *cxld)
7093d8f7ccaSDan Williams {
7103d8f7ccaSDan Williams cxld->hpa_range = (struct range){
7113d8f7ccaSDan Williams .start = 0,
7123d8f7ccaSDan Williams .end = -1,
7133d8f7ccaSDan Williams };
7143d8f7ccaSDan Williams
7153d8f7ccaSDan Williams cxld->interleave_ways = 1;
7163d8f7ccaSDan Williams cxld->interleave_granularity = 256;
7175aa39a91SDan Williams cxld->target_type = CXL_DECODER_HOSTONLYMEM;
7183d8f7ccaSDan Williams cxld->commit = mock_decoder_commit;
7193d8f7ccaSDan Williams cxld->reset = mock_decoder_reset;
7203d8f7ccaSDan Williams }
7213d8f7ccaSDan Williams
first_decoder(struct device * dev,void * data)7223d8f7ccaSDan Williams static int first_decoder(struct device *dev, void *data)
7233d8f7ccaSDan Williams {
7243d8f7ccaSDan Williams struct cxl_decoder *cxld;
7253d8f7ccaSDan Williams
7263d8f7ccaSDan Williams if (!is_switch_decoder(dev))
7273d8f7ccaSDan Williams return 0;
7283d8f7ccaSDan Williams cxld = to_cxl_decoder(dev);
7293d8f7ccaSDan Williams if (cxld->id == 0)
7303d8f7ccaSDan Williams return 1;
7313d8f7ccaSDan Williams return 0;
7323d8f7ccaSDan Williams }
7333d8f7ccaSDan Williams
mock_init_hdm_decoder(struct cxl_decoder * cxld)7343d8f7ccaSDan Williams static void mock_init_hdm_decoder(struct cxl_decoder *cxld)
7353d8f7ccaSDan Williams {
7363d8f7ccaSDan Williams struct acpi_cedt_cfmws *window = mock_cfmws[0];
7373d8f7ccaSDan Williams struct platform_device *pdev = NULL;
7383d8f7ccaSDan Williams struct cxl_endpoint_decoder *cxled;
7393d8f7ccaSDan Williams struct cxl_switch_decoder *cxlsd;
7403d8f7ccaSDan Williams struct cxl_port *port, *iter;
7413d8f7ccaSDan Williams const int size = SZ_512M;
7423d8f7ccaSDan Williams struct cxl_memdev *cxlmd;
7433d8f7ccaSDan Williams struct cxl_dport *dport;
7443d8f7ccaSDan Williams struct device *dev;
7453d8f7ccaSDan Williams bool hb0 = false;
7463d8f7ccaSDan Williams u64 base;
7473d8f7ccaSDan Williams int i;
7483d8f7ccaSDan Williams
7493d8f7ccaSDan Williams if (is_endpoint_decoder(&cxld->dev)) {
7503d8f7ccaSDan Williams cxled = to_cxl_endpoint_decoder(&cxld->dev);
7513d8f7ccaSDan Williams cxlmd = cxled_to_memdev(cxled);
7523d8f7ccaSDan Williams WARN_ON(!dev_is_platform(cxlmd->dev.parent));
7533d8f7ccaSDan Williams pdev = to_platform_device(cxlmd->dev.parent);
7543d8f7ccaSDan Williams
7553d8f7ccaSDan Williams /* check is endpoint is attach to host-bridge0 */
7563d8f7ccaSDan Williams port = cxled_to_port(cxled);
7573d8f7ccaSDan Williams do {
7587481653dSDan Williams if (port->uport_dev == &cxl_host_bridge[0]->dev) {
7593d8f7ccaSDan Williams hb0 = true;
7603d8f7ccaSDan Williams break;
7613d8f7ccaSDan Williams }
7623d8f7ccaSDan Williams if (is_cxl_port(port->dev.parent))
7633d8f7ccaSDan Williams port = to_cxl_port(port->dev.parent);
7643d8f7ccaSDan Williams else
7653d8f7ccaSDan Williams port = NULL;
7663d8f7ccaSDan Williams } while (port);
7673d8f7ccaSDan Williams port = cxled_to_port(cxled);
7683d8f7ccaSDan Williams }
7693d8f7ccaSDan Williams
7703d8f7ccaSDan Williams /*
7713d8f7ccaSDan Williams * The first decoder on the first 2 devices on the first switch
7723d8f7ccaSDan Williams * attached to host-bridge0 mock a fake / static RAM region. All
7733d8f7ccaSDan Williams * other decoders are default disabled. Given the round robin
7743d8f7ccaSDan Williams * assignment those devices are named cxl_mem.0, and cxl_mem.4.
7753d8f7ccaSDan Williams *
7763d8f7ccaSDan Williams * See 'cxl list -BMPu -m cxl_mem.0,cxl_mem.4'
7773d8f7ccaSDan Williams */
7783d8f7ccaSDan Williams if (!hb0 || pdev->id % 4 || pdev->id > 4 || cxld->id > 0) {
7793d8f7ccaSDan Williams default_mock_decoder(cxld);
7803d8f7ccaSDan Williams return;
7813d8f7ccaSDan Williams }
7823d8f7ccaSDan Williams
7833d8f7ccaSDan Williams base = window->base_hpa;
7843d8f7ccaSDan Williams cxld->hpa_range = (struct range) {
7853d8f7ccaSDan Williams .start = base,
7863d8f7ccaSDan Williams .end = base + size - 1,
7873d8f7ccaSDan Williams };
7883d8f7ccaSDan Williams
7893d8f7ccaSDan Williams cxld->interleave_ways = 2;
7903d8f7ccaSDan Williams eig_to_granularity(window->granularity, &cxld->interleave_granularity);
7915aa39a91SDan Williams cxld->target_type = CXL_DECODER_HOSTONLYMEM;
7923d8f7ccaSDan Williams cxld->flags = CXL_DECODER_F_ENABLE;
7933d8f7ccaSDan Williams cxled->state = CXL_DECODER_STATE_AUTO;
7943d8f7ccaSDan Williams port->commit_end = cxld->id;
7953d8f7ccaSDan Williams devm_cxl_dpa_reserve(cxled, 0, size / cxld->interleave_ways, 0);
7963d8f7ccaSDan Williams cxld->commit = mock_decoder_commit;
7973d8f7ccaSDan Williams cxld->reset = mock_decoder_reset;
7983d8f7ccaSDan Williams
7993d8f7ccaSDan Williams /*
8003d8f7ccaSDan Williams * Now that endpoint decoder is set up, walk up the hierarchy
8013d8f7ccaSDan Williams * and setup the switch and root port decoders targeting @cxlmd.
8023d8f7ccaSDan Williams */
8033d8f7ccaSDan Williams iter = port;
8043d8f7ccaSDan Williams for (i = 0; i < 2; i++) {
8053d8f7ccaSDan Williams dport = iter->parent_dport;
8063d8f7ccaSDan Williams iter = dport->port;
8073d8f7ccaSDan Williams dev = device_find_child(&iter->dev, NULL, first_decoder);
8083d8f7ccaSDan Williams /*
8093d8f7ccaSDan Williams * Ancestor ports are guaranteed to be enumerated before
8103d8f7ccaSDan Williams * @port, and all ports have at least one decoder.
8113d8f7ccaSDan Williams */
8123d8f7ccaSDan Williams if (WARN_ON(!dev))
8133d8f7ccaSDan Williams continue;
8143d8f7ccaSDan Williams cxlsd = to_cxl_switch_decoder(dev);
8153d8f7ccaSDan Williams if (i == 0) {
8163d8f7ccaSDan Williams /* put cxl_mem.4 second in the decode order */
8173d8f7ccaSDan Williams if (pdev->id == 4)
8183d8f7ccaSDan Williams cxlsd->target[1] = dport;
8193d8f7ccaSDan Williams else
8203d8f7ccaSDan Williams cxlsd->target[0] = dport;
8213d8f7ccaSDan Williams } else
8223d8f7ccaSDan Williams cxlsd->target[0] = dport;
8233d8f7ccaSDan Williams cxld = &cxlsd->cxld;
8245aa39a91SDan Williams cxld->target_type = CXL_DECODER_HOSTONLYMEM;
8253d8f7ccaSDan Williams cxld->flags = CXL_DECODER_F_ENABLE;
8263d8f7ccaSDan Williams iter->commit_end = 0;
8273d8f7ccaSDan Williams /*
8283d8f7ccaSDan Williams * Switch targets 2 endpoints, while host bridge targets
8293d8f7ccaSDan Williams * one root port
8303d8f7ccaSDan Williams */
8313d8f7ccaSDan Williams if (i == 0)
8323d8f7ccaSDan Williams cxld->interleave_ways = 2;
8333d8f7ccaSDan Williams else
8343d8f7ccaSDan Williams cxld->interleave_ways = 1;
8358a9ab903SJim Harris cxld->interleave_granularity = 4096;
8363d8f7ccaSDan Williams cxld->hpa_range = (struct range) {
8373d8f7ccaSDan Williams .start = base,
8383d8f7ccaSDan Williams .end = base + size - 1,
8393d8f7ccaSDan Williams };
8403d8f7ccaSDan Williams put_device(dev);
8413d8f7ccaSDan Williams }
8423d8f7ccaSDan Williams }
8433d8f7ccaSDan Williams
mock_cxl_enumerate_decoders(struct cxl_hdm * cxlhdm,struct cxl_endpoint_dvsec_info * info)844b777e9beSDave Jiang static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
845b777e9beSDave Jiang struct cxl_endpoint_dvsec_info *info)
846d17d0540SDan Williams {
8477c7d68dbSDan Williams struct cxl_port *port = cxlhdm->port;
8487c7d68dbSDan Williams struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
8497c7d68dbSDan Williams int target_count, i;
8507c7d68dbSDan Williams
8517c7d68dbSDan Williams if (is_cxl_endpoint(port))
8527c7d68dbSDan Williams target_count = 0;
8537c7d68dbSDan Williams else if (is_cxl_root(parent_port))
8547c7d68dbSDan Williams target_count = NR_CXL_ROOT_PORTS;
8557c7d68dbSDan Williams else
8567c7d68dbSDan Williams target_count = NR_CXL_SWITCH_PORTS;
8577c7d68dbSDan Williams
8587c7d68dbSDan Williams for (i = 0; i < NR_CXL_PORT_DECODERS; i++) {
8597c7d68dbSDan Williams int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
8607c7d68dbSDan Williams struct target_map_ctx ctx = {
8617c7d68dbSDan Williams .target_map = target_map,
8627c7d68dbSDan Williams .target_count = target_count,
8637c7d68dbSDan Williams };
8647c7d68dbSDan Williams struct cxl_decoder *cxld;
8657c7d68dbSDan Williams int rc;
8667c7d68dbSDan Williams
867e636479eSDan Williams if (target_count) {
868e636479eSDan Williams struct cxl_switch_decoder *cxlsd;
869e636479eSDan Williams
870e636479eSDan Williams cxlsd = cxl_switch_decoder_alloc(port, target_count);
871e636479eSDan Williams if (IS_ERR(cxlsd)) {
872e636479eSDan Williams dev_warn(&port->dev,
873e636479eSDan Williams "Failed to allocate the decoder\n");
874e636479eSDan Williams return PTR_ERR(cxlsd);
875e636479eSDan Williams }
876e636479eSDan Williams cxld = &cxlsd->cxld;
877e636479eSDan Williams } else {
8783bf65915SDan Williams struct cxl_endpoint_decoder *cxled;
8793bf65915SDan Williams
8803bf65915SDan Williams cxled = cxl_endpoint_decoder_alloc(port);
8813bf65915SDan Williams
8823bf65915SDan Williams if (IS_ERR(cxled)) {
8837c7d68dbSDan Williams dev_warn(&port->dev,
8847c7d68dbSDan Williams "Failed to allocate the decoder\n");
8853bf65915SDan Williams return PTR_ERR(cxled);
8867c7d68dbSDan Williams }
8873bf65915SDan Williams cxld = &cxled->cxld;
888e636479eSDan Williams }
8897c7d68dbSDan Williams
8903d8f7ccaSDan Williams mock_init_hdm_decoder(cxld);
8917c7d68dbSDan Williams
8927c7d68dbSDan Williams if (target_count) {
8937481653dSDan Williams rc = device_for_each_child(port->uport_dev, &ctx,
8947c7d68dbSDan Williams map_targets);
8957c7d68dbSDan Williams if (rc) {
8967c7d68dbSDan Williams put_device(&cxld->dev);
8977c7d68dbSDan Williams return rc;
8987c7d68dbSDan Williams }
8997c7d68dbSDan Williams }
9007c7d68dbSDan Williams
9017c7d68dbSDan Williams rc = cxl_decoder_add_locked(cxld, target_map);
9027c7d68dbSDan Williams if (rc) {
9037c7d68dbSDan Williams put_device(&cxld->dev);
9047c7d68dbSDan Williams dev_err(&port->dev, "Failed to add decoder\n");
9057c7d68dbSDan Williams return rc;
9067c7d68dbSDan Williams }
9077c7d68dbSDan Williams
9087c7d68dbSDan Williams rc = cxl_decoder_autoremove(&port->dev, cxld);
9097c7d68dbSDan Williams if (rc)
9107c7d68dbSDan Williams return rc;
9117c7d68dbSDan Williams dev_dbg(&cxld->dev, "Added to port %s\n", dev_name(&port->dev));
9127c7d68dbSDan Williams }
9137c7d68dbSDan Williams
914d17d0540SDan Williams return 0;
915d17d0540SDan Williams }
916d17d0540SDan Williams
mock_cxl_port_enumerate_dports(struct cxl_port * port)917664bf115SDan Williams static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
91898d2d3a2SDan Williams {
9197c7d68dbSDan Williams struct platform_device **array;
9207c7d68dbSDan Williams int i, array_size;
92198d2d3a2SDan Williams
9227c7d68dbSDan Williams if (port->depth == 1) {
9237481653dSDan Williams if (is_multi_bridge(port->uport_dev)) {
9247c7d68dbSDan Williams array_size = ARRAY_SIZE(cxl_root_port);
9257c7d68dbSDan Williams array = cxl_root_port;
9267481653dSDan Williams } else if (is_single_bridge(port->uport_dev)) {
927e41c8452SDan Williams array_size = ARRAY_SIZE(cxl_root_single);
928e41c8452SDan Williams array = cxl_root_single;
929e41c8452SDan Williams } else {
930e41c8452SDan Williams dev_dbg(&port->dev, "%s: unknown bridge type\n",
9317481653dSDan Williams dev_name(port->uport_dev));
932e41c8452SDan Williams return -ENXIO;
933e41c8452SDan Williams }
9347c7d68dbSDan Williams } else if (port->depth == 2) {
935e41c8452SDan Williams struct cxl_port *parent = to_cxl_port(port->dev.parent);
936e41c8452SDan Williams
9377481653dSDan Williams if (is_multi_bridge(parent->uport_dev)) {
9387c7d68dbSDan Williams array_size = ARRAY_SIZE(cxl_switch_dport);
9397c7d68dbSDan Williams array = cxl_switch_dport;
9407481653dSDan Williams } else if (is_single_bridge(parent->uport_dev)) {
941e41c8452SDan Williams array_size = ARRAY_SIZE(cxl_swd_single);
942e41c8452SDan Williams array = cxl_swd_single;
943e41c8452SDan Williams } else {
944e41c8452SDan Williams dev_dbg(&port->dev, "%s: unknown bridge type\n",
9457481653dSDan Williams dev_name(port->uport_dev));
946e41c8452SDan Williams return -ENXIO;
947e41c8452SDan Williams }
9487c7d68dbSDan Williams } else {
9497c7d68dbSDan Williams dev_WARN_ONCE(&port->dev, 1, "unexpected depth %d\n",
9507c7d68dbSDan Williams port->depth);
9517c7d68dbSDan Williams return -ENXIO;
95298d2d3a2SDan Williams }
95398d2d3a2SDan Williams
9547c7d68dbSDan Williams for (i = 0; i < array_size; i++) {
9557c7d68dbSDan Williams struct platform_device *pdev = array[i];
956c1915142SDan Williams struct cxl_dport *dport;
957c1915142SDan Williams
9587481653dSDan Williams if (pdev->dev.parent != port->uport_dev) {
959e41c8452SDan Williams dev_dbg(&port->dev, "%s: mismatch parent %s\n",
9607481653dSDan Williams dev_name(port->uport_dev),
961e41c8452SDan Williams dev_name(pdev->dev.parent));
962c1915142SDan Williams continue;
963e41c8452SDan Williams }
964c1915142SDan Williams
965c1915142SDan Williams dport = devm_cxl_add_dport(port, &pdev->dev, pdev->id,
966c1915142SDan Williams CXL_RESOURCE_NONE);
967c1915142SDan Williams
96858eef878SRobert Richter if (IS_ERR(dport))
969c1915142SDan Williams return PTR_ERR(dport);
970c1915142SDan Williams }
971c1915142SDan Williams
97298d2d3a2SDan Williams return 0;
97398d2d3a2SDan Williams }
97498d2d3a2SDan Williams
97567dcdd4dSDan Williams static struct cxl_mock_ops cxl_mock_ops = {
97667dcdd4dSDan Williams .is_mock_adev = is_mock_adev,
97767dcdd4dSDan Williams .is_mock_bridge = is_mock_bridge,
97867dcdd4dSDan Williams .is_mock_bus = is_mock_bus,
97967dcdd4dSDan Williams .is_mock_port = is_mock_port,
98067dcdd4dSDan Williams .is_mock_dev = is_mock_dev,
981814dff9aSDan Williams .acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
98267dcdd4dSDan Williams .acpi_evaluate_integer = mock_acpi_evaluate_integer,
98367dcdd4dSDan Williams .acpi_pci_find_root = mock_acpi_pci_find_root,
98498d2d3a2SDan Williams .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
985d17d0540SDan Williams .devm_cxl_setup_hdm = mock_cxl_setup_hdm,
986d17d0540SDan Williams .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,
987d17d0540SDan Williams .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,
98867dcdd4dSDan Williams .list = LIST_HEAD_INIT(cxl_mock_ops.list),
98967dcdd4dSDan Williams };
99067dcdd4dSDan Williams
mock_companion(struct acpi_device * adev,struct device * dev)99167dcdd4dSDan Williams static void mock_companion(struct acpi_device *adev, struct device *dev)
99267dcdd4dSDan Williams {
99367dcdd4dSDan Williams device_initialize(&adev->dev);
99467dcdd4dSDan Williams fwnode_init(&adev->fwnode, NULL);
99567dcdd4dSDan Williams dev->fwnode = &adev->fwnode;
99667dcdd4dSDan Williams adev->fwnode.dev = dev;
99767dcdd4dSDan Williams }
99867dcdd4dSDan Williams
99967dcdd4dSDan Williams #ifndef SZ_64G
100067dcdd4dSDan Williams #define SZ_64G (SZ_32G * 2)
100167dcdd4dSDan Williams #endif
100267dcdd4dSDan Williams
cxl_rch_init(void)1003c9435dbeSDan Williams static __init int cxl_rch_init(void)
1004c9435dbeSDan Williams {
1005c9435dbeSDan Williams int rc, i;
1006c9435dbeSDan Williams
1007c9435dbeSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_rch); i++) {
1008c9435dbeSDan Williams int idx = NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + i;
1009c9435dbeSDan Williams struct acpi_device *adev = &host_bridge[idx];
1010c9435dbeSDan Williams struct platform_device *pdev;
1011c9435dbeSDan Williams
1012c9435dbeSDan Williams pdev = platform_device_alloc("cxl_host_bridge", idx);
1013c9435dbeSDan Williams if (!pdev)
1014c9435dbeSDan Williams goto err_bridge;
1015c9435dbeSDan Williams
1016c9435dbeSDan Williams mock_companion(adev, &pdev->dev);
1017c9435dbeSDan Williams rc = platform_device_add(pdev);
1018c9435dbeSDan Williams if (rc) {
1019c9435dbeSDan Williams platform_device_put(pdev);
1020c9435dbeSDan Williams goto err_bridge;
1021c9435dbeSDan Williams }
1022c9435dbeSDan Williams
1023c9435dbeSDan Williams cxl_rch[i] = pdev;
1024c9435dbeSDan Williams mock_pci_bus[idx].bridge = &pdev->dev;
1025c9435dbeSDan Williams rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
1026c9435dbeSDan Williams "firmware_node");
1027c9435dbeSDan Williams if (rc)
1028c9435dbeSDan Williams goto err_bridge;
1029c9435dbeSDan Williams }
1030c9435dbeSDan Williams
1031c9435dbeSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {
1032c9435dbeSDan Williams int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;
1033c9435dbeSDan Williams struct platform_device *rch = cxl_rch[i];
1034c9435dbeSDan Williams struct platform_device *pdev;
1035c9435dbeSDan Williams
1036c9435dbeSDan Williams pdev = platform_device_alloc("cxl_rcd", idx);
1037c9435dbeSDan Williams if (!pdev)
1038c9435dbeSDan Williams goto err_mem;
1039c9435dbeSDan Williams pdev->dev.parent = &rch->dev;
1040c9435dbeSDan Williams set_dev_node(&pdev->dev, i % 2);
1041c9435dbeSDan Williams
1042c9435dbeSDan Williams rc = platform_device_add(pdev);
1043c9435dbeSDan Williams if (rc) {
1044c9435dbeSDan Williams platform_device_put(pdev);
1045c9435dbeSDan Williams goto err_mem;
1046c9435dbeSDan Williams }
1047c9435dbeSDan Williams cxl_rcd[i] = pdev;
1048c9435dbeSDan Williams }
1049c9435dbeSDan Williams
1050c9435dbeSDan Williams return 0;
1051c9435dbeSDan Williams
1052c9435dbeSDan Williams err_mem:
1053c9435dbeSDan Williams for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
1054c9435dbeSDan Williams platform_device_unregister(cxl_rcd[i]);
1055c9435dbeSDan Williams err_bridge:
1056c9435dbeSDan Williams for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
1057c9435dbeSDan Williams struct platform_device *pdev = cxl_rch[i];
1058c9435dbeSDan Williams
1059c9435dbeSDan Williams if (!pdev)
1060c9435dbeSDan Williams continue;
1061c9435dbeSDan Williams sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
1062c9435dbeSDan Williams platform_device_unregister(cxl_rch[i]);
1063c9435dbeSDan Williams }
1064c9435dbeSDan Williams
1065c9435dbeSDan Williams return rc;
1066c9435dbeSDan Williams }
1067c9435dbeSDan Williams
cxl_rch_exit(void)1068c9435dbeSDan Williams static void cxl_rch_exit(void)
1069c9435dbeSDan Williams {
1070c9435dbeSDan Williams int i;
1071c9435dbeSDan Williams
1072c9435dbeSDan Williams for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
1073c9435dbeSDan Williams platform_device_unregister(cxl_rcd[i]);
1074c9435dbeSDan Williams for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
1075c9435dbeSDan Williams struct platform_device *pdev = cxl_rch[i];
1076c9435dbeSDan Williams
1077c9435dbeSDan Williams if (!pdev)
1078c9435dbeSDan Williams continue;
1079c9435dbeSDan Williams sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
1080c9435dbeSDan Williams platform_device_unregister(cxl_rch[i]);
1081c9435dbeSDan Williams }
1082c9435dbeSDan Williams }
1083c9435dbeSDan Williams
cxl_single_init(void)1084e41c8452SDan Williams static __init int cxl_single_init(void)
1085e41c8452SDan Williams {
1086e41c8452SDan Williams int i, rc;
1087e41c8452SDan Williams
1088e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++) {
1089e41c8452SDan Williams struct acpi_device *adev =
1090e41c8452SDan Williams &host_bridge[NR_CXL_HOST_BRIDGES + i];
1091e41c8452SDan Williams struct platform_device *pdev;
1092e41c8452SDan Williams
1093e41c8452SDan Williams pdev = platform_device_alloc("cxl_host_bridge",
1094e41c8452SDan Williams NR_CXL_HOST_BRIDGES + i);
1095e41c8452SDan Williams if (!pdev)
1096e41c8452SDan Williams goto err_bridge;
1097e41c8452SDan Williams
1098e41c8452SDan Williams mock_companion(adev, &pdev->dev);
1099e41c8452SDan Williams rc = platform_device_add(pdev);
1100e41c8452SDan Williams if (rc) {
1101e41c8452SDan Williams platform_device_put(pdev);
1102e41c8452SDan Williams goto err_bridge;
1103e41c8452SDan Williams }
1104e41c8452SDan Williams
1105e41c8452SDan Williams cxl_hb_single[i] = pdev;
110676f19110SDan Williams mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev;
1107e41c8452SDan Williams rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
1108e41c8452SDan Williams "physical_node");
1109e41c8452SDan Williams if (rc)
1110e41c8452SDan Williams goto err_bridge;
1111e41c8452SDan Williams }
1112e41c8452SDan Williams
1113e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++) {
1114e41c8452SDan Williams struct platform_device *bridge =
1115e41c8452SDan Williams cxl_hb_single[i % ARRAY_SIZE(cxl_hb_single)];
1116e41c8452SDan Williams struct platform_device *pdev;
1117e41c8452SDan Williams
1118e41c8452SDan Williams pdev = platform_device_alloc("cxl_root_port",
1119e41c8452SDan Williams NR_MULTI_ROOT + i);
1120e41c8452SDan Williams if (!pdev)
1121e41c8452SDan Williams goto err_port;
1122e41c8452SDan Williams pdev->dev.parent = &bridge->dev;
1123e41c8452SDan Williams
1124e41c8452SDan Williams rc = platform_device_add(pdev);
1125e41c8452SDan Williams if (rc) {
1126e41c8452SDan Williams platform_device_put(pdev);
1127e41c8452SDan Williams goto err_port;
1128e41c8452SDan Williams }
1129e41c8452SDan Williams cxl_root_single[i] = pdev;
1130e41c8452SDan Williams }
1131e41c8452SDan Williams
1132e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) {
1133e41c8452SDan Williams struct platform_device *root_port = cxl_root_single[i];
1134e41c8452SDan Williams struct platform_device *pdev;
1135e41c8452SDan Williams
1136e41c8452SDan Williams pdev = platform_device_alloc("cxl_switch_uport",
1137e41c8452SDan Williams NR_MULTI_ROOT + i);
1138e41c8452SDan Williams if (!pdev)
1139e41c8452SDan Williams goto err_uport;
1140e41c8452SDan Williams pdev->dev.parent = &root_port->dev;
1141e41c8452SDan Williams
1142e41c8452SDan Williams rc = platform_device_add(pdev);
1143e41c8452SDan Williams if (rc) {
1144e41c8452SDan Williams platform_device_put(pdev);
1145e41c8452SDan Williams goto err_uport;
1146e41c8452SDan Williams }
1147e41c8452SDan Williams cxl_swu_single[i] = pdev;
1148e41c8452SDan Williams }
1149e41c8452SDan Williams
1150e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) {
1151e41c8452SDan Williams struct platform_device *uport =
1152e41c8452SDan Williams cxl_swu_single[i % ARRAY_SIZE(cxl_swu_single)];
1153e41c8452SDan Williams struct platform_device *pdev;
1154e41c8452SDan Williams
1155e41c8452SDan Williams pdev = platform_device_alloc("cxl_switch_dport",
1156e41c8452SDan Williams i + NR_MEM_MULTI);
1157e41c8452SDan Williams if (!pdev)
1158e41c8452SDan Williams goto err_dport;
1159e41c8452SDan Williams pdev->dev.parent = &uport->dev;
1160e41c8452SDan Williams
1161e41c8452SDan Williams rc = platform_device_add(pdev);
1162e41c8452SDan Williams if (rc) {
1163e41c8452SDan Williams platform_device_put(pdev);
1164e41c8452SDan Williams goto err_dport;
1165e41c8452SDan Williams }
1166e41c8452SDan Williams cxl_swd_single[i] = pdev;
1167e41c8452SDan Williams }
1168e41c8452SDan Williams
1169e41c8452SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) {
1170e41c8452SDan Williams struct platform_device *dport = cxl_swd_single[i];
1171e41c8452SDan Williams struct platform_device *pdev;
1172e41c8452SDan Williams
1173e41c8452SDan Williams pdev = platform_device_alloc("cxl_mem", NR_MEM_MULTI + i);
1174e41c8452SDan Williams if (!pdev)
1175e41c8452SDan Williams goto err_mem;
1176e41c8452SDan Williams pdev->dev.parent = &dport->dev;
1177e41c8452SDan Williams set_dev_node(&pdev->dev, i % 2);
1178e41c8452SDan Williams
1179e41c8452SDan Williams rc = platform_device_add(pdev);
1180e41c8452SDan Williams if (rc) {
1181e41c8452SDan Williams platform_device_put(pdev);
1182e41c8452SDan Williams goto err_mem;
1183e41c8452SDan Williams }
1184e41c8452SDan Williams cxl_mem_single[i] = pdev;
1185e41c8452SDan Williams }
1186e41c8452SDan Williams
1187e41c8452SDan Williams return 0;
1188e41c8452SDan Williams
1189e41c8452SDan Williams err_mem:
1190e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
1191e41c8452SDan Williams platform_device_unregister(cxl_mem_single[i]);
1192e41c8452SDan Williams err_dport:
1193e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
1194e41c8452SDan Williams platform_device_unregister(cxl_swd_single[i]);
1195e41c8452SDan Williams err_uport:
1196e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
1197e41c8452SDan Williams platform_device_unregister(cxl_swu_single[i]);
1198e41c8452SDan Williams err_port:
1199e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)
1200e41c8452SDan Williams platform_device_unregister(cxl_root_single[i]);
1201e41c8452SDan Williams err_bridge:
1202e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {
1203e41c8452SDan Williams struct platform_device *pdev = cxl_hb_single[i];
1204e41c8452SDan Williams
1205e41c8452SDan Williams if (!pdev)
1206e41c8452SDan Williams continue;
1207e41c8452SDan Williams sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1208e41c8452SDan Williams platform_device_unregister(cxl_hb_single[i]);
1209e41c8452SDan Williams }
1210e41c8452SDan Williams
1211e41c8452SDan Williams return rc;
1212e41c8452SDan Williams }
1213e41c8452SDan Williams
cxl_single_exit(void)1214e41c8452SDan Williams static void cxl_single_exit(void)
1215e41c8452SDan Williams {
1216e41c8452SDan Williams int i;
1217e41c8452SDan Williams
1218e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
1219e41c8452SDan Williams platform_device_unregister(cxl_mem_single[i]);
1220e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
1221e41c8452SDan Williams platform_device_unregister(cxl_swd_single[i]);
1222e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
1223e41c8452SDan Williams platform_device_unregister(cxl_swu_single[i]);
1224e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)
1225e41c8452SDan Williams platform_device_unregister(cxl_root_single[i]);
1226e41c8452SDan Williams for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {
1227e41c8452SDan Williams struct platform_device *pdev = cxl_hb_single[i];
1228e41c8452SDan Williams
1229e41c8452SDan Williams if (!pdev)
1230e41c8452SDan Williams continue;
1231e41c8452SDan Williams sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1232e41c8452SDan Williams platform_device_unregister(cxl_hb_single[i]);
1233e41c8452SDan Williams }
1234e41c8452SDan Williams }
1235e41c8452SDan Williams
cxl_test_init(void)123667dcdd4dSDan Williams static __init int cxl_test_init(void)
123767dcdd4dSDan Williams {
123867dcdd4dSDan Williams int rc, i;
123967dcdd4dSDan Williams
12408c149eb0SDan Williams cxl_acpi_test();
12418c149eb0SDan Williams cxl_core_test();
12428c149eb0SDan Williams cxl_mem_test();
12438c149eb0SDan Williams cxl_pmem_test();
12448c149eb0SDan Williams cxl_port_test();
12458c149eb0SDan Williams
124667dcdd4dSDan Williams register_cxl_mock_ops(&cxl_mock_ops);
124767dcdd4dSDan Williams
124867dcdd4dSDan Williams cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE);
124967dcdd4dSDan Williams if (!cxl_mock_pool) {
125067dcdd4dSDan Williams rc = -ENOMEM;
125167dcdd4dSDan Williams goto err_gen_pool_create;
125267dcdd4dSDan Williams }
125367dcdd4dSDan Williams
1254b2f3b74eSDan Williams rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,
1255b2f3b74eSDan Williams SZ_64G, NUMA_NO_NODE);
125667dcdd4dSDan Williams if (rc)
125767dcdd4dSDan Williams goto err_gen_pool_add;
125867dcdd4dSDan Williams
12597a7e6edfSAlison Schofield if (interleave_arithmetic == 1) {
12607a7e6edfSAlison Schofield cfmws_start = CFMWS_XOR_ARRAY_START;
12617a7e6edfSAlison Schofield cfmws_end = CFMWS_XOR_ARRAY_END;
12627a7e6edfSAlison Schofield } else {
12637a7e6edfSAlison Schofield cfmws_start = CFMWS_MOD_ARRAY_START;
12647a7e6edfSAlison Schofield cfmws_end = CFMWS_MOD_ARRAY_END;
12657a7e6edfSAlison Schofield }
12667a7e6edfSAlison Schofield
126767dcdd4dSDan Williams rc = populate_cedt();
126867dcdd4dSDan Williams if (rc)
126967dcdd4dSDan Williams goto err_populate;
127067dcdd4dSDan Williams
127167dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) {
127267dcdd4dSDan Williams struct acpi_device *adev = &host_bridge[i];
127367dcdd4dSDan Williams struct platform_device *pdev;
127467dcdd4dSDan Williams
127567dcdd4dSDan Williams pdev = platform_device_alloc("cxl_host_bridge", i);
127667dcdd4dSDan Williams if (!pdev)
127767dcdd4dSDan Williams goto err_bridge;
127867dcdd4dSDan Williams
127967dcdd4dSDan Williams mock_companion(adev, &pdev->dev);
128067dcdd4dSDan Williams rc = platform_device_add(pdev);
128167dcdd4dSDan Williams if (rc) {
128267dcdd4dSDan Williams platform_device_put(pdev);
128367dcdd4dSDan Williams goto err_bridge;
128467dcdd4dSDan Williams }
128564cda3aeSDan Williams
128667dcdd4dSDan Williams cxl_host_bridge[i] = pdev;
128776f19110SDan Williams mock_pci_bus[i].bridge = &pdev->dev;
128864cda3aeSDan Williams rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
128964cda3aeSDan Williams "physical_node");
129064cda3aeSDan Williams if (rc)
129164cda3aeSDan Williams goto err_bridge;
129267dcdd4dSDan Williams }
129367dcdd4dSDan Williams
129467dcdd4dSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) {
129567dcdd4dSDan Williams struct platform_device *bridge =
1296a4a0ce24SDan Williams cxl_host_bridge[i % ARRAY_SIZE(cxl_host_bridge)];
129767dcdd4dSDan Williams struct platform_device *pdev;
129867dcdd4dSDan Williams
129967dcdd4dSDan Williams pdev = platform_device_alloc("cxl_root_port", i);
130067dcdd4dSDan Williams if (!pdev)
130167dcdd4dSDan Williams goto err_port;
130267dcdd4dSDan Williams pdev->dev.parent = &bridge->dev;
130367dcdd4dSDan Williams
130467dcdd4dSDan Williams rc = platform_device_add(pdev);
130567dcdd4dSDan Williams if (rc) {
130667dcdd4dSDan Williams platform_device_put(pdev);
130767dcdd4dSDan Williams goto err_port;
130867dcdd4dSDan Williams }
130967dcdd4dSDan Williams cxl_root_port[i] = pdev;
131067dcdd4dSDan Williams }
131167dcdd4dSDan Williams
1312c1915142SDan Williams BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port));
1313c1915142SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++) {
1314c1915142SDan Williams struct platform_device *root_port = cxl_root_port[i];
1315c1915142SDan Williams struct platform_device *pdev;
1316c1915142SDan Williams
1317c1915142SDan Williams pdev = platform_device_alloc("cxl_switch_uport", i);
1318c1915142SDan Williams if (!pdev)
131986e86c3cSDan Williams goto err_uport;
1320c1915142SDan Williams pdev->dev.parent = &root_port->dev;
1321c1915142SDan Williams
1322c1915142SDan Williams rc = platform_device_add(pdev);
1323c1915142SDan Williams if (rc) {
1324c1915142SDan Williams platform_device_put(pdev);
1325c1915142SDan Williams goto err_uport;
1326c1915142SDan Williams }
1327c1915142SDan Williams cxl_switch_uport[i] = pdev;
1328c1915142SDan Williams }
1329c1915142SDan Williams
1330c1915142SDan Williams for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) {
1331c1915142SDan Williams struct platform_device *uport =
1332c1915142SDan Williams cxl_switch_uport[i % ARRAY_SIZE(cxl_switch_uport)];
1333c1915142SDan Williams struct platform_device *pdev;
1334c1915142SDan Williams
1335c1915142SDan Williams pdev = platform_device_alloc("cxl_switch_dport", i);
1336c1915142SDan Williams if (!pdev)
133786e86c3cSDan Williams goto err_dport;
1338c1915142SDan Williams pdev->dev.parent = &uport->dev;
1339c1915142SDan Williams
1340c1915142SDan Williams rc = platform_device_add(pdev);
1341c1915142SDan Williams if (rc) {
1342c1915142SDan Williams platform_device_put(pdev);
1343c1915142SDan Williams goto err_dport;
1344c1915142SDan Williams }
1345c1915142SDan Williams cxl_switch_dport[i] = pdev;
1346c1915142SDan Williams }
1347c1915142SDan Williams
13487d3eb23cSDan Williams for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {
1349c1915142SDan Williams struct platform_device *dport = cxl_switch_dport[i];
13507d3eb23cSDan Williams struct platform_device *pdev;
13517d3eb23cSDan Williams
1352e7ad1bf6SDan Williams pdev = platform_device_alloc("cxl_mem", i);
13537d3eb23cSDan Williams if (!pdev)
13547d3eb23cSDan Williams goto err_mem;
1355c1915142SDan Williams pdev->dev.parent = &dport->dev;
1356cf1f6877SDan Williams set_dev_node(&pdev->dev, i % 2);
13577d3eb23cSDan Williams
13587d3eb23cSDan Williams rc = platform_device_add(pdev);
13597d3eb23cSDan Williams if (rc) {
13607d3eb23cSDan Williams platform_device_put(pdev);
13617d3eb23cSDan Williams goto err_mem;
13627d3eb23cSDan Williams }
13637d3eb23cSDan Williams cxl_mem[i] = pdev;
13647d3eb23cSDan Williams }
13657d3eb23cSDan Williams
1366e41c8452SDan Williams rc = cxl_single_init();
1367e41c8452SDan Williams if (rc)
1368e41c8452SDan Williams goto err_mem;
1369e41c8452SDan Williams
1370c9435dbeSDan Williams rc = cxl_rch_init();
1371c9435dbeSDan Williams if (rc)
1372c9435dbeSDan Williams goto err_single;
1373c9435dbeSDan Williams
137467dcdd4dSDan Williams cxl_acpi = platform_device_alloc("cxl_acpi", 0);
137567dcdd4dSDan Williams if (!cxl_acpi)
1376c9435dbeSDan Williams goto err_rch;
137767dcdd4dSDan Williams
137867dcdd4dSDan Williams mock_companion(&acpi0017_mock, &cxl_acpi->dev);
137967dcdd4dSDan Williams acpi0017_mock.dev.bus = &platform_bus_type;
138067dcdd4dSDan Williams
138167dcdd4dSDan Williams rc = platform_device_add(cxl_acpi);
138267dcdd4dSDan Williams if (rc)
138367dcdd4dSDan Williams goto err_add;
138467dcdd4dSDan Williams
138567dcdd4dSDan Williams return 0;
138667dcdd4dSDan Williams
138767dcdd4dSDan Williams err_add:
138867dcdd4dSDan Williams platform_device_put(cxl_acpi);
1389c9435dbeSDan Williams err_rch:
1390c9435dbeSDan Williams cxl_rch_exit();
1391e41c8452SDan Williams err_single:
1392e41c8452SDan Williams cxl_single_exit();
13937d3eb23cSDan Williams err_mem:
13947d3eb23cSDan Williams for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
13957d3eb23cSDan Williams platform_device_unregister(cxl_mem[i]);
1396c1915142SDan Williams err_dport:
1397c1915142SDan Williams for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
1398c1915142SDan Williams platform_device_unregister(cxl_switch_dport[i]);
1399c1915142SDan Williams err_uport:
1400c1915142SDan Williams for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
1401c1915142SDan Williams platform_device_unregister(cxl_switch_uport[i]);
140267dcdd4dSDan Williams err_port:
140367dcdd4dSDan Williams for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
140467dcdd4dSDan Williams platform_device_unregister(cxl_root_port[i]);
140567dcdd4dSDan Williams err_bridge:
140664cda3aeSDan Williams for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
140764cda3aeSDan Williams struct platform_device *pdev = cxl_host_bridge[i];
140864cda3aeSDan Williams
140964cda3aeSDan Williams if (!pdev)
141064cda3aeSDan Williams continue;
141164cda3aeSDan Williams sysfs_remove_link(&pdev->dev.kobj, "physical_node");
141267dcdd4dSDan Williams platform_device_unregister(cxl_host_bridge[i]);
141364cda3aeSDan Williams }
141467dcdd4dSDan Williams err_populate:
141567dcdd4dSDan Williams depopulate_all_mock_resources();
141667dcdd4dSDan Williams err_gen_pool_add:
141767dcdd4dSDan Williams gen_pool_destroy(cxl_mock_pool);
141867dcdd4dSDan Williams err_gen_pool_create:
141967dcdd4dSDan Williams unregister_cxl_mock_ops(&cxl_mock_ops);
142067dcdd4dSDan Williams return rc;
142167dcdd4dSDan Williams }
142267dcdd4dSDan Williams
cxl_test_exit(void)142367dcdd4dSDan Williams static __exit void cxl_test_exit(void)
142467dcdd4dSDan Williams {
142567dcdd4dSDan Williams int i;
142667dcdd4dSDan Williams
142767dcdd4dSDan Williams platform_device_unregister(cxl_acpi);
1428c9435dbeSDan Williams cxl_rch_exit();
1429e41c8452SDan Williams cxl_single_exit();
14307d3eb23cSDan Williams for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
14317d3eb23cSDan Williams platform_device_unregister(cxl_mem[i]);
1432c1915142SDan Williams for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
1433c1915142SDan Williams platform_device_unregister(cxl_switch_dport[i]);
1434c1915142SDan Williams for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
1435c1915142SDan Williams platform_device_unregister(cxl_switch_uport[i]);
143667dcdd4dSDan Williams for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
143767dcdd4dSDan Williams platform_device_unregister(cxl_root_port[i]);
143864cda3aeSDan Williams for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
143964cda3aeSDan Williams struct platform_device *pdev = cxl_host_bridge[i];
144064cda3aeSDan Williams
144164cda3aeSDan Williams if (!pdev)
144264cda3aeSDan Williams continue;
144364cda3aeSDan Williams sysfs_remove_link(&pdev->dev.kobj, "physical_node");
144467dcdd4dSDan Williams platform_device_unregister(cxl_host_bridge[i]);
144564cda3aeSDan Williams }
144667dcdd4dSDan Williams depopulate_all_mock_resources();
144767dcdd4dSDan Williams gen_pool_destroy(cxl_mock_pool);
144867dcdd4dSDan Williams unregister_cxl_mock_ops(&cxl_mock_ops);
144967dcdd4dSDan Williams }
145067dcdd4dSDan Williams
145166f3cb79SAlison Schofield module_param(interleave_arithmetic, int, 0444);
14527a7e6edfSAlison Schofield MODULE_PARM_DESC(interleave_arithmetic, "Modulo:0, XOR:1");
145367dcdd4dSDan Williams module_init(cxl_test_init);
145467dcdd4dSDan Williams module_exit(cxl_test_exit);
145567dcdd4dSDan Williams MODULE_LICENSE("GPL v2");
1456814dff9aSDan Williams MODULE_IMPORT_NS(ACPI);
145798d2d3a2SDan Williams MODULE_IMPORT_NS(CXL);
1458