1 // SPDX-License-Identifier: GPL-2.0 AND MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <linux/delay.h> 7 8 #include <kunit/test.h> 9 #include <kunit/visibility.h> 10 11 #include "tests/xe_kunit_helpers.h" 12 #include "tests/xe_pci_test.h" 13 #include "tests/xe_test.h" 14 15 #include "xe_bo.h" 16 #include "xe_device.h" 17 #include "xe_pm.h" 18 19 /* 20 * There are different ways to allocate the G2G buffers. The plan for this test 21 * is to make sure that all the possible options work. The particular option 22 * chosen by the driver may vary from one platform to another, it may also change 23 * with time. So to ensure consistency of testing, the relevant driver code is 24 * replicated here to guarantee it won't change without the test being updated 25 * to keep testing the other options. 26 * 27 * In order to test the actual code being used by the driver, there is also the 28 * 'default' scheme. That will use the official driver routines to test whatever 29 * method the driver is using on the current platform at the current time. 30 */ 31 enum { 32 /* Driver defined allocation scheme */ 33 G2G_CTB_TYPE_DEFAULT, 34 /* Single buffer in host memory */ 35 G2G_CTB_TYPE_HOST, 36 /* Single buffer in a specific tile, loops across all tiles */ 37 G2G_CTB_TYPE_TILE, 38 }; 39 40 /* 41 * Payload is opaque to GuC. So KMD can define any structure or size it wants. 42 */ 43 struct g2g_test_payload { 44 u32 tx_dev; 45 u32 tx_tile; 46 u32 rx_dev; 47 u32 rx_tile; 48 u32 seqno; 49 }; 50 51 static void g2g_test_send(struct kunit *test, struct xe_guc *guc, 52 u32 far_tile, u32 far_dev, 53 struct g2g_test_payload *payload) 54 { 55 struct xe_device *xe = guc_to_xe(guc); 56 struct xe_gt *gt = guc_to_gt(guc); 57 u32 *action, total; 58 size_t payload_len; 59 int ret; 60 61 static_assert(IS_ALIGNED(sizeof(*payload), sizeof(u32))); 62 payload_len = sizeof(*payload) / sizeof(u32); 63 64 total = 4 + payload_len; 65 action = kunit_kmalloc_array(test, total, sizeof(*action), GFP_KERNEL); 66 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, action); 67 68 action[0] = XE_GUC_ACTION_TEST_G2G_SEND; 69 action[1] = far_tile; 70 action[2] = far_dev; 71 action[3] = payload_len; 72 memcpy(action + 4, payload, payload_len * sizeof(u32)); 73 74 atomic_inc(&xe->g2g_test_count); 75 76 /* 77 * Should specify the expected response notification here. Problem is that 78 * the response will be coming from a different GuC. By the end, it should 79 * all add up as long as an equal number of messages are sent from each GuC 80 * and to each GuC. However, in the middle negative reservation space errors 81 * and such like can occur. Rather than add intrusive changes to the CT layer 82 * it is simpler to just not bother counting it at all. The system should be 83 * idle when running the selftest, and the selftest's notification total size 84 * is well within the G2H allocation size. So there should be no issues with 85 * needing to block for space, which is all the tracking code is really for. 86 */ 87 ret = xe_guc_ct_send(&guc->ct, action, total, 0, 0); 88 kunit_kfree(test, action); 89 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G send failed: %d [%d:%d -> %d:%d]\n", ret, 90 gt_to_tile(gt)->id, G2G_DEV(gt), far_tile, far_dev); 91 } 92 93 /* 94 * NB: Can't use KUNIT_ASSERT and friends in here as this is called asynchronously 95 * from the G2H notification handler. Need that to actually complete rather than 96 * thread-abort in order to keep the rest of the driver alive! 97 */ 98 int xe_guc_g2g_test_notification(struct xe_guc *guc, u32 *msg, u32 len) 99 { 100 struct xe_device *xe = guc_to_xe(guc); 101 struct xe_gt *rx_gt = guc_to_gt(guc), *test_gt, *tx_gt = NULL; 102 u32 tx_tile, tx_dev, rx_tile, rx_dev, idx, got_len; 103 struct g2g_test_payload *payload; 104 size_t payload_len; 105 int ret = 0, i; 106 107 payload_len = sizeof(*payload) / sizeof(u32); 108 109 if (unlikely(len != (G2H_LEN_DW_G2G_NOTIFY_MIN + payload_len))) { 110 xe_gt_err(rx_gt, "G2G test notification invalid length %u", len); 111 ret = -EPROTO; 112 goto done; 113 } 114 115 tx_tile = msg[0]; 116 tx_dev = msg[1]; 117 got_len = msg[2]; 118 payload = (struct g2g_test_payload *)(msg + 3); 119 120 rx_tile = gt_to_tile(rx_gt)->id; 121 rx_dev = G2G_DEV(rx_gt); 122 123 if (got_len != payload_len) { 124 xe_gt_err(rx_gt, "G2G: Invalid payload length: %u vs %zu\n", got_len, payload_len); 125 ret = -EPROTO; 126 goto done; 127 } 128 129 if (payload->tx_dev != tx_dev || payload->tx_tile != tx_tile || 130 payload->rx_dev != rx_dev || payload->rx_tile != rx_tile) { 131 xe_gt_err(rx_gt, "G2G: Invalid payload: %d:%d -> %d:%d vs %d:%d -> %d:%d! [%d]\n", 132 payload->tx_tile, payload->tx_dev, payload->rx_tile, payload->rx_dev, 133 tx_tile, tx_dev, rx_tile, rx_dev, payload->seqno); 134 ret = -EPROTO; 135 goto done; 136 } 137 138 if (!xe->g2g_test_array) { 139 xe_gt_err(rx_gt, "G2G: Missing test array!\n"); 140 ret = -ENOMEM; 141 goto done; 142 } 143 144 for_each_gt(test_gt, xe, i) { 145 if (gt_to_tile(test_gt)->id != tx_tile) 146 continue; 147 148 if (G2G_DEV(test_gt) != tx_dev) 149 continue; 150 151 if (tx_gt) { 152 xe_gt_err(rx_gt, "G2G: Got duplicate TX GTs: %d vs %d for %d:%d!\n", 153 tx_gt->info.id, test_gt->info.id, tx_tile, tx_dev); 154 ret = -EINVAL; 155 goto done; 156 } 157 158 tx_gt = test_gt; 159 } 160 if (!tx_gt) { 161 xe_gt_err(rx_gt, "G2G: Failed to find a TX GT for %d:%d!\n", tx_tile, tx_dev); 162 ret = -EINVAL; 163 goto done; 164 } 165 166 idx = (tx_gt->info.id * xe->info.gt_count) + rx_gt->info.id; 167 168 if (xe->g2g_test_array[idx] != payload->seqno - 1) { 169 xe_gt_err(rx_gt, "G2G: Seqno mismatch %d vs %d for %d:%d -> %d:%d!\n", 170 xe->g2g_test_array[idx], payload->seqno - 1, 171 tx_tile, tx_dev, rx_tile, rx_dev); 172 ret = -EINVAL; 173 goto done; 174 } 175 176 xe->g2g_test_array[idx] = payload->seqno; 177 178 done: 179 atomic_dec(&xe->g2g_test_count); 180 return ret; 181 } 182 183 /* 184 * Send the given seqno from all GuCs to all other GuCs in tile/GT order 185 */ 186 static void g2g_test_in_order(struct kunit *test, struct xe_device *xe, u32 seqno) 187 { 188 struct xe_gt *near_gt, *far_gt; 189 int i, j; 190 191 for_each_gt(near_gt, xe, i) { 192 u32 near_tile = gt_to_tile(near_gt)->id; 193 u32 near_dev = G2G_DEV(near_gt); 194 195 for_each_gt(far_gt, xe, j) { 196 u32 far_tile = gt_to_tile(far_gt)->id; 197 u32 far_dev = G2G_DEV(far_gt); 198 struct g2g_test_payload payload; 199 200 if (far_gt->info.id == near_gt->info.id) 201 continue; 202 203 payload.tx_dev = near_dev; 204 payload.tx_tile = near_tile; 205 payload.rx_dev = far_dev; 206 payload.rx_tile = far_tile; 207 payload.seqno = seqno; 208 g2g_test_send(test, &near_gt->uc.guc, far_tile, far_dev, &payload); 209 } 210 } 211 } 212 213 #define WAIT_TIME_MS 100 214 #define WAIT_COUNT (1000 / WAIT_TIME_MS) 215 216 static void g2g_wait_for_complete(void *_xe) 217 { 218 struct xe_device *xe = (struct xe_device *)_xe; 219 struct kunit *test = kunit_get_current_test(); 220 int wait = 0; 221 222 /* Wait for all G2H messages to be received */ 223 while (atomic_read(&xe->g2g_test_count)) { 224 if (++wait > WAIT_COUNT) 225 break; 226 227 msleep(WAIT_TIME_MS); 228 } 229 230 KUNIT_ASSERT_EQ_MSG(test, 0, atomic_read(&xe->g2g_test_count), 231 "Timed out waiting for notifications\n"); 232 kunit_info(test, "Got all notifications back\n"); 233 } 234 235 #undef WAIT_TIME_MS 236 #undef WAIT_COUNT 237 238 static void g2g_clean_array(void *_xe) 239 { 240 struct xe_device *xe = (struct xe_device *)_xe; 241 242 xe->g2g_test_array = NULL; 243 } 244 245 #define NUM_LOOPS 16 246 247 static void g2g_run_test(struct kunit *test, struct xe_device *xe) 248 { 249 u32 seqno, max_array; 250 int ret, i, j; 251 252 max_array = xe->info.gt_count * xe->info.gt_count; 253 xe->g2g_test_array = kunit_kcalloc(test, max_array, sizeof(u32), GFP_KERNEL); 254 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe->g2g_test_array); 255 256 ret = kunit_add_action_or_reset(test, g2g_clean_array, xe); 257 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register clean up action\n"); 258 259 /* 260 * Send incrementing seqnos from all GuCs to all other GuCs in tile/GT order. 261 * Tile/GT order doesn't really mean anything to the hardware but it is going 262 * to be a fixed sequence every time. 263 * 264 * Verify that each one comes back having taken the correct route. 265 */ 266 ret = kunit_add_action(test, g2g_wait_for_complete, xe); 267 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register clean up action\n"); 268 for (seqno = 1; seqno < NUM_LOOPS; seqno++) 269 g2g_test_in_order(test, xe, seqno); 270 seqno--; 271 272 kunit_release_action(test, &g2g_wait_for_complete, xe); 273 274 /* Check for the final seqno in each slot */ 275 for (i = 0; i < xe->info.gt_count; i++) { 276 for (j = 0; j < xe->info.gt_count; j++) { 277 u32 idx = (j * xe->info.gt_count) + i; 278 279 if (i == j) 280 KUNIT_ASSERT_EQ_MSG(test, 0, xe->g2g_test_array[idx], 281 "identity seqno modified: %d for %dx%d!\n", 282 xe->g2g_test_array[idx], i, j); 283 else 284 KUNIT_ASSERT_EQ_MSG(test, seqno, xe->g2g_test_array[idx], 285 "invalid seqno: %d vs %d for %dx%d!\n", 286 xe->g2g_test_array[idx], seqno, i, j); 287 } 288 } 289 290 kunit_kfree(test, xe->g2g_test_array); 291 kunit_release_action(test, &g2g_clean_array, xe); 292 293 kunit_info(test, "Test passed\n"); 294 } 295 296 #undef NUM_LOOPS 297 298 static void g2g_ct_stop(struct xe_guc *guc) 299 { 300 struct xe_gt *remote_gt, *gt = guc_to_gt(guc); 301 struct xe_device *xe = gt_to_xe(gt); 302 int i, t; 303 304 for_each_gt(remote_gt, xe, i) { 305 u32 tile, dev; 306 307 if (remote_gt->info.id == gt->info.id) 308 continue; 309 310 tile = gt_to_tile(remote_gt)->id; 311 dev = G2G_DEV(remote_gt); 312 313 for (t = 0; t < XE_G2G_TYPE_LIMIT; t++) 314 guc_g2g_deregister(guc, tile, dev, t); 315 } 316 } 317 318 /* Size of a single allocation that contains all G2G CTBs across all GTs */ 319 static u32 g2g_ctb_size(struct kunit *test, struct xe_device *xe) 320 { 321 unsigned int count = xe->info.gt_count; 322 u32 num_channels = (count * (count - 1)) / 2; 323 324 kunit_info(test, "Size: (%d * %d / 2) * %d * 0x%08X + 0x%08X => 0x%08X [%d]\n", 325 count, count - 1, XE_G2G_TYPE_LIMIT, G2G_BUFFER_SIZE, G2G_DESC_AREA_SIZE, 326 num_channels * XE_G2G_TYPE_LIMIT * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE, 327 num_channels * XE_G2G_TYPE_LIMIT); 328 329 return num_channels * XE_G2G_TYPE_LIMIT * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE; 330 } 331 332 /* 333 * Use the driver's regular CTB allocation scheme. 334 */ 335 static void g2g_alloc_default(struct kunit *test, struct xe_device *xe) 336 { 337 struct xe_gt *gt; 338 int i; 339 340 kunit_info(test, "Default [tiles = %d, GTs = %d]\n", 341 xe->info.tile_count, xe->info.gt_count); 342 343 for_each_gt(gt, xe, i) { 344 struct xe_guc *guc = >->uc.guc; 345 int ret; 346 347 ret = guc_g2g_alloc(guc); 348 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G alloc failed: %pe", ERR_PTR(ret)); 349 continue; 350 } 351 } 352 353 static void g2g_distribute(struct kunit *test, struct xe_device *xe, struct xe_bo *bo) 354 { 355 struct xe_gt *root_gt, *gt; 356 int i; 357 358 root_gt = xe_device_get_gt(xe, 0); 359 root_gt->uc.guc.g2g.bo = bo; 360 root_gt->uc.guc.g2g.owned = true; 361 kunit_info(test, "[%d.%d] Assigned 0x%p\n", gt_to_tile(root_gt)->id, root_gt->info.id, bo); 362 363 for_each_gt(gt, xe, i) { 364 if (gt->info.id != 0) { 365 gt->uc.guc.g2g.owned = false; 366 gt->uc.guc.g2g.bo = xe_bo_get(bo); 367 kunit_info(test, "[%d.%d] Pinned 0x%p\n", 368 gt_to_tile(gt)->id, gt->info.id, gt->uc.guc.g2g.bo); 369 } 370 371 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gt->uc.guc.g2g.bo); 372 } 373 } 374 375 /* 376 * Allocate a single blob on the host and split between all G2G CTBs. 377 */ 378 static void g2g_alloc_host(struct kunit *test, struct xe_device *xe) 379 { 380 struct xe_bo *bo; 381 u32 g2g_size; 382 383 kunit_info(test, "Host [tiles = %d, GTs = %d]\n", xe->info.tile_count, xe->info.gt_count); 384 385 g2g_size = g2g_ctb_size(test, xe); 386 bo = xe_managed_bo_create_pin_map(xe, xe_device_get_root_tile(xe), g2g_size, 387 XE_BO_FLAG_SYSTEM | 388 XE_BO_FLAG_GGTT | 389 XE_BO_FLAG_GGTT_ALL | 390 XE_BO_FLAG_GGTT_INVALIDATE); 391 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo); 392 kunit_info(test, "[HST] G2G buffer create: 0x%p\n", bo); 393 394 xe_map_memset(xe, &bo->vmap, 0, 0, g2g_size); 395 396 g2g_distribute(test, xe, bo); 397 } 398 399 /* 400 * Allocate a single blob on the given tile and split between all G2G CTBs. 401 */ 402 static void g2g_alloc_tile(struct kunit *test, struct xe_device *xe, struct xe_tile *tile) 403 { 404 struct xe_bo *bo; 405 u32 g2g_size; 406 407 KUNIT_ASSERT_TRUE(test, IS_DGFX(xe)); 408 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tile); 409 410 kunit_info(test, "Tile %d [tiles = %d, GTs = %d]\n", 411 tile->id, xe->info.tile_count, xe->info.gt_count); 412 413 g2g_size = g2g_ctb_size(test, xe); 414 bo = xe_managed_bo_create_pin_map(xe, tile, g2g_size, 415 XE_BO_FLAG_VRAM_IF_DGFX(tile) | 416 XE_BO_FLAG_GGTT | 417 XE_BO_FLAG_GGTT_ALL | 418 XE_BO_FLAG_GGTT_INVALIDATE); 419 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo); 420 kunit_info(test, "[%d.*] G2G buffer create: 0x%p\n", tile->id, bo); 421 422 xe_map_memset(xe, &bo->vmap, 0, 0, g2g_size); 423 424 g2g_distribute(test, xe, bo); 425 } 426 427 static void g2g_free(struct kunit *test, struct xe_device *xe) 428 { 429 struct xe_gt *gt; 430 struct xe_bo *bo; 431 int i; 432 433 for_each_gt(gt, xe, i) { 434 bo = gt->uc.guc.g2g.bo; 435 if (!bo) 436 continue; 437 438 if (gt->uc.guc.g2g.owned) { 439 xe_managed_bo_unpin_map_no_vm(bo); 440 kunit_info(test, "[%d.%d] Unmapped 0x%p\n", 441 gt_to_tile(gt)->id, gt->info.id, bo); 442 } else { 443 xe_bo_put(bo); 444 kunit_info(test, "[%d.%d] Unpinned 0x%p\n", 445 gt_to_tile(gt)->id, gt->info.id, bo); 446 } 447 448 gt->uc.guc.g2g.bo = NULL; 449 } 450 } 451 452 static void g2g_stop(struct kunit *test, struct xe_device *xe) 453 { 454 struct xe_gt *gt; 455 int i; 456 457 for_each_gt(gt, xe, i) { 458 struct xe_guc *guc = >->uc.guc; 459 460 if (!guc->g2g.bo) 461 continue; 462 463 g2g_ct_stop(guc); 464 } 465 466 g2g_free(test, xe); 467 } 468 469 /* 470 * Generate a unique id for each bi-directional CTB for each pair of 471 * near and far tiles/devices. The id can then be used as an index into 472 * a single allocation that is sub-divided into multiple CTBs. 473 * 474 * For example, with two devices per tile and two tiles, the table should 475 * look like: 476 * Far <tile>.<dev> 477 * 0.0 0.1 1.0 1.1 478 * N 0.0 --/-- 00/01 02/03 04/05 479 * e 0.1 01/00 --/-- 06/07 08/09 480 * a 1.0 03/02 07/06 --/-- 10/11 481 * r 1.1 05/04 09/08 11/10 --/-- 482 * 483 * Where each entry is Rx/Tx channel id. 484 * 485 * So GuC #3 (tile 1, dev 1) talking to GuC #2 (tile 1, dev 0) would 486 * be reading from channel #11 and writing to channel #10. Whereas, 487 * GuC #2 talking to GuC #3 would be read on #10 and write to #11. 488 */ 489 static int g2g_slot_flat(u32 near_tile, u32 near_dev, u32 far_tile, u32 far_dev, 490 u32 type, u32 max_inst, bool have_dev) 491 { 492 u32 near = near_tile, far = far_tile; 493 u32 idx = 0, x, y, direction; 494 int i; 495 496 if (have_dev) { 497 near = (near << 1) | near_dev; 498 far = (far << 1) | far_dev; 499 } 500 501 /* No need to send to one's self */ 502 if (far == near) 503 return -1; 504 505 if (far > near) { 506 /* Top right table half */ 507 x = far; 508 y = near; 509 510 /* T/R is 'forwards' direction */ 511 direction = type; 512 } else { 513 /* Bottom left table half */ 514 x = near; 515 y = far; 516 517 /* B/L is 'backwards' direction */ 518 direction = (1 - type); 519 } 520 521 /* Count the rows prior to the target */ 522 for (i = y; i > 0; i--) 523 idx += max_inst - i; 524 525 /* Count this row up to the target */ 526 idx += (x - 1 - y); 527 528 /* Slots are in Rx/Tx pairs */ 529 idx *= 2; 530 531 /* Pick Rx/Tx direction */ 532 idx += direction; 533 534 return idx; 535 } 536 537 static int g2g_register_flat(struct xe_guc *guc, u32 far_tile, u32 far_dev, u32 type, bool have_dev) 538 { 539 struct xe_gt *gt = guc_to_gt(guc); 540 struct xe_device *xe = gt_to_xe(gt); 541 u32 near_tile = gt_to_tile(gt)->id; 542 u32 near_dev = G2G_DEV(gt); 543 u32 max = xe->info.gt_count; 544 int idx; 545 u32 base, desc, buf; 546 547 if (!guc->g2g.bo) 548 return -ENODEV; 549 550 idx = g2g_slot_flat(near_tile, near_dev, far_tile, far_dev, type, max, have_dev); 551 xe_assert(xe, idx >= 0); 552 553 base = guc_bo_ggtt_addr(guc, guc->g2g.bo); 554 desc = base + idx * G2G_DESC_SIZE; 555 buf = base + idx * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE; 556 557 xe_assert(xe, (desc - base + G2G_DESC_SIZE) <= G2G_DESC_AREA_SIZE); 558 xe_assert(xe, (buf - base + G2G_BUFFER_SIZE) <= xe_bo_size(guc->g2g.bo)); 559 560 return guc_action_register_g2g_buffer(guc, type, far_tile, far_dev, 561 desc, buf, G2G_BUFFER_SIZE); 562 } 563 564 static void g2g_start(struct kunit *test, struct xe_guc *guc) 565 { 566 struct xe_gt *remote_gt, *gt = guc_to_gt(guc); 567 struct xe_device *xe = gt_to_xe(gt); 568 unsigned int i; 569 int t, ret; 570 bool have_dev; 571 572 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, guc->g2g.bo); 573 574 /* GuC interface will need extending if more GT device types are ever created. */ 575 KUNIT_ASSERT_TRUE(test, 576 (gt->info.type == XE_GT_TYPE_MAIN) || 577 (gt->info.type == XE_GT_TYPE_MEDIA)); 578 579 /* Channel numbering depends on whether there are multiple GTs per tile */ 580 have_dev = xe->info.gt_count > xe->info.tile_count; 581 582 for_each_gt(remote_gt, xe, i) { 583 u32 tile, dev; 584 585 if (remote_gt->info.id == gt->info.id) 586 continue; 587 588 tile = gt_to_tile(remote_gt)->id; 589 dev = G2G_DEV(remote_gt); 590 591 for (t = 0; t < XE_G2G_TYPE_LIMIT; t++) { 592 ret = g2g_register_flat(guc, tile, dev, t, have_dev); 593 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G register failed: %pe", ERR_PTR(ret)); 594 } 595 } 596 } 597 598 static void g2g_reinit(struct kunit *test, struct xe_device *xe, int ctb_type, struct xe_tile *tile) 599 { 600 struct xe_gt *gt; 601 int i, found = 0; 602 603 g2g_stop(test, xe); 604 605 for_each_gt(gt, xe, i) { 606 struct xe_guc *guc = >->uc.guc; 607 608 KUNIT_ASSERT_NULL(test, guc->g2g.bo); 609 } 610 611 switch (ctb_type) { 612 case G2G_CTB_TYPE_DEFAULT: 613 g2g_alloc_default(test, xe); 614 break; 615 616 case G2G_CTB_TYPE_HOST: 617 g2g_alloc_host(test, xe); 618 break; 619 620 case G2G_CTB_TYPE_TILE: 621 g2g_alloc_tile(test, xe, tile); 622 break; 623 624 default: 625 KUNIT_ASSERT_TRUE(test, false); 626 } 627 628 for_each_gt(gt, xe, i) { 629 struct xe_guc *guc = >->uc.guc; 630 631 if (!guc->g2g.bo) 632 continue; 633 634 if (ctb_type == G2G_CTB_TYPE_DEFAULT) 635 guc_g2g_start(guc); 636 else 637 g2g_start(test, guc); 638 found++; 639 } 640 641 KUNIT_ASSERT_GT_MSG(test, found, 1, "insufficient G2G channels running: %d", found); 642 643 kunit_info(test, "Testing across %d GTs\n", found); 644 } 645 646 static void g2g_recreate_ctb(void *_xe) 647 { 648 struct xe_device *xe = (struct xe_device *)_xe; 649 struct kunit *test = kunit_get_current_test(); 650 651 g2g_stop(test, xe); 652 653 if (xe_guc_g2g_wanted(xe)) 654 g2g_reinit(test, xe, G2G_CTB_TYPE_DEFAULT, NULL); 655 } 656 657 static void g2g_pm_runtime_put(void *_xe) 658 { 659 struct xe_device *xe = (struct xe_device *)_xe; 660 661 xe_pm_runtime_put(xe); 662 } 663 664 static void g2g_pm_runtime_get(struct kunit *test) 665 { 666 struct xe_device *xe = test->priv; 667 int ret; 668 669 xe_pm_runtime_get(xe); 670 ret = kunit_add_action_or_reset(test, g2g_pm_runtime_put, xe); 671 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register runtime PM action\n"); 672 } 673 674 static void g2g_check_skip(struct kunit *test) 675 { 676 struct xe_device *xe = test->priv; 677 struct xe_gt *gt; 678 int i; 679 680 if (IS_SRIOV_VF(xe)) 681 kunit_skip(test, "not supported from a VF"); 682 683 if (xe->info.gt_count <= 1) 684 kunit_skip(test, "not enough GTs"); 685 686 for_each_gt(gt, xe, i) { 687 struct xe_guc *guc = >->uc.guc; 688 689 if (guc->fw.build_type == CSS_UKERNEL_INFO_BUILDTYPE_PROD) 690 kunit_skip(test, 691 "G2G test interface not available in production firmware builds\n"); 692 } 693 } 694 695 /* 696 * Simple test that does not try to recreate the CTBs. 697 * Requires that the platform already enables G2G comms 698 * but has no risk of leaving the system in a broken state 699 * afterwards. 700 */ 701 static void xe_live_guc_g2g_kunit_default(struct kunit *test) 702 { 703 struct xe_device *xe = test->priv; 704 705 if (!xe_guc_g2g_wanted(xe)) 706 kunit_skip(test, "G2G not enabled"); 707 708 g2g_check_skip(test); 709 710 g2g_pm_runtime_get(test); 711 712 kunit_info(test, "Testing default CTBs\n"); 713 g2g_run_test(test, xe); 714 715 kunit_release_action(test, &g2g_pm_runtime_put, xe); 716 } 717 718 /* 719 * More complex test that re-creates the CTBs in various location to 720 * test access to each location from each GuC. Can be run even on 721 * systems that do not enable G2G by default. On the other hand, 722 * because it recreates the CTBs, if something goes wrong it could 723 * leave the system with broken G2G comms. 724 */ 725 static void xe_live_guc_g2g_kunit_allmem(struct kunit *test) 726 { 727 struct xe_device *xe = test->priv; 728 int ret; 729 730 g2g_check_skip(test); 731 732 g2g_pm_runtime_get(test); 733 734 /* Make sure to leave the system as we found it */ 735 ret = kunit_add_action_or_reset(test, g2g_recreate_ctb, xe); 736 KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register CTB re-creation action\n"); 737 738 kunit_info(test, "Testing CTB type 'default'...\n"); 739 g2g_reinit(test, xe, G2G_CTB_TYPE_DEFAULT, NULL); 740 g2g_run_test(test, xe); 741 742 kunit_info(test, "Testing CTB type 'host'...\n"); 743 g2g_reinit(test, xe, G2G_CTB_TYPE_HOST, NULL); 744 g2g_run_test(test, xe); 745 746 if (IS_DGFX(xe)) { 747 struct xe_tile *tile; 748 int id; 749 750 for_each_tile(tile, xe, id) { 751 kunit_info(test, "Testing CTB type 'tile: #%d'...\n", id); 752 753 g2g_reinit(test, xe, G2G_CTB_TYPE_TILE, tile); 754 g2g_run_test(test, xe); 755 } 756 } else { 757 kunit_info(test, "Skipping local memory on integrated platform\n"); 758 } 759 760 kunit_release_action(test, g2g_recreate_ctb, xe); 761 kunit_release_action(test, g2g_pm_runtime_put, xe); 762 } 763 764 static struct kunit_case xe_guc_g2g_tests[] = { 765 KUNIT_CASE_PARAM(xe_live_guc_g2g_kunit_default, xe_pci_live_device_gen_param), 766 KUNIT_CASE_PARAM(xe_live_guc_g2g_kunit_allmem, xe_pci_live_device_gen_param), 767 {} 768 }; 769 770 VISIBLE_IF_KUNIT 771 struct kunit_suite xe_guc_g2g_test_suite = { 772 .name = "xe_guc_g2g", 773 .test_cases = xe_guc_g2g_tests, 774 .init = xe_kunit_helper_xe_device_live_test_init, 775 }; 776 EXPORT_SYMBOL_IF_KUNIT(xe_guc_g2g_test_suite); 777