1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/string.h> 7 #include <linux/xarray.h> 8 9 #include <drm/drm_drv.h> 10 #include <drm/drm_kunit_helpers.h> 11 12 #include <kunit/static_stub.h> 13 #include <kunit/test.h> 14 15 #include "regs/xe_gt_regs.h" 16 #include "regs/xe_reg_defs.h" 17 #include "xe_device.h" 18 #include "xe_device_types.h" 19 #include "xe_gt_mcr.h" 20 #include "xe_kunit_helpers.h" 21 #include "xe_pci_test.h" 22 #include "xe_reg_sr.h" 23 #include "xe_rtp.h" 24 #include "xe_rtp_test.h" 25 26 #define REGULAR_REG1 XE_REG(1) 27 #define REGULAR_REG2 XE_REG(2) 28 #define REGULAR_REG3 XE_REG(3) 29 #define REGULAR_REG4 XE_REG(4) 30 #define BAD_REGULAR_REG5 XE_REG(5) 31 #define MCR_REG1 XE_REG_MCR(1) 32 #define MCR_REG2 XE_REG_MCR(2) 33 #define MCR_REG3 XE_REG_MCR(3) 34 #define BAD_MCR_REG4 XE_REG_MCR(4) 35 #define MCR_REG5 XE_REG_MCR(5) 36 #define MASKED_REG1 XE_REG(1, XE_REG_OPTION_MASKED) 37 38 #undef XE_REG_MCR 39 #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) 40 41 struct rtp_rules_test_case { 42 const char *name; 43 bool expected_match; 44 int expected_err; 45 const struct xe_rtp_rule *rules; 46 u8 n_rules; 47 }; 48 49 struct rtp_to_sr_test_case { 50 const char *name; 51 struct xe_reg expected_reg; 52 u32 expected_set_bits; 53 u32 expected_clr_bits; 54 unsigned long expected_count_sr_entries; 55 unsigned int expected_sr_errors; 56 unsigned long expected_active; 57 const struct xe_rtp_table_sr table; 58 }; 59 60 struct rtp_test_case { 61 const char *name; 62 unsigned long expected_active; 63 const struct xe_rtp_table table; 64 }; 65 66 static bool fake_xe_gt_mcr_check_reg(struct xe_gt *gt, struct xe_reg reg) 67 { 68 /* 69 * All supported platforms in this imaginary setup will always have REG4 70 * as a non-MCR register and REG5 as MCR, meaning that BAD_MCR_REG4 and 71 * BAD_REGULAR_REG5 represent programming errors to be captured by our 72 * tests. 73 */ 74 if (reg.raw == BAD_REGULAR_REG5.raw) 75 return true; 76 77 if (reg.raw == BAD_MCR_REG4.raw) 78 return false; 79 80 return reg.mcr; 81 } 82 83 static bool match_yes(const struct xe_device *xe, const struct xe_gt *gt, 84 const struct xe_hw_engine *hwe) 85 { 86 return true; 87 } 88 89 static bool match_no(const struct xe_device *xe, const struct xe_gt *gt, 90 const struct xe_hw_engine *hwe) 91 { 92 return false; 93 } 94 95 static const struct rtp_rules_test_case rtp_rules_cases[] = { 96 /* 97 * Single rules. 98 * 99 * TODO: Include other types of rules as well: GRAPHICS_VERSION(), 100 * MEDIA_VERSION(), etc. 101 */ 102 { 103 .name = "no", 104 .expected_match = false, 105 XE_RTP_RULES(FUNC(match_no)), 106 }, 107 { 108 .name = "yes", 109 .expected_match = true, 110 XE_RTP_RULES(FUNC(match_yes)), 111 }, 112 113 /* Conjunctions with 2 operands. */ 114 { 115 .name = "no-and-no", 116 .expected_match = false, 117 XE_RTP_RULES(FUNC(match_no), FUNC(match_no)), 118 }, 119 { 120 .name = "no-and-yes", 121 .expected_match = false, 122 XE_RTP_RULES(FUNC(match_no), FUNC(match_yes)), 123 }, 124 { 125 .name = "yes-and-no", 126 .expected_match = false, 127 XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)), 128 }, 129 { 130 .name = "yes-and-yes", 131 .expected_match = true, 132 XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes)), 133 }, 134 135 /* Disjunctions with 2 operands. */ 136 { 137 .name = "no-or-no", 138 .expected_match = false, 139 XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_no)), 140 }, 141 { 142 .name = "no-or-yes", 143 .expected_match = true, 144 XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_yes)), 145 }, 146 { 147 .name = "yes-or-no", 148 .expected_match = true, 149 XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)), 150 }, 151 { 152 .name = "yes-or-yes", 153 .expected_match = true, 154 XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_yes)), 155 }, 156 157 /* Conjunction and disjunctions. */ 158 { 159 .name = "no-yes-or-yes-no", 160 .expected_match = false, 161 XE_RTP_RULES(FUNC(match_no), FUNC(match_yes), OR, 162 FUNC(match_yes), FUNC(match_no)), 163 }, 164 { 165 .name = "no-yes-or-yes-yes", 166 .expected_match = true, 167 XE_RTP_RULES(FUNC(match_no), FUNC(match_yes), OR, 168 FUNC(match_yes), FUNC(match_yes)), 169 }, 170 { 171 .name = "yes-yes-or-no-yes", 172 .expected_match = true, 173 XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes), OR, 174 FUNC(match_no), FUNC(match_yes)), 175 }, 176 { 177 .name = "yes-yes-or-yes-yes", 178 .expected_match = true, 179 XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes), OR, 180 FUNC(match_yes), FUNC(match_yes)), 181 }, 182 { 183 .name = "no-no-or-yes-or-no", 184 .expected_match = true, 185 XE_RTP_RULES(FUNC(match_no), FUNC(match_no), OR, 186 FUNC(match_yes), OR, 187 FUNC(match_no)), 188 }, 189 190 /* Syntax errors. */ 191 { 192 .name = "or", 193 .expected_match = false, 194 .expected_err = -EINVAL, 195 XE_RTP_RULES(OR), 196 }, 197 { 198 .name = "or-yes", 199 .expected_match = true, 200 .expected_err = -EINVAL, 201 XE_RTP_RULES(OR, FUNC(match_yes)), 202 }, 203 { 204 .name = "or-no", 205 .expected_match = false, 206 .expected_err = -EINVAL, 207 XE_RTP_RULES(OR, FUNC(match_no)), 208 }, 209 { 210 .name = "yes-or", 211 .expected_match = true, 212 .expected_err = -EINVAL, 213 XE_RTP_RULES(FUNC(match_yes), OR), 214 }, 215 { 216 .name = "no-or", 217 .expected_match = false, 218 .expected_err = -EINVAL, 219 XE_RTP_RULES(FUNC(match_no), OR), 220 }, 221 { 222 .name = "no-or-or-yes", 223 .expected_match = true, 224 .expected_err = -EINVAL, 225 XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_yes)), 226 }, 227 { 228 .name = "yes-or-or-no", 229 .expected_match = true, 230 .expected_err = -EINVAL, 231 XE_RTP_RULES(FUNC(match_yes), OR, OR, FUNC(match_no)), 232 }, 233 { 234 .name = "no-or-or-no", 235 .expected_match = false, 236 .expected_err = -EINVAL, 237 XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_no)), 238 }, 239 240 /* No match because hwe is NULL. */ 241 { 242 .name = "missing-context-engine-class", 243 .expected_match = false, 244 XE_RTP_RULES(ENGINE_CLASS(RENDER)), 245 }, 246 247 /* 248 * Missing context (hwe==NULL) does not cause parsing to stop, hence we 249 * expect a match. 250 */ 251 { 252 .name = "missing-context-engine-class-or-yes", 253 .expected_match = true, 254 XE_RTP_RULES(ENGINE_CLASS(RENDER), OR, FUNC(match_yes)), 255 }, 256 257 /* 258 * Missing context (hwe==NULL) does not cause parsing to stop, hence we 259 * expect a syntax error. 260 */ 261 { 262 .name = "missing-context-engine-class-or-or-yes", 263 .expected_match = true, 264 .expected_err = -EINVAL, 265 XE_RTP_RULES(ENGINE_CLASS(RENDER), OR, OR, FUNC(match_yes)), 266 }, 267 }; 268 269 static void xe_rtp_rules_tests(struct kunit *test) 270 { 271 const struct rtp_rules_test_case *param = test->param_value; 272 struct xe_device *xe = test->priv; 273 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; 274 int err; 275 bool match; 276 277 match = xe_rtp_rule_matches(xe, gt, NULL, param->rules, param->n_rules, &err); 278 279 KUNIT_EXPECT_EQ(test, match, param->expected_match); 280 KUNIT_EXPECT_EQ(test, err, param->expected_err); 281 } 282 283 static u32 bits_2_3_set(struct xe_gt *gt, struct xe_hw_engine *hwe) 284 { 285 return REG_BIT(2) | REG_BIT(3); 286 } 287 288 static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { 289 { 290 .name = "coalesce-same-reg", 291 .expected_reg = REGULAR_REG1, 292 .expected_set_bits = REG_BIT(0) | REG_BIT(1), 293 .expected_clr_bits = REG_BIT(0) | REG_BIT(1), 294 .expected_active = BIT(0) | BIT(1), 295 .expected_count_sr_entries = 1, 296 /* Different bits on the same register: create a single entry */ 297 .table = XE_RTP_TABLE_SR( 298 { XE_RTP_NAME("basic-1"), 299 XE_RTP_RULES(FUNC(match_yes)), 300 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 301 }, 302 { XE_RTP_NAME("basic-2"), 303 XE_RTP_RULES(FUNC(match_yes)), 304 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 305 }, 306 ), 307 }, 308 { 309 .name = "coalesce-same-reg-literal-and-func", 310 .expected_reg = REGULAR_REG1, 311 .expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2) | REG_BIT(3), 312 .expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2) | REG_BIT(3), 313 .expected_active = BIT(0) | BIT(1), 314 .expected_count_sr_entries = 1, 315 /* Different bits on the same register: create a single entry */ 316 .table = XE_RTP_TABLE_SR( 317 { XE_RTP_NAME("basic-1"), 318 XE_RTP_RULES(FUNC(match_yes)), 319 XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, 320 REG_BIT(0) | REG_BIT(1), 321 REG_BIT(0) | REG_BIT(1))) 322 }, 323 { XE_RTP_NAME("basic-2"), 324 XE_RTP_RULES(FUNC(match_yes)), 325 XE_RTP_ACTIONS(FIELD_SET_FUNC(REGULAR_REG1, 326 REG_BIT(2) | REG_BIT(3), 327 bits_2_3_set)) 328 }, 329 ), 330 }, 331 { 332 .name = "no-match-no-add", 333 .expected_reg = REGULAR_REG1, 334 .expected_set_bits = REG_BIT(0), 335 .expected_clr_bits = REG_BIT(0), 336 .expected_active = BIT(0), 337 .expected_count_sr_entries = 1, 338 /* Don't coalesce second entry since rules don't match */ 339 .table = XE_RTP_TABLE_SR( 340 { XE_RTP_NAME("basic-1"), 341 XE_RTP_RULES(FUNC(match_yes)), 342 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 343 }, 344 { XE_RTP_NAME("basic-2"), 345 XE_RTP_RULES(FUNC(match_no)), 346 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 347 }, 348 ), 349 }, 350 { 351 .name = "two-regs-two-entries", 352 .expected_reg = REGULAR_REG1, 353 .expected_set_bits = REG_BIT(0), 354 .expected_clr_bits = REG_BIT(0), 355 .expected_active = BIT(0) | BIT(1), 356 .expected_count_sr_entries = 2, 357 /* Same bits on different registers are not coalesced */ 358 .table = XE_RTP_TABLE_SR( 359 { XE_RTP_NAME("basic-1"), 360 XE_RTP_RULES(FUNC(match_yes)), 361 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 362 }, 363 { XE_RTP_NAME("basic-2"), 364 XE_RTP_RULES(FUNC(match_yes)), 365 XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0))) 366 }, 367 ), 368 }, 369 { 370 .name = "clr-one-set-other", 371 .expected_reg = REGULAR_REG1, 372 .expected_set_bits = REG_BIT(0), 373 .expected_clr_bits = REG_BIT(1) | REG_BIT(0), 374 .expected_active = BIT(0) | BIT(1), 375 .expected_count_sr_entries = 1, 376 /* Check clr vs set actions on different bits */ 377 .table = XE_RTP_TABLE_SR( 378 { XE_RTP_NAME("basic-1"), 379 XE_RTP_RULES(FUNC(match_yes)), 380 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 381 }, 382 { XE_RTP_NAME("basic-2"), 383 XE_RTP_RULES(FUNC(match_yes)), 384 XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1))) 385 }, 386 ), 387 }, 388 { 389 #define TEMP_MASK REG_GENMASK(10, 8) 390 #define TEMP_FIELD REG_FIELD_PREP(TEMP_MASK, 2) 391 .name = "set-field", 392 .expected_reg = REGULAR_REG1, 393 .expected_set_bits = TEMP_FIELD, 394 .expected_clr_bits = TEMP_MASK, 395 .expected_active = BIT(0), 396 .expected_count_sr_entries = 1, 397 /* Check FIELD_SET works */ 398 .table = XE_RTP_TABLE_SR( 399 { XE_RTP_NAME("basic-1"), 400 XE_RTP_RULES(FUNC(match_yes)), 401 XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, 402 TEMP_MASK, TEMP_FIELD)) 403 }, 404 ), 405 #undef TEMP_MASK 406 #undef TEMP_FIELD 407 }, 408 { 409 .name = "conflict-duplicate", 410 .expected_reg = REGULAR_REG1, 411 .expected_set_bits = REG_BIT(0), 412 .expected_clr_bits = REG_BIT(0), 413 .expected_active = BIT(0) | BIT(1), 414 .expected_count_sr_entries = 1, 415 .expected_sr_errors = 1, 416 .table = XE_RTP_TABLE_SR( 417 { XE_RTP_NAME("basic-1"), 418 XE_RTP_RULES(FUNC(match_yes)), 419 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 420 }, 421 /* drop: setting same values twice */ 422 { XE_RTP_NAME("basic-2"), 423 XE_RTP_RULES(FUNC(match_yes)), 424 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 425 }, 426 ), 427 }, 428 { 429 .name = "conflict-not-disjoint", 430 .expected_reg = REGULAR_REG1, 431 .expected_set_bits = REG_BIT(0), 432 .expected_clr_bits = REG_BIT(0), 433 .expected_active = BIT(0) | BIT(1), 434 .expected_count_sr_entries = 1, 435 .expected_sr_errors = 1, 436 .table = XE_RTP_TABLE_SR( 437 { XE_RTP_NAME("basic-1"), 438 XE_RTP_RULES(FUNC(match_yes)), 439 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 440 }, 441 /* drop: bits are not disjoint with previous entries */ 442 { XE_RTP_NAME("basic-2"), 443 XE_RTP_RULES(FUNC(match_yes)), 444 XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0))) 445 }, 446 ), 447 }, 448 { 449 .name = "conflict-not-disjoint-literal-and-func", 450 .expected_reg = REGULAR_REG1, 451 .expected_set_bits = REG_BIT(1) | REG_BIT(2), 452 .expected_clr_bits = REG_BIT(1) | REG_BIT(2), 453 .expected_active = BIT(0) | BIT(1), 454 .expected_count_sr_entries = 1, 455 .expected_sr_errors = 1, 456 .table = XE_RTP_TABLE_SR( 457 { XE_RTP_NAME("basic-1"), 458 XE_RTP_RULES(FUNC(match_yes)), 459 XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, 460 REG_BIT(1) | REG_BIT(2), 461 REG_BIT(1) | REG_BIT(2))) 462 }, 463 /* drop: bits are not disjoint with previous entries */ 464 { XE_RTP_NAME("basic-2"), 465 XE_RTP_RULES(FUNC(match_yes)), 466 XE_RTP_ACTIONS(FIELD_SET_FUNC(REGULAR_REG1, 467 REG_BIT(2) | REG_BIT(3), 468 bits_2_3_set)) 469 }, 470 ), 471 }, 472 { 473 .name = "conflict-reg-type", 474 .expected_reg = REGULAR_REG1, 475 .expected_set_bits = REG_BIT(0), 476 .expected_clr_bits = REG_BIT(0), 477 .expected_active = BIT(0) | BIT(1) | BIT(2), 478 .expected_count_sr_entries = 1, 479 .expected_sr_errors = 2, 480 .table = XE_RTP_TABLE_SR( 481 { XE_RTP_NAME("basic-1"), 482 XE_RTP_RULES(FUNC(match_yes)), 483 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 484 }, 485 /* drop: regular vs MCR */ 486 { XE_RTP_NAME("basic-2"), 487 XE_RTP_RULES(FUNC(match_yes)), 488 XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1))) 489 }, 490 /* drop: regular vs masked */ 491 { XE_RTP_NAME("basic-3"), 492 XE_RTP_RULES(FUNC(match_yes)), 493 XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0))) 494 }, 495 ), 496 }, 497 { 498 .name = "bad-mcr-reg-forced-to-regular", 499 .expected_reg = REGULAR_REG4, 500 .expected_set_bits = REG_BIT(0), 501 .expected_clr_bits = REG_BIT(0), 502 .expected_active = BIT(0), 503 .expected_count_sr_entries = 1, 504 .expected_sr_errors = 1, 505 .table = XE_RTP_TABLE_SR( 506 { XE_RTP_NAME("bad-mcr-regular-reg"), 507 XE_RTP_RULES(FUNC(match_yes)), 508 XE_RTP_ACTIONS(SET(BAD_MCR_REG4, REG_BIT(0))) 509 }, 510 ), 511 }, 512 { 513 .name = "bad-regular-reg-forced-to-mcr", 514 .expected_reg = MCR_REG5, 515 .expected_set_bits = REG_BIT(0), 516 .expected_clr_bits = REG_BIT(0), 517 .expected_active = BIT(0), 518 .expected_count_sr_entries = 1, 519 .expected_sr_errors = 1, 520 .table = XE_RTP_TABLE_SR( 521 { XE_RTP_NAME("bad-regular-reg"), 522 XE_RTP_RULES(FUNC(match_yes)), 523 XE_RTP_ACTIONS(SET(BAD_REGULAR_REG5, REG_BIT(0))) 524 }, 525 ), 526 }, 527 }; 528 529 static void xe_rtp_process_to_sr_tests(struct kunit *test) 530 { 531 const struct rtp_to_sr_test_case *param = test->param_value; 532 struct xe_device *xe = test->priv; 533 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; 534 struct xe_reg_sr *reg_sr = >->reg_sr; 535 const struct xe_reg_sr_entry *sre, *sr_entry = NULL; 536 struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); 537 unsigned long idx, count_sr_entries = 0, active = 0; 538 539 xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe); 540 541 xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries); 542 xe_rtp_process_to_sr(&ctx, ¶m->table, reg_sr, false); 543 544 xa_for_each(®_sr->xa, idx, sre) { 545 if (idx == param->expected_reg.addr) 546 sr_entry = sre; 547 548 count_sr_entries++; 549 } 550 551 KUNIT_EXPECT_EQ(test, active, param->expected_active); 552 553 KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries); 554 if (count_sr_entries) { 555 KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits); 556 KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits); 557 KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw); 558 } else { 559 KUNIT_EXPECT_NULL(test, sr_entry); 560 } 561 562 KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors); 563 } 564 565 /* 566 * Entries below follow the logic used with xe_wa_oob.rules: 567 * 1) Entries with empty name are OR'ed: all entries marked active since the 568 * last entry with a name 569 * 2) There are no action associated with rules 570 */ 571 static const struct rtp_test_case rtp_cases[] = { 572 { 573 .name = "active1", 574 .expected_active = BIT(0), 575 .table = XE_RTP_TABLE( 576 { XE_RTP_NAME("r1"), 577 XE_RTP_RULES(FUNC(match_yes)), 578 }, 579 ), 580 }, 581 { 582 .name = "active2", 583 .expected_active = BIT(0) | BIT(1), 584 .table = XE_RTP_TABLE( 585 { XE_RTP_NAME("r1"), 586 XE_RTP_RULES(FUNC(match_yes)), 587 }, 588 { XE_RTP_NAME("r2"), 589 XE_RTP_RULES(FUNC(match_yes)), 590 }, 591 ), 592 }, 593 { 594 .name = "active-inactive", 595 .expected_active = BIT(0), 596 .table = XE_RTP_TABLE( 597 { XE_RTP_NAME("r1"), 598 XE_RTP_RULES(FUNC(match_yes)), 599 }, 600 { XE_RTP_NAME("r2"), 601 XE_RTP_RULES(FUNC(match_no)), 602 }, 603 ), 604 }, 605 { 606 .name = "inactive-active", 607 .expected_active = BIT(1), 608 .table = XE_RTP_TABLE( 609 { XE_RTP_NAME("r1"), 610 XE_RTP_RULES(FUNC(match_no)), 611 }, 612 { XE_RTP_NAME("r2"), 613 XE_RTP_RULES(FUNC(match_yes)), 614 }, 615 ), 616 }, 617 { 618 .name = "inactive-active-inactive", 619 .expected_active = BIT(1), 620 .table = XE_RTP_TABLE( 621 { XE_RTP_NAME("r1"), 622 XE_RTP_RULES(FUNC(match_no)), 623 }, 624 { XE_RTP_NAME("r2"), 625 XE_RTP_RULES(FUNC(match_yes)), 626 }, 627 { XE_RTP_NAME("r3"), 628 XE_RTP_RULES(FUNC(match_no)), 629 }, 630 ), 631 }, 632 { 633 .name = "inactive-inactive-inactive", 634 .expected_active = 0, 635 .table = XE_RTP_TABLE( 636 { XE_RTP_NAME("r1"), 637 XE_RTP_RULES(FUNC(match_no)), 638 }, 639 { XE_RTP_NAME("r2"), 640 XE_RTP_RULES(FUNC(match_no)), 641 }, 642 { XE_RTP_NAME("r3"), 643 XE_RTP_RULES(FUNC(match_no)), 644 }, 645 ), 646 }, 647 }; 648 649 static void xe_rtp_process_tests(struct kunit *test) 650 { 651 const struct rtp_test_case *param = test->param_value; 652 struct xe_device *xe = test->priv; 653 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; 654 struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); 655 unsigned long active = 0; 656 657 xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries); 658 xe_rtp_process(&ctx, ¶m->table); 659 660 KUNIT_EXPECT_EQ(test, active, param->expected_active); 661 } 662 663 static void rtp_rules_desc(const struct rtp_rules_test_case *t, char *desc) 664 { 665 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 666 } 667 668 KUNIT_ARRAY_PARAM(rtp_rules, rtp_rules_cases, rtp_rules_desc); 669 670 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc) 671 { 672 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 673 } 674 675 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc); 676 677 static void rtp_desc(const struct rtp_test_case *t, char *desc) 678 { 679 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 680 } 681 682 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc); 683 684 static int xe_rtp_test_init(struct kunit *test) 685 { 686 struct xe_device *xe; 687 struct device *dev; 688 int ret; 689 690 dev = drm_kunit_helper_alloc_device(test); 691 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); 692 693 xe = xe_kunit_helper_alloc_xe_device(test, dev); 694 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); 695 696 /* Initialize an empty device */ 697 test->priv = NULL; 698 ret = xe_pci_fake_device_init(xe); 699 KUNIT_ASSERT_EQ(test, ret, 0); 700 701 xe->drm.dev = dev; 702 test->priv = xe; 703 704 kunit_activate_static_stub(test, xe_gt_mcr_check_reg, fake_xe_gt_mcr_check_reg); 705 706 return 0; 707 } 708 709 static void xe_rtp_test_exit(struct kunit *test) 710 { 711 struct xe_device *xe = test->priv; 712 713 drm_kunit_helper_free_device(test, xe->drm.dev); 714 } 715 716 static struct kunit_case xe_rtp_tests[] = { 717 KUNIT_CASE_PARAM(xe_rtp_rules_tests, rtp_rules_gen_params), 718 KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params), 719 KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params), 720 {} 721 }; 722 723 static struct kunit_suite xe_rtp_test_suite = { 724 .name = "xe_rtp", 725 .init = xe_rtp_test_init, 726 .exit = xe_rtp_test_exit, 727 .test_cases = xe_rtp_tests, 728 }; 729 730 kunit_test_suite(xe_rtp_test_suite); 731