Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Wajdeczko <michal.wajdeczko@intel.com>
To: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>,
	<intel-xe@lists.freedesktop.org>
Subject: Re: [PATCH v10 10/10] drm/xe/tests: Add KUnit tests for VF provisioning error handling
Date: Mon, 21 Sep 2026 18:47:28 +0200	[thread overview]
Message-ID: <574bef27-77be-4a77-8bf2-4389cac8615b@intel.com> (raw)
In-Reply-To: <20260921092101.1243989-22-satyanarayana.k.v.p@intel.com>



On 9/21/2026 11:21 AM, Satyanarayana K V P wrote:
> VF relies on the PF to provide a valid hardware configuration via GuC
> KLV responses. In the unlikely event of PF malfunction or
> misconfiguration, a VF may receive incomplete, zero, or out-of-range
> values for its submission contexts, doorbells, VRAM or GGTT assignment.
> 
> Add KUnit test cases that use the xe_guc_mmio_send_recv() stub to inject
> bad KLV responses and verify that VF can survive without crashing for
> the invalid configuration data received.
> 
> Signed-off-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
> ---
> V9 -> V10:
> - Fixed review comments (Sashiko).
> - Use (hxg_sizeof(u64)) + 1 to keep checkpatch.pl happy.
> 
> V8 -> V9:
> - Fixed review comments (Michal W).
> - Updated test_guc_mmio (Michal W).
> 
> V7 -> V8:
> - Updated kunit test as per changed from other patches.
> 
> V6 -> V7:
> - Fixed review comments (Sashiko, Michal W).
> 
> V5 -> V6:
> - Fixed review comments (Michal W).
> 
> V4 -> V5:
> - Added alignment tests for vram, GGTT base and size (Michal W).
> - Separated stubs for ctx, db, vram and GGTT (Michal W).
> - Added new test cases for xe_guc_mmio_send_recv() (Michal W).
> 
> V3 -> V4:
> - Changed stub function from guc_action_query_single_klv32() and
> guc_action_query_single_klv64() to xe_guc_mmio_send_recv() (Michal W).
> - Fixed review comments (Michal W).
> 
> V2 -> V3:
> - Renamed the test names. (Michal W).
> - Fixed review comments (Michal W).
> 
> V1 -> V2:
> - Renamed the test file (Michal W).
> - Fixed review comments (Michal W).
> ---
>  .../gpu/drm/xe/tests/xe_gt_sriov_vf_kunit.c   | 676 ++++++++++++++++++
>  drivers/gpu/drm/xe/xe_gt_sriov_vf.c           |   4 +
>  2 files changed, 680 insertions(+)
>  create mode 100644 drivers/gpu/drm/xe/tests/xe_gt_sriov_vf_kunit.c
> 
> diff --git a/drivers/gpu/drm/xe/tests/xe_gt_sriov_vf_kunit.c b/drivers/gpu/drm/xe/tests/xe_gt_sriov_vf_kunit.c
> new file mode 100644
> index 000000000000..4830369dd47e
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/tests/xe_gt_sriov_vf_kunit.c
> @@ -0,0 +1,676 @@
> +// SPDX-License-Identifier: GPL-2.0 AND MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#include <kunit/static_stub.h>
> +#include <kunit/test.h>
> +
> +#include "regs/xe_guc_regs.h"
> +#include "xe_device.h"
> +#include "xe_ggtt.h"
> +#include "xe_guc.h"
> +#include "xe_kunit_helpers.h"
> +#include "xe_pci_test.h"
> +
> +#define TEST_VRAM			SZ_8G
> +#define TEST_GGTT_SIZE			SZ_2G
> +#define TEST_GGTT_SIZE_OUT_OF_BOUNDS	0xfffffffffffff000ull
> +#define TEST_CTXS			1024
> +#define TEST_DBS			128
> +#define TEST_GGTT_START			0xa0a000ull
> +
> +static inline void assert_valid_query_klv_msg(struct kunit *test, u32 len,

drop "inline"

> +					      const u32 *request, u32 key)
> +{
> +	KUNIT_ASSERT_EQ(test, len, VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_LEN);
> +	KUNIT_ASSERT_EQ(test,
> +			FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, request[0]),
> +			GUC_ACTION_VF2GUC_QUERY_SINGLE_KLV);
> +	KUNIT_ASSERT_EQ(test,
> +			FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_1_KEY, request[1]),
> +			key);
> +}
> +
> +static inline void fill_resp_buff(u32 *response, u64 query, size_t type)

