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