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
match_yes(const struct xe_gt * gt,const struct xe_hw_engine * hwe)51 static bool match_yes(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
52 {
53 return true;
54 }
55
match_no(const struct xe_gt * gt,const struct xe_hw_engine * hwe)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
xe_rtp_process_to_sr_tests(struct kunit * test)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 = >->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(®_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
xe_rtp_process_tests(struct kunit * test)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
rtp_to_sr_desc(const struct rtp_to_sr_test_case * t,char * desc)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
rtp_desc(const struct rtp_test_case * t,char * desc)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
xe_rtp_test_init(struct kunit * test)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
xe_rtp_test_exit(struct kunit * test)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