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