xref: /linux/drivers/gpu/drm/scheduler/tests/tests_basic.c (revision 5a99350794fec11faaed8a4b36a6931e696f672f)
1*5a993507STvrtko Ursulin // SPDX-License-Identifier: GPL-2.0
2*5a993507STvrtko Ursulin /* Copyright (c) 2025 Valve Corporation */
3*5a993507STvrtko Ursulin 
4*5a993507STvrtko Ursulin #include "sched_tests.h"
5*5a993507STvrtko Ursulin 
6*5a993507STvrtko Ursulin /*
7*5a993507STvrtko Ursulin  * DRM scheduler basic tests should check the basic functional correctness of
8*5a993507STvrtko Ursulin  * the scheduler, including some very light smoke testing. More targeted tests,
9*5a993507STvrtko Ursulin  * for example focusing on testing specific bugs and other more complicated test
10*5a993507STvrtko Ursulin  * scenarios, should be implemented in separate source units.
11*5a993507STvrtko Ursulin  */
12*5a993507STvrtko Ursulin 
13*5a993507STvrtko Ursulin static int drm_sched_basic_init(struct kunit *test)
14*5a993507STvrtko Ursulin {
15*5a993507STvrtko Ursulin 	test->priv = drm_mock_sched_new(test);
16*5a993507STvrtko Ursulin 
17*5a993507STvrtko Ursulin 	return 0;
18*5a993507STvrtko Ursulin }
19*5a993507STvrtko Ursulin 
20*5a993507STvrtko Ursulin static void drm_sched_basic_exit(struct kunit *test)
21*5a993507STvrtko Ursulin {
22*5a993507STvrtko Ursulin 	struct drm_mock_scheduler *sched = test->priv;
23*5a993507STvrtko Ursulin 
24*5a993507STvrtko Ursulin 	drm_mock_sched_fini(sched);
25*5a993507STvrtko Ursulin }
26*5a993507STvrtko Ursulin 
27*5a993507STvrtko Ursulin static void drm_sched_basic_submit(struct kunit *test)
28*5a993507STvrtko Ursulin {
29*5a993507STvrtko Ursulin 	struct drm_mock_scheduler *sched = test->priv;
30*5a993507STvrtko Ursulin 	struct drm_mock_sched_entity *entity;
31*5a993507STvrtko Ursulin 	struct drm_mock_sched_job *job;
32*5a993507STvrtko Ursulin 	unsigned int i;
33*5a993507STvrtko Ursulin 	bool done;
34*5a993507STvrtko Ursulin 
35*5a993507STvrtko Ursulin 	/*
36*5a993507STvrtko Ursulin 	 * Submit one job to the scheduler and verify that it gets scheduled
37*5a993507STvrtko Ursulin 	 * and completed only when the mock hw backend processes it.
38*5a993507STvrtko Ursulin 	 */
39*5a993507STvrtko Ursulin 
40*5a993507STvrtko Ursulin 	entity = drm_mock_sched_entity_new(test,
41*5a993507STvrtko Ursulin 					   DRM_SCHED_PRIORITY_NORMAL,
42*5a993507STvrtko Ursulin 					   sched);
43*5a993507STvrtko Ursulin 	job = drm_mock_sched_job_new(test, entity);
44*5a993507STvrtko Ursulin 
45*5a993507STvrtko Ursulin 	drm_mock_sched_job_submit(job);
46*5a993507STvrtko Ursulin 
47*5a993507STvrtko Ursulin 	done = drm_mock_sched_job_wait_scheduled(job, HZ);
48*5a993507STvrtko Ursulin 	KUNIT_ASSERT_TRUE(test, done);
49*5a993507STvrtko Ursulin 
50*5a993507STvrtko Ursulin 	done = drm_mock_sched_job_wait_finished(job, HZ / 2);
51*5a993507STvrtko Ursulin 	KUNIT_ASSERT_FALSE(test, done);
52*5a993507STvrtko Ursulin 
53*5a993507STvrtko Ursulin 	i = drm_mock_sched_advance(sched, 1);
54*5a993507STvrtko Ursulin 	KUNIT_ASSERT_EQ(test, i, 1);
55*5a993507STvrtko Ursulin 
56*5a993507STvrtko Ursulin 	done = drm_mock_sched_job_wait_finished(job, HZ);
57*5a993507STvrtko Ursulin 	KUNIT_ASSERT_TRUE(test, done);
58*5a993507STvrtko Ursulin 
59*5a993507STvrtko Ursulin 	drm_mock_sched_entity_free(entity);
60*5a993507STvrtko Ursulin }
61*5a993507STvrtko Ursulin 
62*5a993507STvrtko Ursulin struct drm_sched_basic_params {
63*5a993507STvrtko Ursulin 	const char *description;
64*5a993507STvrtko Ursulin 	unsigned int queue_depth;
65*5a993507STvrtko Ursulin 	unsigned int num_entities;
66*5a993507STvrtko Ursulin 	unsigned int job_us;
67*5a993507STvrtko Ursulin 	bool dep_chain;
68*5a993507STvrtko Ursulin };
69*5a993507STvrtko Ursulin 
70*5a993507STvrtko Ursulin static const struct drm_sched_basic_params drm_sched_basic_cases[] = {
71*5a993507STvrtko Ursulin 	{
72*5a993507STvrtko Ursulin 		.description = "A queue of jobs in a single entity",
73*5a993507STvrtko Ursulin 		.queue_depth = 100,
74*5a993507STvrtko Ursulin 		.job_us = 1000,
75*5a993507STvrtko Ursulin 		.num_entities = 1,
76*5a993507STvrtko Ursulin 	},
77*5a993507STvrtko Ursulin 	{
78*5a993507STvrtko Ursulin 		.description = "A chain of dependent jobs across multiple entities",
79*5a993507STvrtko Ursulin 		.queue_depth = 100,
80*5a993507STvrtko Ursulin 		.job_us = 1000,
81*5a993507STvrtko Ursulin 		.num_entities = 1,
82*5a993507STvrtko Ursulin 		.dep_chain = true,
83*5a993507STvrtko Ursulin 	},
84*5a993507STvrtko Ursulin 	{
85*5a993507STvrtko Ursulin 		.description = "Multiple independent job queues",
86*5a993507STvrtko Ursulin 		.queue_depth = 100,
87*5a993507STvrtko Ursulin 		.job_us = 1000,
88*5a993507STvrtko Ursulin 		.num_entities = 4,
89*5a993507STvrtko Ursulin 	},
90*5a993507STvrtko Ursulin 	{
91*5a993507STvrtko Ursulin 		.description = "Multiple inter-dependent job queues",
92*5a993507STvrtko Ursulin 		.queue_depth = 100,
93*5a993507STvrtko Ursulin 		.job_us = 1000,
94*5a993507STvrtko Ursulin 		.num_entities = 4,
95*5a993507STvrtko Ursulin 		.dep_chain = true,
96*5a993507STvrtko Ursulin 	},
97*5a993507STvrtko Ursulin };
98*5a993507STvrtko Ursulin 
99*5a993507STvrtko Ursulin static void
100*5a993507STvrtko Ursulin drm_sched_basic_desc(const struct drm_sched_basic_params *params, char *desc)
101*5a993507STvrtko Ursulin {
102*5a993507STvrtko Ursulin 	strscpy(desc, params->description, KUNIT_PARAM_DESC_SIZE);
103*5a993507STvrtko Ursulin }
104*5a993507STvrtko Ursulin 
105*5a993507STvrtko Ursulin KUNIT_ARRAY_PARAM(drm_sched_basic, drm_sched_basic_cases, drm_sched_basic_desc);
106*5a993507STvrtko Ursulin 
107*5a993507STvrtko Ursulin static void drm_sched_basic_test(struct kunit *test)
108*5a993507STvrtko Ursulin {
109*5a993507STvrtko Ursulin 	const struct drm_sched_basic_params *params = test->param_value;
110*5a993507STvrtko Ursulin 	struct drm_mock_scheduler *sched = test->priv;
111*5a993507STvrtko Ursulin 	struct drm_mock_sched_job *job, *prev = NULL;
112*5a993507STvrtko Ursulin 	struct drm_mock_sched_entity **entity;
113*5a993507STvrtko Ursulin 	unsigned int i, cur_ent = 0;
114*5a993507STvrtko Ursulin 	bool done;
115*5a993507STvrtko Ursulin 
116*5a993507STvrtko Ursulin 	entity = kunit_kcalloc(test, params->num_entities, sizeof(*entity),
117*5a993507STvrtko Ursulin 			       GFP_KERNEL);
118*5a993507STvrtko Ursulin 	KUNIT_ASSERT_NOT_NULL(test, entity);
119*5a993507STvrtko Ursulin 
120*5a993507STvrtko Ursulin 	for (i = 0; i < params->num_entities; i++)
121*5a993507STvrtko Ursulin 		entity[i] = drm_mock_sched_entity_new(test,
122*5a993507STvrtko Ursulin 						      DRM_SCHED_PRIORITY_NORMAL,
123*5a993507STvrtko Ursulin 						      sched);
124*5a993507STvrtko Ursulin 
125*5a993507STvrtko Ursulin 	for (i = 0; i < params->queue_depth; i++) {
126*5a993507STvrtko Ursulin 		job = drm_mock_sched_job_new(test, entity[cur_ent++]);
127*5a993507STvrtko Ursulin 		cur_ent %= params->num_entities;
128*5a993507STvrtko Ursulin 		drm_mock_sched_job_set_duration_us(job, params->job_us);
129*5a993507STvrtko Ursulin 		if (params->dep_chain && prev)
130*5a993507STvrtko Ursulin 			drm_sched_job_add_dependency(&job->base,
131*5a993507STvrtko Ursulin 						     dma_fence_get(&prev->base.s_fence->finished));
132*5a993507STvrtko Ursulin 		drm_mock_sched_job_submit(job);
133*5a993507STvrtko Ursulin 		prev = job;
134*5a993507STvrtko Ursulin 	}
135*5a993507STvrtko Ursulin 
136*5a993507STvrtko Ursulin 	done = drm_mock_sched_job_wait_finished(job, HZ);
137*5a993507STvrtko Ursulin 	KUNIT_ASSERT_TRUE(test, done);
138*5a993507STvrtko Ursulin 
139*5a993507STvrtko Ursulin 	for (i = 0; i < params->num_entities; i++)
140*5a993507STvrtko Ursulin 		drm_mock_sched_entity_free(entity[i]);
141*5a993507STvrtko Ursulin }
142*5a993507STvrtko Ursulin 
143*5a993507STvrtko Ursulin static void drm_sched_basic_entity_cleanup(struct kunit *test)
144*5a993507STvrtko Ursulin {
145*5a993507STvrtko Ursulin 	struct drm_mock_sched_job *job, *mid, *prev = NULL;
146*5a993507STvrtko Ursulin 	struct drm_mock_scheduler *sched = test->priv;
147*5a993507STvrtko Ursulin 	struct drm_mock_sched_entity *entity[4];
148*5a993507STvrtko Ursulin 	const unsigned int qd = 100;
149*5a993507STvrtko Ursulin 	unsigned int i, cur_ent = 0;
150*5a993507STvrtko Ursulin 	bool done;
151*5a993507STvrtko Ursulin 
152*5a993507STvrtko Ursulin 	/*
153*5a993507STvrtko Ursulin 	 * Submit a queue of jobs across different entities with an explicit
154*5a993507STvrtko Ursulin 	 * chain of dependencies between them and trigger entity cleanup while
155*5a993507STvrtko Ursulin 	 * the queue is still being processed.
156*5a993507STvrtko Ursulin 	 */
157*5a993507STvrtko Ursulin 
158*5a993507STvrtko Ursulin 	for (i = 0; i < ARRAY_SIZE(entity); i++)
159*5a993507STvrtko Ursulin 		entity[i] = drm_mock_sched_entity_new(test,
160*5a993507STvrtko Ursulin 						      DRM_SCHED_PRIORITY_NORMAL,
161*5a993507STvrtko Ursulin 						      sched);
162*5a993507STvrtko Ursulin 
163*5a993507STvrtko Ursulin 	for (i = 0; i < qd; i++) {
164*5a993507STvrtko Ursulin 		job = drm_mock_sched_job_new(test, entity[cur_ent++]);
165*5a993507STvrtko Ursulin 		cur_ent %= ARRAY_SIZE(entity);
166*5a993507STvrtko Ursulin 		drm_mock_sched_job_set_duration_us(job, 1000);
167*5a993507STvrtko Ursulin 		if (prev)
168*5a993507STvrtko Ursulin 			drm_sched_job_add_dependency(&job->base,
169*5a993507STvrtko Ursulin 						     dma_fence_get(&prev->base.s_fence->finished));
170*5a993507STvrtko Ursulin 		drm_mock_sched_job_submit(job);
171*5a993507STvrtko Ursulin 		if (i == qd / 2)
172*5a993507STvrtko Ursulin 			mid = job;
173*5a993507STvrtko Ursulin 		prev = job;
174*5a993507STvrtko Ursulin 	}
175*5a993507STvrtko Ursulin 
176*5a993507STvrtko Ursulin 	done = drm_mock_sched_job_wait_finished(mid, HZ);
177*5a993507STvrtko Ursulin 	KUNIT_ASSERT_TRUE(test, done);
178*5a993507STvrtko Ursulin 
179*5a993507STvrtko Ursulin 	/* Exit with half of the queue still pending to be executed. */
180*5a993507STvrtko Ursulin 	for (i = 0; i < ARRAY_SIZE(entity); i++)
181*5a993507STvrtko Ursulin 		drm_mock_sched_entity_free(entity[i]);
182*5a993507STvrtko Ursulin }
183*5a993507STvrtko Ursulin 
184*5a993507STvrtko Ursulin static struct kunit_case drm_sched_basic_tests[] = {
185*5a993507STvrtko Ursulin 	KUNIT_CASE(drm_sched_basic_submit),
186*5a993507STvrtko Ursulin 	KUNIT_CASE_PARAM(drm_sched_basic_test, drm_sched_basic_gen_params),
187*5a993507STvrtko Ursulin 	KUNIT_CASE(drm_sched_basic_entity_cleanup),
188*5a993507STvrtko Ursulin 	{}
189*5a993507STvrtko Ursulin };
190*5a993507STvrtko Ursulin 
191*5a993507STvrtko Ursulin static struct kunit_suite drm_sched_basic = {
192*5a993507STvrtko Ursulin 	.name = "drm_sched_basic_tests",
193*5a993507STvrtko Ursulin 	.init = drm_sched_basic_init,
194*5a993507STvrtko Ursulin 	.exit = drm_sched_basic_exit,
195*5a993507STvrtko Ursulin 	.test_cases = drm_sched_basic_tests,
196*5a993507STvrtko Ursulin };
197*5a993507STvrtko Ursulin 
198*5a993507STvrtko Ursulin kunit_test_suite(drm_sched_basic);
199