Commit 4cc04402 authored by Lucas De Marchi's avatar Lucas De Marchi Committed by Rodrigo Vivi

drm/xe: Add basic unit tests for rtp

Add some basic unit tests for rtp. This is intended to prove the
functionality of the rtp itself, like coalescing entries, rejecting
non-disjoint values, etc.

Contrary to the other tests in xe, this is a unit test to test the
sw-side only, so it can be executed on any machine - it doesn't interact
with the real hardware. Running it produces the following output:

	$ ./tools/testing/kunit/kunit.py run --raw_output-kunit  \
		--kunitconfig drivers/gpu/drm/xe/.kunitconfig xe_rtp
	...
	[01:26:27] Starting KUnit Kernel (1/1)...
	KTAP version 1
	1..1
	    KTAP version 1
	    # Subtest: xe_rtp
	    1..1
		KTAP version 1
		# Subtest: xe_rtp_process_tests
		ok 1 coalesce-same-reg
		ok 2 no-match-no-add
		ok 3 no-match-no-add-multiple-rules
		ok 4 two-regs-two-entries
		ok 5 clr-one-set-other
		ok 6 set-field
	[drm:xe_reg_sr_add] *ERROR* Discarding save-restore reg 0001 (clear: 00000001, set: 00000001, masked: no): ret=-22
		ok 7 conflict-duplicate
	[drm:xe_reg_sr_add] *ERROR* Discarding save-restore reg 0001 (clear: 00000003, set: 00000000, masked: no): ret=-22
		ok 8 conflict-not-disjoint
	[drm:xe_reg_sr_add] *ERROR* Discarding save-restore reg 0001 (clear: 00000002, set: 00000002, masked: no): ret=-22
	[drm:xe_reg_sr_add] *ERROR* Discarding save-restore reg 0001 (clear: 00000001, set: 00000001, masked: yes): ret=-22
		ok 9 conflict-reg-type
	    # xe_rtp_process_tests: pass:9 fail:0 skip:0 total:9
	    ok 1 xe_rtp_process_tests
	# Totals: pass:9 fail:0 skip:0 total:9
	ok 1 xe_rtp
	...

Note that the ERRORs in the kernel log are expected since it's testing
incompatible entries.

