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
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_device *xe, const struct xe_gt *gt,
52 const struct xe_hw_engine *hwe)
53{
54 return true;
55}
56
57static 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
63static 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
309static 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 = &gt->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(sr: reg_sr, name: "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: &ctx, active_entries: &active, n_entries: count_rtp_entries);
325 xe_rtp_process_to_sr(ctx: &ctx, entries: param->entries, n_entries: count_rtp_entries, sr: reg_sr);
326
327 xa_for_each(&reg_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 */
354static 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
474static 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: &ctx, active_entries: &active, n_entries: count_rtp_entries);
486 xe_rtp_process(ctx: &ctx, entries: param->entries);
487
488 KUNIT_EXPECT_EQ(test, active, param->expected_active);
489}
490
491static 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
496KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
497
498static void rtp_desc(const struct rtp_test_case *t, char *desc)
499{
500 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
501}
502
503KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
504
505static 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
528static void xe_rtp_test_exit(struct kunit *test)
529{
530 struct xe_device *xe = test->priv;
531
532 drm_kunit_helper_free_device(test, dev: xe->drm.dev);
533}
534
535static 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
541static 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
548kunit_test_suite(xe_rtp_test_suite);
549

source code of linux/drivers/gpu/drm/xe/tests/xe_rtp_test.c