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 "mock.h" 12 13 #define NR_CXL_HOST_BRIDGES 4 14 #define NR_CXL_ROOT_PORTS 2 15 16 static struct platform_device *cxl_acpi; 17 static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES]; 18 static struct platform_device 19 *cxl_root_port[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS]; 20 struct platform_device *cxl_mem[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS]; 21 22 static struct acpi_device acpi0017_mock; 23 static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES] = { 24 [0] = { 25 .handle = &host_bridge[0], 26 }, 27 [1] = { 28 .handle = &host_bridge[1], 29 }, 30 [2] = { 31 .handle = &host_bridge[2], 32 }, 33 [3] = { 34 .handle = &host_bridge[3], 35 }, 36 }; 37 38 static bool is_mock_dev(struct device *dev) 39 { 40 int i; 41 42 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) 43 if (dev == &cxl_mem[i]->dev) 44 return true; 45 if (dev == &cxl_acpi->dev) 46 return true; 47 return false; 48 } 49 50 static bool is_mock_adev(struct acpi_device *adev) 51 { 52 int i; 53 54 if (adev == &acpi0017_mock) 55 return true; 56 57 for (i = 0; i < ARRAY_SIZE(host_bridge); i++) 58 if (adev == &host_bridge[i]) 59 return true; 60 61 return false; 62 } 63 64 static struct { 65 struct acpi_table_cedt cedt; 66 struct acpi_cedt_chbs chbs[NR_CXL_HOST_BRIDGES]; 67 struct { 68 struct acpi_cedt_cfmws cfmws; 69 u32 target[1]; 70 } cfmws0; 71 struct { 72 struct acpi_cedt_cfmws cfmws; 73 u32 target[4]; 74 } cfmws1; 75 struct { 76 struct acpi_cedt_cfmws cfmws; 77 u32 target[1]; 78 } cfmws2; 79 struct { 80 struct acpi_cedt_cfmws cfmws; 81 u32 target[4]; 82 } cfmws3; 83 } __packed mock_cedt = { 84 .cedt = { 85 .header = { 86 .signature = "CEDT", 87 .length = sizeof(mock_cedt), 88 .revision = 1, 89 }, 90 }, 91 .chbs[0] = { 92 .header = { 93 .type = ACPI_CEDT_TYPE_CHBS, 94 .length = sizeof(mock_cedt.chbs[0]), 95 }, 96 .uid = 0, 97 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, 98 }, 99 .chbs[1] = { 100 .header = { 101 .type = ACPI_CEDT_TYPE_CHBS, 102 .length = sizeof(mock_cedt.chbs[0]), 103 }, 104 .uid = 1, 105 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, 106 }, 107 .chbs[2] = { 108 .header = { 109 .type = ACPI_CEDT_TYPE_CHBS, 110 .length = sizeof(mock_cedt.chbs[0]), 111 }, 112 .uid = 2, 113 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, 114 }, 115 .chbs[3] = { 116 .header = { 117 .type = ACPI_CEDT_TYPE_CHBS, 118 .length = sizeof(mock_cedt.chbs[0]), 119 }, 120 .uid = 3, 121 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, 122 }, 123 .cfmws0 = { 124 .cfmws = { 125 .header = { 126 .type = ACPI_CEDT_TYPE_CFMWS, 127 .length = sizeof(mock_cedt.cfmws0), 128 }, 129 .interleave_ways = 0, 130 .granularity = 4, 131 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 132 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, 133 .qtg_id = 0, 134 .window_size = SZ_256M, 135 }, 136 .target = { 0 }, 137 }, 138 .cfmws1 = { 139 .cfmws = { 140 .header = { 141 .type = ACPI_CEDT_TYPE_CFMWS, 142 .length = sizeof(mock_cedt.cfmws1), 143 }, 144 .interleave_ways = 2, 145 .granularity = 4, 146 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 147 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, 148 .qtg_id = 1, 149 .window_size = SZ_256M * 4, 150 }, 151 .target = { 0, 1, 2, 3 }, 152 }, 153 .cfmws2 = { 154 .cfmws = { 155 .header = { 156 .type = ACPI_CEDT_TYPE_CFMWS, 157 .length = sizeof(mock_cedt.cfmws2), 158 }, 159 .interleave_ways = 0, 160 .granularity = 4, 161 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 162 ACPI_CEDT_CFMWS_RESTRICT_PMEM, 163 .qtg_id = 2, 164 .window_size = SZ_256M, 165 }, 166 .target = { 0 }, 167 }, 168 .cfmws3 = { 169 .cfmws = { 170 .header = { 171 .type = ACPI_CEDT_TYPE_CFMWS, 172 .length = sizeof(mock_cedt.cfmws3), 173 }, 174 .interleave_ways = 2, 175 .granularity = 4, 176 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 177 ACPI_CEDT_CFMWS_RESTRICT_PMEM, 178 .qtg_id = 3, 179 .window_size = SZ_256M * 4, 180 }, 181 .target = { 0, 1, 2, 3 }, 182 }, 183 }; 184 185 struct acpi_cedt_cfmws *mock_cfmws[4] = { 186 [0] = &mock_cedt.cfmws0.cfmws, 187 [1] = &mock_cedt.cfmws1.cfmws, 188 [2] = &mock_cedt.cfmws2.cfmws, 189 [3] = &mock_cedt.cfmws3.cfmws, 190 }; 191 192 struct cxl_mock_res { 193 struct list_head list; 194 struct range range; 195 }; 196 197 static LIST_HEAD(mock_res); 198 static DEFINE_MUTEX(mock_res_lock); 199 static struct gen_pool *cxl_mock_pool; 200 201 static void depopulate_all_mock_resources(void) 202 { 203 struct cxl_mock_res *res, *_res; 204 205 mutex_lock(&mock_res_lock); 206 list_for_each_entry_safe(res, _res, &mock_res, list) { 207 gen_pool_free(cxl_mock_pool, res->range.start, 208 range_len(&res->range)); 209 list_del(&res->list); 210 kfree(res); 211 } 212 mutex_unlock(&mock_res_lock); 213 } 214 215 static struct cxl_mock_res *alloc_mock_res(resource_size_t size) 216 { 217 struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL); 218 struct genpool_data_align data = { 219 .align = SZ_256M, 220 }; 221 unsigned long phys; 222 223 INIT_LIST_HEAD(&res->list); 224 phys = gen_pool_alloc_algo(cxl_mock_pool, size, 225 gen_pool_first_fit_align, &data); 226 if (!phys) 227 return NULL; 228 229 res->range = (struct range) { 230 .start = phys, 231 .end = phys + size - 1, 232 }; 233 mutex_lock(&mock_res_lock); 234 list_add(&res->list, &mock_res); 235 mutex_unlock(&mock_res_lock); 236 237 return res; 238 } 239 240 static int populate_cedt(void) 241 { 242 struct cxl_mock_res *res; 243 int i; 244 245 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) { 246 struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i]; 247 resource_size_t size; 248 249 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20) 250 size = ACPI_CEDT_CHBS_LENGTH_CXL20; 251 else 252 size = ACPI_CEDT_CHBS_LENGTH_CXL11; 253 254 res = alloc_mock_res(size); 255 if (!res) 256 return -ENOMEM; 257 chbs->base = res->range.start; 258 chbs->length = size; 259 } 260 261 for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) { 262 struct acpi_cedt_cfmws *window = mock_cfmws[i]; 263 264 res = alloc_mock_res(window->window_size); 265 if (!res) 266 return -ENOMEM; 267 window->base_hpa = res->range.start; 268 } 269 270 return 0; 271 } 272 273 /* 274 * WARNING, this hack assumes the format of 'struct 275 * cxl_cfmws_context' and 'struct cxl_chbs_context' share the property that 276 * the first struct member is the device being probed by the cxl_acpi 277 * driver. 278 */ 279 struct cxl_cedt_context { 280 struct device *dev; 281 }; 282 283 static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id, 284 acpi_tbl_entry_handler_arg handler_arg, 285 void *arg) 286 { 287 struct cxl_cedt_context *ctx = arg; 288 struct device *dev = ctx->dev; 289 union acpi_subtable_headers *h; 290 unsigned long end; 291 int i; 292 293 if (dev != &cxl_acpi->dev) 294 return acpi_table_parse_cedt(id, handler_arg, arg); 295 296 if (id == ACPI_CEDT_TYPE_CHBS) 297 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) { 298 h = (union acpi_subtable_headers *)&mock_cedt.chbs[i]; 299 end = (unsigned long)&mock_cedt.chbs[i + 1]; 300 handler_arg(h, arg, end); 301 } 302 303 if (id == ACPI_CEDT_TYPE_CFMWS) 304 for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) { 305 h = (union acpi_subtable_headers *) mock_cfmws[i]; 306 end = (unsigned long) h + mock_cfmws[i]->header.length; 307 handler_arg(h, arg, end); 308 } 309 310 return 0; 311 } 312 313 static bool is_mock_bridge(struct device *dev) 314 { 315 int i; 316 317 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) 318 if (dev == &cxl_host_bridge[i]->dev) 319 return true; 320 321 return false; 322 } 323 324 static int host_bridge_index(struct acpi_device *adev) 325 { 326 return adev - host_bridge; 327 } 328 329 static struct acpi_device *find_host_bridge(acpi_handle handle) 330 { 331 int i; 332 333 for (i = 0; i < ARRAY_SIZE(host_bridge); i++) 334 if (handle == host_bridge[i].handle) 335 return &host_bridge[i]; 336 return NULL; 337 } 338 339 static acpi_status 340 mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, 341 struct acpi_object_list *arguments, 342 unsigned long long *data) 343 { 344 struct acpi_device *adev = find_host_bridge(handle); 345 346 if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0) 347 return acpi_evaluate_integer(handle, pathname, arguments, data); 348 349 *data = host_bridge_index(adev); 350 return AE_OK; 351 } 352 353 static struct pci_bus mock_pci_bus[NR_CXL_HOST_BRIDGES]; 354 static struct acpi_pci_root mock_pci_root[NR_CXL_HOST_BRIDGES] = { 355 [0] = { 356 .bus = &mock_pci_bus[0], 357 }, 358 [1] = { 359 .bus = &mock_pci_bus[1], 360 }, 361 [2] = { 362 .bus = &mock_pci_bus[2], 363 }, 364 [3] = { 365 .bus = &mock_pci_bus[3], 366 }, 367 }; 368 369 static struct platform_device *mock_cxl_root_port(struct pci_bus *bus, int index) 370 { 371 int i; 372 373 for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++) 374 if (bus == &mock_pci_bus[i]) 375 return cxl_root_port[index + i * NR_CXL_ROOT_PORTS]; 376 return NULL; 377 } 378 379 static bool is_mock_port(struct platform_device *pdev) 380 { 381 int i; 382 383 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) 384 if (pdev == cxl_root_port[i]) 385 return true; 386 return false; 387 } 388 389 static bool is_mock_bus(struct pci_bus *bus) 390 { 391 int i; 392 393 for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++) 394 if (bus == &mock_pci_bus[i]) 395 return true; 396 return false; 397 } 398 399 static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle) 400 { 401 struct acpi_device *adev = find_host_bridge(handle); 402 403 if (!adev) 404 return acpi_pci_find_root(handle); 405 return &mock_pci_root[host_bridge_index(adev)]; 406 } 407 408 static struct cxl_mock_ops cxl_mock_ops = { 409 .is_mock_adev = is_mock_adev, 410 .is_mock_bridge = is_mock_bridge, 411 .is_mock_bus = is_mock_bus, 412 .is_mock_port = is_mock_port, 413 .is_mock_dev = is_mock_dev, 414 .mock_port = mock_cxl_root_port, 415 .acpi_table_parse_cedt = mock_acpi_table_parse_cedt, 416 .acpi_evaluate_integer = mock_acpi_evaluate_integer, 417 .acpi_pci_find_root = mock_acpi_pci_find_root, 418 .list = LIST_HEAD_INIT(cxl_mock_ops.list), 419 }; 420 421 static void mock_companion(struct acpi_device *adev, struct device *dev) 422 { 423 device_initialize(&adev->dev); 424 fwnode_init(&adev->fwnode, NULL); 425 dev->fwnode = &adev->fwnode; 426 adev->fwnode.dev = dev; 427 } 428 429 #ifndef SZ_64G 430 #define SZ_64G (SZ_32G * 2) 431 #endif 432 433 #ifndef SZ_512G 434 #define SZ_512G (SZ_64G * 8) 435 #endif 436 437 static struct platform_device *alloc_memdev(int id) 438 { 439 struct resource res[] = { 440 [0] = { 441 .flags = IORESOURCE_MEM, 442 }, 443 [1] = { 444 .flags = IORESOURCE_MEM, 445 .desc = IORES_DESC_PERSISTENT_MEMORY, 446 }, 447 }; 448 struct platform_device *pdev; 449 int i, rc; 450 451 for (i = 0; i < ARRAY_SIZE(res); i++) { 452 struct cxl_mock_res *r = alloc_mock_res(SZ_256M); 453 454 if (!r) 455 return NULL; 456 res[i].start = r->range.start; 457 res[i].end = r->range.end; 458 } 459 460 pdev = platform_device_alloc("cxl_mem", id); 461 if (!pdev) 462 return NULL; 463 464 rc = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); 465 if (rc) 466 goto err; 467 468 return pdev; 469 470 err: 471 platform_device_put(pdev); 472 return NULL; 473 } 474 475 static __init int cxl_test_init(void) 476 { 477 int rc, i; 478 479 register_cxl_mock_ops(&cxl_mock_ops); 480 481 cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE); 482 if (!cxl_mock_pool) { 483 rc = -ENOMEM; 484 goto err_gen_pool_create; 485 } 486 487 rc = gen_pool_add(cxl_mock_pool, SZ_512G, SZ_64G, NUMA_NO_NODE); 488 if (rc) 489 goto err_gen_pool_add; 490 491 rc = populate_cedt(); 492 if (rc) 493 goto err_populate; 494 495 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) { 496 struct acpi_device *adev = &host_bridge[i]; 497 struct platform_device *pdev; 498 499 pdev = platform_device_alloc("cxl_host_bridge", i); 500 if (!pdev) 501 goto err_bridge; 502 503 mock_companion(adev, &pdev->dev); 504 rc = platform_device_add(pdev); 505 if (rc) { 506 platform_device_put(pdev); 507 goto err_bridge; 508 } 509 cxl_host_bridge[i] = pdev; 510 } 511 512 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) { 513 struct platform_device *bridge = 514 cxl_host_bridge[i / NR_CXL_ROOT_PORTS]; 515 struct platform_device *pdev; 516 517 pdev = platform_device_alloc("cxl_root_port", i); 518 if (!pdev) 519 goto err_port; 520 pdev->dev.parent = &bridge->dev; 521 522 rc = platform_device_add(pdev); 523 if (rc) { 524 platform_device_put(pdev); 525 goto err_port; 526 } 527 cxl_root_port[i] = pdev; 528 } 529 530 BUILD_BUG_ON(ARRAY_SIZE(cxl_mem) != ARRAY_SIZE(cxl_root_port)); 531 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) { 532 struct platform_device *port = cxl_root_port[i]; 533 struct platform_device *pdev; 534 535 pdev = alloc_memdev(i); 536 if (!pdev) 537 goto err_mem; 538 pdev->dev.parent = &port->dev; 539 540 rc = platform_device_add(pdev); 541 if (rc) { 542 platform_device_put(pdev); 543 goto err_mem; 544 } 545 cxl_mem[i] = pdev; 546 } 547 548 cxl_acpi = platform_device_alloc("cxl_acpi", 0); 549 if (!cxl_acpi) 550 goto err_mem; 551 552 mock_companion(&acpi0017_mock, &cxl_acpi->dev); 553 acpi0017_mock.dev.bus = &platform_bus_type; 554 555 rc = platform_device_add(cxl_acpi); 556 if (rc) 557 goto err_add; 558 559 return 0; 560 561 err_add: 562 platform_device_put(cxl_acpi); 563 err_mem: 564 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--) 565 platform_device_unregister(cxl_mem[i]); 566 err_port: 567 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) 568 platform_device_unregister(cxl_root_port[i]); 569 err_bridge: 570 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) 571 platform_device_unregister(cxl_host_bridge[i]); 572 err_populate: 573 depopulate_all_mock_resources(); 574 err_gen_pool_add: 575 gen_pool_destroy(cxl_mock_pool); 576 err_gen_pool_create: 577 unregister_cxl_mock_ops(&cxl_mock_ops); 578 return rc; 579 } 580 581 static __exit void cxl_test_exit(void) 582 { 583 int i; 584 585 platform_device_unregister(cxl_acpi); 586 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--) 587 platform_device_unregister(cxl_mem[i]); 588 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) 589 platform_device_unregister(cxl_root_port[i]); 590 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) 591 platform_device_unregister(cxl_host_bridge[i]); 592 depopulate_all_mock_resources(); 593 gen_pool_destroy(cxl_mock_pool); 594 unregister_cxl_mock_ops(&cxl_mock_ops); 595 } 596 597 module_init(cxl_test_init); 598 module_exit(cxl_test_exit); 599 MODULE_LICENSE("GPL v2"); 600 MODULE_IMPORT_NS(ACPI); 601