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