drop "inline"

split into:

	static void prep_query_response_32(u32 *msg, u32 value) { }
	static void prep_query_response_64(u32 *msg, u64 value) { }

> +{
> +	if (type == sizeof(u32)) {
> +		response[0] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_LENGTH,
> +					 sizeof(u32) / sizeof(u32));
> +		response[1] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32,
> +					 query);
> +	} else if (type == sizeof(u64)) {
> +		response[0] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_LENGTH,
> +					 sizeof(u64) / sizeof(u32));
> +		response[1] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32,
> +					 lower_32_bits(query));
> +		response[2] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_2_VALUE64,
> +					 upper_32_bits(query));
> +	}
> +}
> +
> +struct config {

nit: little too generic name, maybe "struct params_sched" 

> +	u32 orig;
> +	u32 query;
> +	int expected_ret;
> +	int ret;

nit: forced_ret;

> +	const char *name;
> +};
> +
> +static const struct config vf_ctx_testcase[] = {

nit: redundant "vf" prefix
nit: those are "params" not a "testcases" that could be confused with kunit

> +	{
> +		.orig = TEST_CTXS,
> +		.query = TEST_CTXS,
> +		.expected_ret = 0,

nit: we can drop fields with 0

> +		.name = "same",

nit: maybe better to make it first field instead of last?

> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -ENODATA,
> +		.name = "none",
> +	},
> +	{
> +		.orig = 0,
> +		.query = GUC_ID_MAX + 1,
> +		.expected_ret = -ERANGE,
> +		.name = "overflow",
> +	},
> +	{
> +		.orig = TEST_CTXS,
> +		.query = 0,
> +		.expected_ret = -EREMCHG,
> +		.name =	"lost",
> +	},
> +	{
> +		.orig = TEST_CTXS,
> +		.query = TEST_CTXS / 2,
> +		.expected_ret = -EREMCHG,
> +		.name = "reduced",
> +	},
> +	{
> +		.orig = TEST_CTXS,
> +		.query = TEST_CTXS * 2,
> +		.expected_ret = -EREMCHG,
> +		.name = "increased",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -EPROTO,
> +		.ret = -EPROTO,
> +		.name = "proto_error",

nit: just "eproto" ?

> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -EIO,
> +		.ret = -EIO,
> +		.name =	"IO_error",

nit: just "eio" ?

btw, is there any coverage difference compared to "proto_error" ?

> +	},
> +};
> +
> +KUNIT_ARRAY_PARAM_DESC(ctx_testcase, vf_ctx_testcase, name);
> +
> +static const struct config vf_db_testcase[] = {
> +	{
> +		.orig = TEST_DBS,
> +		.query = TEST_DBS,
> +		.expected_ret = 0,
> +		.name = "same",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = 0,
> +		.name = "none",
> +	},
> +	{
> +		.orig = TEST_DBS,
> +		.query = GUC_NUM_DOORBELLS + 1,
> +		.expected_ret = -ERANGE,
> +		.name = "overflow",
> +	},
> +	{
> +		.orig = TEST_DBS,
> +		.query = 0,
> +		.expected_ret = -EREMCHG,
> +		.name = "lost",
> +	},
> +	{
> +		.orig = TEST_DBS,
> +		.query = TEST_DBS / 2,
> +		.expected_ret = -EREMCHG,
> +		.name = "reduced",
> +	},
> +	{
> +		.orig = TEST_DBS,
> +		.query = GUC_NUM_DOORBELLS - 1,

nit: maybe
		.query = TEST_DBS + 1,

to follow the pattern?

> +		.expected_ret = -EREMCHG,
> +		.name = "increased",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -EPROTO,
> +		.ret = -EPROTO,
> +		.name = "proto_error",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -EIO,
> +		.ret = -EIO,
> +		.name =	"IO_error",
> +	},
> +};
> +
> +KUNIT_ARRAY_PARAM_DESC(db_testcase, vf_db_testcase, name);
> +
> +static int xe_guc_mmio_send_recv_stub_ctx(struct xe_guc *guc, const u32 *request,
> +					  u32 len, u32 *response_buf)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	const struct config *c = test->param_value;
> +
> +	if (c->ret)
> +		return c->ret;
> +
> +	assert_valid_query_klv_msg(test, len, request,
> +				   GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY);
> +	fill_resp_buff(response_buf, c->query, sizeof(u32));
> +
> +	return 0;
> +}
> +
> +static void test_ctxs(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	const struct config *c = test->param_value;
> +
> +	gt->sriov.vf.self_config.num_ctxs = c->orig;
> +	kunit_activate_static_stub(test, xe_guc_mmio_send_recv,
> +				   xe_guc_mmio_send_recv_stub_ctx);
> +	KUNIT_EXPECT_EQ(test, vf_get_ctxs_cfg(gt), c->expected_ret);
> +}
> +
> +static int xe_guc_mmio_send_recv_stub_db(struct xe_guc *guc, const u32 *request,
> +					 u32 len, u32 *response_buf)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	const struct config *c = test->param_value;
> +
> +	if (c->ret)
> +		return c->ret;
> +
> +	assert_valid_query_klv_msg(test, len, request,
> +				   GUC_KLV_VF_CFG_NUM_DOORBELLS_KEY);
> +	fill_resp_buff(response_buf, c->query, sizeof(u32));
> +
> +	return 0;
> +}
> +
> +static void test_dbs(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	const struct config *c = test->param_value;
> +
> +	gt->sriov.vf.self_config.num_dbs = c->orig;
> +	kunit_activate_static_stub(test, xe_guc_mmio_send_recv,
> +				   xe_guc_mmio_send_recv_stub_db);
> +	KUNIT_EXPECT_EQ(test, vf_get_dbs_cfg(gt), c->expected_ret);
> +}
> +
> +struct config_vram {
> +	u64 orig;
> +	u64 query;
> +	int expected_ret;
> +	int ret;
> +	const char *name;
> +};
> +
> +static const struct config_vram vf_vram_testcase[] = {
> +	{
> +		.orig = TEST_VRAM,
> +		.query = TEST_VRAM,
> +		.expected_ret = 0,
> +		.name = "same",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -ENODATA,
> +		.name = "none",
> +	},
> +	{
> +		.orig = TEST_VRAM / 2,
> +		.query = TEST_VRAM + SZ_1G,
> +		.expected_ret = -EREMCHG,
> +		.name = "increased",
> +	},
> +	{
> +		.orig = TEST_VRAM / 2,
> +		.query = 0,
> +		.expected_ret = -EREMCHG,
> +		.name = "lost",
> +	},
> +	{
> +		.orig = TEST_VRAM / 2,
> +		.query = TEST_VRAM / 4,
> +		.expected_ret = -EREMCHG,
> +		.name = "reduced",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -EPROTO,
> +		.ret = -EPROTO,
> +		.name = "proto_error",
> +	},
> +	{
> +		.orig = 0,
> +		.query = 0,
> +		.expected_ret = -EIO,
> +		.ret = -EIO,
> +		.name =	"IO_error",
> +	},

what about params for the "unaligned" case?

> +};
> +
> +KUNIT_ARRAY_PARAM_DESC(vram_testcase, vf_vram_testcase, name);
> +
> +static int xe_guc_mmio_send_recv_stub_vram(struct xe_guc *guc, const u32 *request,
> +					   u32 len, u32 *response_buf)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	const struct config_vram *c = test->param_value;
> +
> +	if (c->ret)
> +		return c->ret;
> +
> +	assert_valid_query_klv_msg(test, len, request,
> +				   GUC_KLV_VF_CFG_LMEM_SIZE_KEY);
> +	fill_resp_buff(response_buf, c->query, sizeof(u64));
> +
> +	return 0;
> +}
> +
> +static void test_vram(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	const struct config_vram *c = test->param_value;
> +
> +	gt->tile->sriov.vf.self_config.lmem_size = c->orig;
> +	kunit_activate_static_stub(test, xe_guc_mmio_send_recv,
> +				   xe_guc_mmio_send_recv_stub_vram);
> +	KUNIT_EXPECT_EQ(test, vf_get_lmem_info(gt), c->expected_ret);
> +}
> +
> +struct config_ggtt {
> +	struct {
> +		u64 start;
> +		u64 size;
> +	} orig, query;
> +	int expected_ret;
> +	int ret;
> +	const char *name;
> +};
> +
> +static const struct config_ggtt vf_ggtt_testcase[] = {
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.name = "same",
> +		.expected_ret = 0,
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.expected_ret = 0,
> +		.name = "query_on_init",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = 0, .size = 0 },
> +		.expected_ret = -ENODATA,
> +		.name = "none",
> +	},
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE + SZ_4G },
> +		.expected_ret = -ERANGE,
> +		.name = "overflow",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE + SZ_4G },
> +		.expected_ret = -ERANGE,
> +		.name =	"overflow_query_on_init",
> +	},
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.query = { .start = TEST_GGTT_START, .size = 0 },
> +		.expected_ret = -ENODATA,
> +		.name = "lost",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = TEST_GGTT_START, .size = 0 },
> +		.expected_ret = -ENODATA,
> +		.name = "lost_on_init",
> +	},
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE - SZ_1M },
> +		.expected_ret = -EREMCHG,
> +		.name = "reduced",
> +	},
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE + SZ_1M },
> +		.expected_ret = -EREMCHG,
> +		.name = "increased",
> +	},
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE - SZ_4K },

