xref: /linux/drivers/gpu/drm/xe/tests/xe_rtp_test.c (revision 26ba30221c03364d6ed9910be8da4c1fd871b07b)
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/static_stub.h>
13 #include <kunit/test.h>
14 
15 #include "regs/xe_gt_regs.h"
16 #include "regs/xe_reg_defs.h"
17 #include "xe_device.h"
18 #include "xe_device_types.h"
19 #include "xe_gt_mcr.h"
20 #include "xe_kunit_helpers.h"
21 #include "xe_pci_test.h"
22 #include "xe_reg_sr.h"
23 #include "xe_rtp.h"
24 #include "xe_rtp_test.h"
25 
26 #define REGULAR_REG1		XE_REG(1)
27 #define REGULAR_REG2		XE_REG(2)
28 #define REGULAR_REG3		XE_REG(3)
29 #define REGULAR_REG4		XE_REG(4)
30 #define BAD_REGULAR_REG5	XE_REG(5)
31 #define MCR_REG1		XE_REG_MCR(1)
32 #define MCR_REG2		XE_REG_MCR(2)
33 #define MCR_REG3		XE_REG_MCR(3)
34 #define BAD_MCR_REG4		XE_REG_MCR(4)
35 #define MCR_REG5		XE_REG_MCR(5)
36 #define MASKED_REG1		XE_REG(1, XE_REG_OPTION_MASKED)
37 
38 #undef XE_REG_MCR
39 #define XE_REG_MCR(...)     XE_REG(__VA_ARGS__, .mcr = 1)
40 
41 struct rtp_rules_test_case {
42 	const char *name;
43 	bool expected_match;
44 	int expected_err;
45 	const struct xe_rtp_rule *rules;
46 	u8 n_rules;
47 };
48 
49 struct rtp_to_sr_test_case {
50 	const char *name;
51 	struct xe_reg expected_reg;
52 	u32 expected_set_bits;
53 	u32 expected_clr_bits;
54 	unsigned long expected_count_sr_entries;
55 	unsigned int expected_sr_errors;
56 	unsigned long expected_active;
57 	const struct xe_rtp_table_sr table;
58 };
59 
60 struct rtp_test_case {
61 	const char *name;
62 	unsigned long expected_active;
63 	const struct xe_rtp_table table;
64 };
65 
66 static bool fake_xe_gt_mcr_check_reg(struct xe_gt *gt, struct xe_reg reg)
67 {
68 	/*
69 	 * All supported platforms in this imaginary setup will always have REG4
70 	 * as a non-MCR register and REG5 as MCR, meaning that BAD_MCR_REG4 and
71 	 * BAD_REGULAR_REG5 represent programming errors to be captured by our
72 	 * tests.
73 	 */
74 	if (reg.raw == BAD_REGULAR_REG5.raw)
75 		return true;
76 
77 	if (reg.raw == BAD_MCR_REG4.raw)
78 		return false;
79 
80 	return reg.mcr;
81 }
82 
83 static bool match_yes(const struct xe_device *xe, const struct xe_gt *gt,
84 		      const struct xe_hw_engine *hwe)
85 {
86 	return true;
87 }
88 
89 static bool match_no(const struct xe_device *xe, const struct xe_gt *gt,
90 		     const struct xe_hw_engine *hwe)
91 {
92 	return false;
93 }
94 
95 static const struct rtp_rules_test_case rtp_rules_cases[] = {
96 	/*
97 	 * Single rules.
98 	 *
99 	 * TODO: Include other types of rules as well: GRAPHICS_VERSION(),
100 	 * MEDIA_VERSION(), etc.
101 	 */
102 	{
103 		.name = "no",
104 		.expected_match = false,
105 		XE_RTP_RULES(FUNC(match_no)),
106 	},
107 	{
108 		.name = "yes",
109 		.expected_match = true,
110 		XE_RTP_RULES(FUNC(match_yes)),
111 	},
112 
113 	/* Conjunctions with 2 operands. */
114 	{
115 		.name = "no-and-no",
116 		.expected_match = false,
117 		XE_RTP_RULES(FUNC(match_no), FUNC(match_no)),
118 	},
119 	{
120 		.name = "no-and-yes",
121 		.expected_match = false,
122 		XE_RTP_RULES(FUNC(match_no), FUNC(match_yes)),
123 	},
124 	{
125 		.name = "yes-and-no",
126 		.expected_match = false,
127 		XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)),
128 	},
129 	{
130 		.name = "yes-and-yes",
131 		.expected_match = true,
132 		XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes)),
133 	},
134 
135 	/* Disjunctions with 2 operands. */
136 	{
137 		.name = "no-or-no",
138 		.expected_match = false,
139 		XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_no)),
140 	},
141 	{
142 		.name = "no-or-yes",
143 		.expected_match = true,
144 		XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_yes)),
145 	},
146 	{
147 		.name = "yes-or-no",
148 		.expected_match = true,
149 		XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)),
150 	},
151 	{
152 		.name = "yes-or-yes",
153 		.expected_match = true,
154 		XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_yes)),
155 	},
156 
157 	/* Conjunction and disjunctions. */
158 	{
159 		.name = "no-yes-or-yes-no",
160 		.expected_match = false,
161 		XE_RTP_RULES(FUNC(match_no), FUNC(match_yes), OR,
162 			     FUNC(match_yes), FUNC(match_no)),
163 	},
164 	{
165 		.name = "no-yes-or-yes-yes",
166 		.expected_match = true,
167 		XE_RTP_RULES(FUNC(match_no), FUNC(match_yes), OR,
168 			     FUNC(match_yes), FUNC(match_yes)),
169 	},
170 	{
171 		.name = "yes-yes-or-no-yes",
172 		.expected_match = true,
173 		XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes), OR,
174 			     FUNC(match_no), FUNC(match_yes)),
175 	},
176 	{
177 		.name = "yes-yes-or-yes-yes",
178 		.expected_match = true,
179 		XE_RTP_RULES(FUNC(match_yes), FUNC(match_yes), OR,
180 			     FUNC(match_yes), FUNC(match_yes)),
181 	},
182 	{
183 		.name = "no-no-or-yes-or-no",
184 		.expected_match = true,
185 		XE_RTP_RULES(FUNC(match_no), FUNC(match_no), OR,
186 			     FUNC(match_yes), OR,
187 			     FUNC(match_no)),
188 	},
189 
190 	/* Syntax errors. */
191 	{
192 		.name = "or",
193 		.expected_match = false,
194 		.expected_err = -EINVAL,
195 		XE_RTP_RULES(OR),
196 	},
197 	{
198 		.name = "or-yes",
199 		.expected_match = true,
200 		.expected_err = -EINVAL,
201 		XE_RTP_RULES(OR, FUNC(match_yes)),
202 	},
203 	{
204 		.name = "or-no",
205 		.expected_match = false,
206 		.expected_err = -EINVAL,
207 		XE_RTP_RULES(OR, FUNC(match_no)),
208 	},
209 	{
210 		.name = "yes-or",
211 		.expected_match = true,
212 		.expected_err = -EINVAL,
213 		XE_RTP_RULES(FUNC(match_yes), OR),
214 	},
215 	{
216 		.name = "no-or",
217 		.expected_match = false,
218 		.expected_err = -EINVAL,
219 		XE_RTP_RULES(FUNC(match_no), OR),
220 	},
221 	{
222 		.name = "no-or-or-yes",
223 		.expected_match = true,
224 		.expected_err = -EINVAL,
225 		XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_yes)),
226 	},
227 	{
228 		.name = "yes-or-or-no",
229 		.expected_match = true,
230 		.expected_err = -EINVAL,
231 		XE_RTP_RULES(FUNC(match_yes), OR, OR, FUNC(match_no)),
232 	},
233 	{
234 		.name = "no-or-or-no",
235 		.expected_match = false,
236 		.expected_err = -EINVAL,
237 		XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_no)),
238 	},
239 
240 	/* No match because hwe is NULL. */
241 	{
242 		.name = "missing-context-engine-class",
243 		.expected_match = false,
244 		XE_RTP_RULES(ENGINE_CLASS(RENDER)),
245 	},
246 
247 	/*
248 	 * Missing context (hwe==NULL) does not cause parsing to stop, hence we
249 	 * expect a match.
250 	 */
251 	{
252 		.name = "missing-context-engine-class-or-yes",
253 		.expected_match = true,
254 		XE_RTP_RULES(ENGINE_CLASS(RENDER), OR, FUNC(match_yes)),
255 	},
256 
257 	/*
258 	 * Missing context (hwe==NULL) does not cause parsing to stop, hence we
259 	 * expect a syntax error.
260 	 */
261 	{
262 		.name = "missing-context-engine-class-or-or-yes",
263 		.expected_match = true,
264 		.expected_err = -EINVAL,
265 		XE_RTP_RULES(ENGINE_CLASS(RENDER), OR, OR, FUNC(match_yes)),
266 	},
267 };
268 
269 static void xe_rtp_rules_tests(struct kunit *test)
270 {
271 	const struct rtp_rules_test_case *param = test->param_value;
272 	struct xe_device *xe = test->priv;
273 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
274 	int err;
275 	bool match;
276 
277 	match = xe_rtp_rule_matches(xe, gt, NULL, param->rules, param->n_rules, &err);
278 
279 	KUNIT_EXPECT_EQ(test, match, param->expected_match);
280 	KUNIT_EXPECT_EQ(test, err, param->expected_err);
281 }
282 
283 static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = {
284 	{
285 		.name = "coalesce-same-reg",
286 		.expected_reg = REGULAR_REG1,
287 		.expected_set_bits = REG_BIT(0) | REG_BIT(1),
288 		.expected_clr_bits = REG_BIT(0) | REG_BIT(1),
289 		.expected_active = BIT(0) | BIT(1),
290 		.expected_count_sr_entries = 1,
291 		/* Different bits on the same register: create a single entry */
292 		.table = XE_RTP_TABLE_SR(
293 			{ XE_RTP_NAME("basic-1"),
294 			  XE_RTP_RULES(FUNC(match_yes)),
295 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
296 			},
297 			{ XE_RTP_NAME("basic-2"),
298 			  XE_RTP_RULES(FUNC(match_yes)),
299 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
300 			},
301 		),
302 	},
303 	{
304 		.name = "no-match-no-add",
305 		.expected_reg = REGULAR_REG1,
306 		.expected_set_bits = REG_BIT(0),
307 		.expected_clr_bits = REG_BIT(0),
308 		.expected_active = BIT(0),
309 		.expected_count_sr_entries = 1,
310 		/* Don't coalesce second entry since rules don't match */
311 		.table = XE_RTP_TABLE_SR(
312 			{ XE_RTP_NAME("basic-1"),
313 			  XE_RTP_RULES(FUNC(match_yes)),
314 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
315 			},
316 			{ XE_RTP_NAME("basic-2"),
317 			  XE_RTP_RULES(FUNC(match_no)),
318 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
319 			},
320 		),
321 	},
322 	{
323 		.name = "two-regs-two-entries",
324 		.expected_reg = REGULAR_REG1,
325 		.expected_set_bits = REG_BIT(0),
326 		.expected_clr_bits = REG_BIT(0),
327 		.expected_active = BIT(0) | BIT(1),
328 		.expected_count_sr_entries = 2,
329 		/* Same bits on different registers are not coalesced */
330 		.table = XE_RTP_TABLE_SR(
331 			{ XE_RTP_NAME("basic-1"),
332 			  XE_RTP_RULES(FUNC(match_yes)),
333 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
334 			},
335 			{ XE_RTP_NAME("basic-2"),
336 			  XE_RTP_RULES(FUNC(match_yes)),
337 			  XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0)))
338 			},
339 		),
340 	},
341 	{
342 		.name = "clr-one-set-other",
343 		.expected_reg = REGULAR_REG1,
344 		.expected_set_bits = REG_BIT(0),
345 		.expected_clr_bits = REG_BIT(1) | REG_BIT(0),
346 		.expected_active = BIT(0) | BIT(1),
347 		.expected_count_sr_entries = 1,
348 		/* Check clr vs set actions on different bits */
349 		.table = XE_RTP_TABLE_SR(
350 			{ XE_RTP_NAME("basic-1"),
351 			  XE_RTP_RULES(FUNC(match_yes)),
352 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
353 			},
354 			{ XE_RTP_NAME("basic-2"),
355 			  XE_RTP_RULES(FUNC(match_yes)),
356 			  XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1)))
357 			},
358 		),
359 	},
360 	{
361 #define TEMP_MASK	REG_GENMASK(10, 8)
362 #define TEMP_FIELD	REG_FIELD_PREP(TEMP_MASK, 2)
363 		.name = "set-field",
364 		.expected_reg = REGULAR_REG1,
365 		.expected_set_bits = TEMP_FIELD,
366 		.expected_clr_bits = TEMP_MASK,
367 		.expected_active = BIT(0),
368 		.expected_count_sr_entries = 1,
369 		/* Check FIELD_SET works */
370 		.table = XE_RTP_TABLE_SR(
371 			{ XE_RTP_NAME("basic-1"),
372 			  XE_RTP_RULES(FUNC(match_yes)),
373 			  XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1,
374 						   TEMP_MASK, TEMP_FIELD))
375 			},
376 		),
377 #undef TEMP_MASK
378 #undef TEMP_FIELD
379 	},
380 	{
381 		.name = "conflict-duplicate",
382 		.expected_reg = REGULAR_REG1,
383 		.expected_set_bits = REG_BIT(0),
384 		.expected_clr_bits = REG_BIT(0),
385 		.expected_active = BIT(0) | BIT(1),
386 		.expected_count_sr_entries = 1,
387 		.expected_sr_errors = 1,
388 		.table = XE_RTP_TABLE_SR(
389 			{ XE_RTP_NAME("basic-1"),
390 			  XE_RTP_RULES(FUNC(match_yes)),
391 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
392 			},
393 			/* drop: setting same values twice */
394 			{ XE_RTP_NAME("basic-2"),
395 			  XE_RTP_RULES(FUNC(match_yes)),
396 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
397 			},
398 		),
399 	},
400 	{
401 		.name = "conflict-not-disjoint",
402 		.expected_reg = REGULAR_REG1,
403 		.expected_set_bits = REG_BIT(0),
404 		.expected_clr_bits = REG_BIT(0),
405 		.expected_active = BIT(0) | BIT(1),
406 		.expected_count_sr_entries = 1,
407 		.expected_sr_errors = 1,
408 		.table = XE_RTP_TABLE_SR(
409 			{ XE_RTP_NAME("basic-1"),
410 			  XE_RTP_RULES(FUNC(match_yes)),
411 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
412 			},
413 			/* drop: bits are not disjoint with previous entries */
414 			{ XE_RTP_NAME("basic-2"),
415 			  XE_RTP_RULES(FUNC(match_yes)),
416 			  XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0)))
417 			},
418 		),
419 	},
420 	{
421 		.name = "conflict-reg-type",
422 		.expected_reg = REGULAR_REG1,
423 		.expected_set_bits = REG_BIT(0),
424 		.expected_clr_bits = REG_BIT(0),
425 		.expected_active = BIT(0) | BIT(1) | BIT(2),
426 		.expected_count_sr_entries = 1,
427 		.expected_sr_errors = 2,
428 		.table = XE_RTP_TABLE_SR(
429 			{ XE_RTP_NAME("basic-1"),
430 			  XE_RTP_RULES(FUNC(match_yes)),
431 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
432 			},
433 			/* drop: regular vs MCR */
434 			{ XE_RTP_NAME("basic-2"),
435 			  XE_RTP_RULES(FUNC(match_yes)),
436 			  XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1)))
437 			},
438 			/* drop: regular vs masked */
439 			{ XE_RTP_NAME("basic-3"),
440 			  XE_RTP_RULES(FUNC(match_yes)),
441 			  XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0)))
442 			},
443 		),
444 	},
445 	{
446 		.name = "bad-mcr-reg-forced-to-regular",
447 		.expected_reg = REGULAR_REG4,
448 		.expected_set_bits = REG_BIT(0),
449 		.expected_clr_bits = REG_BIT(0),
450 		.expected_active = BIT(0),
451 		.expected_count_sr_entries = 1,
452 		.expected_sr_errors = 1,
453 		.table = XE_RTP_TABLE_SR(
454 			{ XE_RTP_NAME("bad-mcr-regular-reg"),
455 			  XE_RTP_RULES(FUNC(match_yes)),
456 			  XE_RTP_ACTIONS(SET(BAD_MCR_REG4, REG_BIT(0)))
457 			},
458 		),
459 	},
460 	{
461 		.name = "bad-regular-reg-forced-to-mcr",
462 		.expected_reg = MCR_REG5,
463 		.expected_set_bits = REG_BIT(0),
464 		.expected_clr_bits = REG_BIT(0),
465 		.expected_active = BIT(0),
466 		.expected_count_sr_entries = 1,
467 		.expected_sr_errors = 1,
468 		.table = XE_RTP_TABLE_SR(
469 			{ XE_RTP_NAME("bad-regular-reg"),
470 			  XE_RTP_RULES(FUNC(match_yes)),
471 			  XE_RTP_ACTIONS(SET(BAD_REGULAR_REG5, REG_BIT(0)))
472 			},
473 		),
474 	},
475 };
476 
477 static void xe_rtp_process_to_sr_tests(struct kunit *test)
478 {
479 	const struct rtp_to_sr_test_case *param = test->param_value;
480 	struct xe_device *xe = test->priv;
481 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
482 	struct xe_reg_sr *reg_sr = &gt->reg_sr;
483 	const struct xe_reg_sr_entry *sre, *sr_entry = NULL;
484 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
485 	unsigned long idx, count_sr_entries = 0, active = 0;
486 
487 	xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe);
488 
489 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries);
490 	xe_rtp_process_to_sr(&ctx, &param->table, reg_sr, false);
491 
492 	xa_for_each(&reg_sr->xa, idx, sre) {
493 		if (idx == param->expected_reg.addr)
494 			sr_entry = sre;
495 
496 		count_sr_entries++;
497 	}
498 
499 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
500 
501 	KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries);
502 	if (count_sr_entries) {
503 		KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits);
504 		KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits);
505 		KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw);
506 	} else {
507 		KUNIT_EXPECT_NULL(test, sr_entry);
508 	}
509 
510 	KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors);
511 }
512 
513 /*
514  * Entries below follow the logic used with xe_wa_oob.rules:
515  * 1) Entries with empty name are OR'ed: all entries marked active since the
516  *    last entry with a name
517  * 2) There are no action associated with rules
518  */
519 static const struct rtp_test_case rtp_cases[] = {
520 	{
521 		.name = "active1",
522 		.expected_active = BIT(0),
523 		.table = XE_RTP_TABLE(
524 			{ XE_RTP_NAME("r1"),
525 			  XE_RTP_RULES(FUNC(match_yes)),
526 			},
527 		),
528 	},
529 	{
530 		.name = "active2",
531 		.expected_active = BIT(0) | BIT(1),
532 		.table = XE_RTP_TABLE(
533 			{ XE_RTP_NAME("r1"),
534 			  XE_RTP_RULES(FUNC(match_yes)),
535 			},
536 			{ XE_RTP_NAME("r2"),
537 			  XE_RTP_RULES(FUNC(match_yes)),
538 			},
539 		),
540 	},
541 	{
542 		.name = "active-inactive",
543 		.expected_active = BIT(0),
544 		.table = XE_RTP_TABLE(
545 			{ XE_RTP_NAME("r1"),
546 			  XE_RTP_RULES(FUNC(match_yes)),
547 			},
548 			{ XE_RTP_NAME("r2"),
549 			  XE_RTP_RULES(FUNC(match_no)),
550 			},
551 		),
552 	},
553 	{
554 		.name = "inactive-active",
555 		.expected_active = BIT(1),
556 		.table = XE_RTP_TABLE(
557 			{ XE_RTP_NAME("r1"),
558 			  XE_RTP_RULES(FUNC(match_no)),
559 			},
560 			{ XE_RTP_NAME("r2"),
561 			  XE_RTP_RULES(FUNC(match_yes)),
562 			},
563 		),
564 	},
565 	{
566 		.name = "inactive-active-inactive",
567 		.expected_active = BIT(1),
568 		.table = XE_RTP_TABLE(
569 			{ XE_RTP_NAME("r1"),
570 			  XE_RTP_RULES(FUNC(match_no)),
571 			},
572 			{ XE_RTP_NAME("r2"),
573 			  XE_RTP_RULES(FUNC(match_yes)),
574 			},
575 			{ XE_RTP_NAME("r3"),
576 			  XE_RTP_RULES(FUNC(match_no)),
577 			},
578 		),
579 	},
580 	{
581 		.name = "inactive-inactive-inactive",
582 		.expected_active = 0,
583 		.table = XE_RTP_TABLE(
584 			{ XE_RTP_NAME("r1"),
585 			  XE_RTP_RULES(FUNC(match_no)),
586 			},
587 			{ XE_RTP_NAME("r2"),
588 			  XE_RTP_RULES(FUNC(match_no)),
589 			},
590 			{ XE_RTP_NAME("r3"),
591 			  XE_RTP_RULES(FUNC(match_no)),
592 			},
593 		),
594 	},
595 };
596 
597 static void xe_rtp_process_tests(struct kunit *test)
598 {
599 	const struct rtp_test_case *param = test->param_value;
600 	struct xe_device *xe = test->priv;
601 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
602 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
603 	unsigned long active = 0;
604 
605 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries);
606 	xe_rtp_process(&ctx, &param->table);
607 
608 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
609 }
610 
611 static void rtp_rules_desc(const struct rtp_rules_test_case *t, char *desc)
612 {
613 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
614 }
615 
616 KUNIT_ARRAY_PARAM(rtp_rules, rtp_rules_cases, rtp_rules_desc);
617 
618 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc)
619 {
620 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
621 }
622 
623 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
624 
625 static void rtp_desc(const struct rtp_test_case *t, char *desc)
626 {
627 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
628 }
629 
630 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
631 
632 static int xe_rtp_test_init(struct kunit *test)
633 {
634 	struct xe_device *xe;
635 	struct device *dev;
636 	int ret;
637 
638 	dev = drm_kunit_helper_alloc_device(test);
639 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
640 
641 	xe = xe_kunit_helper_alloc_xe_device(test, dev);
642 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
643 
644 	/* Initialize an empty device */
645 	test->priv = NULL;
646 	ret = xe_pci_fake_device_init(xe);
647 	KUNIT_ASSERT_EQ(test, ret, 0);
648 
649 	xe->drm.dev = dev;
650 	test->priv = xe;
651 
652 	kunit_activate_static_stub(test, xe_gt_mcr_check_reg, fake_xe_gt_mcr_check_reg);
653 
654 	return 0;
655 }
656 
657 static void xe_rtp_test_exit(struct kunit *test)
658 {
659 	struct xe_device *xe = test->priv;
660 
661 	drm_kunit_helper_free_device(test, xe->drm.dev);
662 }
663 
664 static struct kunit_case xe_rtp_tests[] = {
665 	KUNIT_CASE_PARAM(xe_rtp_rules_tests, rtp_rules_gen_params),
666 	KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params),
667 	KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
668 	{}
669 };
670 
671 static struct kunit_suite xe_rtp_test_suite = {
672 	.name = "xe_rtp",
673 	.init = xe_rtp_test_init,
674 	.exit = xe_rtp_test_exit,
675 	.test_cases = xe_rtp_tests,
676 };
677 
678 kunit_test_suite(xe_rtp_test_suite);
679