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