xref: /linux/drivers/gpu/drm/xe/tests/xe_rtp_test.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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_gt *gt, const struct xe_hw_engine *hwe)
52 {
53 	return true;
54 }
55 
56 static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
57 {
58 	return false;
59 }
60 
61 static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = {
62 	{
63 		.name = "coalesce-same-reg",
64 		.expected_reg = REGULAR_REG1,
65 		.expected_set_bits = REG_BIT(0) | REG_BIT(1),
66 		.expected_clr_bits = REG_BIT(0) | REG_BIT(1),
67 		.expected_active = BIT(0) | BIT(1),
68 		.expected_count_sr_entries = 1,
69 		/* Different bits on the same register: create a single entry */
70 		.entries = (const struct xe_rtp_entry_sr[]) {
71 			{ XE_RTP_NAME("basic-1"),
72 			  XE_RTP_RULES(FUNC(match_yes)),
73 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
74 			},
75 			{ XE_RTP_NAME("basic-2"),
76 			  XE_RTP_RULES(FUNC(match_yes)),
77 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
78 			},
79 			{}
80 		},
81 	},
82 	{
83 		.name = "no-match-no-add",
84 		.expected_reg = REGULAR_REG1,
85 		.expected_set_bits = REG_BIT(0),
86 		.expected_clr_bits = REG_BIT(0),
87 		.expected_active = BIT(0),
88 		.expected_count_sr_entries = 1,
89 		/* Don't coalesce second entry since rules don't match */
90 		.entries = (const struct xe_rtp_entry_sr[]) {
91 			{ XE_RTP_NAME("basic-1"),
92 			  XE_RTP_RULES(FUNC(match_yes)),
93 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
94 			},
95 			{ XE_RTP_NAME("basic-2"),
96 			  XE_RTP_RULES(FUNC(match_no)),
97 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
98 			},
99 			{}
100 		},
101 	},
102 	{
103 		.name = "match-or",
104 		.expected_reg = REGULAR_REG1,
105 		.expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2),
106 		.expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2),
107 		.expected_active = BIT(0) | BIT(1) | BIT(2),
108 		.expected_count_sr_entries = 1,
109 		.entries = (const struct xe_rtp_entry_sr[]) {
110 			{ XE_RTP_NAME("first"),
111 			  XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)),
112 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
113 			},
114 			{ XE_RTP_NAME("middle"),
115 			  XE_RTP_RULES(FUNC(match_no), FUNC(match_no), OR,
116 				       FUNC(match_yes), OR,
117 				       FUNC(match_no)),
118 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
119 			},
120 			{ XE_RTP_NAME("last"),
121 			  XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_yes)),
122 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(2)))
123 			},
124 			{ XE_RTP_NAME("no-match"),
125 			  XE_RTP_RULES(FUNC(match_no), OR, FUNC(match_no)),
126 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(3)))
127 			},
128 			{}
129 		},
130 	},
131 	{
132 		.name = "match-or-xfail",
133 		.expected_reg = REGULAR_REG1,
134 		.expected_count_sr_entries = 0,
135 		.entries = (const struct xe_rtp_entry_sr[]) {
136 			{ XE_RTP_NAME("leading-or"),
137 			  XE_RTP_RULES(OR, FUNC(match_yes)),
138 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
139 			},
140 			{ XE_RTP_NAME("trailing-or"),
141 			  /*
142 			   * First condition is match_no, otherwise the failure
143 			   * wouldn't really trigger as RTP stops processing as
144 			   * soon as it has a matching set of rules
145 			   */
146 			  XE_RTP_RULES(FUNC(match_no), OR),
147 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
148 			},
149 			{ XE_RTP_NAME("no-or-or-yes"),
150 			  XE_RTP_RULES(FUNC(match_no), OR, OR, FUNC(match_yes)),
151 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(2)))
152 			},
153 			{}
154 		},
155 	},
156 	{
157 		.name = "no-match-no-add-multiple-rules",
158 		.expected_reg = REGULAR_REG1,
159 		.expected_set_bits = REG_BIT(0),
160 		.expected_clr_bits = REG_BIT(0),
161 		.expected_active = BIT(0),
162 		.expected_count_sr_entries = 1,
163 		/* Don't coalesce second entry due to one of the rules */
164 		.entries = (const struct xe_rtp_entry_sr[]) {
165 			{ XE_RTP_NAME("basic-1"),
166 			  XE_RTP_RULES(FUNC(match_yes)),
167 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
168 			},
169 			{ XE_RTP_NAME("basic-2"),
170 			  XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)),
171 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
172 			},
173 			{}
174 		},
175 	},
176 	{
177 		.name = "two-regs-two-entries",
178 		.expected_reg = REGULAR_REG1,
179 		.expected_set_bits = REG_BIT(0),
180 		.expected_clr_bits = REG_BIT(0),
181 		.expected_active = BIT(0) | BIT(1),
182 		.expected_count_sr_entries = 2,
183 		/* Same bits on different registers are not coalesced */
184 		.entries = (const struct xe_rtp_entry_sr[]) {
185 			{ XE_RTP_NAME("basic-1"),
186 			  XE_RTP_RULES(FUNC(match_yes)),
187 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
188 			},
189 			{ XE_RTP_NAME("basic-2"),
190 			  XE_RTP_RULES(FUNC(match_yes)),
191 			  XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0)))
192 			},
193 			{}
194 		},
195 	},
196 	{
197 		.name = "clr-one-set-other",
198 		.expected_reg = REGULAR_REG1,
199 		.expected_set_bits = REG_BIT(0),
200 		.expected_clr_bits = REG_BIT(1) | REG_BIT(0),
201 		.expected_active = BIT(0) | BIT(1),
202 		.expected_count_sr_entries = 1,
203 		/* Check clr vs set actions on different bits */
204 		.entries = (const struct xe_rtp_entry_sr[]) {
205 			{ XE_RTP_NAME("basic-1"),
206 			  XE_RTP_RULES(FUNC(match_yes)),
207 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
208 			},
209 			{ XE_RTP_NAME("basic-2"),
210 			  XE_RTP_RULES(FUNC(match_yes)),
211 			  XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1)))
212 			},
213 			{}
214 		},
215 	},
216 	{
217 #define TEMP_MASK	REG_GENMASK(10, 8)
218 #define TEMP_FIELD	REG_FIELD_PREP(TEMP_MASK, 2)
219 		.name = "set-field",
220 		.expected_reg = REGULAR_REG1,
221 		.expected_set_bits = TEMP_FIELD,
222 		.expected_clr_bits = TEMP_MASK,
223 		.expected_active = BIT(0),
224 		.expected_count_sr_entries = 1,
225 		/* Check FIELD_SET works */
226 		.entries = (const struct xe_rtp_entry_sr[]) {
227 			{ XE_RTP_NAME("basic-1"),
228 			  XE_RTP_RULES(FUNC(match_yes)),
229 			  XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1,
230 						   TEMP_MASK, TEMP_FIELD))
231 			},
232 			{}
233 		},
234 #undef TEMP_MASK
235 #undef TEMP_FIELD
236 	},
237 	{
238 		.name = "conflict-duplicate",
239 		.expected_reg = REGULAR_REG1,
240 		.expected_set_bits = REG_BIT(0),
241 		.expected_clr_bits = REG_BIT(0),
242 		.expected_active = BIT(0) | BIT(1),
243 		.expected_count_sr_entries = 1,
244 		.expected_sr_errors = 1,
245 		.entries = (const struct xe_rtp_entry_sr[]) {
246 			{ XE_RTP_NAME("basic-1"),
247 			  XE_RTP_RULES(FUNC(match_yes)),
248 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
249 			},
250 			/* drop: setting same values twice */
251 			{ XE_RTP_NAME("basic-2"),
252 			  XE_RTP_RULES(FUNC(match_yes)),
253 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
254 			},
255 			{}
256 		},
257 	},
258 	{
259 		.name = "conflict-not-disjoint",
260 		.expected_reg = REGULAR_REG1,
261 		.expected_set_bits = REG_BIT(0),
262 		.expected_clr_bits = REG_BIT(0),
263 		.expected_active = BIT(0) | BIT(1),
264 		.expected_count_sr_entries = 1,
265 		.expected_sr_errors = 1,
266 		.entries = (const struct xe_rtp_entry_sr[]) {
267 			{ XE_RTP_NAME("basic-1"),
268 			  XE_RTP_RULES(FUNC(match_yes)),
269 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
270 			},
271 			/* drop: bits are not disjoint with previous entries */
272 			{ XE_RTP_NAME("basic-2"),
273 			  XE_RTP_RULES(FUNC(match_yes)),
274 			  XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0)))
275 			},
276 			{}
277 		},
278 	},
279 	{
280 		.name = "conflict-reg-type",
281 		.expected_reg = REGULAR_REG1,
282 		.expected_set_bits = REG_BIT(0),
283 		.expected_clr_bits = REG_BIT(0),
284 		.expected_active = BIT(0) | BIT(1) | BIT(2),
285 		.expected_count_sr_entries = 1,
286 		.expected_sr_errors = 2,
287 		.entries = (const struct xe_rtp_entry_sr[]) {
288 			{ XE_RTP_NAME("basic-1"),
289 			  XE_RTP_RULES(FUNC(match_yes)),
290 			  XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
291 			},
292 			/* drop: regular vs MCR */
293 			{ XE_RTP_NAME("basic-2"),
294 			  XE_RTP_RULES(FUNC(match_yes)),
295 			  XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1)))
296 			},
297 			/* drop: regular vs masked */
298 			{ XE_RTP_NAME("basic-3"),
299 			  XE_RTP_RULES(FUNC(match_yes)),
300 			  XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0)))
301 			},
302 			{}
303 		},
304 	},
305 };
306 
307 static void xe_rtp_process_to_sr_tests(struct kunit *test)
308 {
309 	const struct rtp_to_sr_test_case *param = test->param_value;
310 	struct xe_device *xe = test->priv;
311 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
312 	struct xe_reg_sr *reg_sr = &gt->reg_sr;
313 	const struct xe_reg_sr_entry *sre, *sr_entry = NULL;
314 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
315 	unsigned long idx, count_sr_entries = 0, count_rtp_entries = 0, active = 0;
316 
317 	xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe);
318 
319 	while (param->entries[count_rtp_entries].rules)
320 		count_rtp_entries++;
321 
322 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries);
323 	xe_rtp_process_to_sr(&ctx, param->entries, reg_sr);
324 
325 	xa_for_each(&reg_sr->xa, idx, sre) {
326 		if (idx == param->expected_reg.addr)
327 			sr_entry = sre;
328 
329 		count_sr_entries++;
330 	}
331 
332 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
333 
334 	KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries);
335 	if (count_sr_entries) {
336 		KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits);
337 		KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits);
338 		KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw);
339 	} else {
340 		KUNIT_EXPECT_NULL(test, sr_entry);
341 	}
342 
343 	KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors);
344 }
345 
346 /*
347  * Entries below follow the logic used with xe_wa_oob.rules:
348  * 1) Entries with empty name are OR'ed: all entries marked active since the
349  *    last entry with a name
350  * 2) There are no action associated with rules
351  */
352 static const struct rtp_test_case rtp_cases[] = {
353 	{
354 		.name = "active1",
355 		.expected_active = BIT(0),
356 		.entries = (const struct xe_rtp_entry[]) {
357 			{ XE_RTP_NAME("r1"),
358 			  XE_RTP_RULES(FUNC(match_yes)),
359 			},
360 			{}
361 		},
362 	},
363 	{
364 		.name = "active2",
365 		.expected_active = BIT(0) | BIT(1),
366 		.entries = (const struct xe_rtp_entry[]) {
367 			{ XE_RTP_NAME("r1"),
368 			  XE_RTP_RULES(FUNC(match_yes)),
369 			},
370 			{ XE_RTP_NAME("r2"),
371 			  XE_RTP_RULES(FUNC(match_yes)),
372 			},
373 			{}
374 		},
375 	},
376 	{
377 		.name = "active-inactive",
378 		.expected_active = BIT(0),
379 		.entries = (const struct xe_rtp_entry[]) {
380 			{ XE_RTP_NAME("r1"),
381 			  XE_RTP_RULES(FUNC(match_yes)),
382 			},
383 			{ XE_RTP_NAME("r2"),
384 			  XE_RTP_RULES(FUNC(match_no)),
385 			},
386 			{}
387 		},
388 	},
389 	{
390 		.name = "inactive-active",
391 		.expected_active = BIT(1),
392 		.entries = (const struct xe_rtp_entry[]) {
393 			{ XE_RTP_NAME("r1"),
394 			  XE_RTP_RULES(FUNC(match_no)),
395 			},
396 			{ XE_RTP_NAME("r2"),
397 			  XE_RTP_RULES(FUNC(match_yes)),
398 			},
399 			{}
400 		},
401 	},
402 	{
403 		.name = "inactive-1st_or_active-inactive",
404 		.expected_active = BIT(1),
405 		.entries = (const struct xe_rtp_entry[]) {
406 			{ XE_RTP_NAME("r1"),
407 			  XE_RTP_RULES(FUNC(match_no)),
408 			},
409 			{ XE_RTP_NAME("r2_or_conditions"),
410 			  XE_RTP_RULES(FUNC(match_yes), OR,
411 				       FUNC(match_no), OR,
412 				       FUNC(match_no)) },
413 			{ XE_RTP_NAME("r3"),
414 			  XE_RTP_RULES(FUNC(match_no)),
415 			},
416 			{}
417 		},
418 	},
419 	{
420 		.name = "inactive-2nd_or_active-inactive",
421 		.expected_active = BIT(1),
422 		.entries = (const struct xe_rtp_entry[]) {
423 			{ XE_RTP_NAME("r1"),
424 			  XE_RTP_RULES(FUNC(match_no)),
425 			},
426 			{ XE_RTP_NAME("r2_or_conditions"),
427 			  XE_RTP_RULES(FUNC(match_no), OR,
428 				       FUNC(match_yes), OR,
429 				       FUNC(match_no)) },
430 			{ XE_RTP_NAME("r3"),
431 			  XE_RTP_RULES(FUNC(match_no)),
432 			},
433 			{}
434 		},
435 	},
436 	{
437 		.name = "inactive-last_or_active-inactive",
438 		.expected_active = BIT(1),
439 		.entries = (const struct xe_rtp_entry[]) {
440 			{ XE_RTP_NAME("r1"),
441 			  XE_RTP_RULES(FUNC(match_no)),
442 			},
443 			{ XE_RTP_NAME("r2_or_conditions"),
444 			  XE_RTP_RULES(FUNC(match_no), OR,
445 				       FUNC(match_no), OR,
446 				       FUNC(match_yes)) },
447 			{ XE_RTP_NAME("r3"),
448 			  XE_RTP_RULES(FUNC(match_no)),
449 			},
450 			{}
451 		},
452 	},
453 	{
454 		.name = "inactive-no_or_active-inactive",
455 		.expected_active = 0,
456 		.entries = (const struct xe_rtp_entry[]) {
457 			{ XE_RTP_NAME("r1"),
458 			  XE_RTP_RULES(FUNC(match_no)),
459 			},
460 			{ XE_RTP_NAME("r2_or_conditions"),
461 			  XE_RTP_RULES(FUNC(match_no), OR,
462 				       FUNC(match_no), OR,
463 				       FUNC(match_no)) },
464 			{ XE_RTP_NAME("r3"),
465 			  XE_RTP_RULES(FUNC(match_no)),
466 			},
467 			{}
468 		},
469 	},
470 };
471 
472 static void xe_rtp_process_tests(struct kunit *test)
473 {
474 	const struct rtp_test_case *param = test->param_value;
475 	struct xe_device *xe = test->priv;
476 	struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt;
477 	struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt);
478 	unsigned long count_rtp_entries = 0, active = 0;
479 
480 	while (param->entries[count_rtp_entries].rules)
481 		count_rtp_entries++;
482 
483 	xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries);
484 	xe_rtp_process(&ctx, param->entries);
485 
486 	KUNIT_EXPECT_EQ(test, active, param->expected_active);
487 }
488 
489 static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc)
490 {
491 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
492 }
493 
494 KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
495 
496 static void rtp_desc(const struct rtp_test_case *t, char *desc)
497 {
498 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
499 }
500 
501 KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
502 
503 static int xe_rtp_test_init(struct kunit *test)
504 {
505 	struct xe_device *xe;
506 	struct device *dev;
507 	int ret;
508 
509 	dev = drm_kunit_helper_alloc_device(test);
510 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
511 
512 	xe = xe_kunit_helper_alloc_xe_device(test, dev);
513 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
514 
515 	/* Initialize an empty device */
516 	test->priv = NULL;
517 	ret = xe_pci_fake_device_init(xe);
518 	KUNIT_ASSERT_EQ(test, ret, 0);
519 
520 	xe->drm.dev = dev;
521 	test->priv = xe;
522 
523 	return 0;
524 }
525 
526 static void xe_rtp_test_exit(struct kunit *test)
527 {
528 	struct xe_device *xe = test->priv;
529 
530 	drm_kunit_helper_free_device(test, xe->drm.dev);
531 }
532 
533 static struct kunit_case xe_rtp_tests[] = {
534 	KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params),
535 	KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
536 	{}
537 };
538 
539 static struct kunit_suite xe_rtp_test_suite = {
540 	.name = "xe_rtp",
541 	.init = xe_rtp_test_init,
542 	.exit = xe_rtp_test_exit,
543 	.test_cases = xe_rtp_tests,
544 };
545 
546 kunit_test_suite(xe_rtp_test_suite);
547