0001
0002
0003
0004 #include <linux/platform_device.h>
0005 #include <linux/genalloc.h>
0006 #include <linux/module.h>
0007 #include <linux/mutex.h>
0008 #include <linux/acpi.h>
0009 #include <linux/pci.h>
0010 #include <linux/mm.h>
0011 #include <cxlmem.h>
0012 #include "mock.h"
0013
0014 #define NR_CXL_HOST_BRIDGES 2
0015 #define NR_CXL_ROOT_PORTS 2
0016 #define NR_CXL_SWITCH_PORTS 2
0017 #define NR_CXL_PORT_DECODERS 8
0018
0019 static struct platform_device *cxl_acpi;
0020 static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
0021 static struct platform_device
0022 *cxl_root_port[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS];
0023 static struct platform_device
0024 *cxl_switch_uport[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS];
0025 static struct platform_device
0026 *cxl_switch_dport[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS *
0027 NR_CXL_SWITCH_PORTS];
0028 struct platform_device
0029 *cxl_mem[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS * NR_CXL_SWITCH_PORTS];
0030
0031 static struct acpi_device acpi0017_mock;
0032 static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES] = {
0033 [0] = {
0034 .handle = &host_bridge[0],
0035 },
0036 [1] = {
0037 .handle = &host_bridge[1],
0038 },
0039 };
0040
0041 static bool is_mock_dev(struct device *dev)
0042 {
0043 int i;
0044
0045 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++)
0046 if (dev == &cxl_mem[i]->dev)
0047 return true;
0048 if (dev == &cxl_acpi->dev)
0049 return true;
0050 return false;
0051 }
0052
0053 static bool is_mock_adev(struct acpi_device *adev)
0054 {
0055 int i;
0056
0057 if (adev == &acpi0017_mock)
0058 return true;
0059
0060 for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
0061 if (adev == &host_bridge[i])
0062 return true;
0063
0064 return false;
0065 }
0066
0067 static struct {
0068 struct acpi_table_cedt cedt;
0069 struct acpi_cedt_chbs chbs[NR_CXL_HOST_BRIDGES];
0070 struct {
0071 struct acpi_cedt_cfmws cfmws;
0072 u32 target[1];
0073 } cfmws0;
0074 struct {
0075 struct acpi_cedt_cfmws cfmws;
0076 u32 target[2];
0077 } cfmws1;
0078 struct {
0079 struct acpi_cedt_cfmws cfmws;
0080 u32 target[1];
0081 } cfmws2;
0082 struct {
0083 struct acpi_cedt_cfmws cfmws;
0084 u32 target[2];
0085 } cfmws3;
0086 } __packed mock_cedt = {
0087 .cedt = {
0088 .header = {
0089 .signature = "CEDT",
0090 .length = sizeof(mock_cedt),
0091 .revision = 1,
0092 },
0093 },
0094 .chbs[0] = {
0095 .header = {
0096 .type = ACPI_CEDT_TYPE_CHBS,
0097 .length = sizeof(mock_cedt.chbs[0]),
0098 },
0099 .uid = 0,
0100 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
0101 },
0102 .chbs[1] = {
0103 .header = {
0104 .type = ACPI_CEDT_TYPE_CHBS,
0105 .length = sizeof(mock_cedt.chbs[0]),
0106 },
0107 .uid = 1,
0108 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
0109 },
0110 .cfmws0 = {
0111 .cfmws = {
0112 .header = {
0113 .type = ACPI_CEDT_TYPE_CFMWS,
0114 .length = sizeof(mock_cedt.cfmws0),
0115 },
0116 .interleave_ways = 0,
0117 .granularity = 4,
0118 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
0119 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
0120 .qtg_id = 0,
0121 .window_size = SZ_256M * 4UL,
0122 },
0123 .target = { 0 },
0124 },
0125 .cfmws1 = {
0126 .cfmws = {
0127 .header = {
0128 .type = ACPI_CEDT_TYPE_CFMWS,
0129 .length = sizeof(mock_cedt.cfmws1),
0130 },
0131 .interleave_ways = 1,
0132 .granularity = 4,
0133 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
0134 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
0135 .qtg_id = 1,
0136 .window_size = SZ_256M * 8UL,
0137 },
0138 .target = { 0, 1, },
0139 },
0140 .cfmws2 = {
0141 .cfmws = {
0142 .header = {
0143 .type = ACPI_CEDT_TYPE_CFMWS,
0144 .length = sizeof(mock_cedt.cfmws2),
0145 },
0146 .interleave_ways = 0,
0147 .granularity = 4,
0148 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
0149 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
0150 .qtg_id = 2,
0151 .window_size = SZ_256M * 4UL,
0152 },
0153 .target = { 0 },
0154 },
0155 .cfmws3 = {
0156 .cfmws = {
0157 .header = {
0158 .type = ACPI_CEDT_TYPE_CFMWS,
0159 .length = sizeof(mock_cedt.cfmws3),
0160 },
0161 .interleave_ways = 1,
0162 .granularity = 4,
0163 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
0164 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
0165 .qtg_id = 3,
0166 .window_size = SZ_256M * 8UL,
0167 },
0168 .target = { 0, 1, },
0169 },
0170 };
0171
0172 struct acpi_cedt_cfmws *mock_cfmws[4] = {
0173 [0] = &mock_cedt.cfmws0.cfmws,
0174 [1] = &mock_cedt.cfmws1.cfmws,
0175 [2] = &mock_cedt.cfmws2.cfmws,
0176 [3] = &mock_cedt.cfmws3.cfmws,
0177 };
0178
0179 struct cxl_mock_res {
0180 struct list_head list;
0181 struct range range;
0182 };
0183
0184 static LIST_HEAD(mock_res);
0185 static DEFINE_MUTEX(mock_res_lock);
0186 static struct gen_pool *cxl_mock_pool;
0187
0188 static void depopulate_all_mock_resources(void)
0189 {
0190 struct cxl_mock_res *res, *_res;
0191
0192 mutex_lock(&mock_res_lock);
0193 list_for_each_entry_safe(res, _res, &mock_res, list) {
0194 gen_pool_free(cxl_mock_pool, res->range.start,
0195 range_len(&res->range));
0196 list_del(&res->list);
0197 kfree(res);
0198 }
0199 mutex_unlock(&mock_res_lock);
0200 }
0201
0202 static struct cxl_mock_res *alloc_mock_res(resource_size_t size)
0203 {
0204 struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
0205 struct genpool_data_align data = {
0206 .align = SZ_256M,
0207 };
0208 unsigned long phys;
0209
0210 INIT_LIST_HEAD(&res->list);
0211 phys = gen_pool_alloc_algo(cxl_mock_pool, size,
0212 gen_pool_first_fit_align, &data);
0213 if (!phys)
0214 return NULL;
0215
0216 res->range = (struct range) {
0217 .start = phys,
0218 .end = phys + size - 1,
0219 };
0220 mutex_lock(&mock_res_lock);
0221 list_add(&res->list, &mock_res);
0222 mutex_unlock(&mock_res_lock);
0223
0224 return res;
0225 }
0226
0227 static int populate_cedt(void)
0228 {
0229 struct cxl_mock_res *res;
0230 int i;
0231
0232 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
0233 struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i];
0234 resource_size_t size;
0235
0236 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20)
0237 size = ACPI_CEDT_CHBS_LENGTH_CXL20;
0238 else
0239 size = ACPI_CEDT_CHBS_LENGTH_CXL11;
0240
0241 res = alloc_mock_res(size);
0242 if (!res)
0243 return -ENOMEM;
0244 chbs->base = res->range.start;
0245 chbs->length = size;
0246 }
0247
0248 for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
0249 struct acpi_cedt_cfmws *window = mock_cfmws[i];
0250
0251 res = alloc_mock_res(window->window_size);
0252 if (!res)
0253 return -ENOMEM;
0254 window->base_hpa = res->range.start;
0255 }
0256
0257 return 0;
0258 }
0259
0260
0261
0262
0263
0264
0265
0266 struct cxl_cedt_context {
0267 struct device *dev;
0268 };
0269
0270 static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
0271 acpi_tbl_entry_handler_arg handler_arg,
0272 void *arg)
0273 {
0274 struct cxl_cedt_context *ctx = arg;
0275 struct device *dev = ctx->dev;
0276 union acpi_subtable_headers *h;
0277 unsigned long end;
0278 int i;
0279
0280 if (dev != &cxl_acpi->dev)
0281 return acpi_table_parse_cedt(id, handler_arg, arg);
0282
0283 if (id == ACPI_CEDT_TYPE_CHBS)
0284 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
0285 h = (union acpi_subtable_headers *)&mock_cedt.chbs[i];
0286 end = (unsigned long)&mock_cedt.chbs[i + 1];
0287 handler_arg(h, arg, end);
0288 }
0289
0290 if (id == ACPI_CEDT_TYPE_CFMWS)
0291 for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
0292 h = (union acpi_subtable_headers *) mock_cfmws[i];
0293 end = (unsigned long) h + mock_cfmws[i]->header.length;
0294 handler_arg(h, arg, end);
0295 }
0296
0297 return 0;
0298 }
0299
0300 static bool is_mock_bridge(struct device *dev)
0301 {
0302 int i;
0303
0304 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
0305 if (dev == &cxl_host_bridge[i]->dev)
0306 return true;
0307 return false;
0308 }
0309
0310 static bool is_mock_port(struct device *dev)
0311 {
0312 int i;
0313
0314 if (is_mock_bridge(dev))
0315 return true;
0316
0317 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++)
0318 if (dev == &cxl_root_port[i]->dev)
0319 return true;
0320
0321 for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++)
0322 if (dev == &cxl_switch_uport[i]->dev)
0323 return true;
0324
0325 for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++)
0326 if (dev == &cxl_switch_dport[i]->dev)
0327 return true;
0328
0329 if (is_cxl_memdev(dev))
0330 return is_mock_dev(dev->parent);
0331
0332 return false;
0333 }
0334
0335 static int host_bridge_index(struct acpi_device *adev)
0336 {
0337 return adev - host_bridge;
0338 }
0339
0340 static struct acpi_device *find_host_bridge(acpi_handle handle)
0341 {
0342 int i;
0343
0344 for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
0345 if (handle == host_bridge[i].handle)
0346 return &host_bridge[i];
0347 return NULL;
0348 }
0349
0350 static acpi_status
0351 mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname,
0352 struct acpi_object_list *arguments,
0353 unsigned long long *data)
0354 {
0355 struct acpi_device *adev = find_host_bridge(handle);
0356
0357 if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0)
0358 return acpi_evaluate_integer(handle, pathname, arguments, data);
0359
0360 *data = host_bridge_index(adev);
0361 return AE_OK;
0362 }
0363
0364 static struct pci_bus mock_pci_bus[NR_CXL_HOST_BRIDGES];
0365 static struct acpi_pci_root mock_pci_root[NR_CXL_HOST_BRIDGES] = {
0366 [0] = {
0367 .bus = &mock_pci_bus[0],
0368 },
0369 [1] = {
0370 .bus = &mock_pci_bus[1],
0371 },
0372 };
0373
0374 static bool is_mock_bus(struct pci_bus *bus)
0375 {
0376 int i;
0377
0378 for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++)
0379 if (bus == &mock_pci_bus[i])
0380 return true;
0381 return false;
0382 }
0383
0384 static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle)
0385 {
0386 struct acpi_device *adev = find_host_bridge(handle);
0387
0388 if (!adev)
0389 return acpi_pci_find_root(handle);
0390 return &mock_pci_root[host_bridge_index(adev)];
0391 }
0392
0393 static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port)
0394 {
0395 struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL);
0396
0397 if (!cxlhdm)
0398 return ERR_PTR(-ENOMEM);
0399
0400 cxlhdm->port = port;
0401 return cxlhdm;
0402 }
0403
0404 static int mock_cxl_add_passthrough_decoder(struct cxl_port *port)
0405 {
0406 dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n");
0407 return -EOPNOTSUPP;
0408 }
0409
0410
0411 struct target_map_ctx {
0412 int *target_map;
0413 int index;
0414 int target_count;
0415 };
0416
0417 static int map_targets(struct device *dev, void *data)
0418 {
0419 struct platform_device *pdev = to_platform_device(dev);
0420 struct target_map_ctx *ctx = data;
0421
0422 ctx->target_map[ctx->index++] = pdev->id;
0423
0424 if (ctx->index > ctx->target_count) {
0425 dev_WARN_ONCE(dev, 1, "too many targets found?\n");
0426 return -ENXIO;
0427 }
0428
0429 return 0;
0430 }
0431
0432 static int mock_decoder_commit(struct cxl_decoder *cxld)
0433 {
0434 struct cxl_port *port = to_cxl_port(cxld->dev.parent);
0435 int id = cxld->id;
0436
0437 if (cxld->flags & CXL_DECODER_F_ENABLE)
0438 return 0;
0439
0440 dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
0441 if (port->commit_end + 1 != id) {
0442 dev_dbg(&port->dev,
0443 "%s: out of order commit, expected decoder%d.%d\n",
0444 dev_name(&cxld->dev), port->id, port->commit_end + 1);
0445 return -EBUSY;
0446 }
0447
0448 port->commit_end++;
0449 cxld->flags |= CXL_DECODER_F_ENABLE;
0450
0451 return 0;
0452 }
0453
0454 static int mock_decoder_reset(struct cxl_decoder *cxld)
0455 {
0456 struct cxl_port *port = to_cxl_port(cxld->dev.parent);
0457 int id = cxld->id;
0458
0459 if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
0460 return 0;
0461
0462 dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
0463 if (port->commit_end != id) {
0464 dev_dbg(&port->dev,
0465 "%s: out of order reset, expected decoder%d.%d\n",
0466 dev_name(&cxld->dev), port->id, port->commit_end);
0467 return -EBUSY;
0468 }
0469
0470 port->commit_end--;
0471 cxld->flags &= ~CXL_DECODER_F_ENABLE;
0472
0473 return 0;
0474 }
0475
0476 static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
0477 {
0478 struct cxl_port *port = cxlhdm->port;
0479 struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
0480 int target_count, i;
0481
0482 if (is_cxl_endpoint(port))
0483 target_count = 0;
0484 else if (is_cxl_root(parent_port))
0485 target_count = NR_CXL_ROOT_PORTS;
0486 else
0487 target_count = NR_CXL_SWITCH_PORTS;
0488
0489 for (i = 0; i < NR_CXL_PORT_DECODERS; i++) {
0490 int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
0491 struct target_map_ctx ctx = {
0492 .target_map = target_map,
0493 .target_count = target_count,
0494 };
0495 struct cxl_decoder *cxld;
0496 int rc;
0497
0498 if (target_count) {
0499 struct cxl_switch_decoder *cxlsd;
0500
0501 cxlsd = cxl_switch_decoder_alloc(port, target_count);
0502 if (IS_ERR(cxlsd)) {
0503 dev_warn(&port->dev,
0504 "Failed to allocate the decoder\n");
0505 return PTR_ERR(cxlsd);
0506 }
0507 cxld = &cxlsd->cxld;
0508 } else {
0509 struct cxl_endpoint_decoder *cxled;
0510
0511 cxled = cxl_endpoint_decoder_alloc(port);
0512
0513 if (IS_ERR(cxled)) {
0514 dev_warn(&port->dev,
0515 "Failed to allocate the decoder\n");
0516 return PTR_ERR(cxled);
0517 }
0518 cxld = &cxled->cxld;
0519 }
0520
0521 cxld->hpa_range = (struct range) {
0522 .start = 0,
0523 .end = -1,
0524 };
0525
0526 cxld->interleave_ways = min_not_zero(target_count, 1);
0527 cxld->interleave_granularity = SZ_4K;
0528 cxld->target_type = CXL_DECODER_EXPANDER;
0529 cxld->commit = mock_decoder_commit;
0530 cxld->reset = mock_decoder_reset;
0531
0532 if (target_count) {
0533 rc = device_for_each_child(port->uport, &ctx,
0534 map_targets);
0535 if (rc) {
0536 put_device(&cxld->dev);
0537 return rc;
0538 }
0539 }
0540
0541 rc = cxl_decoder_add_locked(cxld, target_map);
0542 if (rc) {
0543 put_device(&cxld->dev);
0544 dev_err(&port->dev, "Failed to add decoder\n");
0545 return rc;
0546 }
0547
0548 rc = cxl_decoder_autoremove(&port->dev, cxld);
0549 if (rc)
0550 return rc;
0551 dev_dbg(&cxld->dev, "Added to port %s\n", dev_name(&port->dev));
0552 }
0553
0554 return 0;
0555 }
0556
0557 static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
0558 {
0559 struct device *dev = &port->dev;
0560 struct platform_device **array;
0561 int i, array_size;
0562
0563 if (port->depth == 1) {
0564 array_size = ARRAY_SIZE(cxl_root_port);
0565 array = cxl_root_port;
0566 } else if (port->depth == 2) {
0567 array_size = ARRAY_SIZE(cxl_switch_dport);
0568 array = cxl_switch_dport;
0569 } else {
0570 dev_WARN_ONCE(&port->dev, 1, "unexpected depth %d\n",
0571 port->depth);
0572 return -ENXIO;
0573 }
0574
0575 for (i = 0; i < array_size; i++) {
0576 struct platform_device *pdev = array[i];
0577 struct cxl_dport *dport;
0578
0579 if (pdev->dev.parent != port->uport)
0580 continue;
0581
0582 dport = devm_cxl_add_dport(port, &pdev->dev, pdev->id,
0583 CXL_RESOURCE_NONE);
0584
0585 if (IS_ERR(dport)) {
0586 dev_err(dev, "failed to add dport: %s (%ld)\n",
0587 dev_name(&pdev->dev), PTR_ERR(dport));
0588 return PTR_ERR(dport);
0589 }
0590
0591 dev_dbg(dev, "add dport%d: %s\n", pdev->id,
0592 dev_name(&pdev->dev));
0593 }
0594
0595 return 0;
0596 }
0597
0598 static struct cxl_mock_ops cxl_mock_ops = {
0599 .is_mock_adev = is_mock_adev,
0600 .is_mock_bridge = is_mock_bridge,
0601 .is_mock_bus = is_mock_bus,
0602 .is_mock_port = is_mock_port,
0603 .is_mock_dev = is_mock_dev,
0604 .acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
0605 .acpi_evaluate_integer = mock_acpi_evaluate_integer,
0606 .acpi_pci_find_root = mock_acpi_pci_find_root,
0607 .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
0608 .devm_cxl_setup_hdm = mock_cxl_setup_hdm,
0609 .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,
0610 .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,
0611 .list = LIST_HEAD_INIT(cxl_mock_ops.list),
0612 };
0613
0614 static void mock_companion(struct acpi_device *adev, struct device *dev)
0615 {
0616 device_initialize(&adev->dev);
0617 fwnode_init(&adev->fwnode, NULL);
0618 dev->fwnode = &adev->fwnode;
0619 adev->fwnode.dev = dev;
0620 }
0621
0622 #ifndef SZ_64G
0623 #define SZ_64G (SZ_32G * 2)
0624 #endif
0625
0626 #ifndef SZ_512G
0627 #define SZ_512G (SZ_64G * 8)
0628 #endif
0629
0630 static __init int cxl_test_init(void)
0631 {
0632 int rc, i;
0633
0634 register_cxl_mock_ops(&cxl_mock_ops);
0635
0636 cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE);
0637 if (!cxl_mock_pool) {
0638 rc = -ENOMEM;
0639 goto err_gen_pool_create;
0640 }
0641
0642 rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,
0643 SZ_64G, NUMA_NO_NODE);
0644 if (rc)
0645 goto err_gen_pool_add;
0646
0647 rc = populate_cedt();
0648 if (rc)
0649 goto err_populate;
0650
0651 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) {
0652 struct acpi_device *adev = &host_bridge[i];
0653 struct platform_device *pdev;
0654
0655 pdev = platform_device_alloc("cxl_host_bridge", i);
0656 if (!pdev)
0657 goto err_bridge;
0658
0659 mock_companion(adev, &pdev->dev);
0660 rc = platform_device_add(pdev);
0661 if (rc) {
0662 platform_device_put(pdev);
0663 goto err_bridge;
0664 }
0665
0666 cxl_host_bridge[i] = pdev;
0667 rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
0668 "physical_node");
0669 if (rc)
0670 goto err_bridge;
0671 }
0672
0673 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) {
0674 struct platform_device *bridge =
0675 cxl_host_bridge[i % ARRAY_SIZE(cxl_host_bridge)];
0676 struct platform_device *pdev;
0677
0678 pdev = platform_device_alloc("cxl_root_port", i);
0679 if (!pdev)
0680 goto err_port;
0681 pdev->dev.parent = &bridge->dev;
0682
0683 rc = platform_device_add(pdev);
0684 if (rc) {
0685 platform_device_put(pdev);
0686 goto err_port;
0687 }
0688 cxl_root_port[i] = pdev;
0689 }
0690
0691 BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port));
0692 for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++) {
0693 struct platform_device *root_port = cxl_root_port[i];
0694 struct platform_device *pdev;
0695
0696 pdev = platform_device_alloc("cxl_switch_uport", i);
0697 if (!pdev)
0698 goto err_port;
0699 pdev->dev.parent = &root_port->dev;
0700
0701 rc = platform_device_add(pdev);
0702 if (rc) {
0703 platform_device_put(pdev);
0704 goto err_uport;
0705 }
0706 cxl_switch_uport[i] = pdev;
0707 }
0708
0709 for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) {
0710 struct platform_device *uport =
0711 cxl_switch_uport[i % ARRAY_SIZE(cxl_switch_uport)];
0712 struct platform_device *pdev;
0713
0714 pdev = platform_device_alloc("cxl_switch_dport", i);
0715 if (!pdev)
0716 goto err_port;
0717 pdev->dev.parent = &uport->dev;
0718
0719 rc = platform_device_add(pdev);
0720 if (rc) {
0721 platform_device_put(pdev);
0722 goto err_dport;
0723 }
0724 cxl_switch_dport[i] = pdev;
0725 }
0726
0727 BUILD_BUG_ON(ARRAY_SIZE(cxl_mem) != ARRAY_SIZE(cxl_switch_dport));
0728 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {
0729 struct platform_device *dport = cxl_switch_dport[i];
0730 struct platform_device *pdev;
0731
0732 pdev = platform_device_alloc("cxl_mem", i);
0733 if (!pdev)
0734 goto err_mem;
0735 pdev->dev.parent = &dport->dev;
0736 set_dev_node(&pdev->dev, i % 2);
0737
0738 rc = platform_device_add(pdev);
0739 if (rc) {
0740 platform_device_put(pdev);
0741 goto err_mem;
0742 }
0743 cxl_mem[i] = pdev;
0744 }
0745
0746 cxl_acpi = platform_device_alloc("cxl_acpi", 0);
0747 if (!cxl_acpi)
0748 goto err_mem;
0749
0750 mock_companion(&acpi0017_mock, &cxl_acpi->dev);
0751 acpi0017_mock.dev.bus = &platform_bus_type;
0752
0753 rc = platform_device_add(cxl_acpi);
0754 if (rc)
0755 goto err_add;
0756
0757 return 0;
0758
0759 err_add:
0760 platform_device_put(cxl_acpi);
0761 err_mem:
0762 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
0763 platform_device_unregister(cxl_mem[i]);
0764 err_dport:
0765 for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
0766 platform_device_unregister(cxl_switch_dport[i]);
0767 err_uport:
0768 for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
0769 platform_device_unregister(cxl_switch_uport[i]);
0770 err_port:
0771 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
0772 platform_device_unregister(cxl_root_port[i]);
0773 err_bridge:
0774 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
0775 struct platform_device *pdev = cxl_host_bridge[i];
0776
0777 if (!pdev)
0778 continue;
0779 sysfs_remove_link(&pdev->dev.kobj, "physical_node");
0780 platform_device_unregister(cxl_host_bridge[i]);
0781 }
0782 err_populate:
0783 depopulate_all_mock_resources();
0784 err_gen_pool_add:
0785 gen_pool_destroy(cxl_mock_pool);
0786 err_gen_pool_create:
0787 unregister_cxl_mock_ops(&cxl_mock_ops);
0788 return rc;
0789 }
0790
0791 static __exit void cxl_test_exit(void)
0792 {
0793 int i;
0794
0795 platform_device_unregister(cxl_acpi);
0796 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
0797 platform_device_unregister(cxl_mem[i]);
0798 for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
0799 platform_device_unregister(cxl_switch_dport[i]);
0800 for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
0801 platform_device_unregister(cxl_switch_uport[i]);
0802 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
0803 platform_device_unregister(cxl_root_port[i]);
0804 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
0805 struct platform_device *pdev = cxl_host_bridge[i];
0806
0807 if (!pdev)
0808 continue;
0809 sysfs_remove_link(&pdev->dev.kobj, "physical_node");
0810 platform_device_unregister(cxl_host_bridge[i]);
0811 }
0812 depopulate_all_mock_resources();
0813 gen_pool_destroy(cxl_mock_pool);
0814 unregister_cxl_mock_ops(&cxl_mock_ops);
0815 }
0816
0817 module_init(cxl_test_init);
0818 module_exit(cxl_test_exit);
0819 MODULE_LICENSE("GPL v2");
0820 MODULE_IMPORT_NS(ACPI);
0821 MODULE_IMPORT_NS(CXL);