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/test.h> 13 14 #include "regs/xe_gt_regs.h" 15 #include "regs/xe_reg_defs.h" 16 #include "xe_device.h" 17 #include "xe_device_types.h" 18 #include "xe_kunit_helpers.h" 19 #include "xe_pci_test.h" 20 #include "xe_reg_sr.h" 21 #include "xe_rtp.h" 22 23 #define REGULAR_REG1 XE_REG(1) 24 #define REGULAR_REG2 XE_REG(2) 25 #define REGULAR_REG3 XE_REG(3) 26 #define MCR_REG1 XE_REG_MCR(1) 27 #define MCR_REG2 XE_REG_MCR(2) 28 #define MCR_REG3 XE_REG_MCR(3) 29 #define MASKED_REG1 XE_REG(1, XE_REG_OPTION_MASKED) 30 31 #undef XE_REG_MCR 32 #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) 33 34 struct rtp_to_sr_test_case { 35 const char *name; 36 struct xe_reg expected_reg; 37 u32 expected_set_bits; 38 u32 expected_clr_bits; 39 unsigned long expected_count_sr_entries; 40 unsigned int expected_sr_errors; 41 unsigned long expected_active; 42 const struct xe_rtp_entry_sr *entries; 43 }; 44 45 struct rtp_test_case { 46 const char *name; 47 unsigned long expected_active; 48 const struct xe_rtp_entry *entries; 49 }; 50 51 static bool match_yes(const struct xe_gt *gt, const struct xe_hw_engine *hwe) 52 { 53 return true; 54 } 55 56 static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe) 57 { 58 return false; 59 } 60 61 static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { 62 { 63 .name = "coalesce-same-reg", 64 .expected_reg = REGULAR_REG1, 65 .expected_set_bits = REG_BIT(0) | REG_BIT(1), 66 .expected_clr_bits = REG_BIT(0) | REG_BIT(1), 67 .expected_active = BIT(0) | BIT(1), 68 .expected_count_sr_entries = 1, 69 /* Different bits on the same register: create a single entry */ 70 .entries = (const struct xe_rtp_entry_sr[]) { 71 { XE_RTP_NAME("basic-1"), 72 XE_RTP_RULES(FUNC(match_yes)), 73 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 74 }, 75 { XE_RTP_NAME("basic-2"), 76 XE_RTP_RULES(FUNC(match_yes)), 77 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 78 }, 79 {} 80 }, 81 }, 82 { 83 .name = "no-match-no-add", 84 .expected_reg = REGULAR_REG1, 85 .expected_set_bits = REG_BIT(0), 86 .expected_clr_bits = REG_BIT(0), 87 .expected_active = BIT(0), 88 .expected_count_sr_entries = 1, 89 /* Don't coalesce second entry since rules don't match */ 90 .entries = (const struct xe_rtp_entry_sr[]) { 91 { XE_RTP_NAME("basic-1"), 92 XE_RTP_RULES(FUNC(match_yes)), 93 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 94 }, 95 { XE_RTP_NAME("basic-2"), 96 XE_RTP_RULES(FUNC(match_no)), 97 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 98 }, 99 {} 100 }, 101 }, 102 { 103 .name = "match-or", 104 .expected_reg = REGULAR_REG1, 105 .expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2), 106 .expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2), 107 .expected_active = BIT(0) | BIT(1) | BIT(2), 108 .expected_count_sr_entries = 1, 109 .entries = (const struct xe_rtp_entry_sr[]) { 110 { XE_RTP_NAME("first"), 111 XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)), 112 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 113 }, 114 { XE_RTP_NAME("middle"), 115 XE_RTP_RULES(FUNC(match_no), FUNC(match_no), OR, 116 FUNC(match_yes), OR, 117 FUNC(match_no)), 118 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 119 }, 120 { XE_RTP_NAME("last"), 121 XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_yes)), 122 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(2))) 123 }, 124 { XE_RTP_NAME("no-match"), 125 XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_no)), 126 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(3))) 127 }, 128 {} 129 }, 130 }, 131 { 132 .name = "match-or-xfail", 133 .expected_reg = REGULAR_REG1, 134 .expected_count_sr_entries = 0, 135 .entries = (const struct xe_rtp_entry_sr[]) { 136 { XE_RTP_NAME("leading-or"), 137 XE_RTP_RULES(OR, FUNC(match_yes)), 138 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 139 }, 140 { XE_RTP_NAME("trailing-or"), 141 /* 142 * First condition is match_no, otherwise the failure 143 * wouldn't really trigger as RTP stops processing as 144 * soon as it has a matching set of rules 145 */ 146 XE_RTP_RULES(FUNC(match_no), OR), 147 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 148 }, 149 { XE_RTP_NAME("no-or-or-yes"), 150 XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_yes)), 151 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(2))) 152 }, 153 {} 154 }, 155 }, 156 { 157 .name = "no-match-no-add-multiple-rules", 158 .expected_reg = REGULAR_REG1, 159 .expected_set_bits = REG_BIT(0), 160 .expected_clr_bits = REG_BIT(0), 161 .expected_active = BIT(0), 162 .expected_count_sr_entries = 1, 163 /* Don't coalesce second entry due to one of the rules */ 164 .entries = (const struct xe_rtp_entry_sr[]) { 165 { XE_RTP_NAME("basic-1"), 166 XE_RTP_RULES(FUNC(match_yes)), 167 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 168 }, 169 { XE_RTP_NAME("basic-2"), 170 XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)), 171 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) 172 }, 173 {} 174 }, 175 }, 176 { 177 .name = "two-regs-two-entries", 178 .expected_reg = REGULAR_REG1, 179 .expected_set_bits = REG_BIT(0), 180 .expected_clr_bits = REG_BIT(0), 181 .expected_active = BIT(0) | BIT(1), 182 .expected_count_sr_entries = 2, 183 /* Same bits on different registers are not coalesced */ 184 .entries = (const struct xe_rtp_entry_sr[]) { 185 { XE_RTP_NAME("basic-1"), 186 XE_RTP_RULES(FUNC(match_yes)), 187 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 188 }, 189 { XE_RTP_NAME("basic-2"), 190 XE_RTP_RULES(FUNC(match_yes)), 191 XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0))) 192 }, 193 {} 194 }, 195 }, 196 { 197 .name = "clr-one-set-other", 198 .expected_reg = REGULAR_REG1, 199 .expected_set_bits = REG_BIT(0), 200 .expected_clr_bits = REG_BIT(1) | REG_BIT(0), 201 .expected_active = BIT(0) | BIT(1), 202 .expected_count_sr_entries = 1, 203 /* Check clr vs set actions on different bits */ 204 .entries = (const struct xe_rtp_entry_sr[]) { 205 { XE_RTP_NAME("basic-1"), 206 XE_RTP_RULES(FUNC(match_yes)), 207 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 208 }, 209 { XE_RTP_NAME("basic-2"), 210 XE_RTP_RULES(FUNC(match_yes)), 211 XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1))) 212 }, 213 {} 214 }, 215 }, 216 { 217 #define TEMP_MASK REG_GENMASK(10, 8) 218 #define TEMP_FIELD REG_FIELD_PREP(TEMP_MASK, 2) 219 .name = "set-field", 220 .expected_reg = REGULAR_REG1, 221 .expected_set_bits = TEMP_FIELD, 222 .expected_clr_bits = TEMP_MASK, 223 .expected_active = BIT(0), 224 .expected_count_sr_entries = 1, 225 /* Check FIELD_SET works */ 226 .entries = (const struct xe_rtp_entry_sr[]) { 227 { XE_RTP_NAME("basic-1"), 228 XE_RTP_RULES(FUNC(match_yes)), 229 XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, 230 TEMP_MASK, TEMP_FIELD)) 231 }, 232 {} 233 }, 234 #undef TEMP_MASK 235 #undef TEMP_FIELD 236 }, 237 { 238 .name = "conflict-duplicate", 239 .expected_reg = REGULAR_REG1, 240 .expected_set_bits = REG_BIT(0), 241 .expected_clr_bits = REG_BIT(0), 242 .expected_active = BIT(0) | BIT(1), 243 .expected_count_sr_entries = 1, 244 .expected_sr_errors = 1, 245 .entries = (const struct xe_rtp_entry_sr[]) { 246 { XE_RTP_NAME("basic-1"), 247 XE_RTP_RULES(FUNC(match_yes)), 248 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 249 }, 250 /* drop: setting same values twice */ 251 { XE_RTP_NAME("basic-2"), 252 XE_RTP_RULES(FUNC(match_yes)), 253 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 254 }, 255 {} 256 }, 257 }, 258 { 259 .name = "conflict-not-disjoint", 260 .expected_reg = REGULAR_REG1, 261 .expected_set_bits = REG_BIT(0), 262 .expected_clr_bits = REG_BIT(0), 263 .expected_active = BIT(0) | BIT(1), 264 .expected_count_sr_entries = 1, 265 .expected_sr_errors = 1, 266 .entries = (const struct xe_rtp_entry_sr[]) { 267 { XE_RTP_NAME("basic-1"), 268 XE_RTP_RULES(FUNC(match_yes)), 269 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 270 }, 271 /* drop: bits are not disjoint with previous entries */ 272 { XE_RTP_NAME("basic-2"), 273 XE_RTP_RULES(FUNC(match_yes)), 274 XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0))) 275 }, 276 {} 277 }, 278 }, 279 { 280 .name = "conflict-reg-type", 281 .expected_reg = REGULAR_REG1, 282 .expected_set_bits = REG_BIT(0), 283 .expected_clr_bits = REG_BIT(0), 284 .expected_active = BIT(0) | BIT(1) | BIT(2), 285 .expected_count_sr_entries = 1, 286 .expected_sr_errors = 2, 287 .entries = (const struct xe_rtp_entry_sr[]) { 288 { XE_RTP_NAME("basic-1"), 289 XE_RTP_RULES(FUNC(match_yes)), 290 XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) 291 }, 292 /* drop: regular vs MCR */ 293 { XE_RTP_NAME("basic-2"), 294 XE_RTP_RULES(FUNC(match_yes)), 295 XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1))) 296 }, 297 /* drop: regular vs masked */ 298 { XE_RTP_NAME("basic-3"), 299 XE_RTP_RULES(FUNC(match_yes)), 300 XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0))) 301 }, 302 {} 303 }, 304 }, 305 }; 306 307 static void xe_rtp_process_to_sr_tests(struct kunit *test) 308 { 309 const struct rtp_to_sr_test_case *param = test->param_value; 310 struct xe_device *xe = test->priv; 311 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; 312 struct xe_reg_sr *reg_sr = >->reg_sr; 313 const struct xe_reg_sr_entry *sre, *sr_entry = NULL; 314 struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); 315 unsigned long idx, count_sr_entries = 0, count_rtp_entries = 0, active = 0; 316 317 xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe); 318 319 while (param->entries[count_rtp_entries].rules) 320 count_rtp_entries++; 321 322 xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); 323 xe_rtp_process_to_sr(&ctx, param->entries, reg_sr); 324 325 xa_for_each(®_sr->xa, idx, sre) { 326 if (idx == param->expected_reg.addr) 327 sr_entry = sre; 328 329 count_sr_entries++; 330 } 331 332 KUNIT_EXPECT_EQ(test, active, param->expected_active); 333 334 KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries); 335 if (count_sr_entries) { 336 KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits); 337 KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits); 338 KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw); 339 } else { 340 KUNIT_EXPECT_NULL(test, sr_entry); 341 } 342 343 KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors); 344 } 345 346 /* 347 * Entries below follow the logic used with xe_wa_oob.rules: 348 * 1) Entries with empty name are OR'ed: all entries marked active since the 349 * last entry with a name 350 * 2) There are no action associated with rules 351 */ 352 static const struct rtp_test_case rtp_cases[] = { 353 { 354 .name = "active1", 355 .expected_active = BIT(0), 356 .entries = (const struct xe_rtp_entry[]) { 357 { XE_RTP_NAME("r1"), 358 XE_RTP_RULES(FUNC(match_yes)), 359 }, 360 {} 361 }, 362 }, 363 { 364 .name = "active2", 365 .expected_active = BIT(0) | BIT(1), 366 .entries = (const struct xe_rtp_entry[]) { 367 { XE_RTP_NAME("r1"), 368 XE_RTP_RULES(FUNC(match_yes)), 369 }, 370 { XE_RTP_NAME("r2"), 371 XE_RTP_RULES(FUNC(match_yes)), 372 }, 373 {} 374 }, 375 }, 376 { 377 .name = "active-inactive", 378 .expected_active = BIT(0), 379 .entries = (const struct xe_rtp_entry[]) { 380 { XE_RTP_NAME("r1"), 381 XE_RTP_RULES(FUNC(match_yes)), 382 }, 383 { XE_RTP_NAME("r2"), 384 XE_RTP_RULES(FUNC(match_no)), 385 }, 386 {} 387 }, 388 }, 389 { 390 .name = "inactive-active", 391 .expected_active = BIT(1), 392 .entries = (const struct xe_rtp_entry[]) { 393 { XE_RTP_NAME("r1"), 394 XE_RTP_RULES(FUNC(match_no)), 395 }, 396 { XE_RTP_NAME("r2"), 397 XE_RTP_RULES(FUNC(match_yes)), 398 }, 399 {} 400 }, 401 }, 402 { 403 .name = "inactive-1st_or_active-inactive", 404 .expected_active = BIT(1), 405 .entries = (const struct xe_rtp_entry[]) { 406 { XE_RTP_NAME("r1"), 407 XE_RTP_RULES(FUNC(match_no)), 408 }, 409 { XE_RTP_NAME("r2_or_conditions"), 410 XE_RTP_RULES(FUNC(match_yes), OR, 411 FUNC(match_no), OR, 412 FUNC(match_no)) }, 413 { XE_RTP_NAME("r3"), 414 XE_RTP_RULES(FUNC(match_no)), 415 }, 416 {} 417 }, 418 }, 419 { 420 .name = "inactive-2nd_or_active-inactive", 421 .expected_active = BIT(1), 422 .entries = (const struct xe_rtp_entry[]) { 423 { XE_RTP_NAME("r1"), 424 XE_RTP_RULES(FUNC(match_no)), 425 }, 426 { XE_RTP_NAME("r2_or_conditions"), 427 XE_RTP_RULES(FUNC(match_no), OR, 428 FUNC(match_yes), OR, 429 FUNC(match_no)) }, 430 { XE_RTP_NAME("r3"), 431 XE_RTP_RULES(FUNC(match_no)), 432 }, 433 {} 434 }, 435 }, 436 { 437 .name = "inactive-last_or_active-inactive", 438 .expected_active = BIT(1), 439 .entries = (const struct xe_rtp_entry[]) { 440 { XE_RTP_NAME("r1"), 441 XE_RTP_RULES(FUNC(match_no)), 442 }, 443 { XE_RTP_NAME("r2_or_conditions"), 444 XE_RTP_RULES(FUNC(match_no), OR, 445 FUNC(match_no), OR, 446 FUNC(match_yes)) }, 447 { XE_RTP_NAME("r3"), 448 XE_RTP_RULES(FUNC(match_no)), 449 }, 450 {} 451 }, 452 }, 453 { 454 .name = "inactive-no_or_active-inactive", 455 .expected_active = 0, 456 .entries = (const struct xe_rtp_entry[]) { 457 { XE_RTP_NAME("r1"), 458 XE_RTP_RULES(FUNC(match_no)), 459 }, 460 { XE_RTP_NAME("r2_or_conditions"), 461 XE_RTP_RULES(FUNC(match_no), OR, 462 FUNC(match_no), OR, 463 FUNC(match_no)) }, 464 { XE_RTP_NAME("r3"), 465 XE_RTP_RULES(FUNC(match_no)), 466 }, 467 {} 468 }, 469 }, 470 }; 471 472 static void xe_rtp_process_tests(struct kunit *test) 473 { 474 const struct rtp_test_case *param = test->param_value; 475 struct xe_device *xe = test->priv; 476 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; 477 struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); 478 unsigned long count_rtp_entries = 0, active = 0; 479 480 while (param->entries[count_rtp_entries].rules) 481 count_rtp_entries++; 482 483 xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); 484 xe_rtp_process(&ctx, param->entries); 485 486 KUNIT_EXPECT_EQ(test, active, param->expected_active); 487 } 488 489 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc) 490 { 491 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 492 } 493 494 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc); 495 496 static void rtp_desc(const struct rtp_test_case *t, char *desc) 497 { 498 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 499 } 500 501 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc); 502 503 static int xe_rtp_test_init(struct kunit *test) 504 { 505 struct xe_device *xe; 506 struct device *dev; 507 int ret; 508 509 dev = drm_kunit_helper_alloc_device(test); 510 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); 511 512 xe = xe_kunit_helper_alloc_xe_device(test, dev); 513 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); 514 515 /* Initialize an empty device */ 516 test->priv = NULL; 517 ret = xe_pci_fake_device_init(xe); 518 KUNIT_ASSERT_EQ(test, ret, 0); 519 520 xe->drm.dev = dev; 521 test->priv = xe; 522 523 return 0; 524 } 525 526 static void xe_rtp_test_exit(struct kunit *test) 527 { 528 struct xe_device *xe = test->priv; 529 530 drm_kunit_helper_free_device(test, xe->drm.dev); 531 } 532 533 static struct kunit_case xe_rtp_tests[] = { 534 KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params), 535 KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params), 536 {} 537 }; 538 539 static struct kunit_suite xe_rtp_test_suite = { 540 .name = "xe_rtp", 541 .init = xe_rtp_test_init, 542 .exit = xe_rtp_test_exit, 543 .test_cases = xe_rtp_tests, 544 }; 545 546 kunit_test_suite(xe_rtp_test_suite); 547