why -4K ? just use valid size

> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE - SZ_2K },
> +		.expected_ret = 0,

hmm, shouldn't we fail with unaligned size?

> +		.name = "unaligned_size_4K",

as it looks we don't need to deal with 64K, maybe drop the 4K suffix?

> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE - SZ_2K },
> +		.expected_ret = 0,
> +		.name =	"unaligned_size_4K_on_init",
> +	},
> +	{
> +		.orig =  { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE },
> +		.query = { .start = TEST_GGTT_START - SZ_2K, .size = TEST_GGTT_SIZE },
> +		.expected_ret = -EREMCHG,
> +		.name = "unaligned_base_4K",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = TEST_GGTT_START - SZ_2K, .size = TEST_GGTT_SIZE },
> +		.expected_ret = 0,
> +		.name = "unaligned_base_4K_on_init",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = 0, .size = 0 },
> +		.expected_ret = -EPROTO,
> +		.ret = -EPROTO,
> +		.name = "proto_error",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = 0, .size = 0 },
> +		.expected_ret = -EIO,
> +		.ret = -EIO,
> +		.name = "IO_error",
> +	},
> +	{
> +		.orig =  { .start = 0, .size = 0 },
> +		.query = { .start = TEST_GGTT_START, .size = TEST_GGTT_SIZE_OUT_OF_BOUNDS },
> +		.expected_ret = -ERANGE,
> +		.name = "out_of_bounds_size_on_init",
> +	},
> +};
> +
> +KUNIT_ARRAY_PARAM_DESC(ggtt_testcase, vf_ggtt_testcase, name);
> +
> +static int xe_guc_mmio_send_recv_stub_ggtt(struct xe_guc *guc, const u32 *request,
> +					   u32 len, u32 *response_buf)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	const struct config_ggtt *c = test->param_value;
> +	u32 key;
> +
> +	if (c->ret)
> +		return c->ret;
> +
> +	KUNIT_ASSERT_EQ(test, FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, request[0]),
> +			GUC_ACTION_VF2GUC_QUERY_SINGLE_KLV);
> +	KUNIT_ASSERT_EQ(test, len, VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_LEN);
> +	key = FIELD_GET(VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_1_KEY, request[1]);
> +	KUNIT_ASSERT_TRUE(test,
> +			  key == GUC_KLV_VF_CFG_GGTT_START_KEY ||
> +			  key == GUC_KLV_VF_CFG_GGTT_SIZE_KEY);

