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