File Index
Files and directories
Sign in
FILE

xe_rtp_test.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/xe/tests/xe_rtp_test.c C
  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 = &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 */
354static 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
474static 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
491static 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
496KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
497
498static void rtp_desc(const struct rtp_test_case *t, char *desc)
499{
500	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
501}
502
503KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
504
505static 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
528static 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
535static 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
541static 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
548kunit_test_suite(xe_rtp_test_suite);
~/ Read-only file preview.