instead above see [2]

> +
> +	response_buf[0] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_LENGTH,
> +				     sizeof(u64) / sizeof(u32));
> +	if (key == GUC_KLV_VF_CFG_GGTT_START_KEY) {
> +		response_buf[1] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32,
> +					     lower_32_bits(c->query.start));
> +		response_buf[2] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_2_VALUE64,
> +					     upper_32_bits(c->query.start));

didn't you introduce a helper for this?

> +	} else if (key == GUC_KLV_VF_CFG_GGTT_SIZE_KEY) {
> +		response_buf[1] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32,
> +					     lower_32_bits(c->query.size));
> +		response_buf[2] = FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_2_VALUE64,
> +					     upper_32_bits(c->query.size));
> +	}

[2] use this:

	else {
		KUNIT_FAIL(test, "bad key %#x\n", key);
	}> +
> +	return 0;
> +}
> +
> +static void xe_ggtt_shift_nodes_stub(struct xe_ggtt *ggtt, u64 new_start)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	const struct config_ggtt *c = test->param_value;
> +	struct xe_gt *gt = test->priv;
> +	u64 expected_start = ALIGN(c->query.start, vf_get_ggtt_alignment(gt));
> +
> +	KUNIT_EXPECT_EQ(test, new_start, expected_start);
> +}
> +
> +static void test_ggtt(struct kunit *test)
> +{
> +	const struct config_ggtt *c = test->param_value;
> +	struct xe_gt *gt = test->priv;
> +

	xe_ggtt_init_kunit() ?

here or in init()

> +	gt->tile->sriov.vf.self_config.ggtt_base = c->orig.start;
> +	gt->tile->sriov.vf.self_config.ggtt_size = c->orig.size;
> +
> +	kunit_activate_static_stub(test, xe_guc_mmio_send_recv,
> +				   xe_guc_mmio_send_recv_stub_ggtt);
> +	kunit_activate_static_stub(test, xe_ggtt_shift_nodes,
> +				   xe_ggtt_shift_nodes_stub);
> +	KUNIT_EXPECT_EQ(test, vf_get_ggtt_info(gt), c->expected_ret);
> +}
> +
> +struct config_mmio {
> +	struct {
> +		u32 length;
> +		u32 mbz;

LEN and MBZ are in msg_data0

> +		u32 data0;
> +		u32 data1;

so these should be either:

		u32 data1;
		u32 data2;
or
		u32 value32;
		u32 value64;

> +	} response;
> +	u64 value;
> +	u64 value_len;
> +	u32 key;
> +	int expected_ret;
> +	int ret;
> +	const char *name;
> +};
> +
> +static const struct config_mmio guc_mmio_resp_testcase[] = {
> +	{
> +		.key = GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY,
> +		.value = TEST_CTXS,
> +		.value_len = hxg_sizeof(u32),
> +		.response = {
> +			.length = hxg_sizeof(u32),
> +			.mbz = 0,
> +			.data0 = TEST_CTXS,
> +			.data1 = 0,
> +		},
> +		.expected_ret = 0,
> +		.name = "klv32_successful"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY,
> +		.value = TEST_CTXS,
> +		.value_len = hxg_sizeof(u32),
> +		.response = {
> +			.length = hxg_sizeof(u32),
> +			.mbz = hxg_sizeof(u32),
> +			.data0 = TEST_CTXS,
> +			.data1 = 0,
> +		},
> +		.expected_ret = -EPROTO,
> +		.name = "klv32_proto_error"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY,
> +		.value = TEST_CTXS,
> +		.value_len = hxg_sizeof(u32),
> +		.response = {
> +			.length = hxg_sizeof(u64),
> +			.mbz = 0,
> +			.data0 = TEST_CTXS,
> +			.data1 = 0,
> +		},
> +		.expected_ret = -EOVERFLOW,
> +		.name = "klv32_overflow"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY,
> +		.value = TEST_CTXS,
> +		.value_len = hxg_sizeof(u32),
> +		.response = {
> +			.length = 0,
> +			.mbz = 0,
> +			.data0 = TEST_CTXS,
> +			.data1 = 0,
> +		},
> +		.expected_ret = -ENODATA,
> +		.name = "klv32_underflow"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_LMEM_SIZE_KEY,
> +		.value = TEST_VRAM,
> +		.value_len = hxg_sizeof(u64),
> +		.response = {
> +			.length = hxg_sizeof(u64),
> +			.mbz = 0,
> +			.data0 = lower_32_bits(TEST_VRAM),
> +			.data1 = upper_32_bits(TEST_VRAM),
> +		},
> +		.expected_ret = 0,
> +		.name = "klv64_successful"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_LMEM_SIZE_KEY,
> +		.value = TEST_VRAM,
> +		.value_len = hxg_sizeof(u64),
> +		.response = {
> +			.length = hxg_sizeof(u64),
> +			.mbz = hxg_sizeof(u32),
> +			.data0 = lower_32_bits(TEST_VRAM),
> +			.data1 = upper_32_bits(TEST_VRAM),
> +		},
> +		.expected_ret = -EPROTO,
> +		.name = "klv64_proto_error"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_LMEM_SIZE_KEY,
> +		.value = TEST_VRAM,
> +		.value_len = hxg_sizeof(u64),
> +		.response = {
> +			.length = (hxg_sizeof(u64)) + 1,
> +			.mbz = 0,
> +			.data0 = lower_32_bits(TEST_VRAM),
> +			.data1 = upper_32_bits(TEST_VRAM),
> +		},
> +		.expected_ret = -EOVERFLOW,
> +		.name = "klv64_overflow"
> +	},
> +	{
> +		.key = GUC_KLV_VF_CFG_LMEM_SIZE_KEY,
> +		.value = TEST_VRAM,
> +		.value_len = hxg_sizeof(u64),
> +		.response = {
> +			.length = 1,
> +			.mbz = 0,
> +			.data0 = lower_32_bits(TEST_VRAM),
> +			.data1 = upper_32_bits(TEST_VRAM),
> +		},
> +		.expected_ret = -ENODATA,
> +		.name = "klv64_underflow"
> +	},
> +};
> +
> +KUNIT_ARRAY_PARAM_DESC(guc_mmio_resp, guc_mmio_resp_testcase, name);
> +
> +static int xe_guc_mmio_send_recv_stub(struct xe_guc *guc, const u32 *request,
> +				      u32 len, u32 *response_buf)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	const struct config_mmio *c = test->param_value;
> +
> +	response_buf[0] =
> +		FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_LENGTH, c->response.length) |
> +		FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_MBZ, c->response.mbz);
> +	response_buf[1] =
> +		FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32, c->response.data0);
> +	response_buf[2] =
> +		FIELD_PREP(VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_2_VALUE64, c->response.data1);
> +
> +	return 0;
> +}
> +
> +static void test_guc_mmio(struct kunit *test)
> +{
> +	const struct config_mmio *c = test->param_value;
> +	struct xe_gt *gt = test->priv;
> +	struct xe_guc *guc = &gt->uc.guc;
> +	u32 value[2];
> +
> +	kunit_activate_static_stub(test, xe_guc_mmio_send_recv,
> +				   xe_guc_mmio_send_recv_stub);
> +	KUNIT_EXPECT_EQ(test,
> +			guc_action_query_single_klv(guc, c->key, value, c->value_len),
> +			c->expected_ret);
> +}
> +
> +static int vf_gt_config_test_init(struct kunit *test)
> +{
> +	struct xe_pci_fake_data fake = {
> +		.sriov_mode = XE_SRIOV_MODE_VF,
> +		.platform = XE_BATTLEMAGE, /* any random DGFX platform with SR-IOV */
> +		.subplatform = XE_SUBPLATFORM_NONE,
> +		.graphics_verx100 = 2001,
> +	};
> +	struct xe_device *xe;
> +	struct xe_gt *gt;
> +
> +	test->priv = &fake;
> +	xe_kunit_helper_xe_device_test_init(test);
> +
> +	xe = test->priv;
> +	KUNIT_ASSERT_TRUE(test, IS_SRIOV_VF(xe));
> +	KUNIT_ASSERT_TRUE(test, IS_DGFX(xe));
> +
> +	gt = xe_root_mmio_gt(xe);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gt);
> +	test->priv = gt;
> +
> +	return 0;
> +}
> +
> +static struct kunit_case vf_gt_config_test_cases[] = {
> +	KUNIT_CASE_PARAM(test_ctxs, ctx_testcase_gen_params),
> +	KUNIT_CASE_PARAM(test_dbs, db_testcase_gen_params),
> +	KUNIT_CASE_PARAM(test_vram, vram_testcase_gen_params),
> +	KUNIT_CASE_PARAM(test_ggtt, ggtt_testcase_gen_params),
> +	KUNIT_CASE_PARAM(test_guc_mmio, guc_mmio_resp_gen_params),
> +	{}
> +};
> +
> +static struct kunit_suite vf_gt_config_suite = {
> +	.name = "vf_gt_config",
> +	.test_cases = vf_gt_config_test_cases,
> +	.init = vf_gt_config_test_init,
> +};
> +
> +kunit_test_suite(vf_gt_config_suite);
> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
> index 37baeb1058b2..e80e3cdb5afe 100644
> --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
> @@ -1708,3 +1708,7 @@ int xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt)
>  
>  	return atomic_read(&gt->sriov.vf.migration.fixups_complete_count);
>  }
> +
> +#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
> +#include "tests/xe_gt_sriov_vf_kunit.c"
> +#endif


  reply	other threads:[~2026-09-21 16:47 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21  9:20 [PATCH v10 00/10] KUnit test for VF provisioning error handling Satyanarayana K V P
2026-09-21  9:21 ` [PATCH v10 01/10] drm/xe/guc: Allow to replace xe_guc_mmio_send_recv() with KUNIT stub Satyanarayana K V P
2026-09-21  9:21 ` [PATCH v10 02/10] drm/xe/vf: Split submission config query helpers Satyanarayana K V P
2026-09-21  9:21 ` [PATCH v10 03/10] drm/xe/vf: Add bounds checking for queried context and doorbell counts Satyanarayana K V P
2026-09-21  9:21 ` [PATCH v10 04/10] drm/xe: Introduce helpers for VRAM alignment Satyanarayana K V P
2026-09-21  9:21 ` [PATCH v10 05/10] drm/xe/ggtt: Avoid integer overflow when validating VF GGTT range Satyanarayana K V P
2026-09-21 14:03   ` Michal Wajdeczko
2026-09-21  9:21 ` [PATCH v10 06/10] drm/xe/sriov: Add helper for VF GGTT provisioning alignment Satyanarayana K V P
2026-09-21 13:26   ` Michal Wajdeczko
2026-09-21  9:21 ` [PATCH v10 07/10] drm/xe/vf: Add bounds checking for queried GGTT base and size Satyanarayana K V P
2026-09-21 14:36   ` Michal Wajdeczko
2026-09-21  9:21 ` [PATCH v10 08/10] drm/xe/vf: Add alignment check for queried VRAM size Satyanarayana K V P
2026-09-21  9:21 ` [PATCH v10 09/10] drm/xe/ggtt: Add KUnit stub for xe_ggtt_shift_nodes() Satyanarayana K V P
2026-09-21 14:45   ` Michal Wajdeczko
2026-09-21  9:21 ` [PATCH v10 10/10] drm/xe/tests: Add KUnit tests for VF provisioning error handling Satyanarayana K V P
2026-09-21 16:47   ` Michal Wajdeczko [this message]
2026-09-21  9:49 ` ✗ CI.checkpatch: warning for KUnit test for VF provisioning error handling (rev10) Patchwork
2026-09-21  9:51 ` ✓ CI.KUnit: success " Patchwork
2026-09-21 11:32 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-09-21 14:10 ` ✗ Xe.CI.FULL: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=574bef27-77be-4a77-8bf2-4389cac8615b@intel.com \
    --to=michal.wajdeczko@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=satyanarayana.k.v.p@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox