[PATCH 11/12] drm/xe/tests: Add KUnit tests for VF control state machines

Piotr Piórkowski piotr.piorkowski at intel.com
Thu Aug 22 10:47:57 UTC 2024


Michal Wajdeczko <michal.wajdeczko at intel.com> wrote on pią [2024-sie-09 18:51:58 +0200]:
> Add KUnit tests (~200) for all VF control state machines (FLR,
> PAUSE, STOP and RESUME) to make sure they work as expected and
> will not be broken while extending them with new functionality.
> 
> Signed-off-by: Michal Wajdeczko <michal.wajdeczko at intel.com>
> Cc: Lucas De Marchi <lucas.demarchi at intel.com>
> ---
> Test file named according to the new best practices [1]
> [1] https://lore.kernel.org/linux-hardening/20240724201354.make.730-kees@kernel.org/
> ---
>  .../xe/tests/xe_gt_sriov_pf_control_kunit.c   | 1360 +++++++++++++++++
>  drivers/gpu/drm/xe/xe_gt_sriov_pf_control.c   |    7 +
>  2 files changed, 1367 insertions(+)
>  create mode 100644 drivers/gpu/drm/xe/tests/xe_gt_sriov_pf_control_kunit.c
> 
> diff --git a/drivers/gpu/drm/xe/tests/xe_gt_sriov_pf_control_kunit.c b/drivers/gpu/drm/xe/tests/xe_gt_sriov_pf_control_kunit.c
> new file mode 100644
> index 000000000000..4252577b4bbd
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/tests/xe_gt_sriov_pf_control_kunit.c
> @@ -0,0 +1,1360 @@
> +// SPDX-License-Identifier: GPL-2.0 AND MIT
> +/*
> + * Copyright © 2024 Intel Corporation
> + */
> +
> +#include <kunit/test.h>
> +#include <kunit/static_stub.h>
> +
> +#include "tests/xe_kunit_helpers.h"
> +#include "tests/xe_pci_test.h"
> +
> +#include "xe_gt_sriov_pf.h"
> +
> +static const unsigned int DUT_NUM_VFS = 2;
> +static const unsigned int VFUT1 = VFID(1);
> +static const unsigned int VFUT2 = VFID(2);
> +
> +static void dump_state(void *arg)
> +{
> +	struct xe_gt *gt = arg;
> +
> +	pf_dump_vf_state(gt, VFUT1);
> +}
> +
> +static unsigned long replacement_timeout(enum xe_gt_sriov_control_bits bit)
> +{
> +	return HZ;
> +}
> +
> +static int pf_control_test_init(struct kunit *test)
> +{
> +	struct xe_pci_fake_data fake = {
> +		.sriov_mode = XE_SRIOV_MODE_PF,
> +		.platform = XE_TIGERLAKE, /* some random platform */
> +		.subplatform = XE_SUBPLATFORM_NONE,
> +	};
> +	struct xe_device *xe;
> +	struct xe_gt *gt;
> +
> +	test->priv = &fake;
> +	xe_kunit_helper_xe_device_test_init(test);
> +
> +	xe = test->priv;
> +	KUNIT_ASSERT_EQ(test, xe_sriov_init(xe), 0);
> +
> +	xe->sriov.pf.driver_max_vfs = DUT_NUM_VFS;
> +	KUNIT_EXPECT_NE(test, xe_sriov_pf_get_totalvfs(xe), 0);
> +
> +	gt = xe_device_get_gt(xe, 0);
> +	KUNIT_ASSERT_EQ(test, xe_gt_sriov_pf_init_early(gt), 0);
> +
> +	KUNIT_ASSERT_EQ(test, 0ul, *__pf_peek_vf_state(gt, VFUT1));
> +	KUNIT_ASSERT_EQ(test, 0ul, *__pf_peek_vf_state(gt, VFUT2));
> +
> +	KUNIT_EXPECT_EQ(test, 0, kunit_add_action_or_reset(test, dump_state, gt));
> +
> +	kunit_activate_static_stub(test, pf_get_default_timeout, replacement_timeout);
> +
> +	test->priv = gt;
> +	return 0;
> +}
> +
> +static int sanitize_vf_resources_fail(struct xe_gt *gt, u32 vfid, long timeout)
> +{
> +	return -ETIMEDOUT;
> +}
> +
> +static int send_vf_control_cmd_reject(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	return -EIO;
> +}
> +
> +static int send_vf_control_cmd_fail(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	return -ENODEV;
> +}
> +
> +static int send_vf_control_cmd_pass_no_reply(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	return 0;
> +}
> +
> +static int send_vf_control_cmd_pass_and_reply(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	switch (cmd) {
> +	case GUC_PF_TRIGGER_VF_PAUSE:
> +		pf_handle_vf_event(gt, vfid, GUC_PF_NOTIFY_VF_PAUSE_DONE);
> +		break;
> +	case GUC_PF_TRIGGER_VF_FLR_START:
> +		pf_handle_vf_event(gt, vfid, GUC_PF_NOTIFY_VF_FLR_DONE);
> +		break;
> +	case GUC_PF_TRIGGER_VF_RESUME:
> +	case GUC_PF_TRIGGER_VF_STOP:
> +	case GUC_PF_TRIGGER_VF_FLR_FINISH:
> +		break;
> +	default:
> +		return -EPROTO;
> +	}
> +	return 0;
> +}
> +
> +static int send_vf_control_cmd_busy_wait(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	schedule_timeout_interruptible(HZ / 20);
> +	return -EBUSY;
> +}
> +
> +static int send_vf_control_cmd_pass_but_reply_flr_only(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	return cmd == GUC_PF_TRIGGER_VF_FLR_START ?
> +		send_vf_control_cmd_pass_and_reply(gt, vfid, cmd) :
> +		send_vf_control_cmd_pass_no_reply(gt, vfid, cmd);
> +}
> +
> +static int send_vf_control_cmd_busy_except_flr(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	return cmd == GUC_PF_TRIGGER_VF_FLR_START || cmd == GUC_PF_TRIGGER_VF_FLR_FINISH ?
> +		send_vf_control_cmd_pass_and_reply(gt, vfid, cmd) :
> +		send_vf_control_cmd_busy_wait(gt, vfid, cmd);
> +}
> +
> +static int send_vf_control_cmd_busy_except_stop(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	return cmd == GUC_PF_TRIGGER_VF_STOP ?
> +		send_vf_control_cmd_pass_and_reply(gt, vfid, cmd) :
> +		send_vf_control_cmd_busy_wait(gt, vfid, cmd);
> +}
> +
> +static int BUSY_MAGIC = 3;
> +
> +static int send_vf_control_cmd_busy_no_reply(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	static int counter;
> +
> +	return ++counter % BUSY_MAGIC ? -EBUSY : 0;
> +}
> +
> +static int send_vf_control_cmd_busy_and_reply(struct xe_gt *gt, unsigned int vfid, u32 cmd)
> +{
> +	static int counter;
> +
> +	return ++counter % BUSY_MAGIC ? -EBUSY :
> +		send_vf_control_cmd_pass_and_reply(gt, vfid, cmd);
> +}
> +
> +static const enum xe_gt_sriov_control_bits ready[] = {
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_starting[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_SEND_START,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_starting_paused[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_SEND_START,
> +	XE_GT_SRIOV_STATE_PAUSED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_starting_stopped[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_SEND_START,
> +	XE_GT_SRIOV_STATE_STOPPED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_waiting[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WAIT_GUC,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_guc_done[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_GUC_DONE,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_resetting[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_RESET_CONFIG,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_finishing[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_FLR_WIP,
> +	XE_GT_SRIOV_STATE_FLR_SEND_FINISH,
> +};
> +
> +static const enum xe_gt_sriov_control_bits flr_failed[] = {
> +	XE_GT_SRIOV_STATE_FLR_FAILED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits stopping[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_STOP_WIP,
> +	XE_GT_SRIOV_STATE_STOP_SEND_STOP,
> +};
> +
> +static const enum xe_gt_sriov_control_bits stopping_paused[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_STOP_WIP,
> +	XE_GT_SRIOV_STATE_STOP_SEND_STOP,
> +	XE_GT_SRIOV_STATE_PAUSED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits stop_failed[] = {
> +	XE_GT_SRIOV_STATE_STOP_FAILED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits stop_rejected[] = {
> +	XE_GT_SRIOV_STATE_STOP_FAILED,
> +	XE_GT_SRIOV_STATE_MISMATCH,
> +};
> +
> +static const enum xe_gt_sriov_control_bits stopped[] = {
> +	XE_GT_SRIOV_STATE_STOPPED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits pausing[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSE_SEND_PAUSE,
> +};
> +
> +static const enum xe_gt_sriov_control_bits pausing_wait_guc[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSE_WAIT_GUC,
> +};
> +
> +static const enum xe_gt_sriov_control_bits pausing_guc_done[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSE_GUC_DONE,
> +};
> +
> +static const enum xe_gt_sriov_control_bits pause_failed[] = {
> +	XE_GT_SRIOV_STATE_PAUSE_FAILED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits pause_rejected[] = {
> +	XE_GT_SRIOV_STATE_PAUSE_FAILED,
> +	XE_GT_SRIOV_STATE_MISMATCH,
> +};
> +
> +static const enum xe_gt_sriov_control_bits paused[] = {
> +	XE_GT_SRIOV_STATE_PAUSED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits resuming[] = {
> +	XE_GT_SRIOV_STATE_WIP,
> +	XE_GT_SRIOV_STATE_PAUSED,
> +	XE_GT_SRIOV_STATE_RESUME_WIP,
> +	XE_GT_SRIOV_STATE_RESUME_SEND_RESUME,
> +};
> +
> +static const enum xe_gt_sriov_control_bits resume_failed[] = {
> +	XE_GT_SRIOV_STATE_PAUSED,
> +	XE_GT_SRIOV_STATE_RESUME_FAILED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits resume_rejected[] = {
> +	XE_GT_SRIOV_STATE_PAUSED,
> +	XE_GT_SRIOV_STATE_RESUME_FAILED,
> +	XE_GT_SRIOV_STATE_MISMATCH,
> +};
> +
> +static const enum xe_gt_sriov_control_bits resumed[] = {
> +	XE_GT_SRIOV_STATE_RESUMED,
> +};
> +
> +static const enum xe_gt_sriov_control_bits mismatch[] = {
> +	XE_GT_SRIOV_STATE_MISMATCH,
> +};
> +
> +struct state_param {
> +	const char *name;
> +	const enum xe_gt_sriov_control_bits *bits;
> +	size_t num_bits;
> +};
> +
> +static void state_param_get_desc(struct state_param *p, char *desc)
> +{
> +	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", p->name);
> +}
> +
> +#define MAKE_STATE_PARAM(X) { .name = #X, .bits = X, .num_bits = ARRAY_SIZE(X) }
> +
> +/*
> + * Due to the test case logic the all "must_pass" params include "_rejected" states
> + * since our "GuC" calls by default will not complain again about the INVALID_STATE
> + * thus our state machine is able to fully recover.
> + */
> +
> +static struct state_param flr_must_pass_from[] = {
> +	MAKE_STATE_PARAM(ready),
> +	MAKE_STATE_PARAM(flr_starting),
> +	MAKE_STATE_PARAM(flr_starting_paused),
> +	MAKE_STATE_PARAM(flr_starting_stopped),
> +	MAKE_STATE_PARAM(flr_waiting),
> +	MAKE_STATE_PARAM(flr_guc_done),
> +	MAKE_STATE_PARAM(flr_resetting),
> +	MAKE_STATE_PARAM(flr_finishing),
> +	MAKE_STATE_PARAM(flr_failed),
> +	MAKE_STATE_PARAM(stopping),
> +	MAKE_STATE_PARAM(stop_failed),
> +	MAKE_STATE_PARAM(stop_rejected),
> +	MAKE_STATE_PARAM(stopped),
> +	MAKE_STATE_PARAM(pausing),
> +	MAKE_STATE_PARAM(pausing_wait_guc),
> +	MAKE_STATE_PARAM(pausing_guc_done),
> +	MAKE_STATE_PARAM(pause_failed),
> +	MAKE_STATE_PARAM(pause_rejected),
> +	MAKE_STATE_PARAM(paused),
> +	MAKE_STATE_PARAM(resuming),
> +	MAKE_STATE_PARAM(resume_failed),
> +	MAKE_STATE_PARAM(resume_rejected),
> +	MAKE_STATE_PARAM(resumed),
> +	MAKE_STATE_PARAM(mismatch),
> +};
> +
> +static struct state_param stop_must_pass_from[] = {
> +	MAKE_STATE_PARAM(ready),
> +	MAKE_STATE_PARAM(stop_failed),
> +	MAKE_STATE_PARAM(stop_rejected),
> +	MAKE_STATE_PARAM(pausing),
> +	MAKE_STATE_PARAM(pausing_wait_guc),
> +	MAKE_STATE_PARAM(pausing_guc_done),
> +	MAKE_STATE_PARAM(pause_failed),
> +	MAKE_STATE_PARAM(pause_rejected),
> +	MAKE_STATE_PARAM(paused),
> +	MAKE_STATE_PARAM(resuming),
> +	MAKE_STATE_PARAM(resume_failed),
> +	MAKE_STATE_PARAM(resume_rejected),
> +	MAKE_STATE_PARAM(resumed),
> +	MAKE_STATE_PARAM(mismatch),
> +	MAKE_STATE_PARAM(flr_failed),
> +};
> +
> +static struct state_param stop_must_cancel_from[] = {
> +	MAKE_STATE_PARAM(flr_starting),
> +	MAKE_STATE_PARAM(flr_starting_paused),
> +	MAKE_STATE_PARAM(flr_waiting),
> +	MAKE_STATE_PARAM(flr_guc_done),
> +	MAKE_STATE_PARAM(flr_resetting),
> +	MAKE_STATE_PARAM(flr_finishing),
> +};
> +
> +static struct state_param stop_must_fail_from[] = {
> +	MAKE_STATE_PARAM(stopping),
> +	MAKE_STATE_PARAM(stopping_paused),
> +	MAKE_STATE_PARAM(stopped),
> +	MAKE_STATE_PARAM(flr_starting_stopped),
> +};
> +
> +static struct state_param pause_must_pass_from[] = {
> +	MAKE_STATE_PARAM(ready),
> +	MAKE_STATE_PARAM(pause_failed),
> +	MAKE_STATE_PARAM(pause_rejected),
> +	MAKE_STATE_PARAM(resumed),
> +	MAKE_STATE_PARAM(mismatch),
> +	MAKE_STATE_PARAM(stop_failed),
> +	MAKE_STATE_PARAM(stop_rejected),
> +	MAKE_STATE_PARAM(flr_failed),
> +};
> +
> +static struct state_param pause_must_cancel_from[] = {
> +	MAKE_STATE_PARAM(flr_starting),
> +	MAKE_STATE_PARAM(flr_waiting),
> +	MAKE_STATE_PARAM(flr_guc_done),
> +	MAKE_STATE_PARAM(flr_resetting),
> +	MAKE_STATE_PARAM(flr_finishing),
> +	MAKE_STATE_PARAM(stopping),
> +};
> +
> +static struct state_param pause_must_fail_from[] = {
> +	MAKE_STATE_PARAM(pausing),
> +	MAKE_STATE_PARAM(pausing_wait_guc),
> +	MAKE_STATE_PARAM(pausing_guc_done),
> +	MAKE_STATE_PARAM(paused),
> +	MAKE_STATE_PARAM(resuming),
> +	MAKE_STATE_PARAM(resume_failed),
> +	MAKE_STATE_PARAM(resume_rejected),
> +	MAKE_STATE_PARAM(stopped),
> +};
> +
> +static struct state_param resume_must_pass_from[] = {
> +	MAKE_STATE_PARAM(paused),
> +	MAKE_STATE_PARAM(resume_failed),
> +	MAKE_STATE_PARAM(resume_rejected),
> +};
> +
> +static struct state_param resume_must_cancel_from[] = {
> +	MAKE_STATE_PARAM(flr_starting_paused),
> +	MAKE_STATE_PARAM(stopping_paused),
> +};
> +
> +static struct state_param resume_must_fail_from[] = {
> +	MAKE_STATE_PARAM(ready),
> +	MAKE_STATE_PARAM(pausing),
> +	MAKE_STATE_PARAM(pausing_wait_guc),
> +	MAKE_STATE_PARAM(pausing_guc_done),
> +	MAKE_STATE_PARAM(pause_failed),
> +	MAKE_STATE_PARAM(pause_rejected),
> +	MAKE_STATE_PARAM(resuming),
> +	MAKE_STATE_PARAM(resumed),
> +	MAKE_STATE_PARAM(stopping),
> +	MAKE_STATE_PARAM(stop_failed),
> +	MAKE_STATE_PARAM(stop_rejected),
> +	MAKE_STATE_PARAM(stopped),
> +	MAKE_STATE_PARAM(flr_starting),
> +	MAKE_STATE_PARAM(flr_waiting),
> +	MAKE_STATE_PARAM(flr_guc_done),
> +	MAKE_STATE_PARAM(flr_resetting),
> +	MAKE_STATE_PARAM(flr_finishing),
> +	MAKE_STATE_PARAM(flr_failed),
> +	MAKE_STATE_PARAM(mismatch),
> +};
> +
> +KUNIT_ARRAY_PARAM(flr_must_pass_from, flr_must_pass_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(stop_must_pass_from, stop_must_pass_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(stop_must_fail_from, stop_must_fail_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(stop_must_cancel_from, stop_must_cancel_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(pause_must_pass_from, pause_must_pass_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(pause_must_fail_from, pause_must_fail_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(pause_must_cancel_from, pause_must_cancel_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(resume_must_pass_from, resume_must_pass_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(resume_must_fail_from, resume_must_fail_from, state_param_get_desc);
> +KUNIT_ARRAY_PARAM(resume_must_cancel_from, resume_must_cancel_from, state_param_get_desc);
> +
> +static int mimic_pf_handle_vf_flr_done(struct xe_gt *gt, unsigned int vfid)
> +{
> +	pf_handle_vf_flr_done(gt, vfid);
> +	return 0;
> +}
> +
> +static int mimic_pf_handle_vf_pause_done(struct xe_gt *gt, unsigned int vfid)
> +{
> +	pf_handle_vf_pause_done(gt, vfid);
> +	return 0;
> +}
> +
> +static void prepare_state(struct kunit *test, unsigned int vfid,
> +			  const enum xe_gt_sriov_control_bits *bits, size_t num_bits)
> +{
> +	struct xe_gt *gt = test->priv;
> +	size_t n;
> +
> +	for (n = 0; n < num_bits; n++) {
> +		enum xe_gt_sriov_control_bits bit = bits[n];
> +
> +		KUNIT_ASSERT_TRUE(test, pf_enter_vf_state(gt, vfid, bit));
> +
> +		if (bit == XE_GT_SRIOV_STATE_WIP) {
> +			pf_queue_vf(gt, vfid);
> +		} else if (bit == XE_GT_SRIOV_STATE_FLR_WAIT_GUC) {
> +			xe_kunit_helper_delayed_call(test, HZ / 100,
> +						     mimic_pf_handle_vf_flr_done, gt, vfid);
> +		} else if (bit == XE_GT_SRIOV_STATE_PAUSE_WAIT_GUC) {
> +			xe_kunit_helper_delayed_call(test, HZ / 100,
> +						     mimic_pf_handle_vf_pause_done, gt, vfid);
> +		}
> +	}
> +}
> +
> +static void prepare_state_from_param(struct kunit *test)
> +{
> +	const struct state_param *p = test->param_value;
> +
> +	prepare_state(test, VFUT1, p->bits, p->num_bits);
> +}
> +
> +static void expect_not_pausing(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WIP));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_SEND_PAUSE));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WAIT_GUC));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_GUC_DONE));
> +}
> +
> +static void expect_not_in_pause(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	expect_not_pausing(test);
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_FAILED));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +}
> +
> +static void expect_not_resuming(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_WIP));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_SEND_RESUME));
> +}
> +
> +static void expect_not_in_resume(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	expect_not_resuming(test);
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_FAILED));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUMED));
> +}
> +
> +static void expect_not_stopping(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_WIP));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_SEND_STOP));
> +}
> +
> +static void expect_not_in_stop(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	expect_not_stopping(test);
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_FAILED));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOPPED));
> +}
> +
> +static void expect_not_in_flr(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_SEND_START));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WAIT_GUC));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_GUC_DONE));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_SEND_FINISH));
> +	KUNIT_EXPECT_TRUE(test,
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +}
> +
> +static void expect_not_in_wip(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void expect_not_in_mismatch(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +}
> +
> +static void try_flr_vf(struct kunit *test, bool mimic_busy, bool late_reply)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      mimic_busy ? late_reply ? send_vf_control_cmd_busy_no_reply :
> +			      send_vf_control_cmd_busy_and_reply :
> +			      late_reply ? send_vf_control_cmd_pass_no_reply :
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	if (late_reply)
> +		xe_kunit_helper_delayed_call(test, HZ / 10,
> +					     mimic_pf_handle_vf_flr_done, gt, VFUT1);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +
> +	expect_not_in_flr(test);
> +	expect_not_in_pause(test);
> +	expect_not_in_resume(test);
> +	expect_not_in_stop(test);
> +	expect_not_in_mismatch(test);
> +	expect_not_in_wip(test);
> +}
> +
> +static void flr_vf_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_flr_vf(test, false, false);
> +}
> +
> +static void flr_vf_needs_retry_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_flr_vf(test, true, false);
> +}
> +
> +static void flr_vf_needs_retry_late_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_flr_vf(test, true, true);
> +}
> +
> +static void flr_vf_fails_on_send(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_fail);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ETIMEDOUT);
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void flr_vf_fails_on_reset(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.vfs[VFUT1].config.sanitize,
> +			      sanitize_vf_resources_fail);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ETIMEDOUT);
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void flr_vf_rejected_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_reject);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ETIMEDOUT);
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void flr_vf_unconfirmed_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_no_reply);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, err, -ETIMEDOUT);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +}
> +
> +static void flr_vf_confirmed_early_continue_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, flr_starting, ARRAY_SIZE(flr_starting));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_no_reply);
> +
> +	pf_handle_vf_flr_done(gt, VFUT1);
> +
> +	/*
> +	 * make sure SEND_START completes;
> +	 * successful reply from cmd_pass_no_reply should exit mismatch state
> +	 */
> +	flush_work(&gt->sriov.pf.control.worker);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +}
> +
> +static void flr_vf_confirmed_early_reject_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, flr_starting, ARRAY_SIZE(flr_starting));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_reject);
> +
> +	pf_handle_vf_flr_done(gt, VFUT1);
> +
> +	/*
> +	 * make sure SEND_START completes;
> +	 * error from send_vf_control_cmd_reject should keep mismatch state
> +	 */
> +	flush_work(&gt->sriov.pf.control.worker);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void flr_vf_confirmed_twice_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, flr_guc_done, ARRAY_SIZE(flr_guc_done));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_no_reply);
> +
> +	pf_handle_vf_flr_done(gt, VFUT1);
> +
> +	/* this is fully recoverable */
> +	KUNIT_EXPECT_EQ(test, 0, pf_wait_vf_wip_done(gt, VFUT1, HZ));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +}
> +
> +static void flr_vf_confirmed_too_late_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, flr_failed, ARRAY_SIZE(flr_failed));
> +
> +	pf_handle_vf_flr_done(gt, VFUT1);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void flr_vf_unsolicited_confirmation_from_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +
> +	pf_handle_vf_flr_done(gt, VFUT1);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_FLR_FAILED));
> +}
> +
> +static void flr_vf_wrong_confirmation_from_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, flr_waiting, ARRAY_SIZE(flr_waiting));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	pf_handle_vf_pause_done(gt, VFUT1);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +}
> +
> +static void flr_vf_canceled_by_restart(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_busy_wait);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10, xe_gt_sriov_pf_control_restart, gt);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	expect_not_in_flr(test);
> +}
> +
> +static void try_stop_vf(struct kunit *test, bool mimic_busy)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      mimic_busy ? send_vf_control_cmd_busy_and_reply :
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOPPED));
> +	expect_not_stopping(test);
> +	expect_not_in_pause(test);
> +	expect_not_in_resume(test);
> +	expect_not_in_mismatch(test);
> +}
> +
> +static void stop_vf_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_stop_vf(test, false);
> +}
> +
> +static void stop_vf_needs_retry_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_stop_vf(test, true);
> +}
> +
> +static void stop_vf_refused_from(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	prepare_state_from_param(test);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	KUNIT_EXPECT_TRUE(test, err == -EALREADY ||
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_FAILED));
> +}
> +
> +static void stop_vf_fails_on_send(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_fail);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ETIMEDOUT);
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_FAILED));
> +	expect_not_stopping(test);
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOPPED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void stop_vf_rejected_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_reject);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ETIMEDOUT);
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	expect_not_stopping(test);
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOPPED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void stop_vf_canceled_from(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state_from_param(test);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOP_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_STOPPED));
> +}
> +
> +static void stop_vf_canceled_by_restart(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_busy_except_flr);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10, xe_gt_sriov_pf_control_restart, gt);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +	expect_not_in_stop(test);
> +}
> +
> +static void stop_vf_canceled_by_flr(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_busy_except_flr);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10,
> +				     xe_gt_sriov_pf_control_trigger_flr, gt, VFUT1);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +	expect_not_in_stop(test);
> +}
> +
> +static void try_pause_vf(struct kunit *test, bool mimic_busy)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      mimic_busy ? send_vf_control_cmd_busy_and_reply :
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +	expect_not_pausing(test);
> +	expect_not_in_mismatch(test);
> +}
> +
> +static void pause_vf_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_pause_vf(test, false);
> +}
> +
> +static void pause_vf_needs_retry_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_pause_vf(test, true);
> +}
> +
> +static void pause_vf_canceled_from(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state_from_param(test);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	expect_not_in_pause(test);
> +}
> +
> +static void pause_vf_refused_from(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	prepare_state_from_param(test);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -ECANCELED);
> +
> +	KUNIT_EXPECT_TRUE(test, err == -EALREADY ||
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_FAILED));
> +}
> +
> +static void pause_vf_rejected_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_reject);
> +
> +	KUNIT_EXPECT_NE(test, 0, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void pause_vf_fails_on_send(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_fail);
> +
> +	KUNIT_EXPECT_NE(test, 0, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_FAILED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_WIP));
> +}
> +
> +static void pause_vf_unconfirmed_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_no_reply);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, err, -ETIMEDOUT);
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_WAIT_GUC));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSE_FAILED));
> +}
> +
> +static void pause_vf_canceled_by_restart(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_no_reply);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10, xe_gt_sriov_pf_control_restart, gt);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	expect_not_in_pause(test);
> +}
> +
> +static void pause_vf_canceled_by_flr(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_but_reply_flr_only);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10,
> +				     xe_gt_sriov_pf_control_trigger_flr, gt, VFUT1);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	expect_not_in_pause(test);
> +}
> +
> +static void pause_vf_canceled_by_stop(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_no_reply);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10,
> +				     xe_gt_sriov_pf_control_stop_vf, gt, VFUT1);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	expect_not_in_pause(test);
> +}
> +
> +static void try_resume_vf(struct kunit *test, bool mimic_busy)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      mimic_busy ? send_vf_control_cmd_busy_and_reply :
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUMED));
> +	expect_not_resuming(test);
> +	expect_not_in_pause(test);
> +	expect_not_in_mismatch(test);
> +	expect_not_in_wip(test);
> +}
> +
> +static void resume_vf_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_resume_vf(test, false);
> +}
> +
> +static void resume_vf_needs_retry_from(struct kunit *test)
> +{
> +	prepare_state_from_param(test);
> +	try_resume_vf(test, true);
> +}
> +
> +static void resume_vf_fails_on_send(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, paused, ARRAY_SIZE(paused));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_fail);
> +
> +	KUNIT_EXPECT_NE(test, 0, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_FAILED));
> +
> +	expect_not_resuming(test);
> +	expect_not_in_mismatch(test);
> +	expect_not_in_wip(test);
> +}
> +
> +static void resume_vf_rejected_by_guc(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, paused, ARRAY_SIZE(paused));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_reject);
> +
> +	KUNIT_EXPECT_NE(test, 0, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_PAUSED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_MISMATCH));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_FAILED));
> +
> +	expect_not_resuming(test);
> +	expect_not_in_wip(test);
> +}
> +
> +static void resume_vf_canceled_from(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state_from_param(test);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUMED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_FAILED));
> +	expect_not_resuming(test);
> +}
> +
> +static void resume_vf_refused_from(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +	int err;
> +
> +	prepare_state_from_param(test);
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_NE(test, 0, err = xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +	KUNIT_EXPECT_NE(test, err, -EIO);
> +
> +	KUNIT_EXPECT_TRUE(test, err == -EALREADY ||
> +			  pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_WIP));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_FAILED));
> +}
> +
> +static void resume_vf_canceled_by_restart(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, paused, ARRAY_SIZE(paused));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_busy_except_flr);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10, xe_gt_sriov_pf_control_restart, gt);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUMED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_WIP));
> +}
> +
> +static void resume_vf_canceled_by_flr(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, paused, ARRAY_SIZE(paused));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_busy_except_flr);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10,
> +				     xe_gt_sriov_pf_control_trigger_flr, gt, VFUT1);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUMED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_WIP));
> +}
> +
> +static void resume_vf_canceled_by_stop(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	prepare_state(test, VFUT1, paused, ARRAY_SIZE(paused));
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_busy_except_stop);
> +
> +	xe_kunit_helper_delayed_call(test, HZ / 10,
> +				     xe_gt_sriov_pf_control_stop_vf, gt, VFUT1);
> +
> +	KUNIT_EXPECT_EQ(test, -ECANCELED, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUMED));
> +	KUNIT_EXPECT_TRUE(test, pf_expect_vf_not_state(gt, VFUT1, XE_GT_SRIOV_STATE_RESUME_WIP));
> +}
> +
> +static void basic_pause_and_resume_vf(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_ASSERT_EQ(test, 0, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_resume_vf(gt, VFUT1));
> +}
> +
> +static void basic_pause_and_stop_vf(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_ASSERT_EQ(test, 0, xe_gt_sriov_pf_control_pause_vf(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +}
> +
> +static void basic_stop_and_flr_vf(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_stop_vf(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +}
> +
> +static void basic_flr_and_flr_vf(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +}
> +
> +static void basic_flr_vfs(struct kunit *test)
> +{
> +	struct xe_gt *gt = test->priv;
> +
> +	XE_TEST_ACTIVATE_STUB(test, gt->sriov.pf.control.send_vf_control_cmd,
> +			      send_vf_control_cmd_pass_and_reply);
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT1));
> +	KUNIT_EXPECT_EQ(test, 0, xe_gt_sriov_pf_control_trigger_flr(gt, VFUT2));
> +}
> +
> +static struct kunit_case pf_control_test_cases[] = {
> +	KUNIT_CASE(basic_pause_and_resume_vf),
> +	KUNIT_CASE(basic_pause_and_stop_vf),
> +	KUNIT_CASE(basic_stop_and_flr_vf),
> +	KUNIT_CASE(basic_flr_and_flr_vf),
> +	KUNIT_CASE(basic_flr_vfs),
> +
> +	KUNIT_CASE_PARAM(flr_vf_from, flr_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(flr_vf_needs_retry_from, flr_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(flr_vf_needs_retry_late_from, flr_must_pass_from_gen_params),
> +	KUNIT_CASE(flr_vf_fails_on_send),
> +	KUNIT_CASE(flr_vf_fails_on_reset),
> +	KUNIT_CASE(flr_vf_rejected_by_guc),
> +	KUNIT_CASE_SLOW(flr_vf_unconfirmed_by_guc),
> +	KUNIT_CASE(flr_vf_confirmed_early_continue_by_guc),
> +	KUNIT_CASE(flr_vf_confirmed_early_reject_by_guc),
> +	KUNIT_CASE(flr_vf_confirmed_twice_by_guc),
> +	KUNIT_CASE(flr_vf_confirmed_too_late_by_guc),
> +	KUNIT_CASE(flr_vf_wrong_confirmation_from_guc),
> +	KUNIT_CASE(flr_vf_unsolicited_confirmation_from_guc),
> +	KUNIT_CASE(flr_vf_canceled_by_restart),
> +
> +	KUNIT_CASE_PARAM(stop_vf_from, stop_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(stop_vf_needs_retry_from, stop_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(stop_vf_refused_from, stop_must_fail_from_gen_params),
> +	KUNIT_CASE_PARAM(stop_vf_canceled_from, stop_must_cancel_from_gen_params),
> +	KUNIT_CASE(stop_vf_fails_on_send),
> +	KUNIT_CASE(stop_vf_rejected_by_guc),
> +	KUNIT_CASE(stop_vf_canceled_by_flr),
> +	KUNIT_CASE(stop_vf_canceled_by_restart),
> +
> +	KUNIT_CASE_PARAM(pause_vf_from, pause_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(pause_vf_needs_retry_from, pause_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(pause_vf_refused_from, pause_must_fail_from_gen_params),
> +	KUNIT_CASE_PARAM(pause_vf_canceled_from, pause_must_cancel_from_gen_params),
> +	KUNIT_CASE(pause_vf_fails_on_send),
> +	KUNIT_CASE(pause_vf_rejected_by_guc),
> +	KUNIT_CASE_SLOW(pause_vf_unconfirmed_by_guc),
> +	KUNIT_CASE(pause_vf_canceled_by_flr),
> +	KUNIT_CASE(pause_vf_canceled_by_stop),
> +	KUNIT_CASE(pause_vf_canceled_by_restart),
> +
> +	KUNIT_CASE_PARAM(resume_vf_from, resume_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(resume_vf_needs_retry_from, resume_must_pass_from_gen_params),
> +	KUNIT_CASE_PARAM(resume_vf_refused_from, resume_must_fail_from_gen_params),
> +	KUNIT_CASE_PARAM(resume_vf_canceled_from, resume_must_cancel_from_gen_params),
> +	KUNIT_CASE(resume_vf_fails_on_send),
> +	KUNIT_CASE(resume_vf_rejected_by_guc),
> +	KUNIT_CASE(resume_vf_canceled_by_flr),
> +	KUNIT_CASE(resume_vf_canceled_by_stop),
> +	KUNIT_CASE(resume_vf_canceled_by_restart),
> +
> +	{}
> +};
> +
> +static struct kunit_suite pf_control_suite = {
> +	.name = "pf_control",
> +	.test_cases = pf_control_test_cases,
> +	.init = pf_control_test_init,
> +};
> +
> +kunit_test_suite(pf_control_suite);
> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_control.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_control.c
> index e91c71d768ff..4863d79f72e0 100644
> --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_control.c
> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_control.c
> @@ -4,6 +4,7 @@
>   */
>  
>  #include <drm/drm_managed.h>
> +#include <kunit/static_stub.h>
>  
>  #include "abi/guc_actions_sriov_abi.h"
>  
> @@ -196,6 +197,8 @@ static const char *control_bit_to_string(enum xe_gt_sriov_control_bits bit)
>  
>  static unsigned long pf_get_default_timeout(enum xe_gt_sriov_control_bits bit)
>  {
> +	KUNIT_STATIC_STUB_REDIRECT(pf_get_default_timeout, bit);
> +
>  	switch (bit) {
>  	case XE_GT_SRIOV_STATE_FLR_WAIT_GUC:
>  	case XE_GT_SRIOV_STATE_PAUSE_WAIT_GUC:
> @@ -1458,3 +1461,7 @@ void xe_gt_sriov_pf_control_restart(struct xe_gt *gt)
>  	for (n = 1; n <= totalvfs; n++)
>  		pf_enter_vf_ready(gt, n);
>  }
> +
> +#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
> +#include "tests/xe_gt_sriov_pf_control_kunit.c"
> +#endif
The tests look fine. I tried to verify the states according to the available
drawings of the state machine and I did not find any incorrectness.
It seems to me that the tests could be expanded to include an additional
basic test: basic_pause_and_flr_vf
But still:
Reviewed-by: Piotr Piórkowski <piotr.piorkowski at intel.com>



> -- 
> 2.43.0
> 

-- 


More information about the Intel-xe mailing list