xref: /linux/drivers/gpu/drm/xe/tests/xe_rtp_test.c (revision 4b99990cdf9560e8a071640baf19f312e6ae02f4)
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_entry_sr *entries;
58 };
59 
60 struct rtp_test_case {
61 	const char *name;
62 	unsigned long expected_active;
63 	const struct xe_rtp_entry *entries;
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 		.entries = (const struct xe_rtp_entry_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 	{
305 		.name = "no-match-no-add",
306 		.expected_reg = REGULAR_REG1,
307 		.expected_set_bits = REG_BIT(0),
308 		.expected_clr_bits = REG_BIT(0),
309 		.expected_active = BIT(0),
310 		.expected_count_sr_entries = 1,
311 		/* Don't coalesce second entry since rules don't match */
312 		.entries = (const struct xe_rtp_entry_sr[]) {
313 			{ XE_RTP_NAME("basic-1"),
314 			  XE_RTP_RULES(FUNC(match_yes)),
315 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
316 			},
317 			{ XE_RTP_NAME("basic-2"),
318 			  XE_RTP_RULES(FUNC(match_no)),
319 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
320 			},
321 			{}
322 		},
323 	},
324 	{
325 		.name = "two-regs-two-entries",
326 		.expected_reg = REGULAR_REG1,
327 		.expected_set_bits = REG_BIT(0),
328 		.expected_clr_bits = REG_BIT(0),
329 		.expected_active = BIT(0) | BIT(1),
330 		.expected_count_sr_entries = 2,
331 		/* Same bits on different registers are not coalesced */
332 		.entries = (const struct xe_rtp_entry_sr[]) {
333 			{ XE_RTP_NAME("basic-1"),
334 			  XE_RTP_RULES(FUNC(match_yes)),
335 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
336 			},
337 			{ XE_RTP_NAME("basic-2"),
338 			  XE_RTP_RULES(FUNC(match_yes)),
339 			  XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0)))
340 			},
341 			{}
342 		},
343 	},
344 	{
345 		.name = "clr-one-set-other",
346 		.expected_reg = REGULAR_REG1,
347 		.expected_set_bits = REG_BIT(0),
348 		.expected_clr_bits = REG_BIT(1) | REG_BIT(0),
349 		.expected_active = BIT(0) | BIT(1),
350 		.expected_count_sr_entries = 1,
351 		/* Check clr vs set actions on different bits */
352 		.entries = (const struct xe_rtp_entry_sr[]) {
353 			{ XE_RTP_NAME("basic-1"),
354 			  XE_RTP_RULES(FUNC(match_yes)),
355 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
356 			},
357 			{ XE_RTP_NAME("basic-2"),
358 			  XE_RTP_RULES(FUNC(match_yes)),
359 			  XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1)))
360 			},
361 			{}
362 		},
363 	},
364 	{
365 #define TEMP_MASK	REG_GENMASK(10, 8)
366 #define TEMP_FIELD	REG_FIELD_PREP(TEMP_MASK, 2)
367 		.name = "set-field",
368 		.expected_reg = REGULAR_REG1,
369 		.expected_set_bits = TEMP_FIELD,
370 		.expected_clr_bits = TEMP_MASK,
371 		.expected_active = BIT(0),
372 		.expected_count_sr_entries = 1,
373 		/* Check FIELD_SET works */
374 		.entries = (const struct xe_rtp_entry_sr[]) {
375 			{ XE_RTP_NAME("basic-1"),
376 			  XE_RTP_RULES(FUNC(match_yes)),
377 			  XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1,
378 						   TEMP_MASK, TEMP_FIELD))
379 			},
380 			{}
381 		},
382 #undef TEMP_MASK
383 #undef TEMP_FIELD
384 	},
385 	{
386 		.name = "conflict-duplicate",
387 		.expected_reg = REGULAR_REG1,
388 		.expected_set_bits = REG_BIT(0),
389 		.expected_clr_bits = REG_BIT(0),
390 		.expected_active = BIT(0) | BIT(1),
391 		.expected_count_sr_entries = 1,
392 		.expected_sr_errors = 1,
393 		.entries = (const struct xe_rtp_entry_sr[]) {
394 			{ XE_RTP_NAME("basic-1"),
395 			  XE_RTP_RULES(FUNC(match_yes)),
396 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
397 			},
398 			/* drop: setting same values twice */
399 			{ XE_RTP_NAME("basic-2"),
400 			  XE_RTP_RULES(FUNC(match_yes)),
401 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
402 			},
403 			{}
404 		},
405 	},
406 	{
407 		.name = "conflict-not-disjoint",
408 		.expected_reg = REGULAR_REG1,
409 		.expected_set_bits = REG_BIT(0),
410 		.expected_clr_bits = REG_BIT(0),
411 		.expected_active = BIT(0) | BIT(1),
412 		.expected_count_sr_entries = 1,
413 		.expected_sr_errors = 1,
414 		.entries = (const struct xe_rtp_entry_sr[]) {
415 			{ XE_RTP_NAME("basic-1"),
416 			  XE_RTP_RULES(FUNC(match_yes)),
417 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
418 			},
419 			/* drop: bits are not disjoint with previous entries */
420 			{ XE_RTP_NAME("basic-2"),
421 			  XE_RTP_RULES(FUNC(match_yes)),
422 			  XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0)))
423 			},
424 			{}
425 		},
426 	},
427 	{
428 		.name = "conflict-reg-type",
429 		.expected_reg = REGULAR_REG1,
430 		.expected_set_bits = REG_BIT(0),
431 		.expected_clr_bits = REG_BIT(0),
432 		.expected_active = BIT(0) | BIT(1) | BIT(2),
433 		.expected_count_sr_entries = 1,
434 		.expected_sr_errors = 2,
435 		.entries = (const struct xe_rtp_entry_sr[]) {
436 			{ XE_RTP_NAME("basic-1"),
437 			  XE_RTP_RULES(FUNC(match_yes)),
438 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
439 			},
440 			/* drop: regular vs MCR */
441 			{ XE_RTP_NAME("basic-2"),
442 			  XE_RTP_RULES(FUNC(match_yes)),
443 			  XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1)))
444 			},
445 			/* drop: regular vs masked */
446 			{ XE_RTP_NAME("basic-3"),
447 			  XE_RTP_RULES(FUNC(match_yes)),
448 			  XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0)))
449 			},
450 			{}
451 		},
452 	},
453 	{
454 		.name = "bad-mcr-reg-forced-to-regular",
455 		.expected_reg = REGULAR_REG4,
456 		.expected_set_bits = REG_BIT(0),
457 		.expected_clr_bits = REG_BIT(0),
458 		.expected_active = BIT(0),
459 		.expected_count_sr_entries = 1,
460 		.expected_sr_errors = 1,
461 		.entries = (const struct xe_rtp_entry_sr[]) {
462 			{ XE_RTP_NAME("bad-mcr-regular-reg"),
463 			  XE_RTP_RULES(FUNC(match_yes)),
464 			  XE_RTP_ACTIONS(SET(BAD_MCR_REG4, REG_BIT(0)))
465 			},
466 			{}
467 		},
468 	},
469 	{
470 		.name = "bad-regular-reg-forced-to-mcr",
471 		.expected_reg = MCR_REG5,
472 		.expected_set_bits = REG_BIT(0),
473 		.expected_clr_bits = REG_BIT(0),
474 		.expected_active = BIT(0),
475 		.expected_count_sr_entries = 1,
476 		.expected_sr_errors = 1,
477 		.entries = (const struct xe_rtp_entry_sr[]) {
478 			{ XE_RTP_NAME("bad-regular-reg"),
479 			  XE_RTP_RULES(FUNC(match_yes)),
480 			  XE_RTP_ACTIONS(SET(BAD_REGULAR_REG5, REG_BIT(0)))
481 			},
482 			{}
483 		},
484 	},
485 };
486 
487 static void xe_rtp_process_to_sr_tests(struct kunit *test)
488 {
489 	const struct rtp_to_sr_test_case *param = test->param_value;
490 	struct xe_device *xe = test->priv;
491 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
492 	struct xe_reg_sr *reg_sr = &gt->reg_sr;
493 	const struct xe_reg_sr_entry *sre, *sr_entry = NULL;
494 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
495 	unsigned long idx, count_sr_entries = 0, count_rtp_entries = 0, active = 0;
496 
497 	xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe);
498 
499 	while (param->entries[count_rtp_entries].rules)
500 		count_rtp_entries++;
501 
502 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries);
503 	xe_rtp_process_to_sr(&ctx, param->entries, count_rtp_entries,
504 			     reg_sr, false);
505 
506 	xa_for_each(&reg_sr->xa, idx, sre) {
507 		if (idx == param->expected_reg.addr)
508 			sr_entry = sre;
509 
510 		count_sr_entries++;
511 	}
512 
513 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
514 
515 	KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries);
516 	if (count_sr_entries) {
517 		KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits);
518 		KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits);
519 		KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw);
520 	} else {
521 		KUNIT_EXPECT_NULL(test, sr_entry);
522 	}
523 
524 	KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors);
525 }
526 
527 /*
528  * Entries below follow the logic used with xe_wa_oob.rules:
529  * 1) Entries with empty name are OR'ed: all entries marked active since the
530  *    last entry with a name
531  * 2) There are no action associated with rules
532  */
533 static const struct rtp_test_case rtp_cases[] = {
534 	{
535 		.name = "active1",
536 		.expected_active = BIT(0),
537 		.entries = (const struct xe_rtp_entry[]) {
538 			{ XE_RTP_NAME("r1"),
539 			  XE_RTP_RULES(FUNC(match_yes)),
540 			},
541 			{}
542 		},
543 	},
544 	{
545 		.name = "active2",
546 		.expected_active = BIT(0) | BIT(1),
547 		.entries = (const struct xe_rtp_entry[]) {
548 			{ XE_RTP_NAME("r1"),
549 			  XE_RTP_RULES(FUNC(match_yes)),
550 			},
551 			{ XE_RTP_NAME("r2"),
552 			  XE_RTP_RULES(FUNC(match_yes)),
553 			},
554 			{}
555 		},
556 	},
557 	{
558 		.name = "active-inactive",
559 		.expected_active = BIT(0),
560 		.entries = (const struct xe_rtp_entry[]) {
561 			{ XE_RTP_NAME("r1"),
562 			  XE_RTP_RULES(FUNC(match_yes)),
563 			},
564 			{ XE_RTP_NAME("r2"),
565 			  XE_RTP_RULES(FUNC(match_no)),
566 			},
567 			{}
568 		},
569 	},
570 	{
571 		.name = "inactive-active",
572 		.expected_active = BIT(1),
573 		.entries = (const struct xe_rtp_entry[]) {
574 			{ XE_RTP_NAME("r1"),
575 			  XE_RTP_RULES(FUNC(match_no)),
576 			},
577 			{ XE_RTP_NAME("r2"),
578 			  XE_RTP_RULES(FUNC(match_yes)),
579 			},
580 			{}
581 		},
582 	},
583 	{
584 		.name = "inactive-active-inactive",
585 		.expected_active = BIT(1),
586 		.entries = (const struct xe_rtp_entry[]) {
587 			{ XE_RTP_NAME("r1"),
588 			  XE_RTP_RULES(FUNC(match_no)),
589 			},
590 			{ XE_RTP_NAME("r2"),
591 			  XE_RTP_RULES(FUNC(match_yes)),
592 			},
593 			{ XE_RTP_NAME("r3"),
594 			  XE_RTP_RULES(FUNC(match_no)),
595 			},
596 			{}
597 		},
598 	},
599 	{
600 		.name = "inactive-inactive-inactive",
601 		.expected_active = 0,
602 		.entries = (const struct xe_rtp_entry[]) {
603 			{ XE_RTP_NAME("r1"),
604 			  XE_RTP_RULES(FUNC(match_no)),
605 			},
606 			{ XE_RTP_NAME("r2"),
607 			  XE_RTP_RULES(FUNC(match_no)),
608 			},
609 			{ XE_RTP_NAME("r3"),
610 			  XE_RTP_RULES(FUNC(match_no)),
611 			},
612 			{}
613 		},
614 	},
615 };
616 
617 static void xe_rtp_process_tests(struct kunit *test)
618 {
619 	const struct rtp_test_case *param = test->param_value;
620 	struct xe_device *xe = test->priv;
621 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
622 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
623 	unsigned long count_rtp_entries = 0, active = 0;
624 
625 	while (param->entries[count_rtp_entries].rules)
626 		count_rtp_entries++;
627 
628 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries);
629 	xe_rtp_process(&ctx, param->entries);
630 
631 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
632 }
633 
634 static void rtp_rules_desc(const struct rtp_rules_test_case *t, char *desc)
635 {
636 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
637 }
638 
639 KUNIT_ARRAY_PARAM(rtp_rules, rtp_rules_cases, rtp_rules_desc);
640 
641 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc)
642 {
643 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
644 }
645 
646 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
647 
648 static void rtp_desc(const struct rtp_test_case *t, char *desc)
649 {
650 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
651 }
652 
653 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
654 
655 static int xe_rtp_test_init(struct kunit *test)
656 {
657 	struct xe_device *xe;
658 	struct device *dev;
659 	int ret;
660 
661 	dev = drm_kunit_helper_alloc_device(test);
662 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
663 
664 	xe = xe_kunit_helper_alloc_xe_device(test, dev);
665 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
666 
667 	/* Initialize an empty device */
668 	test->priv = NULL;
669 	ret = xe_pci_fake_device_init(xe);
670 	KUNIT_ASSERT_EQ(test, ret, 0);
671 
672 	xe->drm.dev = dev;
673 	test->priv = xe;
674 
675 	kunit_activate_static_stub(test, xe_gt_mcr_check_reg, fake_xe_gt_mcr_check_reg);
676 
677 	return 0;
678 }
679 
680 static void xe_rtp_test_exit(struct kunit *test)
681 {
682 	struct xe_device *xe = test->priv;
683 
684 	drm_kunit_helper_free_device(test, xe->drm.dev);
685 }
686 
687 static struct kunit_case xe_rtp_tests[] = {
688 	KUNIT_CASE_PARAM(xe_rtp_rules_tests, rtp_rules_gen_params),
689 	KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params),
690 	KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
691 	{}
692 };
693 
694 static struct kunit_suite xe_rtp_test_suite = {
695 	.name = "xe_rtp",
696 	.init = xe_rtp_test_init,
697 	.exit = xe_rtp_test_exit,
698 	.test_cases = xe_rtp_tests,
699 };
700 
701 kunit_test_suite(xe_rtp_test_suite);
702