v2:
  - Use parameterized table for tests  (Michał Winiarski)
  - Move everything to the xe_rtp_test.ko and only add a few exports to the
    right namespace
  - Add more tests to cover FIELD_SET, CLR, partially true rules, etc
Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Maarten Lankhorst<maarten.lankhorst@linux.intel.com> # v1
Reviewed-by: default avatarMichał Winiarski <michal.winiarski@intel.com>
Link: https://lore.kernel.org/r/20230401085151.1786204-7-lucas.demarchi@intel.comSigned-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 7bf350ec
...@@ -66,6 +66,7 @@ config DRM_XE_KUNIT_TEST ...@@ -66,6 +66,7 @@ config DRM_XE_KUNIT_TEST
depends on DRM_XE && KUNIT && DEBUG_FS depends on DRM_XE && KUNIT && DEBUG_FS
default KUNIT_ALL_TESTS default KUNIT_ALL_TESTS
select DRM_EXPORT_FOR_TESTS if m select DRM_EXPORT_FOR_TESTS if m
select DRM_KUNIT_TEST_HELPERS
help help
Choose this option to allow the driver to perform selftests under Choose this option to allow the driver to perform selftests under
the kunit framework the kunit framework
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_bo_test.o xe_dma_buf_test.o \ obj-$(CONFIG_DRM_XE_KUNIT_TEST) += \
xe_migrate_test.o xe_bo_test.o \
xe_dma_buf_test.o \
xe_migrate_test.o \
xe_rtp_test.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright © 2023 Intel Corporation
*/
#include <linux/string.h>
#include <linux/xarray.h>
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include <kunit/test.h>
#include "regs/xe_gt_regs.h"
#include "regs/xe_reg_defs.h"
#include "xe_device_types.h"
#include "xe_pci_test.h"
#include "xe_reg_sr.h"
#include "xe_rtp.h"
#undef _MMIO
#undef MCR_REG
#define _MMIO(x) _XE_RTP_REG(x)
#define MCR_REG(x) _XE_RTP_MCR_REG(x)
#define REGULAR_REG1 _MMIO(1)
#define REGULAR_REG2 _MMIO(2)
#define REGULAR_REG3 _MMIO(3)
#define MCR_REG1 MCR_REG(1)
#define MCR_REG2 MCR_REG(2)
#define MCR_REG3 MCR_REG(3)
struct rtp_test_case {
const char *name;
struct {
u32 offset;
u32 type;
} expected_reg;
u32 expected_set_bits;
u32 expected_clr_bits;
unsigned long expected_count;
unsigned int expected_sr_errors;
const struct xe_rtp_entry *entries;
};
static bool match_yes(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
{
return true;
}
static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe)
{
return false;
}
static const struct rtp_test_case cases[] = {
{
.name = "coalesce-same-reg",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0) | REG_BIT(1),
.expected_clr_bits = REG_BIT(0) | REG_BIT(1),
.expected_count = 1,
/* Different bits on the same register: create a single entry */
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
},
{}
},
},
{
.name = "no-match-no-add",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(0),
.expected_count = 1,
/* Don't coalesce second entry since rules don't match */
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_no)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
},
{}
},
},
{
.name = "no-match-no-add-multiple-rules",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(0),
.expected_count = 1,
/* Don't coalesce second entry due to one of the rules */
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes), FUNC(match_no)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1)))
},
{}
},
},
{
.name = "two-regs-two-entries",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(0),
.expected_count = 2,
/* Same bits on different registers are not coalesced */
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0)))
},
{}
},
},
{
.name = "clr-one-set-other",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(1) | REG_BIT(0),
.expected_count = 1,
/* Check clr vs set actions on different bits */
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1)))
},
{}
},
},
{
#define TEMP_MASK REG_GENMASK(10, 8)
#define TEMP_FIELD REG_FIELD_PREP(TEMP_MASK, 2)
.name = "set-field",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = TEMP_FIELD,
.expected_clr_bits = TEMP_MASK,
.expected_count = 1,
/* Check FIELD_SET works */
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1,
TEMP_MASK, TEMP_FIELD))
},
{}
},
#undef TEMP_MASK
#undef TEMP_FIELD
},
{
.name = "conflict-duplicate",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(0),
.expected_count = 1,
.expected_sr_errors = 1,
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
/* drop: setting same values twice */
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
{}
},
},
{
.name = "conflict-not-disjoint",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(0),
.expected_count = 1,
.expected_sr_errors = 1,
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
/* drop: bits are not disjoint with previous entries */
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0)))
},
{}
},
},
{
.name = "conflict-reg-type",
.expected_reg = { REGULAR_REG1 },
.expected_set_bits = REG_BIT(0),
.expected_clr_bits = REG_BIT(0),
.expected_count = 1,
.expected_sr_errors = 2,
.entries = (const struct xe_rtp_entry[]) {
{ XE_RTP_NAME("basic-1"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0)))
},
/* drop: regular vs MCR */
{ XE_RTP_NAME("basic-2"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(MCR_REG1, REG_BIT(1)))
},
/* drop: regular vs masked */
{ XE_RTP_NAME("basic-3"),
XE_RTP_RULES(FUNC(match_yes)),
XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0),
XE_RTP_ACTION_FLAG(MASKED_REG)))
},
{}
},
},
};
static void xe_rtp_process_tests(struct kunit *test)
{
const struct rtp_test_case *param = test->param_value;
struct xe_device *xe = test->priv;
struct xe_reg_sr *reg_sr = &xe->gt[0].reg_sr;
const struct xe_reg_sr_entry *sre, *sr_entry = NULL;
unsigned long idx, count = 0;
xe_reg_sr_init(reg_sr, "xe_rtp_tests", xe);
xe_rtp_process(param->entries, reg_sr, &xe->gt[0], NULL);
xa_for_each(&reg_sr->xa, idx, sre) {
if (idx == param->expected_reg.offset)
sr_entry = sre;
count++;
}
KUNIT_EXPECT_EQ(test, count, param->expected_count);
KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits);
KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits);
KUNIT_EXPECT_EQ(test, sr_entry->reg_type, param->expected_reg.type);
KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors);
}
static void rtp_desc(const struct rtp_test_case *t, char *desc)
{
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
}
KUNIT_ARRAY_PARAM(rtp, cases, rtp_desc);
static int xe_rtp_test_init(struct kunit *test)
{
struct xe_device *xe;
struct device *dev;
int ret;
dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
xe = drm_kunit_helper_alloc_drm_device(test, dev,
struct xe_device,
drm, DRIVER_GEM);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
ret = xe_pci_fake_device_init_any(xe);
KUNIT_ASSERT_EQ(test, ret, 0);
xe->drm.dev = dev;
test->priv = xe;
return 0;
}
static void xe_rtp_test_exit(struct kunit *test)
{
struct xe_device *xe = test->priv;
drm_kunit_helper_free_device(test, xe->drm.dev);
}
static struct kunit_case xe_rtp_tests[] = {
KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params),
{}
};
static struct kunit_suite xe_rtp_test_suite = {
.name = "xe_rtp",
.init = xe_rtp_test_init,
.exit = xe_rtp_test_exit,
.test_cases = xe_rtp_tests,
};
kunit_test_suite(xe_rtp_test_suite);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "xe_reg_sr.h" #include "xe_reg_sr.h"
#include <kunit/visibility.h>
#include <linux/align.h> #include <linux/align.h>
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
#include <linux/xarray.h> #include <linux/xarray.h>
...@@ -43,6 +44,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe) ...@@ -43,6 +44,7 @@ int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe)
return drmm_add_action_or_reset(&xe->drm, reg_sr_fini, sr); return drmm_add_action_or_reset(&xe->drm, reg_sr_fini, sr);
} }
EXPORT_SYMBOL_IF_KUNIT(xe_reg_sr_init);
static struct xe_reg_sr_entry *alloc_entry(struct xe_reg_sr *sr) static struct xe_reg_sr_entry *alloc_entry(struct xe_reg_sr *sr)
{ {
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "xe_rtp.h" #include "xe_rtp.h"
#include <kunit/visibility.h>
#include <drm/xe_drm.h> #include <drm/xe_drm.h>
#include "xe_gt.h" #include "xe_gt.h"
...@@ -155,6 +157,7 @@ void xe_rtp_process(const struct xe_rtp_entry *entries, struct xe_reg_sr *sr, ...@@ -155,6 +157,7 @@ void xe_rtp_process(const struct xe_rtp_entry *entries, struct xe_reg_sr *sr,
} }
} }
} }
EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process);
bool xe_rtp_match_even_instance(const struct xe_gt *gt, bool xe_rtp_match_even_instance(const struct xe_gt *gt,
const struct xe_hw_engine *hwe) const struct xe_hw_engine *hwe)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment