547 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright © 2023 Intel Corporation4 */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_MCR32#define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1)33 34struct 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 45struct rtp_test_case {46 const char *name;47 unsigned long expected_active;48 const struct xe_rtp_entry *entries;49};50 51static bool match_yes(const struct xe_gt *gt, const struct xe_hw_engine *hwe)52{53 return true;54}55 56static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe)57{58 return false;59}60 61static 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 failure143 * wouldn't really trigger as RTP stops processing as144 * soon as it has a matching set of rules145 */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_MASK235#undef TEMP_FIELD236 },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 307static 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 the349 * last entry with a name350 * 2) There are no action associated with rules351 */352static 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 472static 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 489static 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 494KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);495 496static void rtp_desc(const struct rtp_test_case *t, char *desc)497{498 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);499}500 501KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);502 503static 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 526static 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 533static 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 539static 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 546kunit_test_suite(xe_rtp_test_suite);547