Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
34struct 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
45struct rtp_test_case {
46 const char *name;
47 unsigned long expected_active;
48 const struct xe_rtp_entry *entries;
49};
50
51static 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
57static 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
63static 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
309static 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 = >->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(®_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 */
355static 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
475static 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
492static 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
497KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
498
499static void rtp_desc(const struct rtp_test_case *t, char *desc)
500{
501 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
502}
503
504KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
505
506static 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
529static 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
536static 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
542static 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
549kunit_test_suite(xe_rtp_test_suite);