brintos

brintos / linux-shallow public Read only

0
0
Text · 36.0 KiB · 050725a Raw
1536 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// 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 13#include "../watermark.h"14#include "mock.h"15 16static int interleave_arithmetic;17 18#define FAKE_QTG_ID	4219 20#define NR_CXL_HOST_BRIDGES 221#define NR_CXL_SINGLE_HOST 122#define NR_CXL_RCH 123#define NR_CXL_ROOT_PORTS 224#define NR_CXL_SWITCH_PORTS 225#define NR_CXL_PORT_DECODERS 826#define NR_BRIDGES (NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + NR_CXL_RCH)27 28static struct platform_device *cxl_acpi;29static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];30#define NR_MULTI_ROOT (NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS)31static struct platform_device *cxl_root_port[NR_MULTI_ROOT];32static struct platform_device *cxl_switch_uport[NR_MULTI_ROOT];33#define NR_MEM_MULTI \34	(NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS * NR_CXL_SWITCH_PORTS)35static struct platform_device *cxl_switch_dport[NR_MEM_MULTI];36 37static struct platform_device *cxl_hb_single[NR_CXL_SINGLE_HOST];38static struct platform_device *cxl_root_single[NR_CXL_SINGLE_HOST];39static struct platform_device *cxl_swu_single[NR_CXL_SINGLE_HOST];40#define NR_MEM_SINGLE (NR_CXL_SINGLE_HOST * NR_CXL_SWITCH_PORTS)41static struct platform_device *cxl_swd_single[NR_MEM_SINGLE];42 43struct platform_device *cxl_mem[NR_MEM_MULTI];44struct platform_device *cxl_mem_single[NR_MEM_SINGLE];45 46static struct platform_device *cxl_rch[NR_CXL_RCH];47static struct platform_device *cxl_rcd[NR_CXL_RCH];48 49static inline bool is_multi_bridge(struct device *dev)50{51	int i;52 53	for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)54		if (&cxl_host_bridge[i]->dev == dev)55			return true;56	return false;57}58 59static inline bool is_single_bridge(struct device *dev)60{61	int i;62 63	for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)64		if (&cxl_hb_single[i]->dev == dev)65			return true;66	return false;67}68 69static struct acpi_device acpi0017_mock;70static struct acpi_device host_bridge[NR_BRIDGES] = {71	[0] = {72		.handle = &host_bridge[0],73		.pnp.unique_id = "0",74	},75	[1] = {76		.handle = &host_bridge[1],77		.pnp.unique_id = "1",78	},79	[2] = {80		.handle = &host_bridge[2],81		.pnp.unique_id = "2",82	},83	[3] = {84		.handle = &host_bridge[3],85		.pnp.unique_id = "3",86	},87};88 89static bool is_mock_dev(struct device *dev)90{91	int i;92 93	for (i = 0; i < ARRAY_SIZE(cxl_mem); i++)94		if (dev == &cxl_mem[i]->dev)95			return true;96	for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++)97		if (dev == &cxl_mem_single[i]->dev)98			return true;99	for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++)100		if (dev == &cxl_rcd[i]->dev)101			return true;102	if (dev == &cxl_acpi->dev)103		return true;104	return false;105}106 107static bool is_mock_adev(struct acpi_device *adev)108{109	int i;110 111	if (adev == &acpi0017_mock)112		return true;113 114	for (i = 0; i < ARRAY_SIZE(host_bridge); i++)115		if (adev == &host_bridge[i])116			return true;117 118	return false;119}120 121static struct {122	struct acpi_table_cedt cedt;123	struct acpi_cedt_chbs chbs[NR_BRIDGES];124	struct {125		struct acpi_cedt_cfmws cfmws;126		u32 target[1];127	} cfmws0;128	struct {129		struct acpi_cedt_cfmws cfmws;130		u32 target[2];131	} cfmws1;132	struct {133		struct acpi_cedt_cfmws cfmws;134		u32 target[1];135	} cfmws2;136	struct {137		struct acpi_cedt_cfmws cfmws;138		u32 target[2];139	} cfmws3;140	struct {141		struct acpi_cedt_cfmws cfmws;142		u32 target[1];143	} cfmws4;144	struct {145		struct acpi_cedt_cfmws cfmws;146		u32 target[1];147	} cfmws5;148	struct {149		struct acpi_cedt_cfmws cfmws;150		u32 target[1];151	} cfmws6;152	struct {153		struct acpi_cedt_cfmws cfmws;154		u32 target[2];155	} cfmws7;156	struct {157		struct acpi_cedt_cfmws cfmws;158		u32 target[4];159	} cfmws8;160	struct {161		struct acpi_cedt_cxims cxims;162		u64 xormap_list[2];163	} cxims0;164} __packed mock_cedt = {165	.cedt = {166		.header = {167			.signature = "CEDT",168			.length = sizeof(mock_cedt),169			.revision = 1,170		},171	},172	.chbs[0] = {173		.header = {174			.type = ACPI_CEDT_TYPE_CHBS,175			.length = sizeof(mock_cedt.chbs[0]),176		},177		.uid = 0,178		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,179	},180	.chbs[1] = {181		.header = {182			.type = ACPI_CEDT_TYPE_CHBS,183			.length = sizeof(mock_cedt.chbs[0]),184		},185		.uid = 1,186		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,187	},188	.chbs[2] = {189		.header = {190			.type = ACPI_CEDT_TYPE_CHBS,191			.length = sizeof(mock_cedt.chbs[0]),192		},193		.uid = 2,194		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,195	},196	.chbs[3] = {197		.header = {198			.type = ACPI_CEDT_TYPE_CHBS,199			.length = sizeof(mock_cedt.chbs[0]),200		},201		.uid = 3,202		.cxl_version = ACPI_CEDT_CHBS_VERSION_CXL11,203	},204	.cfmws0 = {205		.cfmws = {206			.header = {207				.type = ACPI_CEDT_TYPE_CFMWS,208				.length = sizeof(mock_cedt.cfmws0),209			},210			.interleave_ways = 0,211			.granularity = 4,212			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |213					ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,214			.qtg_id = FAKE_QTG_ID,215			.window_size = SZ_256M * 4UL,216		},217		.target = { 0 },218	},219	.cfmws1 = {220		.cfmws = {221			.header = {222				.type = ACPI_CEDT_TYPE_CFMWS,223				.length = sizeof(mock_cedt.cfmws1),224			},225			.interleave_ways = 1,226			.granularity = 4,227			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |228					ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,229			.qtg_id = FAKE_QTG_ID,230			.window_size = SZ_256M * 8UL,231		},232		.target = { 0, 1, },233	},234	.cfmws2 = {235		.cfmws = {236			.header = {237				.type = ACPI_CEDT_TYPE_CFMWS,238				.length = sizeof(mock_cedt.cfmws2),239			},240			.interleave_ways = 0,241			.granularity = 4,242			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |243					ACPI_CEDT_CFMWS_RESTRICT_PMEM,244			.qtg_id = FAKE_QTG_ID,245			.window_size = SZ_256M * 4UL,246		},247		.target = { 0 },248	},249	.cfmws3 = {250		.cfmws = {251			.header = {252				.type = ACPI_CEDT_TYPE_CFMWS,253				.length = sizeof(mock_cedt.cfmws3),254			},255			.interleave_ways = 1,256			.granularity = 4,257			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |258					ACPI_CEDT_CFMWS_RESTRICT_PMEM,259			.qtg_id = FAKE_QTG_ID,260			.window_size = SZ_256M * 8UL,261		},262		.target = { 0, 1, },263	},264	.cfmws4 = {265		.cfmws = {266			.header = {267				.type = ACPI_CEDT_TYPE_CFMWS,268				.length = sizeof(mock_cedt.cfmws4),269			},270			.interleave_ways = 0,271			.granularity = 4,272			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |273					ACPI_CEDT_CFMWS_RESTRICT_PMEM,274			.qtg_id = FAKE_QTG_ID,275			.window_size = SZ_256M * 4UL,276		},277		.target = { 2 },278	},279	.cfmws5 = {280		.cfmws = {281			.header = {282				.type = ACPI_CEDT_TYPE_CFMWS,283				.length = sizeof(mock_cedt.cfmws5),284			},285			.interleave_ways = 0,286			.granularity = 4,287			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |288					ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,289			.qtg_id = FAKE_QTG_ID,290			.window_size = SZ_256M,291		},292		.target = { 3 },293	},294	/* .cfmws6,7,8 use ACPI_CEDT_CFMWS_ARITHMETIC_XOR */295	.cfmws6 = {296		.cfmws = {297			.header = {298				.type = ACPI_CEDT_TYPE_CFMWS,299				.length = sizeof(mock_cedt.cfmws6),300			},301			.interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,302			.interleave_ways = 0,303			.granularity = 4,304			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |305					ACPI_CEDT_CFMWS_RESTRICT_PMEM,306			.qtg_id = FAKE_QTG_ID,307			.window_size = SZ_256M * 8UL,308		},309		.target = { 0, },310	},311	.cfmws7 = {312		.cfmws = {313			.header = {314				.type = ACPI_CEDT_TYPE_CFMWS,315				.length = sizeof(mock_cedt.cfmws7),316			},317			.interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,318			.interleave_ways = 1,319			.granularity = 0,320			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |321					ACPI_CEDT_CFMWS_RESTRICT_PMEM,322			.qtg_id = FAKE_QTG_ID,323			.window_size = SZ_256M * 8UL,324		},325		.target = { 0, 1, },326	},327	.cfmws8 = {328		.cfmws = {329			.header = {330				.type = ACPI_CEDT_TYPE_CFMWS,331				.length = sizeof(mock_cedt.cfmws8),332			},333			.interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,334			.interleave_ways = 2,335			.granularity = 0,336			.restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |337					ACPI_CEDT_CFMWS_RESTRICT_PMEM,338			.qtg_id = FAKE_QTG_ID,339			.window_size = SZ_256M * 16UL,340		},341		.target = { 0, 1, 0, 1, },342	},343	.cxims0 = {344		.cxims = {345			.header = {346				.type = ACPI_CEDT_TYPE_CXIMS,347				.length = sizeof(mock_cedt.cxims0),348			},349			.hbig = 0,350			.nr_xormaps = 2,351		},352		.xormap_list = { 0x404100, 0x808200, },353	},354};355 356struct acpi_cedt_cfmws *mock_cfmws[] = {357	[0] = &mock_cedt.cfmws0.cfmws,358	[1] = &mock_cedt.cfmws1.cfmws,359	[2] = &mock_cedt.cfmws2.cfmws,360	[3] = &mock_cedt.cfmws3.cfmws,361	[4] = &mock_cedt.cfmws4.cfmws,362	[5] = &mock_cedt.cfmws5.cfmws,363	/* Modulo Math above, XOR Math below */364	[6] = &mock_cedt.cfmws6.cfmws,365	[7] = &mock_cedt.cfmws7.cfmws,366	[8] = &mock_cedt.cfmws8.cfmws,367};368 369static int cfmws_start;370static int cfmws_end;371#define CFMWS_MOD_ARRAY_START 0372#define CFMWS_MOD_ARRAY_END   5373#define CFMWS_XOR_ARRAY_START 6374#define CFMWS_XOR_ARRAY_END   8375 376struct acpi_cedt_cxims *mock_cxims[1] = {377	[0] = &mock_cedt.cxims0.cxims,378};379 380struct cxl_mock_res {381	struct list_head list;382	struct range range;383};384 385static LIST_HEAD(mock_res);386static DEFINE_MUTEX(mock_res_lock);387static struct gen_pool *cxl_mock_pool;388 389static void depopulate_all_mock_resources(void)390{391	struct cxl_mock_res *res, *_res;392 393	mutex_lock(&mock_res_lock);394	list_for_each_entry_safe(res, _res, &mock_res, list) {395		gen_pool_free(cxl_mock_pool, res->range.start,396			      range_len(&res->range));397		list_del(&res->list);398		kfree(res);399	}400	mutex_unlock(&mock_res_lock);401}402 403static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)404{405	struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);406	struct genpool_data_align data = {407		.align = align,408	};409	unsigned long phys;410 411	INIT_LIST_HEAD(&res->list);412	phys = gen_pool_alloc_algo(cxl_mock_pool, size,413				   gen_pool_first_fit_align, &data);414	if (!phys)415		return NULL;416 417	res->range = (struct range) {418		.start = phys,419		.end = phys + size - 1,420	};421	mutex_lock(&mock_res_lock);422	list_add(&res->list, &mock_res);423	mutex_unlock(&mock_res_lock);424 425	return res;426}427 428static int populate_cedt(void)429{430	struct cxl_mock_res *res;431	int i;432 433	for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {434		struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i];435		resource_size_t size;436 437		if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20)438			size = ACPI_CEDT_CHBS_LENGTH_CXL20;439		else440			size = ACPI_CEDT_CHBS_LENGTH_CXL11;441 442		res = alloc_mock_res(size, size);443		if (!res)444			return -ENOMEM;445		chbs->base = res->range.start;446		chbs->length = size;447	}448 449	for (i = cfmws_start; i <= cfmws_end; i++) {450		struct acpi_cedt_cfmws *window = mock_cfmws[i];451 452		res = alloc_mock_res(window->window_size, SZ_256M);453		if (!res)454			return -ENOMEM;455		window->base_hpa = res->range.start;456	}457 458	return 0;459}460 461static bool is_mock_port(struct device *dev);462 463/*464 * WARNING, this hack assumes the format of 'struct cxl_cfmws_context'465 * and 'struct cxl_chbs_context' share the property that the first466 * struct member is a cxl_test device being probed by the cxl_acpi467 * driver.468 */469struct cxl_cedt_context {470	struct device *dev;471};472 473static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,474				      acpi_tbl_entry_handler_arg handler_arg,475				      void *arg)476{477	struct cxl_cedt_context *ctx = arg;478	struct device *dev = ctx->dev;479	union acpi_subtable_headers *h;480	unsigned long end;481	int i;482 483	if (!is_mock_port(dev) && !is_mock_dev(dev))484		return acpi_table_parse_cedt(id, handler_arg, arg);485 486	if (id == ACPI_CEDT_TYPE_CHBS)487		for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {488			h = (union acpi_subtable_headers *)&mock_cedt.chbs[i];489			end = (unsigned long)&mock_cedt.chbs[i + 1];490			handler_arg(h, arg, end);491		}492 493	if (id == ACPI_CEDT_TYPE_CFMWS)494		for (i = cfmws_start; i <= cfmws_end; i++) {495			h = (union acpi_subtable_headers *) mock_cfmws[i];496			end = (unsigned long) h + mock_cfmws[i]->header.length;497			handler_arg(h, arg, end);498		}499 500	if (id == ACPI_CEDT_TYPE_CXIMS)501		for (i = 0; i < ARRAY_SIZE(mock_cxims); i++) {502			h = (union acpi_subtable_headers *)mock_cxims[i];503			end = (unsigned long)h + mock_cxims[i]->header.length;504			handler_arg(h, arg, end);505		}506 507	return 0;508}509 510static bool is_mock_bridge(struct device *dev)511{512	int i;513 514	for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)515		if (dev == &cxl_host_bridge[i]->dev)516			return true;517	for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)518		if (dev == &cxl_hb_single[i]->dev)519			return true;520	for (i = 0; i < ARRAY_SIZE(cxl_rch); i++)521		if (dev == &cxl_rch[i]->dev)522			return true;523 524	return false;525}526 527static bool is_mock_port(struct device *dev)528{529	int i;530 531	if (is_mock_bridge(dev))532		return true;533 534	for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++)535		if (dev == &cxl_root_port[i]->dev)536			return true;537 538	for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++)539		if (dev == &cxl_switch_uport[i]->dev)540			return true;541 542	for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++)543		if (dev == &cxl_switch_dport[i]->dev)544			return true;545 546	for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++)547		if (dev == &cxl_root_single[i]->dev)548			return true;549 550	for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++)551		if (dev == &cxl_swu_single[i]->dev)552			return true;553 554	for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++)555		if (dev == &cxl_swd_single[i]->dev)556			return true;557 558	if (is_cxl_memdev(dev))559		return is_mock_dev(dev->parent);560 561	return false;562}563 564static int host_bridge_index(struct acpi_device *adev)565{566	return adev - host_bridge;567}568 569static struct acpi_device *find_host_bridge(acpi_handle handle)570{571	int i;572 573	for (i = 0; i < ARRAY_SIZE(host_bridge); i++)574		if (handle == host_bridge[i].handle)575			return &host_bridge[i];576	return NULL;577}578 579static acpi_status580mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname,581			   struct acpi_object_list *arguments,582			   unsigned long long *data)583{584	struct acpi_device *adev = find_host_bridge(handle);585 586	if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0)587		return acpi_evaluate_integer(handle, pathname, arguments, data);588 589	*data = host_bridge_index(adev);590	return AE_OK;591}592 593static struct pci_bus mock_pci_bus[NR_BRIDGES];594static struct acpi_pci_root mock_pci_root[ARRAY_SIZE(mock_pci_bus)] = {595	[0] = {596		.bus = &mock_pci_bus[0],597	},598	[1] = {599		.bus = &mock_pci_bus[1],600	},601	[2] = {602		.bus = &mock_pci_bus[2],603	},604	[3] = {605		.bus = &mock_pci_bus[3],606	},607 608};609 610static bool is_mock_bus(struct pci_bus *bus)611{612	int i;613 614	for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++)615		if (bus == &mock_pci_bus[i])616			return true;617	return false;618}619 620static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle)621{622	struct acpi_device *adev = find_host_bridge(handle);623 624	if (!adev)625		return acpi_pci_find_root(handle);626	return &mock_pci_root[host_bridge_index(adev)];627}628 629static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port,630					  struct cxl_endpoint_dvsec_info *info)631{632	struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL);633	struct device *dev = &port->dev;634 635	if (!cxlhdm)636		return ERR_PTR(-ENOMEM);637 638	cxlhdm->port = port;639	cxlhdm->interleave_mask = ~0U;640	cxlhdm->iw_cap_mask = ~0UL;641	dev_set_drvdata(dev, cxlhdm);642	return cxlhdm;643}644 645static int mock_cxl_add_passthrough_decoder(struct cxl_port *port)646{647	dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n");648	return -EOPNOTSUPP;649}650 651 652struct target_map_ctx {653	int *target_map;654	int index;655	int target_count;656};657 658static int map_targets(struct device *dev, void *data)659{660	struct platform_device *pdev = to_platform_device(dev);661	struct target_map_ctx *ctx = data;662 663	ctx->target_map[ctx->index++] = pdev->id;664 665	if (ctx->index > ctx->target_count) {666		dev_WARN_ONCE(dev, 1, "too many targets found?\n");667		return -ENXIO;668	}669 670	return 0;671}672 673static int mock_decoder_commit(struct cxl_decoder *cxld)674{675	struct cxl_port *port = to_cxl_port(cxld->dev.parent);676	int id = cxld->id;677 678	if (cxld->flags & CXL_DECODER_F_ENABLE)679		return 0;680 681	dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));682	if (cxl_num_decoders_committed(port) != id) {683		dev_dbg(&port->dev,684			"%s: out of order commit, expected decoder%d.%d\n",685			dev_name(&cxld->dev), port->id,686			cxl_num_decoders_committed(port));687		return -EBUSY;688	}689 690	port->commit_end++;691	cxld->flags |= CXL_DECODER_F_ENABLE;692 693	return 0;694}695 696static void mock_decoder_reset(struct cxl_decoder *cxld)697{698	struct cxl_port *port = to_cxl_port(cxld->dev.parent);699	int id = cxld->id;700 701	if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)702		return;703 704	dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));705	if (port->commit_end == id)706		cxl_port_commit_reap(cxld);707	else708		dev_dbg(&port->dev,709			"%s: out of order reset, expected decoder%d.%d\n",710			dev_name(&cxld->dev), port->id, port->commit_end);711	cxld->flags &= ~CXL_DECODER_F_ENABLE;712}713 714static void default_mock_decoder(struct cxl_decoder *cxld)715{716	cxld->hpa_range = (struct range){717		.start = 0,718		.end = -1,719	};720 721	cxld->interleave_ways = 1;722	cxld->interleave_granularity = 256;723	cxld->target_type = CXL_DECODER_HOSTONLYMEM;724	cxld->commit = mock_decoder_commit;725	cxld->reset = mock_decoder_reset;726}727 728static int first_decoder(struct device *dev, void *data)729{730	struct cxl_decoder *cxld;731 732	if (!is_switch_decoder(dev))733		return 0;734	cxld = to_cxl_decoder(dev);735	if (cxld->id == 0)736		return 1;737	return 0;738}739 740static void mock_init_hdm_decoder(struct cxl_decoder *cxld)741{742	struct acpi_cedt_cfmws *window = mock_cfmws[0];743	struct platform_device *pdev = NULL;744	struct cxl_endpoint_decoder *cxled;745	struct cxl_switch_decoder *cxlsd;746	struct cxl_port *port, *iter;747	const int size = SZ_512M;748	struct cxl_memdev *cxlmd;749	struct cxl_dport *dport;750	struct device *dev;751	bool hb0 = false;752	u64 base;753	int i;754 755	if (is_endpoint_decoder(&cxld->dev)) {756		cxled = to_cxl_endpoint_decoder(&cxld->dev);757		cxlmd = cxled_to_memdev(cxled);758		WARN_ON(!dev_is_platform(cxlmd->dev.parent));759		pdev = to_platform_device(cxlmd->dev.parent);760 761		/* check is endpoint is attach to host-bridge0 */762		port = cxled_to_port(cxled);763		do {764			if (port->uport_dev == &cxl_host_bridge[0]->dev) {765				hb0 = true;766				break;767			}768			if (is_cxl_port(port->dev.parent))769				port = to_cxl_port(port->dev.parent);770			else771				port = NULL;772		} while (port);773		port = cxled_to_port(cxled);774	}775 776	/*777	 * The first decoder on the first 2 devices on the first switch778	 * attached to host-bridge0 mock a fake / static RAM region. All779	 * other decoders are default disabled. Given the round robin780	 * assignment those devices are named cxl_mem.0, and cxl_mem.4.781	 *782	 * See 'cxl list -BMPu -m cxl_mem.0,cxl_mem.4'783	 */784	if (!hb0 || pdev->id % 4 || pdev->id > 4 || cxld->id > 0) {785		default_mock_decoder(cxld);786		return;787	}788 789	base = window->base_hpa;790	cxld->hpa_range = (struct range) {791		.start = base,792		.end = base + size - 1,793	};794 795	cxld->interleave_ways = 2;796	eig_to_granularity(window->granularity, &cxld->interleave_granularity);797	cxld->target_type = CXL_DECODER_HOSTONLYMEM;798	cxld->flags = CXL_DECODER_F_ENABLE;799	cxled->state = CXL_DECODER_STATE_AUTO;800	port->commit_end = cxld->id;801	devm_cxl_dpa_reserve(cxled, 0, size / cxld->interleave_ways, 0);802	cxld->commit = mock_decoder_commit;803	cxld->reset = mock_decoder_reset;804 805	/*806	 * Now that endpoint decoder is set up, walk up the hierarchy807	 * and setup the switch and root port decoders targeting @cxlmd.808	 */809	iter = port;810	for (i = 0; i < 2; i++) {811		dport = iter->parent_dport;812		iter = dport->port;813		dev = device_find_child(&iter->dev, NULL, first_decoder);814		/*815		 * Ancestor ports are guaranteed to be enumerated before816		 * @port, and all ports have at least one decoder.817		 */818		if (WARN_ON(!dev))819			continue;820		cxlsd = to_cxl_switch_decoder(dev);821		if (i == 0) {822			/* put cxl_mem.4 second in the decode order */823			if (pdev->id == 4)824				cxlsd->target[1] = dport;825			else826				cxlsd->target[0] = dport;827		} else828			cxlsd->target[0] = dport;829		cxld = &cxlsd->cxld;830		cxld->target_type = CXL_DECODER_HOSTONLYMEM;831		cxld->flags = CXL_DECODER_F_ENABLE;832		iter->commit_end = 0;833		/*834		 * Switch targets 2 endpoints, while host bridge targets835		 * one root port836		 */837		if (i == 0)838			cxld->interleave_ways = 2;839		else840			cxld->interleave_ways = 1;841		cxld->interleave_granularity = 4096;842		cxld->hpa_range = (struct range) {843			.start = base,844			.end = base + size - 1,845		};846		put_device(dev);847	}848}849 850static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,851				       struct cxl_endpoint_dvsec_info *info)852{853	struct cxl_port *port = cxlhdm->port;854	struct cxl_port *parent_port = to_cxl_port(port->dev.parent);855	int target_count, i;856 857	if (is_cxl_endpoint(port))858		target_count = 0;859	else if (is_cxl_root(parent_port))860		target_count = NR_CXL_ROOT_PORTS;861	else862		target_count = NR_CXL_SWITCH_PORTS;863 864	for (i = 0; i < NR_CXL_PORT_DECODERS; i++) {865		int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };866		struct target_map_ctx ctx = {867			.target_map = target_map,868			.target_count = target_count,869		};870		struct cxl_decoder *cxld;871		int rc;872 873		if (target_count) {874			struct cxl_switch_decoder *cxlsd;875 876			cxlsd = cxl_switch_decoder_alloc(port, target_count);877			if (IS_ERR(cxlsd)) {878				dev_warn(&port->dev,879					 "Failed to allocate the decoder\n");880				return PTR_ERR(cxlsd);881			}882			cxld = &cxlsd->cxld;883		} else {884			struct cxl_endpoint_decoder *cxled;885 886			cxled = cxl_endpoint_decoder_alloc(port);887 888			if (IS_ERR(cxled)) {889				dev_warn(&port->dev,890					 "Failed to allocate the decoder\n");891				return PTR_ERR(cxled);892			}893			cxld = &cxled->cxld;894		}895 896		mock_init_hdm_decoder(cxld);897 898		if (target_count) {899			rc = device_for_each_child(port->uport_dev, &ctx,900						   map_targets);901			if (rc) {902				put_device(&cxld->dev);903				return rc;904			}905		}906 907		rc = cxl_decoder_add_locked(cxld, target_map);908		if (rc) {909			put_device(&cxld->dev);910			dev_err(&port->dev, "Failed to add decoder\n");911			return rc;912		}913 914		rc = cxl_decoder_autoremove(&port->dev, cxld);915		if (rc)916			return rc;917		dev_dbg(&cxld->dev, "Added to port %s\n", dev_name(&port->dev));918	}919 920	return 0;921}922 923static int mock_cxl_port_enumerate_dports(struct cxl_port *port)924{925	struct platform_device **array;926	int i, array_size;927 928	if (port->depth == 1) {929		if (is_multi_bridge(port->uport_dev)) {930			array_size = ARRAY_SIZE(cxl_root_port);931			array = cxl_root_port;932		} else if (is_single_bridge(port->uport_dev)) {933			array_size = ARRAY_SIZE(cxl_root_single);934			array = cxl_root_single;935		} else {936			dev_dbg(&port->dev, "%s: unknown bridge type\n",937				dev_name(port->uport_dev));938			return -ENXIO;939		}940	} else if (port->depth == 2) {941		struct cxl_port *parent = to_cxl_port(port->dev.parent);942 943		if (is_multi_bridge(parent->uport_dev)) {944			array_size = ARRAY_SIZE(cxl_switch_dport);945			array = cxl_switch_dport;946		} else if (is_single_bridge(parent->uport_dev)) {947			array_size = ARRAY_SIZE(cxl_swd_single);948			array = cxl_swd_single;949		} else {950			dev_dbg(&port->dev, "%s: unknown bridge type\n",951				dev_name(port->uport_dev));952			return -ENXIO;953		}954	} else {955		dev_WARN_ONCE(&port->dev, 1, "unexpected depth %d\n",956			      port->depth);957		return -ENXIO;958	}959 960	for (i = 0; i < array_size; i++) {961		struct platform_device *pdev = array[i];962		struct cxl_dport *dport;963 964		if (pdev->dev.parent != port->uport_dev) {965			dev_dbg(&port->dev, "%s: mismatch parent %s\n",966				dev_name(port->uport_dev),967				dev_name(pdev->dev.parent));968			continue;969		}970 971		dport = devm_cxl_add_dport(port, &pdev->dev, pdev->id,972					   CXL_RESOURCE_NONE);973 974		if (IS_ERR(dport))975			return PTR_ERR(dport);976	}977 978	return 0;979}980 981/*982 * Faking the cxl_dpa_perf for the memdev when appropriate.983 */984static void dpa_perf_setup(struct cxl_port *endpoint, struct range *range,985			   struct cxl_dpa_perf *dpa_perf)986{987	dpa_perf->qos_class = FAKE_QTG_ID;988	dpa_perf->dpa_range = *range;989	for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {990		dpa_perf->coord[i].read_latency = 500;991		dpa_perf->coord[i].write_latency = 500;992		dpa_perf->coord[i].read_bandwidth = 1000;993		dpa_perf->coord[i].write_bandwidth = 1000;994	}995}996 997static void mock_cxl_endpoint_parse_cdat(struct cxl_port *port)998{999	struct cxl_root *cxl_root __free(put_cxl_root) =1000		find_cxl_root(port);1001	struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);1002	struct cxl_dev_state *cxlds = cxlmd->cxlds;1003	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);1004	struct access_coordinate ep_c[ACCESS_COORDINATE_MAX];1005	struct range pmem_range = {1006		.start = cxlds->pmem_res.start,1007		.end = cxlds->pmem_res.end,1008	};1009	struct range ram_range = {1010		.start = cxlds->ram_res.start,1011		.end = cxlds->ram_res.end,1012	};1013 1014	if (!cxl_root)1015		return;1016 1017	if (range_len(&ram_range))1018		dpa_perf_setup(port, &ram_range, &mds->ram_perf);1019 1020	if (range_len(&pmem_range))1021		dpa_perf_setup(port, &pmem_range, &mds->pmem_perf);1022 1023	cxl_memdev_update_perf(cxlmd);1024 1025	/*1026	 * This function is here to only test the topology iterator. It serves1027	 * no other purpose.1028	 */1029	cxl_endpoint_get_perf_coordinates(port, ep_c);1030}1031 1032static struct cxl_mock_ops cxl_mock_ops = {1033	.is_mock_adev = is_mock_adev,1034	.is_mock_bridge = is_mock_bridge,1035	.is_mock_bus = is_mock_bus,1036	.is_mock_port = is_mock_port,1037	.is_mock_dev = is_mock_dev,1038	.acpi_table_parse_cedt = mock_acpi_table_parse_cedt,1039	.acpi_evaluate_integer = mock_acpi_evaluate_integer,1040	.acpi_pci_find_root = mock_acpi_pci_find_root,1041	.devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,1042	.devm_cxl_setup_hdm = mock_cxl_setup_hdm,1043	.devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,1044	.devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,1045	.cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat,1046	.list = LIST_HEAD_INIT(cxl_mock_ops.list),1047};1048 1049static void mock_companion(struct acpi_device *adev, struct device *dev)1050{1051	device_initialize(&adev->dev);1052	fwnode_init(&adev->fwnode, NULL);1053	dev->fwnode = &adev->fwnode;1054	adev->fwnode.dev = dev;1055}1056 1057#ifndef SZ_64G1058#define SZ_64G (SZ_32G * 2)1059#endif1060 1061static __init int cxl_rch_topo_init(void)1062{1063	int rc, i;1064 1065	for (i = 0; i < ARRAY_SIZE(cxl_rch); i++) {1066		int idx = NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + i;1067		struct acpi_device *adev = &host_bridge[idx];1068		struct platform_device *pdev;1069 1070		pdev = platform_device_alloc("cxl_host_bridge", idx);1071		if (!pdev)1072			goto err_bridge;1073 1074		mock_companion(adev, &pdev->dev);1075		rc = platform_device_add(pdev);1076		if (rc) {1077			platform_device_put(pdev);1078			goto err_bridge;1079		}1080 1081		cxl_rch[i] = pdev;1082		mock_pci_bus[idx].bridge = &pdev->dev;1083		rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,1084				       "firmware_node");1085		if (rc)1086			goto err_bridge;1087	}1088 1089	return 0;1090 1091err_bridge:1092	for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {1093		struct platform_device *pdev = cxl_rch[i];1094 1095		if (!pdev)1096			continue;1097		sysfs_remove_link(&pdev->dev.kobj, "firmware_node");1098		platform_device_unregister(cxl_rch[i]);1099	}1100 1101	return rc;1102}1103 1104static void cxl_rch_topo_exit(void)1105{1106	int i;1107 1108	for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {1109		struct platform_device *pdev = cxl_rch[i];1110 1111		if (!pdev)1112			continue;1113		sysfs_remove_link(&pdev->dev.kobj, "firmware_node");1114		platform_device_unregister(cxl_rch[i]);1115	}1116}1117 1118static __init int cxl_single_topo_init(void)1119{1120	int i, rc;1121 1122	for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++) {1123		struct acpi_device *adev =1124			&host_bridge[NR_CXL_HOST_BRIDGES + i];1125		struct platform_device *pdev;1126 1127		pdev = platform_device_alloc("cxl_host_bridge",1128					     NR_CXL_HOST_BRIDGES + i);1129		if (!pdev)1130			goto err_bridge;1131 1132		mock_companion(adev, &pdev->dev);1133		rc = platform_device_add(pdev);1134		if (rc) {1135			platform_device_put(pdev);1136			goto err_bridge;1137		}1138 1139		cxl_hb_single[i] = pdev;1140		mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev;1141		rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,1142				       "physical_node");1143		if (rc)1144			goto err_bridge;1145	}1146 1147	for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++) {1148		struct platform_device *bridge =1149			cxl_hb_single[i % ARRAY_SIZE(cxl_hb_single)];1150		struct platform_device *pdev;1151 1152		pdev = platform_device_alloc("cxl_root_port",1153					     NR_MULTI_ROOT + i);1154		if (!pdev)1155			goto err_port;1156		pdev->dev.parent = &bridge->dev;1157 1158		rc = platform_device_add(pdev);1159		if (rc) {1160			platform_device_put(pdev);1161			goto err_port;1162		}1163		cxl_root_single[i] = pdev;1164	}1165 1166	for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) {1167		struct platform_device *root_port = cxl_root_single[i];1168		struct platform_device *pdev;1169 1170		pdev = platform_device_alloc("cxl_switch_uport",1171					     NR_MULTI_ROOT + i);1172		if (!pdev)1173			goto err_uport;1174		pdev->dev.parent = &root_port->dev;1175 1176		rc = platform_device_add(pdev);1177		if (rc) {1178			platform_device_put(pdev);1179			goto err_uport;1180		}1181		cxl_swu_single[i] = pdev;1182	}1183 1184	for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) {1185		struct platform_device *uport =1186			cxl_swu_single[i % ARRAY_SIZE(cxl_swu_single)];1187		struct platform_device *pdev;1188 1189		pdev = platform_device_alloc("cxl_switch_dport",1190					     i + NR_MEM_MULTI);1191		if (!pdev)1192			goto err_dport;1193		pdev->dev.parent = &uport->dev;1194 1195		rc = platform_device_add(pdev);1196		if (rc) {1197			platform_device_put(pdev);1198			goto err_dport;1199		}1200		cxl_swd_single[i] = pdev;1201	}1202 1203	return 0;1204 1205err_dport:1206	for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)1207		platform_device_unregister(cxl_swd_single[i]);1208err_uport:1209	for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)1210		platform_device_unregister(cxl_swu_single[i]);1211err_port:1212	for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)1213		platform_device_unregister(cxl_root_single[i]);1214err_bridge:1215	for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {1216		struct platform_device *pdev = cxl_hb_single[i];1217 1218		if (!pdev)1219			continue;1220		sysfs_remove_link(&pdev->dev.kobj, "physical_node");1221		platform_device_unregister(cxl_hb_single[i]);1222	}1223 1224	return rc;1225}1226 1227static void cxl_single_topo_exit(void)1228{1229	int i;1230 1231	for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)1232		platform_device_unregister(cxl_swd_single[i]);1233	for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)1234		platform_device_unregister(cxl_swu_single[i]);1235	for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)1236		platform_device_unregister(cxl_root_single[i]);1237	for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {1238		struct platform_device *pdev = cxl_hb_single[i];1239 1240		if (!pdev)1241			continue;1242		sysfs_remove_link(&pdev->dev.kobj, "physical_node");1243		platform_device_unregister(cxl_hb_single[i]);1244	}1245}1246 1247static void cxl_mem_exit(void)1248{1249	int i;1250 1251	for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)1252		platform_device_unregister(cxl_rcd[i]);1253	for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)1254		platform_device_unregister(cxl_mem_single[i]);1255	for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)1256		platform_device_unregister(cxl_mem[i]);1257}1258 1259static int cxl_mem_init(void)1260{1261	int i, rc;1262 1263	for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {1264		struct platform_device *dport = cxl_switch_dport[i];1265		struct platform_device *pdev;1266 1267		pdev = platform_device_alloc("cxl_mem", i);1268		if (!pdev)1269			goto err_mem;1270		pdev->dev.parent = &dport->dev;1271		set_dev_node(&pdev->dev, i % 2);1272 1273		rc = platform_device_add(pdev);1274		if (rc) {1275			platform_device_put(pdev);1276			goto err_mem;1277		}1278		cxl_mem[i] = pdev;1279	}1280 1281	for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) {1282		struct platform_device *dport = cxl_swd_single[i];1283		struct platform_device *pdev;1284 1285		pdev = platform_device_alloc("cxl_mem", NR_MEM_MULTI + i);1286		if (!pdev)1287			goto err_single;1288		pdev->dev.parent = &dport->dev;1289		set_dev_node(&pdev->dev, i % 2);1290 1291		rc = platform_device_add(pdev);1292		if (rc) {1293			platform_device_put(pdev);1294			goto err_single;1295		}1296		cxl_mem_single[i] = pdev;1297	}1298 1299	for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {1300		int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;1301		struct platform_device *rch = cxl_rch[i];1302		struct platform_device *pdev;1303 1304		pdev = platform_device_alloc("cxl_rcd", idx);1305		if (!pdev)1306			goto err_rcd;1307		pdev->dev.parent = &rch->dev;1308		set_dev_node(&pdev->dev, i % 2);1309 1310		rc = platform_device_add(pdev);1311		if (rc) {1312			platform_device_put(pdev);1313			goto err_rcd;1314		}1315		cxl_rcd[i] = pdev;1316	}1317 1318	return 0;1319 1320err_rcd:1321	for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)1322		platform_device_unregister(cxl_rcd[i]);1323err_single:1324	for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)1325		platform_device_unregister(cxl_mem_single[i]);1326err_mem:1327	for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)1328		platform_device_unregister(cxl_mem[i]);1329	return rc;1330}1331 1332static __init int cxl_test_init(void)1333{1334	int rc, i;1335 1336	cxl_acpi_test();1337	cxl_core_test();1338	cxl_mem_test();1339	cxl_pmem_test();1340	cxl_port_test();1341 1342	register_cxl_mock_ops(&cxl_mock_ops);1343 1344	cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE);1345	if (!cxl_mock_pool) {1346		rc = -ENOMEM;1347		goto err_gen_pool_create;1348	}1349 1350	rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,1351			  SZ_64G, NUMA_NO_NODE);1352	if (rc)1353		goto err_gen_pool_add;1354 1355	if (interleave_arithmetic == 1) {1356		cfmws_start = CFMWS_XOR_ARRAY_START;1357		cfmws_end = CFMWS_XOR_ARRAY_END;1358	} else {1359		cfmws_start = CFMWS_MOD_ARRAY_START;1360		cfmws_end = CFMWS_MOD_ARRAY_END;1361	}1362 1363	rc = populate_cedt();1364	if (rc)1365		goto err_populate;1366 1367	for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) {1368		struct acpi_device *adev = &host_bridge[i];1369		struct platform_device *pdev;1370 1371		pdev = platform_device_alloc("cxl_host_bridge", i);1372		if (!pdev)1373			goto err_bridge;1374 1375		mock_companion(adev, &pdev->dev);1376		rc = platform_device_add(pdev);1377		if (rc) {1378			platform_device_put(pdev);1379			goto err_bridge;1380		}1381 1382		cxl_host_bridge[i] = pdev;1383		mock_pci_bus[i].bridge = &pdev->dev;1384		rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,1385				       "physical_node");1386		if (rc)1387			goto err_bridge;1388	}1389 1390	for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) {1391		struct platform_device *bridge =1392			cxl_host_bridge[i % ARRAY_SIZE(cxl_host_bridge)];1393		struct platform_device *pdev;1394 1395		pdev = platform_device_alloc("cxl_root_port", i);1396		if (!pdev)1397			goto err_port;1398		pdev->dev.parent = &bridge->dev;1399 1400		rc = platform_device_add(pdev);1401		if (rc) {1402			platform_device_put(pdev);1403			goto err_port;1404		}1405		cxl_root_port[i] = pdev;1406	}1407 1408	BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port));1409	for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++) {1410		struct platform_device *root_port = cxl_root_port[i];1411		struct platform_device *pdev;1412 1413		pdev = platform_device_alloc("cxl_switch_uport", i);1414		if (!pdev)1415			goto err_uport;1416		pdev->dev.parent = &root_port->dev;1417 1418		rc = platform_device_add(pdev);1419		if (rc) {1420			platform_device_put(pdev);1421			goto err_uport;1422		}1423		cxl_switch_uport[i] = pdev;1424	}1425 1426	for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) {1427		struct platform_device *uport =1428			cxl_switch_uport[i % ARRAY_SIZE(cxl_switch_uport)];1429		struct platform_device *pdev;1430 1431		pdev = platform_device_alloc("cxl_switch_dport", i);1432		if (!pdev)1433			goto err_dport;1434		pdev->dev.parent = &uport->dev;1435 1436		rc = platform_device_add(pdev);1437		if (rc) {1438			platform_device_put(pdev);1439			goto err_dport;1440		}1441		cxl_switch_dport[i] = pdev;1442	}1443 1444	rc = cxl_single_topo_init();1445	if (rc)1446		goto err_dport;1447 1448	rc = cxl_rch_topo_init();1449	if (rc)1450		goto err_single;1451 1452	cxl_acpi = platform_device_alloc("cxl_acpi", 0);1453	if (!cxl_acpi)1454		goto err_rch;1455 1456	mock_companion(&acpi0017_mock, &cxl_acpi->dev);1457	acpi0017_mock.dev.bus = &platform_bus_type;1458 1459	rc = platform_device_add(cxl_acpi);1460	if (rc)1461		goto err_root;1462 1463	rc = cxl_mem_init();1464	if (rc)1465		goto err_root;1466 1467	return 0;1468 1469err_root:1470	platform_device_put(cxl_acpi);1471err_rch:1472	cxl_rch_topo_exit();1473err_single:1474	cxl_single_topo_exit();1475err_dport:1476	for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)1477		platform_device_unregister(cxl_switch_dport[i]);1478err_uport:1479	for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)1480		platform_device_unregister(cxl_switch_uport[i]);1481err_port:1482	for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)1483		platform_device_unregister(cxl_root_port[i]);1484err_bridge:1485	for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {1486		struct platform_device *pdev = cxl_host_bridge[i];1487 1488		if (!pdev)1489			continue;1490		sysfs_remove_link(&pdev->dev.kobj, "physical_node");1491		platform_device_unregister(cxl_host_bridge[i]);1492	}1493err_populate:1494	depopulate_all_mock_resources();1495err_gen_pool_add:1496	gen_pool_destroy(cxl_mock_pool);1497err_gen_pool_create:1498	unregister_cxl_mock_ops(&cxl_mock_ops);1499	return rc;1500}1501 1502static __exit void cxl_test_exit(void)1503{1504	int i;1505 1506	cxl_mem_exit();1507	platform_device_unregister(cxl_acpi);1508	cxl_rch_topo_exit();1509	cxl_single_topo_exit();1510	for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)1511		platform_device_unregister(cxl_switch_dport[i]);1512	for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)1513		platform_device_unregister(cxl_switch_uport[i]);1514	for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)1515		platform_device_unregister(cxl_root_port[i]);1516	for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {1517		struct platform_device *pdev = cxl_host_bridge[i];1518 1519		if (!pdev)1520			continue;1521		sysfs_remove_link(&pdev->dev.kobj, "physical_node");1522		platform_device_unregister(cxl_host_bridge[i]);1523	}1524	depopulate_all_mock_resources();1525	gen_pool_destroy(cxl_mock_pool);1526	unregister_cxl_mock_ops(&cxl_mock_ops);1527}1528 1529module_param(interleave_arithmetic, int, 0444);1530MODULE_PARM_DESC(interleave_arithmetic, "Modulo:0, XOR:1");1531module_init(cxl_test_init);1532module_exit(cxl_test_exit);1533MODULE_LICENSE("GPL v2");1534MODULE_IMPORT_NS(ACPI);1535MODULE_IMPORT_NS(CXL);1536