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