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 cxl_mock_res { 186 struct list_head list; 187 struct range range; 188 }; 189 190 static LIST_HEAD(mock_res); 191 static DEFINE_MUTEX(mock_res_lock); 192 static struct gen_pool *cxl_mock_pool; 193 194 static void depopulate_all_mock_resources(void) 195 { 196 struct cxl_mock_res *res, *_res; 197 198 mutex_lock(&mock_res_lock); 199 list_for_each_entry_safe(res, _res, &mock_res, list) { 200 gen_pool_free(cxl_mock_pool, res->range.start, 201 range_len(&res->range)); 202 list_del(&res->list); 203 kfree(res); 204 } 205 mutex_unlock(&mock_res_lock); 206 } 207 208 static struct cxl_mock_res *alloc_mock_res(resource_size_t size) 209 { 210 struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL); 211 struct genpool_data_align data = { 212 .align = SZ_256M, 213 }; 214 unsigned long phys; 215 216 INIT_LIST_HEAD(&res->list); 217 phys = gen_pool_alloc_algo(cxl_mock_pool, size, 218 gen_pool_first_fit_align, &data); 219 if (!phys) 220 return NULL; 221 222 res->range = (struct range) { 223 .start = phys, 224 .end = phys + size - 1, 225 }; 226 mutex_lock(&mock_res_lock); 227 list_add(&res->list, &mock_res); 228 mutex_unlock(&mock_res_lock); 229 230 return res; 231 } 232 233 static int populate_cedt(void) 234 { 235 struct acpi_cedt_cfmws *cfmws[4] = { 236 [0] = &mock_cedt.cfmws0.cfmws, 237 [1] = &mock_cedt.cfmws1.cfmws, 238 [2] = &mock_cedt.cfmws2.cfmws, 239 [3] = &mock_cedt.cfmws3.cfmws, 240 }; 241 struct cxl_mock_res *res; 242 int i; 243 244 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) { 245 struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i]; 246 resource_size_t size; 247 248 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20) 249 size = ACPI_CEDT_CHBS_LENGTH_CXL20; 250 else 251 size = ACPI_CEDT_CHBS_LENGTH_CXL11; 252 253 res = alloc_mock_res(size); 254 if (!res) 255 return -ENOMEM; 256 chbs->base = res->range.start; 257 chbs->length = size; 258 } 259 260 for (i = 0; i < ARRAY_SIZE(cfmws); i++) { 261 struct acpi_cedt_cfmws *window = cfmws[i]; 262 263 res = alloc_mock_res(window->window_size); 264 if (!res) 265 return -ENOMEM; 266 window->base_hpa = res->range.start; 267 } 268 269 return 0; 270 } 271 272 static acpi_status mock_acpi_get_table(char *signature, u32 instance, 273 struct acpi_table_header **out_table) 274 { 275 if (instance < U32_MAX || strcmp(signature, ACPI_SIG_CEDT) != 0) 276 return acpi_get_table(signature, instance, out_table); 277 278 *out_table = (struct acpi_table_header *) &mock_cedt; 279 return AE_OK; 280 } 281 282 static void mock_acpi_put_table(struct acpi_table_header *table) 283 { 284 if (table == (struct acpi_table_header *) &mock_cedt) 285 return; 286 acpi_put_table(table); 287 } 288 289 static bool is_mock_bridge(struct device *dev) 290 { 291 int i; 292 293 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) 294 if (dev == &cxl_host_bridge[i]->dev) 295 return true; 296 297 return false; 298 } 299 300 static int host_bridge_index(struct acpi_device *adev) 301 { 302 return adev - host_bridge; 303 } 304 305 static struct acpi_device *find_host_bridge(acpi_handle handle) 306 { 307 int i; 308 309 for (i = 0; i < ARRAY_SIZE(host_bridge); i++) 310 if (handle == host_bridge[i].handle) 311 return &host_bridge[i]; 312 return NULL; 313 } 314 315 static acpi_status 316 mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, 317 struct acpi_object_list *arguments, 318 unsigned long long *data) 319 { 320 struct acpi_device *adev = find_host_bridge(handle); 321 322 if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0) 323 return acpi_evaluate_integer(handle, pathname, arguments, data); 324 325 *data = host_bridge_index(adev); 326 return AE_OK; 327 } 328 329 static struct pci_bus mock_pci_bus[NR_CXL_HOST_BRIDGES]; 330 static struct acpi_pci_root mock_pci_root[NR_CXL_HOST_BRIDGES] = { 331 [0] = { 332 .bus = &mock_pci_bus[0], 333 }, 334 [1] = { 335 .bus = &mock_pci_bus[1], 336 }, 337 [2] = { 338 .bus = &mock_pci_bus[2], 339 }, 340 [3] = { 341 .bus = &mock_pci_bus[3], 342 }, 343 }; 344 345 static struct platform_device *mock_cxl_root_port(struct pci_bus *bus, int index) 346 { 347 int i; 348 349 for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++) 350 if (bus == &mock_pci_bus[i]) 351 return cxl_root_port[index + i * NR_CXL_ROOT_PORTS]; 352 return NULL; 353 } 354 355 static bool is_mock_port(struct platform_device *pdev) 356 { 357 int i; 358 359 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) 360 if (pdev == cxl_root_port[i]) 361 return true; 362 return false; 363 } 364 365 static bool is_mock_bus(struct pci_bus *bus) 366 { 367 int i; 368 369 for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++) 370 if (bus == &mock_pci_bus[i]) 371 return true; 372 return false; 373 } 374 375 static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle) 376 { 377 struct acpi_device *adev = find_host_bridge(handle); 378 379 if (!adev) 380 return acpi_pci_find_root(handle); 381 return &mock_pci_root[host_bridge_index(adev)]; 382 } 383 384 static struct cxl_mock_ops cxl_mock_ops = { 385 .is_mock_adev = is_mock_adev, 386 .is_mock_bridge = is_mock_bridge, 387 .is_mock_bus = is_mock_bus, 388 .is_mock_port = is_mock_port, 389 .is_mock_dev = is_mock_dev, 390 .mock_port = mock_cxl_root_port, 391 .acpi_get_table = mock_acpi_get_table, 392 .acpi_put_table = mock_acpi_put_table, 393 .acpi_evaluate_integer = mock_acpi_evaluate_integer, 394 .acpi_pci_find_root = mock_acpi_pci_find_root, 395 .list = LIST_HEAD_INIT(cxl_mock_ops.list), 396 }; 397 398 static void mock_companion(struct acpi_device *adev, struct device *dev) 399 { 400 device_initialize(&adev->dev); 401 fwnode_init(&adev->fwnode, NULL); 402 dev->fwnode = &adev->fwnode; 403 adev->fwnode.dev = dev; 404 } 405 406 #ifndef SZ_64G 407 #define SZ_64G (SZ_32G * 2) 408 #endif 409 410 #ifndef SZ_512G 411 #define SZ_512G (SZ_64G * 8) 412 #endif 413 414 static struct platform_device *alloc_memdev(int id) 415 { 416 struct resource res[] = { 417 [0] = { 418 .flags = IORESOURCE_MEM, 419 }, 420 [1] = { 421 .flags = IORESOURCE_MEM, 422 .desc = IORES_DESC_PERSISTENT_MEMORY, 423 }, 424 }; 425 struct platform_device *pdev; 426 int i, rc; 427 428 for (i = 0; i < ARRAY_SIZE(res); i++) { 429 struct cxl_mock_res *r = alloc_mock_res(SZ_256M); 430 431 if (!r) 432 return NULL; 433 res[i].start = r->range.start; 434 res[i].end = r->range.end; 435 } 436 437 pdev = platform_device_alloc("cxl_mem", id); 438 if (!pdev) 439 return NULL; 440 441 rc = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); 442 if (rc) 443 goto err; 444 445 return pdev; 446 447 err: 448 platform_device_put(pdev); 449 return NULL; 450 } 451 452 static __init int cxl_test_init(void) 453 { 454 int rc, i; 455 456 register_cxl_mock_ops(&cxl_mock_ops); 457 458 cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE); 459 if (!cxl_mock_pool) { 460 rc = -ENOMEM; 461 goto err_gen_pool_create; 462 } 463 464 rc = gen_pool_add(cxl_mock_pool, SZ_512G, SZ_64G, NUMA_NO_NODE); 465 if (rc) 466 goto err_gen_pool_add; 467 468 rc = populate_cedt(); 469 if (rc) 470 goto err_populate; 471 472 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) { 473 struct acpi_device *adev = &host_bridge[i]; 474 struct platform_device *pdev; 475 476 pdev = platform_device_alloc("cxl_host_bridge", i); 477 if (!pdev) 478 goto err_bridge; 479 480 mock_companion(adev, &pdev->dev); 481 rc = platform_device_add(pdev); 482 if (rc) { 483 platform_device_put(pdev); 484 goto err_bridge; 485 } 486 cxl_host_bridge[i] = pdev; 487 } 488 489 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) { 490 struct platform_device *bridge = 491 cxl_host_bridge[i / NR_CXL_ROOT_PORTS]; 492 struct platform_device *pdev; 493 494 pdev = platform_device_alloc("cxl_root_port", i); 495 if (!pdev) 496 goto err_port; 497 pdev->dev.parent = &bridge->dev; 498 499 rc = platform_device_add(pdev); 500 if (rc) { 501 platform_device_put(pdev); 502 goto err_port; 503 } 504 cxl_root_port[i] = pdev; 505 } 506 507 BUILD_BUG_ON(ARRAY_SIZE(cxl_mem) != ARRAY_SIZE(cxl_root_port)); 508 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) { 509 struct platform_device *port = cxl_root_port[i]; 510 struct platform_device *pdev; 511 512 pdev = alloc_memdev(i); 513 if (!pdev) 514 goto err_mem; 515 pdev->dev.parent = &port->dev; 516 517 rc = platform_device_add(pdev); 518 if (rc) { 519 platform_device_put(pdev); 520 goto err_mem; 521 } 522 cxl_mem[i] = pdev; 523 } 524 525 cxl_acpi = platform_device_alloc("cxl_acpi", 0); 526 if (!cxl_acpi) 527 goto err_mem; 528 529 mock_companion(&acpi0017_mock, &cxl_acpi->dev); 530 acpi0017_mock.dev.bus = &platform_bus_type; 531 532 rc = platform_device_add(cxl_acpi); 533 if (rc) 534 goto err_add; 535 536 return 0; 537 538 err_add: 539 platform_device_put(cxl_acpi); 540 err_mem: 541 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--) 542 platform_device_unregister(cxl_mem[i]); 543 err_port: 544 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) 545 platform_device_unregister(cxl_root_port[i]); 546 err_bridge: 547 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) 548 platform_device_unregister(cxl_host_bridge[i]); 549 err_populate: 550 depopulate_all_mock_resources(); 551 err_gen_pool_add: 552 gen_pool_destroy(cxl_mock_pool); 553 err_gen_pool_create: 554 unregister_cxl_mock_ops(&cxl_mock_ops); 555 return rc; 556 } 557 558 static __exit void cxl_test_exit(void) 559 { 560 int i; 561 562 platform_device_unregister(cxl_acpi); 563 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--) 564 platform_device_unregister(cxl_mem[i]); 565 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) 566 platform_device_unregister(cxl_root_port[i]); 567 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) 568 platform_device_unregister(cxl_host_bridge[i]); 569 depopulate_all_mock_resources(); 570 gen_pool_destroy(cxl_mock_pool); 571 unregister_cxl_mock_ops(&cxl_mock_ops); 572 } 573 574 module_init(cxl_test_init); 575 module_exit(cxl_test_exit); 576 MODULE_LICENSE("GPL v2"); 577