xref: /openbmc/linux/tools/testing/cxl/test/cxl.c (revision 5f8b7d4b2e9604d03ae06f1a2dd5a1f34c33e533)
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