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