xref: /openbmc/linux/tools/testing/cxl/test/cxl.c (revision b755063e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2021 Intel Corporation. All rights reserved.
3 
4 #include <linux/platform_device.h>
5 #include <linux/genalloc.h>
6 #include <linux/module.h>
7 #include <linux/mutex.h>
8 #include <linux/acpi.h>
9 #include <linux/pci.h>
10 #include <linux/mm.h>
11 #include <cxlmem.h>
12 #include "mock.h"
13 
14 static int interleave_arithmetic;
15 
16 #define NR_CXL_HOST_BRIDGES 2
17 #define NR_CXL_SINGLE_HOST 1
18 #define NR_CXL_RCH 1
19 #define NR_CXL_ROOT_PORTS 2
20 #define NR_CXL_SWITCH_PORTS 2
21 #define NR_CXL_PORT_DECODERS 8
22 #define NR_BRIDGES (NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + NR_CXL_RCH)
23 
24 static struct platform_device *cxl_acpi;
25 static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
26 #define NR_MULTI_ROOT (NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS)
27 static struct platform_device *cxl_root_port[NR_MULTI_ROOT];
28 static struct platform_device *cxl_switch_uport[NR_MULTI_ROOT];
29 #define NR_MEM_MULTI \
30 	(NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS * NR_CXL_SWITCH_PORTS)
31 static struct platform_device *cxl_switch_dport[NR_MEM_MULTI];
32 
33 static struct platform_device *cxl_hb_single[NR_CXL_SINGLE_HOST];
34 static struct platform_device *cxl_root_single[NR_CXL_SINGLE_HOST];
35 static struct platform_device *cxl_swu_single[NR_CXL_SINGLE_HOST];
36 #define NR_MEM_SINGLE (NR_CXL_SINGLE_HOST * NR_CXL_SWITCH_PORTS)
37 static struct platform_device *cxl_swd_single[NR_MEM_SINGLE];
38 
39 struct platform_device *cxl_mem[NR_MEM_MULTI];
40 struct platform_device *cxl_mem_single[NR_MEM_SINGLE];
41 
42 static struct platform_device *cxl_rch[NR_CXL_RCH];
43 static struct platform_device *cxl_rcd[NR_CXL_RCH];
44 
45 static inline bool is_multi_bridge(struct device *dev)
46 {
47 	int i;
48 
49 	for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
50 		if (&cxl_host_bridge[i]->dev == dev)
51 			return true;
52 	return false;
53 }
54 
55 static inline bool is_single_bridge(struct device *dev)
56 {
57 	int i;
58 
59 	for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
60 		if (&cxl_hb_single[i]->dev == dev)
61 			return true;
62 	return false;
63 }
64 
65 static struct acpi_device acpi0017_mock;
66 static struct acpi_device host_bridge[NR_BRIDGES] = {
67 	[0] = {
68 		.handle = &host_bridge[0],
69 	},
70 	[1] = {
71 		.handle = &host_bridge[1],
72 	},
73 	[2] = {
74 		.handle = &host_bridge[2],
75 	},
76 	[3] = {
77 		.handle = &host_bridge[3],
78 	},
79 };
80 
81 static bool is_mock_dev(struct device *dev)
82 {
83 	int i;
84 
85 	for (i = 0; i < ARRAY_SIZE(cxl_mem); i++)
86 		if (dev == &cxl_mem[i]->dev)
87 			return true;
88 	for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++)
89 		if (dev == &cxl_mem_single[i]->dev)
90 			return true;
91 	for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++)
92 		if (dev == &cxl_rcd[i]->dev)
93 			return true;
94 	if (dev == &cxl_acpi->dev)
95 		return true;
96 	return false;
97 }
98 
99 static bool is_mock_adev(struct acpi_device *adev)
100 {
101 	int i;
102 
103 	if (adev == &acpi0017_mock)
104 		return true;
105 
106 	for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
107 		if (adev == &host_bridge[i])
108 			return true;
109 
110 	return false;
111 }
112 
113 static struct {
114 	struct acpi_table_cedt cedt;
115 	struct acpi_cedt_chbs chbs[NR_BRIDGES];
116 	struct {
117 		struct acpi_cedt_cfmws cfmws;
118 		u32 target[1];
119 	} cfmws0;
120 	struct {
121 		struct acpi_cedt_cfmws cfmws;
122 		u32 target[2];
123 	} cfmws1;
124 	struct {
125 		struct acpi_cedt_cfmws cfmws;
126 		u32 target[1];
127 	} cfmws2;
128 	struct {
129 		struct acpi_cedt_cfmws cfmws;
130 		u32 target[2];
131 	} cfmws3;
132 	struct {
133 		struct acpi_cedt_cfmws cfmws;
134 		u32 target[1];
135 	} cfmws4;
136 	struct {
137 		struct acpi_cedt_cfmws cfmws;
138 		u32 target[1];
139 	} cfmws5;
140 	struct {
141 		struct acpi_cedt_cfmws cfmws;
142 		u32 target[1];
143 	} cfmws6;
144 	struct {
145 		struct acpi_cedt_cfmws cfmws;
146 		u32 target[2];
147 	} cfmws7;
148 	struct {
149 		struct acpi_cedt_cfmws cfmws;
150 		u32 target[4];
151 	} cfmws8;
152 	struct {
153 		struct acpi_cedt_cxims cxims;
154 		u64 xormap_list[2];
155 	} cxims0;
156 } __packed mock_cedt = {
157 	.cedt = {
158 		.header = {
159 			.signature = "CEDT",
160 			.length = sizeof(mock_cedt),
161 			.revision = 1,
162 		},
163 	},
164 	.chbs[0] = {
165 		.header = {
166 			.type = ACPI_CEDT_TYPE_CHBS,
167 			.length = sizeof(mock_cedt.chbs[0]),
168 		},
169 		.uid = 0,
170 		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
171 	},
172 	.chbs[1] = {
173 		.header = {
174 			.type = ACPI_CEDT_TYPE_CHBS,
175 			.length = sizeof(mock_cedt.chbs[0]),
176 		},
177 		.uid = 1,
178 		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
179 	},
180 	.chbs[2] = {
181 		.header = {
182 			.type = ACPI_CEDT_TYPE_CHBS,
183 			.length = sizeof(mock_cedt.chbs[0]),
184 		},
185 		.uid = 2,
186 		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
187 	},
188 	.chbs[3] = {
189 		.header = {
190 			.type = ACPI_CEDT_TYPE_CHBS,
191 			.length = sizeof(mock_cedt.chbs[0]),
192 		},
193 		.uid = 3,
194 		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL11,
195 	},
196 	.cfmws0 = {
197 		.cfmws = {
198 			.header = {
199 				.type = ACPI_CEDT_TYPE_CFMWS,
200 				.length = sizeof(mock_cedt.cfmws0),
201 			},
202 			.interleave_ways = 0,
203 			.granularity = 4,
204 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
205 					ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
206 			.qtg_id = 0,
207 			.window_size = SZ_256M * 4UL,
208 		},
209 		.target = { 0 },
210 	},
211 	.cfmws1 = {
212 		.cfmws = {
213 			.header = {
214 				.type = ACPI_CEDT_TYPE_CFMWS,
215 				.length = sizeof(mock_cedt.cfmws1),
216 			},
217 			.interleave_ways = 1,
218 			.granularity = 4,
219 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
220 					ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
221 			.qtg_id = 1,
222 			.window_size = SZ_256M * 8UL,
223 		},
224 		.target = { 0, 1, },
225 	},
226 	.cfmws2 = {
227 		.cfmws = {
228 			.header = {
229 				.type = ACPI_CEDT_TYPE_CFMWS,
230 				.length = sizeof(mock_cedt.cfmws2),
231 			},
232 			.interleave_ways = 0,
233 			.granularity = 4,
234 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
235 					ACPI_CEDT_CFMWS_RESTRICT_PMEM,
236 			.qtg_id = 2,
237 			.window_size = SZ_256M * 4UL,
238 		},
239 		.target = { 0 },
240 	},
241 	.cfmws3 = {
242 		.cfmws = {
243 			.header = {
244 				.type = ACPI_CEDT_TYPE_CFMWS,
245 				.length = sizeof(mock_cedt.cfmws3),
246 			},
247 			.interleave_ways = 1,
248 			.granularity = 4,
249 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
250 					ACPI_CEDT_CFMWS_RESTRICT_PMEM,
251 			.qtg_id = 3,
252 			.window_size = SZ_256M * 8UL,
253 		},
254 		.target = { 0, 1, },
255 	},
256 	.cfmws4 = {
257 		.cfmws = {
258 			.header = {
259 				.type = ACPI_CEDT_TYPE_CFMWS,
260 				.length = sizeof(mock_cedt.cfmws4),
261 			},
262 			.interleave_ways = 0,
263 			.granularity = 4,
264 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
265 					ACPI_CEDT_CFMWS_RESTRICT_PMEM,
266 			.qtg_id = 4,
267 			.window_size = SZ_256M * 4UL,
268 		},
269 		.target = { 2 },
270 	},
271 	.cfmws5 = {
272 		.cfmws = {
273 			.header = {
274 				.type = ACPI_CEDT_TYPE_CFMWS,
275 				.length = sizeof(mock_cedt.cfmws5),
276 			},
277 			.interleave_ways = 0,
278 			.granularity = 4,
279 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
280 					ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
281 			.qtg_id = 5,
282 			.window_size = SZ_256M,
283 		},
284 		.target = { 3 },
285 	},
286 	/* .cfmws6,7,8 use ACPI_CEDT_CFMWS_ARITHMETIC_XOR */
287 	.cfmws6 = {
288 		.cfmws = {
289 			.header = {
290 				.type = ACPI_CEDT_TYPE_CFMWS,
291 				.length = sizeof(mock_cedt.cfmws6),
292 			},
293 			.interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
294 			.interleave_ways = 0,
295 			.granularity = 4,
296 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
297 					ACPI_CEDT_CFMWS_RESTRICT_PMEM,
298 			.qtg_id = 0,
299 			.window_size = SZ_256M * 8UL,
300 		},
301 		.target = { 0, },
302 	},
303 	.cfmws7 = {
304 		.cfmws = {
305 			.header = {
306 				.type = ACPI_CEDT_TYPE_CFMWS,
307 				.length = sizeof(mock_cedt.cfmws7),
308 			},
309 			.interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
310 			.interleave_ways = 1,
311 			.granularity = 0,
312 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
313 					ACPI_CEDT_CFMWS_RESTRICT_PMEM,
314 			.qtg_id = 1,
315 			.window_size = SZ_256M * 8UL,
316 		},
317 		.target = { 0, 1, },
318 	},
319 	.cfmws8 = {
320 		.cfmws = {
321 			.header = {
322 				.type = ACPI_CEDT_TYPE_CFMWS,
323 				.length = sizeof(mock_cedt.cfmws8),
324 			},
325 			.interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
326 			.interleave_ways = 2,
327 			.granularity = 0,
328 			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
329 					ACPI_CEDT_CFMWS_RESTRICT_PMEM,
330 			.qtg_id = 0,
331 			.window_size = SZ_256M * 16UL,
332 		},
333 		.target = { 0, 1, 0, 1, },
334 	},
335 	.cxims0 = {
336 		.cxims = {
337 			.header = {
338 				.type = ACPI_CEDT_TYPE_CXIMS,
339 				.length = sizeof(mock_cedt.cxims0),
340 			},
341 			.hbig = 0,
342 			.nr_xormaps = 2,
343 		},
344 		.xormap_list = { 0x404100, 0x808200, },
345 	},
346 };
347 
348 struct acpi_cedt_cfmws *mock_cfmws[] = {
349 	[0] = &mock_cedt.cfmws0.cfmws,
350 	[1] = &mock_cedt.cfmws1.cfmws,
351 	[2] = &mock_cedt.cfmws2.cfmws,
352 	[3] = &mock_cedt.cfmws3.cfmws,
353 	[4] = &mock_cedt.cfmws4.cfmws,
354 	[5] = &mock_cedt.cfmws5.cfmws,
355 	/* Modulo Math above, XOR Math below */
356 	[6] = &mock_cedt.cfmws6.cfmws,
357 	[7] = &mock_cedt.cfmws7.cfmws,
358 	[8] = &mock_cedt.cfmws8.cfmws,
359 };
360 
361 static int cfmws_start;
362 static int cfmws_end;
363 #define CFMWS_MOD_ARRAY_START 0
364 #define CFMWS_MOD_ARRAY_END   5
365 #define CFMWS_XOR_ARRAY_START 6
366 #define CFMWS_XOR_ARRAY_END   8
367 
368 struct acpi_cedt_cxims *mock_cxims[1] = {
369 	[0] = &mock_cedt.cxims0.cxims,
370 };
371 
372 struct cxl_mock_res {
373 	struct list_head list;
374 	struct range range;
375 };
376 
377 static LIST_HEAD(mock_res);
378 static DEFINE_MUTEX(mock_res_lock);
379 static struct gen_pool *cxl_mock_pool;
380 
381 static void depopulate_all_mock_resources(void)
382 {
383 	struct cxl_mock_res *res, *_res;
384 
385 	mutex_lock(&mock_res_lock);
386 	list_for_each_entry_safe(res, _res, &mock_res, list) {
387 		gen_pool_free(cxl_mock_pool, res->range.start,
388 			      range_len(&res->range));
389 		list_del(&res->list);
390 		kfree(res);
391 	}
392 	mutex_unlock(&mock_res_lock);
393 }
394 
395 static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
396 {
397 	struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
398 	struct genpool_data_align data = {
399 		.align = align,
400 	};
401 	unsigned long phys;
402 
403 	INIT_LIST_HEAD(&res->list);
404 	phys = gen_pool_alloc_algo(cxl_mock_pool, size,
405 				   gen_pool_first_fit_align, &data);
406 	if (!phys)
407 		return NULL;
408 
409 	res->range = (struct range) {
410 		.start = phys,
411 		.end = phys + size - 1,
412 	};
413 	mutex_lock(&mock_res_lock);
414 	list_add(&res->list, &mock_res);
415 	mutex_unlock(&mock_res_lock);
416 
417 	return res;
418 }
419 
420 static int populate_cedt(void)
421 {
422 	struct cxl_mock_res *res;
423 	int i;
424 
425 	for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
426 		struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i];
427 		resource_size_t size;
428 
429 		if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20)
430 			size = ACPI_CEDT_CHBS_LENGTH_CXL20;
431 		else
432 			size = ACPI_CEDT_CHBS_LENGTH_CXL11;
433 
434 		res = alloc_mock_res(size, size);
435 		if (!res)
436 			return -ENOMEM;
437 		chbs->base = res->range.start;
438 		chbs->length = size;
439 	}
440 
441 	for (i = cfmws_start; i <= cfmws_end; i++) {
442 		struct acpi_cedt_cfmws *window = mock_cfmws[i];
443 
444 		res = alloc_mock_res(window->window_size, SZ_256M);
445 		if (!res)
446 			return -ENOMEM;
447 		window->base_hpa = res->range.start;
448 	}
449 
450 	return 0;
451 }
452 
453 static bool is_mock_port(struct device *dev);
454 
455 /*
456  * WARNING, this hack assumes the format of 'struct cxl_cfmws_context'
457  * and 'struct cxl_chbs_context' share the property that the first
458  * struct member is a cxl_test device being probed by the cxl_acpi
459  * driver.
460  */
461 struct cxl_cedt_context {
462 	struct device *dev;
463 };
464 
465 static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
466 				      acpi_tbl_entry_handler_arg handler_arg,
467 				      void *arg)
468 {
469 	struct cxl_cedt_context *ctx = arg;
470 	struct device *dev = ctx->dev;
471 	union acpi_subtable_headers *h;
472 	unsigned long end;
473 	int i;
474 
475 	if (!is_mock_port(dev) && !is_mock_dev(dev))
476 		return acpi_table_parse_cedt(id, handler_arg, arg);
477 
478 	if (id == ACPI_CEDT_TYPE_CHBS)
479 		for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
480 			h = (union acpi_subtable_headers *)&mock_cedt.chbs[i];
481 			end = (unsigned long)&mock_cedt.chbs[i + 1];
482 			handler_arg(h, arg, end);
483 		}
484 
485 	if (id == ACPI_CEDT_TYPE_CFMWS)
486 		for (i = cfmws_start; i <= cfmws_end; i++) {
487 			h = (union acpi_subtable_headers *) mock_cfmws[i];
488 			end = (unsigned long) h + mock_cfmws[i]->header.length;
489 			handler_arg(h, arg, end);
490 		}
491 
492 	if (id == ACPI_CEDT_TYPE_CXIMS)
493 		for (i = 0; i < ARRAY_SIZE(mock_cxims); i++) {
494 			h = (union acpi_subtable_headers *)mock_cxims[i];
495 			end = (unsigned long)h + mock_cxims[i]->header.length;
496 			handler_arg(h, arg, end);
497 		}
498 
499 	return 0;
500 }
501 
502 static bool is_mock_bridge(struct device *dev)
503 {
504 	int i;
505 
506 	for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
507 		if (dev == &cxl_host_bridge[i]->dev)
508 			return true;
509 	for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
510 		if (dev == &cxl_hb_single[i]->dev)
511 			return true;
512 	for (i = 0; i < ARRAY_SIZE(cxl_rch); i++)
513 		if (dev == &cxl_rch[i]->dev)
514 			return true;
515 
516 	return false;
517 }
518 
519 static bool is_mock_port(struct device *dev)
520 {
521 	int i;
522 
523 	if (is_mock_bridge(dev))
524 		return true;
525 
526 	for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++)
527 		if (dev == &cxl_root_port[i]->dev)
528 			return true;
529 
530 	for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++)
531 		if (dev == &cxl_switch_uport[i]->dev)
532 			return true;
533 
534 	for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++)
535 		if (dev == &cxl_switch_dport[i]->dev)
536 			return true;
537 
538 	for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++)
539 		if (dev == &cxl_root_single[i]->dev)
540 			return true;
541 
542 	for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++)
543 		if (dev == &cxl_swu_single[i]->dev)
544 			return true;
545 
546 	for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++)
547 		if (dev == &cxl_swd_single[i]->dev)
548 			return true;
549 
550 	if (is_cxl_memdev(dev))
551 		return is_mock_dev(dev->parent);
552 
553 	return false;
554 }
555 
556 static int host_bridge_index(struct acpi_device *adev)
557 {
558 	return adev - host_bridge;
559 }
560 
561 static struct acpi_device *find_host_bridge(acpi_handle handle)
562 {
563 	int i;
564 
565 	for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
566 		if (handle == host_bridge[i].handle)
567 			return &host_bridge[i];
568 	return NULL;
569 }
570 
571 static acpi_status
572 mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname,
573 			   struct acpi_object_list *arguments,
574 			   unsigned long long *data)
575 {
576 	struct acpi_device *adev = find_host_bridge(handle);
577 
578 	if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0)
579 		return acpi_evaluate_integer(handle, pathname, arguments, data);
580 
581 	*data = host_bridge_index(adev);
582 	return AE_OK;
583 }
584 
585 static struct pci_bus mock_pci_bus[NR_BRIDGES];
586 static struct acpi_pci_root mock_pci_root[ARRAY_SIZE(mock_pci_bus)] = {
587 	[0] = {
588 		.bus = &mock_pci_bus[0],
589 	},
590 	[1] = {
591 		.bus = &mock_pci_bus[1],
592 	},
593 	[2] = {
594 		.bus = &mock_pci_bus[2],
595 	},
596 	[3] = {
597 		.bus = &mock_pci_bus[3],
598 	},
599 
600 };
601 
602 static bool is_mock_bus(struct pci_bus *bus)
603 {
604 	int i;
605 
606 	for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++)
607 		if (bus == &mock_pci_bus[i])
608 			return true;
609 	return false;
610 }
611 
612 static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle)
613 {
614 	struct acpi_device *adev = find_host_bridge(handle);
615 
616 	if (!adev)
617 		return acpi_pci_find_root(handle);
618 	return &mock_pci_root[host_bridge_index(adev)];
619 }
620 
621 static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port)
622 {
623 	struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL);
624 
625 	if (!cxlhdm)
626 		return ERR_PTR(-ENOMEM);
627 
628 	cxlhdm->port = port;
629 	return cxlhdm;
630 }
631 
632 static int mock_cxl_add_passthrough_decoder(struct cxl_port *port)
633 {
634 	dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n");
635 	return -EOPNOTSUPP;
636 }
637 
638 
639 struct target_map_ctx {
640 	int *target_map;
641 	int index;
642 	int target_count;
643 };
644 
645 static int map_targets(struct device *dev, void *data)
646 {
647 	struct platform_device *pdev = to_platform_device(dev);
648 	struct target_map_ctx *ctx = data;
649 
650 	ctx->target_map[ctx->index++] = pdev->id;
651 
652 	if (ctx->index > ctx->target_count) {
653 		dev_WARN_ONCE(dev, 1, "too many targets found?\n");
654 		return -ENXIO;
655 	}
656 
657 	return 0;
658 }
659 
660 static int mock_decoder_commit(struct cxl_decoder *cxld)
661 {
662 	struct cxl_port *port = to_cxl_port(cxld->dev.parent);
663 	int id = cxld->id;
664 
665 	if (cxld->flags & CXL_DECODER_F_ENABLE)
666 		return 0;
667 
668 	dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
669 	if (port->commit_end + 1 != id) {
670 		dev_dbg(&port->dev,
671 			"%s: out of order commit, expected decoder%d.%d\n",
672 			dev_name(&cxld->dev), port->id, port->commit_end + 1);
673 		return -EBUSY;
674 	}
675 
676 	port->commit_end++;
677 	cxld->flags |= CXL_DECODER_F_ENABLE;
678 
679 	return 0;
680 }
681 
682 static int mock_decoder_reset(struct cxl_decoder *cxld)
683 {
684 	struct cxl_port *port = to_cxl_port(cxld->dev.parent);
685 	int id = cxld->id;
686 
687 	if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
688 		return 0;
689 
690 	dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
691 	if (port->commit_end != id) {
692 		dev_dbg(&port->dev,
693 			"%s: out of order reset, expected decoder%d.%d\n",
694 			dev_name(&cxld->dev), port->id, port->commit_end);
695 		return -EBUSY;
696 	}
697 
698 	port->commit_end--;
699 	cxld->flags &= ~CXL_DECODER_F_ENABLE;
700 
701 	return 0;
702 }
703 
704 static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
705 {
706 	struct cxl_port *port = cxlhdm->port;
707 	struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
708 	int target_count, i;
709 
710 	if (is_cxl_endpoint(port))
711 		target_count = 0;
712 	else if (is_cxl_root(parent_port))
713 		target_count = NR_CXL_ROOT_PORTS;
714 	else
715 		target_count = NR_CXL_SWITCH_PORTS;
716 
717 	for (i = 0; i < NR_CXL_PORT_DECODERS; i++) {
718 		int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
719 		struct target_map_ctx ctx = {
720 			.target_map = target_map,
721 			.target_count = target_count,
722 		};
723 		struct cxl_decoder *cxld;
724 		int rc;
725 
726 		if (target_count) {
727 			struct cxl_switch_decoder *cxlsd;
728 
729 			cxlsd = cxl_switch_decoder_alloc(port, target_count);
730 			if (IS_ERR(cxlsd)) {
731 				dev_warn(&port->dev,
732 					 "Failed to allocate the decoder\n");
733 				return PTR_ERR(cxlsd);
734 			}
735 			cxld = &cxlsd->cxld;
736 		} else {
737 			struct cxl_endpoint_decoder *cxled;
738 
739 			cxled = cxl_endpoint_decoder_alloc(port);
740 
741 			if (IS_ERR(cxled)) {
742 				dev_warn(&port->dev,
743 					 "Failed to allocate the decoder\n");
744 				return PTR_ERR(cxled);
745 			}
746 			cxld = &cxled->cxld;
747 		}
748 
749 		cxld->hpa_range = (struct range) {
750 			.start = 0,
751 			.end = -1,
752 		};
753 
754 		cxld->interleave_ways = min_not_zero(target_count, 1);
755 		cxld->interleave_granularity = SZ_4K;
756 		cxld->target_type = CXL_DECODER_EXPANDER;
757 		cxld->commit = mock_decoder_commit;
758 		cxld->reset = mock_decoder_reset;
759 
760 		if (target_count) {
761 			rc = device_for_each_child(port->uport, &ctx,
762 						   map_targets);
763 			if (rc) {
764 				put_device(&cxld->dev);
765 				return rc;
766 			}
767 		}
768 
769 		rc = cxl_decoder_add_locked(cxld, target_map);
770 		if (rc) {
771 			put_device(&cxld->dev);
772 			dev_err(&port->dev, "Failed to add decoder\n");
773 			return rc;
774 		}
775 
776 		rc = cxl_decoder_autoremove(&port->dev, cxld);
777 		if (rc)
778 			return rc;
779 		dev_dbg(&cxld->dev, "Added to port %s\n", dev_name(&port->dev));
780 	}
781 
782 	return 0;
783 }
784 
785 static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
786 {
787 	struct platform_device **array;
788 	int i, array_size;
789 
790 	if (port->depth == 1) {
791 		if (is_multi_bridge(port->uport)) {
792 			array_size = ARRAY_SIZE(cxl_root_port);
793 			array = cxl_root_port;
794 		} else if (is_single_bridge(port->uport)) {
795 			array_size = ARRAY_SIZE(cxl_root_single);
796 			array = cxl_root_single;
797 		} else {
798 			dev_dbg(&port->dev, "%s: unknown bridge type\n",
799 				dev_name(port->uport));
800 			return -ENXIO;
801 		}
802 	} else if (port->depth == 2) {
803 		struct cxl_port *parent = to_cxl_port(port->dev.parent);
804 
805 		if (is_multi_bridge(parent->uport)) {
806 			array_size = ARRAY_SIZE(cxl_switch_dport);
807 			array = cxl_switch_dport;
808 		} else if (is_single_bridge(parent->uport)) {
809 			array_size = ARRAY_SIZE(cxl_swd_single);
810 			array = cxl_swd_single;
811 		} else {
812 			dev_dbg(&port->dev, "%s: unknown bridge type\n",
813 				dev_name(port->uport));
814 			return -ENXIO;
815 		}
816 	} else {
817 		dev_WARN_ONCE(&port->dev, 1, "unexpected depth %d\n",
818 			      port->depth);
819 		return -ENXIO;
820 	}
821 
822 	for (i = 0; i < array_size; i++) {
823 		struct platform_device *pdev = array[i];
824 		struct cxl_dport *dport;
825 
826 		if (pdev->dev.parent != port->uport) {
827 			dev_dbg(&port->dev, "%s: mismatch parent %s\n",
828 				dev_name(port->uport),
829 				dev_name(pdev->dev.parent));
830 			continue;
831 		}
832 
833 		dport = devm_cxl_add_dport(port, &pdev->dev, pdev->id,
834 					   CXL_RESOURCE_NONE);
835 
836 		if (IS_ERR(dport))
837 			return PTR_ERR(dport);
838 	}
839 
840 	return 0;
841 }
842 
843 resource_size_t mock_cxl_rcrb_to_component(struct device *dev,
844 					   resource_size_t rcrb,
845 					   enum cxl_rcrb which)
846 {
847 	dev_dbg(dev, "rcrb: %pa which: %d\n", &rcrb, which);
848 
849 	return (resource_size_t) which + 1;
850 }
851 
852 static struct cxl_mock_ops cxl_mock_ops = {
853 	.is_mock_adev = is_mock_adev,
854 	.is_mock_bridge = is_mock_bridge,
855 	.is_mock_bus = is_mock_bus,
856 	.is_mock_port = is_mock_port,
857 	.is_mock_dev = is_mock_dev,
858 	.acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
859 	.acpi_evaluate_integer = mock_acpi_evaluate_integer,
860 	.cxl_rcrb_to_component = mock_cxl_rcrb_to_component,
861 	.acpi_pci_find_root = mock_acpi_pci_find_root,
862 	.devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
863 	.devm_cxl_setup_hdm = mock_cxl_setup_hdm,
864 	.devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,
865 	.devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,
866 	.list = LIST_HEAD_INIT(cxl_mock_ops.list),
867 };
868 
869 static void mock_companion(struct acpi_device *adev, struct device *dev)
870 {
871 	device_initialize(&adev->dev);
872 	fwnode_init(&adev->fwnode, NULL);
873 	dev->fwnode = &adev->fwnode;
874 	adev->fwnode.dev = dev;
875 }
876 
877 #ifndef SZ_64G
878 #define SZ_64G (SZ_32G * 2)
879 #endif
880 
881 #ifndef SZ_512G
882 #define SZ_512G (SZ_64G * 8)
883 #endif
884 
885 static __init int cxl_rch_init(void)
886 {
887 	int rc, i;
888 
889 	for (i = 0; i < ARRAY_SIZE(cxl_rch); i++) {
890 		int idx = NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + i;
891 		struct acpi_device *adev = &host_bridge[idx];
892 		struct platform_device *pdev;
893 
894 		pdev = platform_device_alloc("cxl_host_bridge", idx);
895 		if (!pdev)
896 			goto err_bridge;
897 
898 		mock_companion(adev, &pdev->dev);
899 		rc = platform_device_add(pdev);
900 		if (rc) {
901 			platform_device_put(pdev);
902 			goto err_bridge;
903 		}
904 
905 		cxl_rch[i] = pdev;
906 		mock_pci_bus[idx].bridge = &pdev->dev;
907 		rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
908 				       "firmware_node");
909 		if (rc)
910 			goto err_bridge;
911 	}
912 
913 	for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {
914 		int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;
915 		struct platform_device *rch = cxl_rch[i];
916 		struct platform_device *pdev;
917 
918 		pdev = platform_device_alloc("cxl_rcd", idx);
919 		if (!pdev)
920 			goto err_mem;
921 		pdev->dev.parent = &rch->dev;
922 		set_dev_node(&pdev->dev, i % 2);
923 
924 		rc = platform_device_add(pdev);
925 		if (rc) {
926 			platform_device_put(pdev);
927 			goto err_mem;
928 		}
929 		cxl_rcd[i] = pdev;
930 	}
931 
932 	return 0;
933 
934 err_mem:
935 	for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
936 		platform_device_unregister(cxl_rcd[i]);
937 err_bridge:
938 	for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
939 		struct platform_device *pdev = cxl_rch[i];
940 
941 		if (!pdev)
942 			continue;
943 		sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
944 		platform_device_unregister(cxl_rch[i]);
945 	}
946 
947 	return rc;
948 }
949 
950 static void cxl_rch_exit(void)
951 {
952 	int i;
953 
954 	for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
955 		platform_device_unregister(cxl_rcd[i]);
956 	for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
957 		struct platform_device *pdev = cxl_rch[i];
958 
959 		if (!pdev)
960 			continue;
961 		sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
962 		platform_device_unregister(cxl_rch[i]);
963 	}
964 }
965 
966 static __init int cxl_single_init(void)
967 {
968 	int i, rc;
969 
970 	for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++) {
971 		struct acpi_device *adev =
972 			&host_bridge[NR_CXL_HOST_BRIDGES + i];
973 		struct platform_device *pdev;
974 
975 		pdev = platform_device_alloc("cxl_host_bridge",
976 					     NR_CXL_HOST_BRIDGES + i);
977 		if (!pdev)
978 			goto err_bridge;
979 
980 		mock_companion(adev, &pdev->dev);
981 		rc = platform_device_add(pdev);
982 		if (rc) {
983 			platform_device_put(pdev);
984 			goto err_bridge;
985 		}
986 
987 		cxl_hb_single[i] = pdev;
988 		mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev;
989 		rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
990 				       "physical_node");
991 		if (rc)
992 			goto err_bridge;
993 	}
994 
995 	for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++) {
996 		struct platform_device *bridge =
997 			cxl_hb_single[i % ARRAY_SIZE(cxl_hb_single)];
998 		struct platform_device *pdev;
999 
1000 		pdev = platform_device_alloc("cxl_root_port",
1001 					     NR_MULTI_ROOT + i);
1002 		if (!pdev)
1003 			goto err_port;
1004 		pdev->dev.parent = &bridge->dev;
1005 
1006 		rc = platform_device_add(pdev);
1007 		if (rc) {
1008 			platform_device_put(pdev);
1009 			goto err_port;
1010 		}
1011 		cxl_root_single[i] = pdev;
1012 	}
1013 
1014 	for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) {
1015 		struct platform_device *root_port = cxl_root_single[i];
1016 		struct platform_device *pdev;
1017 
1018 		pdev = platform_device_alloc("cxl_switch_uport",
1019 					     NR_MULTI_ROOT + i);
1020 		if (!pdev)
1021 			goto err_uport;
1022 		pdev->dev.parent = &root_port->dev;
1023 
1024 		rc = platform_device_add(pdev);
1025 		if (rc) {
1026 			platform_device_put(pdev);
1027 			goto err_uport;
1028 		}
1029 		cxl_swu_single[i] = pdev;
1030 	}
1031 
1032 	for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) {
1033 		struct platform_device *uport =
1034 			cxl_swu_single[i % ARRAY_SIZE(cxl_swu_single)];
1035 		struct platform_device *pdev;
1036 
1037 		pdev = platform_device_alloc("cxl_switch_dport",
1038 					     i + NR_MEM_MULTI);
1039 		if (!pdev)
1040 			goto err_dport;
1041 		pdev->dev.parent = &uport->dev;
1042 
1043 		rc = platform_device_add(pdev);
1044 		if (rc) {
1045 			platform_device_put(pdev);
1046 			goto err_dport;
1047 		}
1048 		cxl_swd_single[i] = pdev;
1049 	}
1050 
1051 	for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) {
1052 		struct platform_device *dport = cxl_swd_single[i];
1053 		struct platform_device *pdev;
1054 
1055 		pdev = platform_device_alloc("cxl_mem", NR_MEM_MULTI + i);
1056 		if (!pdev)
1057 			goto err_mem;
1058 		pdev->dev.parent = &dport->dev;
1059 		set_dev_node(&pdev->dev, i % 2);
1060 
1061 		rc = platform_device_add(pdev);
1062 		if (rc) {
1063 			platform_device_put(pdev);
1064 			goto err_mem;
1065 		}
1066 		cxl_mem_single[i] = pdev;
1067 	}
1068 
1069 	return 0;
1070 
1071 err_mem:
1072 	for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
1073 		platform_device_unregister(cxl_mem_single[i]);
1074 err_dport:
1075 	for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
1076 		platform_device_unregister(cxl_swd_single[i]);
1077 err_uport:
1078 	for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
1079 		platform_device_unregister(cxl_swu_single[i]);
1080 err_port:
1081 	for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)
1082 		platform_device_unregister(cxl_root_single[i]);
1083 err_bridge:
1084 	for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {
1085 		struct platform_device *pdev = cxl_hb_single[i];
1086 
1087 		if (!pdev)
1088 			continue;
1089 		sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1090 		platform_device_unregister(cxl_hb_single[i]);
1091 	}
1092 
1093 	return rc;
1094 }
1095 
1096 static void cxl_single_exit(void)
1097 {
1098 	int i;
1099 
1100 	for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
1101 		platform_device_unregister(cxl_mem_single[i]);
1102 	for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
1103 		platform_device_unregister(cxl_swd_single[i]);
1104 	for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
1105 		platform_device_unregister(cxl_swu_single[i]);
1106 	for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)
1107 		platform_device_unregister(cxl_root_single[i]);
1108 	for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {
1109 		struct platform_device *pdev = cxl_hb_single[i];
1110 
1111 		if (!pdev)
1112 			continue;
1113 		sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1114 		platform_device_unregister(cxl_hb_single[i]);
1115 	}
1116 }
1117 
1118 static __init int cxl_test_init(void)
1119 {
1120 	int rc, i;
1121 
1122 	register_cxl_mock_ops(&cxl_mock_ops);
1123 
1124 	cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE);
1125 	if (!cxl_mock_pool) {
1126 		rc = -ENOMEM;
1127 		goto err_gen_pool_create;
1128 	}
1129 
1130 	rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,
1131 			  SZ_64G, NUMA_NO_NODE);
1132 	if (rc)
1133 		goto err_gen_pool_add;
1134 
1135 	if (interleave_arithmetic == 1) {
1136 		cfmws_start = CFMWS_XOR_ARRAY_START;
1137 		cfmws_end = CFMWS_XOR_ARRAY_END;
1138 		dev_dbg(NULL, "cxl_test loading xor math option\n");
1139 	} else {
1140 		cfmws_start = CFMWS_MOD_ARRAY_START;
1141 		cfmws_end = CFMWS_MOD_ARRAY_END;
1142 		dev_dbg(NULL, "cxl_test loading modulo math option\n");
1143 	}
1144 
1145 	rc = populate_cedt();
1146 	if (rc)
1147 		goto err_populate;
1148 
1149 	for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) {
1150 		struct acpi_device *adev = &host_bridge[i];
1151 		struct platform_device *pdev;
1152 
1153 		pdev = platform_device_alloc("cxl_host_bridge", i);
1154 		if (!pdev)
1155 			goto err_bridge;
1156 
1157 		mock_companion(adev, &pdev->dev);
1158 		rc = platform_device_add(pdev);
1159 		if (rc) {
1160 			platform_device_put(pdev);
1161 			goto err_bridge;
1162 		}
1163 
1164 		cxl_host_bridge[i] = pdev;
1165 		mock_pci_bus[i].bridge = &pdev->dev;
1166 		rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
1167 				       "physical_node");
1168 		if (rc)
1169 			goto err_bridge;
1170 	}
1171 
1172 	for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) {
1173 		struct platform_device *bridge =
1174 			cxl_host_bridge[i % ARRAY_SIZE(cxl_host_bridge)];
1175 		struct platform_device *pdev;
1176 
1177 		pdev = platform_device_alloc("cxl_root_port", i);
1178 		if (!pdev)
1179 			goto err_port;
1180 		pdev->dev.parent = &bridge->dev;
1181 
1182 		rc = platform_device_add(pdev);
1183 		if (rc) {
1184 			platform_device_put(pdev);
1185 			goto err_port;
1186 		}
1187 		cxl_root_port[i] = pdev;
1188 	}
1189 
1190 	BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port));
1191 	for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++) {
1192 		struct platform_device *root_port = cxl_root_port[i];
1193 		struct platform_device *pdev;
1194 
1195 		pdev = platform_device_alloc("cxl_switch_uport", i);
1196 		if (!pdev)
1197 			goto err_uport;
1198 		pdev->dev.parent = &root_port->dev;
1199 
1200 		rc = platform_device_add(pdev);
1201 		if (rc) {
1202 			platform_device_put(pdev);
1203 			goto err_uport;
1204 		}
1205 		cxl_switch_uport[i] = pdev;
1206 	}
1207 
1208 	for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) {
1209 		struct platform_device *uport =
1210 			cxl_switch_uport[i % ARRAY_SIZE(cxl_switch_uport)];
1211 		struct platform_device *pdev;
1212 
1213 		pdev = platform_device_alloc("cxl_switch_dport", i);
1214 		if (!pdev)
1215 			goto err_dport;
1216 		pdev->dev.parent = &uport->dev;
1217 
1218 		rc = platform_device_add(pdev);
1219 		if (rc) {
1220 			platform_device_put(pdev);
1221 			goto err_dport;
1222 		}
1223 		cxl_switch_dport[i] = pdev;
1224 	}
1225 
1226 	for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {
1227 		struct platform_device *dport = cxl_switch_dport[i];
1228 		struct platform_device *pdev;
1229 
1230 		pdev = platform_device_alloc("cxl_mem", i);
1231 		if (!pdev)
1232 			goto err_mem;
1233 		pdev->dev.parent = &dport->dev;
1234 		set_dev_node(&pdev->dev, i % 2);
1235 
1236 		rc = platform_device_add(pdev);
1237 		if (rc) {
1238 			platform_device_put(pdev);
1239 			goto err_mem;
1240 		}
1241 		cxl_mem[i] = pdev;
1242 	}
1243 
1244 	rc = cxl_single_init();
1245 	if (rc)
1246 		goto err_mem;
1247 
1248 	rc = cxl_rch_init();
1249 	if (rc)
1250 		goto err_single;
1251 
1252 	cxl_acpi = platform_device_alloc("cxl_acpi", 0);
1253 	if (!cxl_acpi)
1254 		goto err_rch;
1255 
1256 	mock_companion(&acpi0017_mock, &cxl_acpi->dev);
1257 	acpi0017_mock.dev.bus = &platform_bus_type;
1258 
1259 	rc = platform_device_add(cxl_acpi);
1260 	if (rc)
1261 		goto err_add;
1262 
1263 	return 0;
1264 
1265 err_add:
1266 	platform_device_put(cxl_acpi);
1267 err_rch:
1268 	cxl_rch_exit();
1269 err_single:
1270 	cxl_single_exit();
1271 err_mem:
1272 	for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
1273 		platform_device_unregister(cxl_mem[i]);
1274 err_dport:
1275 	for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
1276 		platform_device_unregister(cxl_switch_dport[i]);
1277 err_uport:
1278 	for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
1279 		platform_device_unregister(cxl_switch_uport[i]);
1280 err_port:
1281 	for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
1282 		platform_device_unregister(cxl_root_port[i]);
1283 err_bridge:
1284 	for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
1285 		struct platform_device *pdev = cxl_host_bridge[i];
1286 
1287 		if (!pdev)
1288 			continue;
1289 		sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1290 		platform_device_unregister(cxl_host_bridge[i]);
1291 	}
1292 err_populate:
1293 	depopulate_all_mock_resources();
1294 err_gen_pool_add:
1295 	gen_pool_destroy(cxl_mock_pool);
1296 err_gen_pool_create:
1297 	unregister_cxl_mock_ops(&cxl_mock_ops);
1298 	return rc;
1299 }
1300 
1301 static __exit void cxl_test_exit(void)
1302 {
1303 	int i;
1304 
1305 	platform_device_unregister(cxl_acpi);
1306 	cxl_rch_exit();
1307 	cxl_single_exit();
1308 	for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
1309 		platform_device_unregister(cxl_mem[i]);
1310 	for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
1311 		platform_device_unregister(cxl_switch_dport[i]);
1312 	for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
1313 		platform_device_unregister(cxl_switch_uport[i]);
1314 	for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
1315 		platform_device_unregister(cxl_root_port[i]);
1316 	for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
1317 		struct platform_device *pdev = cxl_host_bridge[i];
1318 
1319 		if (!pdev)
1320 			continue;
1321 		sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1322 		platform_device_unregister(cxl_host_bridge[i]);
1323 	}
1324 	depopulate_all_mock_resources();
1325 	gen_pool_destroy(cxl_mock_pool);
1326 	unregister_cxl_mock_ops(&cxl_mock_ops);
1327 }
1328 
1329 module_param(interleave_arithmetic, int, 0000);
1330 MODULE_PARM_DESC(interleave_arithmetic, "Modulo:0, XOR:1");
1331 module_init(cxl_test_init);
1332 module_exit(cxl_test_exit);
1333 MODULE_LICENSE("GPL v2");
1334 MODULE_IMPORT_NS(ACPI);
1335 MODULE_IMPORT_NS(CXL);
1336