xref: /linux/drivers/gpu/drm/xe/tests/xe_rtp_test.c (revision f5bd7da05a5988506dedcb3e67aecb3a13a4cdf0)
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 
34 struct 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 
45 struct rtp_test_case {
46 	const char *name;
47 	unsigned long expected_active;
48 	const struct xe_rtp_entry *entries;
49 };
50 
51 static 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 
57 static 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 
63 static 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 
309 static 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(reg_sr, "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, &active, count_rtp_entries);
325 	xe_rtp_process_to_sr(&ctx, param->entries, count_rtp_entries,
326 			     reg_sr, false);
327 
328 	xa_for_each(&reg_sr->xa, idx, sre) {
329 		if (idx == param->expected_reg.addr)
330 			sr_entry = sre;
331 
332 		count_sr_entries++;
333 	}
334 
335 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
336 
337 	KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries);
338 	if (count_sr_entries) {
339 		KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits);
340 		KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits);
341 		KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw);
342 	} else {
343 		KUNIT_EXPECT_NULL(test, sr_entry);
344 	}
345 
346 	KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors);
347 }
348 
349 /*
350  * Entries below follow the logic used with xe_wa_oob.rules:
351  * 1) Entries with empty name are OR'ed: all entries marked active since the
352  *    last entry with a name
353  * 2) There are no action associated with rules
354  */
355 static const struct rtp_test_case rtp_cases[] = {
356 	{
357 		.name = "active1",
358 		.expected_active = BIT(0),
359 		.entries = (const struct xe_rtp_entry[]) {
360 			{ XE_RTP_NAME("r1"),
361 			  XE_RTP_RULES(FUNC(match_yes)),
362 			},
363 			{}
364 		},
365 	},
366 	{
367 		.name = "active2",
368 		.expected_active = BIT(0) | BIT(1),
369 		.entries = (const struct xe_rtp_entry[]) {
370 			{ XE_RTP_NAME("r1"),
371 			  XE_RTP_RULES(FUNC(match_yes)),
372 			},
373 			{ XE_RTP_NAME("r2"),
374 			  XE_RTP_RULES(FUNC(match_yes)),
375 			},
376 			{}
377 		},
378 	},
379 	{
380 		.name = "active-inactive",
381 		.expected_active = BIT(0),
382 		.entries = (const struct xe_rtp_entry[]) {
383 			{ XE_RTP_NAME("r1"),
384 			  XE_RTP_RULES(FUNC(match_yes)),
385 			},
386 			{ XE_RTP_NAME("r2"),
387 			  XE_RTP_RULES(FUNC(match_no)),
388 			},
389 			{}
390 		},
391 	},
392 	{
393 		.name = "inactive-active",
394 		.expected_active = BIT(1),
395 		.entries = (const struct xe_rtp_entry[]) {
396 			{ XE_RTP_NAME("r1"),
397 			  XE_RTP_RULES(FUNC(match_no)),
398 			},
399 			{ XE_RTP_NAME("r2"),
400 			  XE_RTP_RULES(FUNC(match_yes)),
401 			},
402 			{}
403 		},
404 	},
405 	{
406 		.name = "inactive-1st_or_active-inactive",
407 		.expected_active = BIT(1),
408 		.entries = (const struct xe_rtp_entry[]) {
409 			{ XE_RTP_NAME("r1"),
410 			  XE_RTP_RULES(FUNC(match_no)),
411 			},
412 			{ XE_RTP_NAME("r2_or_conditions"),
413 			  XE_RTP_RULES(FUNC(match_yes), OR,
414 				       FUNC(match_no), OR,
415 				       FUNC(match_no)) },
416 			{ XE_RTP_NAME("r3"),
417 			  XE_RTP_RULES(FUNC(match_no)),
418 			},
419 			{}
420 		},
421 	},
422 	{
423 		.name = "inactive-2nd_or_active-inactive",
424 		.expected_active = BIT(1),
425 		.entries = (const struct xe_rtp_entry[]) {
426 			{ XE_RTP_NAME("r1"),
427 			  XE_RTP_RULES(FUNC(match_no)),
428 			},
429 			{ XE_RTP_NAME("r2_or_conditions"),
430 			  XE_RTP_RULES(FUNC(match_no), OR,
431 				       FUNC(match_yes), OR,
432 				       FUNC(match_no)) },
433 			{ XE_RTP_NAME("r3"),
434 			  XE_RTP_RULES(FUNC(match_no)),
435 			},
436 			{}
437 		},
438 	},
439 	{
440 		.name = "inactive-last_or_active-inactive",
441 		.expected_active = BIT(1),
442 		.entries = (const struct xe_rtp_entry[]) {
443 			{ XE_RTP_NAME("r1"),
444 			  XE_RTP_RULES(FUNC(match_no)),
445 			},
446 			{ XE_RTP_NAME("r2_or_conditions"),
447 			  XE_RTP_RULES(FUNC(match_no), OR,
448 				       FUNC(match_no), OR,
449 				       FUNC(match_yes)) },
450 			{ XE_RTP_NAME("r3"),
451 			  XE_RTP_RULES(FUNC(match_no)),
452 			},
453 			{}
454 		},
455 	},
456 	{
457 		.name = "inactive-no_or_active-inactive",
458 		.expected_active = 0,
459 		.entries = (const struct xe_rtp_entry[]) {
460 			{ XE_RTP_NAME("r1"),
461 			  XE_RTP_RULES(FUNC(match_no)),
462 			},
463 			{ XE_RTP_NAME("r2_or_conditions"),
464 			  XE_RTP_RULES(FUNC(match_no), OR,
465 				       FUNC(match_no), OR,
466 				       FUNC(match_no)) },
467 			{ XE_RTP_NAME("r3"),
468 			  XE_RTP_RULES(FUNC(match_no)),
469 			},
470 			{}
471 		},
472 	},
473 };
474 
475 static void xe_rtp_process_tests(struct kunit *test)
476 {
477 	const struct rtp_test_case *param = test->param_value;
478 	struct xe_device *xe = test->priv;
479 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
480 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
481 	unsigned long count_rtp_entries = 0, active = 0;
482 
483 	while (param->entries[count_rtp_entries].rules)
484 		count_rtp_entries++;
485 
486 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries);
487 	xe_rtp_process(&ctx, param->entries);
488 
489 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
490 }
491 
492 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc)
493 {
494 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
495 }
496 
497 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
498 
499 static void rtp_desc(const struct rtp_test_case *t, char *desc)
500 {
501 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
502 }
503 
504 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
505 
506 static int xe_rtp_test_init(struct kunit *test)
507 {
508 	struct xe_device *xe;
509 	struct device *dev;
510 	int ret;
511 
512 	dev = drm_kunit_helper_alloc_device(test);
513 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
514 
515 	xe = xe_kunit_helper_alloc_xe_device(test, dev);
516 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
517 
518 	/* Initialize an empty device */
519 	test->priv = NULL;
520 	ret = xe_pci_fake_device_init(xe);
521 	KUNIT_ASSERT_EQ(test, ret, 0);
522 
523 	xe->drm.dev = dev;
524 	test->priv = xe;
525 
526 	return 0;
527 }
528 
529 static void xe_rtp_test_exit(struct kunit *test)
530 {
531 	struct xe_device *xe = test->priv;
532 
533 	drm_kunit_helper_free_device(test, xe->drm.dev);
534 }
535 
536 static struct kunit_case xe_rtp_tests[] = {
537 	KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params),
538 	KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
539 	{}
540 };
541 
542 static struct kunit_suite xe_rtp_test_suite = {
543 	.name = "xe_rtp",
544 	.init = xe_rtp_test_init,
545 	.exit = xe_rtp_test_exit,
546 	.test_cases = xe_rtp_tests,
547 };
548 
549 kunit_test_suite(xe_rtp_test_suite);
550