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, reg_sr); 326 327 xa_for_each(®_sr->xa, idx, sre) { 328 if (idx == param->expected_reg.addr) 329 sr_entry = sre; 330 331 count_sr_entries++; 332 } 333 334 KUNIT_EXPECT_EQ(test, active, param->expected_active); 335 336 KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries); 337 if (count_sr_entries) { 338 KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits); 339 KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits); 340 KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw); 341 } else { 342 KUNIT_EXPECT_NULL(test, sr_entry); 343 } 344 345 KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors); 346 } 347 348 /* 349 * Entries below follow the logic used with xe_wa_oob.rules: 350 * 1) Entries with empty name are OR'ed: all entries marked active since the 351 * last entry with a name 352 * 2) There are no action associated with rules 353 */ 354 static const struct rtp_test_case rtp_cases[] = { 355 { 356 .name = "active1", 357 .expected_active = BIT(0), 358 .entries = (const struct xe_rtp_entry[]) { 359 { XE_RTP_NAME("r1"), 360 XE_RTP_RULES(FUNC(match_yes)), 361 }, 362 {} 363 }, 364 }, 365 { 366 .name = "active2", 367 .expected_active = BIT(0) | BIT(1), 368 .entries = (const struct xe_rtp_entry[]) { 369 { XE_RTP_NAME("r1"), 370 XE_RTP_RULES(FUNC(match_yes)), 371 }, 372 { XE_RTP_NAME("r2"), 373 XE_RTP_RULES(FUNC(match_yes)), 374 }, 375 {} 376 }, 377 }, 378 { 379 .name = "active-inactive", 380 .expected_active = BIT(0), 381 .entries = (const struct xe_rtp_entry[]) { 382 { XE_RTP_NAME("r1"), 383 XE_RTP_RULES(FUNC(match_yes)), 384 }, 385 { XE_RTP_NAME("r2"), 386 XE_RTP_RULES(FUNC(match_no)), 387 }, 388 {} 389 }, 390 }, 391 { 392 .name = "inactive-active", 393 .expected_active = BIT(1), 394 .entries = (const struct xe_rtp_entry[]) { 395 { XE_RTP_NAME("r1"), 396 XE_RTP_RULES(FUNC(match_no)), 397 }, 398 { XE_RTP_NAME("r2"), 399 XE_RTP_RULES(FUNC(match_yes)), 400 }, 401 {} 402 }, 403 }, 404 { 405 .name = "inactive-1st_or_active-inactive", 406 .expected_active = BIT(1), 407 .entries = (const struct xe_rtp_entry[]) { 408 { XE_RTP_NAME("r1"), 409 XE_RTP_RULES(FUNC(match_no)), 410 }, 411 { XE_RTP_NAME("r2_or_conditions"), 412 XE_RTP_RULES(FUNC(match_yes), OR, 413 FUNC(match_no), OR, 414 FUNC(match_no)) }, 415 { XE_RTP_NAME("r3"), 416 XE_RTP_RULES(FUNC(match_no)), 417 }, 418 {} 419 }, 420 }, 421 { 422 .name = "inactive-2nd_or_active-inactive", 423 .expected_active = BIT(1), 424 .entries = (const struct xe_rtp_entry[]) { 425 { XE_RTP_NAME("r1"), 426 XE_RTP_RULES(FUNC(match_no)), 427 }, 428 { XE_RTP_NAME("r2_or_conditions"), 429 XE_RTP_RULES(FUNC(match_no), OR, 430 FUNC(match_yes), OR, 431 FUNC(match_no)) }, 432 { XE_RTP_NAME("r3"), 433 XE_RTP_RULES(FUNC(match_no)), 434 }, 435 {} 436 }, 437 }, 438 { 439 .name = "inactive-last_or_active-inactive", 440 .expected_active = BIT(1), 441 .entries = (const struct xe_rtp_entry[]) { 442 { XE_RTP_NAME("r1"), 443 XE_RTP_RULES(FUNC(match_no)), 444 }, 445 { XE_RTP_NAME("r2_or_conditions"), 446 XE_RTP_RULES(FUNC(match_no), OR, 447 FUNC(match_no), OR, 448 FUNC(match_yes)) }, 449 { XE_RTP_NAME("r3"), 450 XE_RTP_RULES(FUNC(match_no)), 451 }, 452 {} 453 }, 454 }, 455 { 456 .name = "inactive-no_or_active-inactive", 457 .expected_active = 0, 458 .entries = (const struct xe_rtp_entry[]) { 459 { XE_RTP_NAME("r1"), 460 XE_RTP_RULES(FUNC(match_no)), 461 }, 462 { XE_RTP_NAME("r2_or_conditions"), 463 XE_RTP_RULES(FUNC(match_no), OR, 464 FUNC(match_no), OR, 465 FUNC(match_no)) }, 466 { XE_RTP_NAME("r3"), 467 XE_RTP_RULES(FUNC(match_no)), 468 }, 469 {} 470 }, 471 }, 472 }; 473 474 static void xe_rtp_process_tests(struct kunit *test) 475 { 476 const struct rtp_test_case *param = test->param_value; 477 struct xe_device *xe = test->priv; 478 struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; 479 struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); 480 unsigned long count_rtp_entries = 0, active = 0; 481 482 while (param->entries[count_rtp_entries].rules) 483 count_rtp_entries++; 484 485 xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); 486 xe_rtp_process(&ctx, param->entries); 487 488 KUNIT_EXPECT_EQ(test, active, param->expected_active); 489 } 490 491 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc) 492 { 493 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 494 } 495 496 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc); 497 498 static void rtp_desc(const struct rtp_test_case *t, char *desc) 499 { 500 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 501 } 502 503 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc); 504 505 static int xe_rtp_test_init(struct kunit *test) 506 { 507 struct xe_device *xe; 508 struct device *dev; 509 int ret; 510 511 dev = drm_kunit_helper_alloc_device(test); 512 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); 513 514 xe = xe_kunit_helper_alloc_xe_device(test, dev); 515 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); 516 517 /* Initialize an empty device */ 518 test->priv = NULL; 519 ret = xe_pci_fake_device_init(xe); 520 KUNIT_ASSERT_EQ(test, ret, 0); 521 522 xe->drm.dev = dev; 523 test->priv = xe; 524 525 return 0; 526 } 527 528 static void xe_rtp_test_exit(struct kunit *test) 529 { 530 struct xe_device *xe = test->priv; 531 532 drm_kunit_helper_free_device(test, xe->drm.dev); 533 } 534 535 static struct kunit_case xe_rtp_tests[] = { 536 KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params), 537 KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params), 538 {} 539 }; 540 541 static struct kunit_suite xe_rtp_test_suite = { 542 .name = "xe_rtp", 543 .init = xe_rtp_test_init, 544 .exit = xe_rtp_test_exit, 545 .test_cases = xe_rtp_tests, 546 }; 547 548 kunit_test_suite(xe_rtp_test_suite); 549