Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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_gt *gt, const struct xe_hw_engine *hwe)
 52{
 53	return true;
 54}
 55
 56static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
 57{
 58	return false;
 59}
 60
 61static 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
307static 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 */
352static 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
472static 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
489static 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
494KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc);
495
496static void rtp_desc(const struct rtp_test_case *t, char *desc)
497{
498	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
499}
500
501KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc);
502
503static 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
526static 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
533static 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
539static 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
546kunit_test_suite(xe_rtp_test_suite);