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