15a993507STvrtko Ursulin // SPDX-License-Identifier: GPL-2.0
25a993507STvrtko Ursulin /* Copyright (c) 2025 Valve Corporation */
35a993507STvrtko Ursulin
47b765cdaSTvrtko Ursulin #include <linux/delay.h>
57b765cdaSTvrtko Ursulin
65a993507STvrtko Ursulin #include "sched_tests.h"
75a993507STvrtko Ursulin
89b9b5a36SMaíra Canal #define MOCK_TIMEOUT (HZ / 5)
99b9b5a36SMaíra Canal
105a993507STvrtko Ursulin /*
115a993507STvrtko Ursulin * DRM scheduler basic tests should check the basic functional correctness of
125a993507STvrtko Ursulin * the scheduler, including some very light smoke testing. More targeted tests,
135a993507STvrtko Ursulin * for example focusing on testing specific bugs and other more complicated test
145a993507STvrtko Ursulin * scenarios, should be implemented in separate source units.
155a993507STvrtko Ursulin */
165a993507STvrtko Ursulin
drm_sched_basic_init(struct kunit * test)175a993507STvrtko Ursulin static int drm_sched_basic_init(struct kunit *test)
185a993507STvrtko Ursulin {
1953e65974STvrtko Ursulin test->priv = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT);
205a993507STvrtko Ursulin
215a993507STvrtko Ursulin return 0;
225a993507STvrtko Ursulin }
235a993507STvrtko Ursulin
drm_sched_basic_exit(struct kunit * test)245a993507STvrtko Ursulin static void drm_sched_basic_exit(struct kunit *test)
255a993507STvrtko Ursulin {
265a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
275a993507STvrtko Ursulin
285a993507STvrtko Ursulin drm_mock_sched_fini(sched);
295a993507STvrtko Ursulin }
305a993507STvrtko Ursulin
drm_sched_timeout_init(struct kunit * test)3153e65974STvrtko Ursulin static int drm_sched_timeout_init(struct kunit *test)
3253e65974STvrtko Ursulin {
339b9b5a36SMaíra Canal test->priv = drm_mock_sched_new(test, MOCK_TIMEOUT);
3453e65974STvrtko Ursulin
3553e65974STvrtko Ursulin return 0;
3653e65974STvrtko Ursulin }
3753e65974STvrtko Ursulin
drm_sched_basic_submit(struct kunit * test)385a993507STvrtko Ursulin static void drm_sched_basic_submit(struct kunit *test)
395a993507STvrtko Ursulin {
405a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
415a993507STvrtko Ursulin struct drm_mock_sched_entity *entity;
425a993507STvrtko Ursulin struct drm_mock_sched_job *job;
435a993507STvrtko Ursulin unsigned int i;
445a993507STvrtko Ursulin bool done;
455a993507STvrtko Ursulin
465a993507STvrtko Ursulin /*
475a993507STvrtko Ursulin * Submit one job to the scheduler and verify that it gets scheduled
485a993507STvrtko Ursulin * and completed only when the mock hw backend processes it.
495a993507STvrtko Ursulin */
505a993507STvrtko Ursulin
515a993507STvrtko Ursulin entity = drm_mock_sched_entity_new(test,
525a993507STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL,
535a993507STvrtko Ursulin sched);
545a993507STvrtko Ursulin job = drm_mock_sched_job_new(test, entity);
555a993507STvrtko Ursulin
565a993507STvrtko Ursulin drm_mock_sched_job_submit(job);
575a993507STvrtko Ursulin
585a993507STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job, HZ);
595a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
605a993507STvrtko Ursulin
615a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ / 2);
625a993507STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done);
635a993507STvrtko Ursulin
645a993507STvrtko Ursulin i = drm_mock_sched_advance(sched, 1);
655a993507STvrtko Ursulin KUNIT_ASSERT_EQ(test, i, 1);
665a993507STvrtko Ursulin
675a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ);
685a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
695a993507STvrtko Ursulin
705a993507STvrtko Ursulin drm_mock_sched_entity_free(entity);
715a993507STvrtko Ursulin }
725a993507STvrtko Ursulin
735a993507STvrtko Ursulin struct drm_sched_basic_params {
745a993507STvrtko Ursulin const char *description;
755a993507STvrtko Ursulin unsigned int queue_depth;
765a993507STvrtko Ursulin unsigned int num_entities;
775a993507STvrtko Ursulin unsigned int job_us;
785a993507STvrtko Ursulin bool dep_chain;
795a993507STvrtko Ursulin };
805a993507STvrtko Ursulin
815a993507STvrtko Ursulin static const struct drm_sched_basic_params drm_sched_basic_cases[] = {
825a993507STvrtko Ursulin {
835a993507STvrtko Ursulin .description = "A queue of jobs in a single entity",
845a993507STvrtko Ursulin .queue_depth = 100,
855a993507STvrtko Ursulin .job_us = 1000,
865a993507STvrtko Ursulin .num_entities = 1,
875a993507STvrtko Ursulin },
885a993507STvrtko Ursulin {
895a993507STvrtko Ursulin .description = "A chain of dependent jobs across multiple entities",
905a993507STvrtko Ursulin .queue_depth = 100,
915a993507STvrtko Ursulin .job_us = 1000,
925a993507STvrtko Ursulin .num_entities = 1,
935a993507STvrtko Ursulin .dep_chain = true,
945a993507STvrtko Ursulin },
955a993507STvrtko Ursulin {
965a993507STvrtko Ursulin .description = "Multiple independent job queues",
975a993507STvrtko Ursulin .queue_depth = 100,
985a993507STvrtko Ursulin .job_us = 1000,
995a993507STvrtko Ursulin .num_entities = 4,
1005a993507STvrtko Ursulin },
1015a993507STvrtko Ursulin {
1025a993507STvrtko Ursulin .description = "Multiple inter-dependent job queues",
1035a993507STvrtko Ursulin .queue_depth = 100,
1045a993507STvrtko Ursulin .job_us = 1000,
1055a993507STvrtko Ursulin .num_entities = 4,
1065a993507STvrtko Ursulin .dep_chain = true,
1075a993507STvrtko Ursulin },
1085a993507STvrtko Ursulin };
1095a993507STvrtko Ursulin
1105a993507STvrtko Ursulin static void
drm_sched_basic_desc(const struct drm_sched_basic_params * params,char * desc)1115a993507STvrtko Ursulin drm_sched_basic_desc(const struct drm_sched_basic_params *params, char *desc)
1125a993507STvrtko Ursulin {
1135a993507STvrtko Ursulin strscpy(desc, params->description, KUNIT_PARAM_DESC_SIZE);
1145a993507STvrtko Ursulin }
1155a993507STvrtko Ursulin
1165a993507STvrtko Ursulin KUNIT_ARRAY_PARAM(drm_sched_basic, drm_sched_basic_cases, drm_sched_basic_desc);
1175a993507STvrtko Ursulin
drm_sched_basic_test(struct kunit * test)1185a993507STvrtko Ursulin static void drm_sched_basic_test(struct kunit *test)
1195a993507STvrtko Ursulin {
1205a993507STvrtko Ursulin const struct drm_sched_basic_params *params = test->param_value;
1215a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
1225a993507STvrtko Ursulin struct drm_mock_sched_job *job, *prev = NULL;
1235a993507STvrtko Ursulin struct drm_mock_sched_entity **entity;
1245a993507STvrtko Ursulin unsigned int i, cur_ent = 0;
1255a993507STvrtko Ursulin bool done;
1265a993507STvrtko Ursulin
1275a993507STvrtko Ursulin entity = kunit_kcalloc(test, params->num_entities, sizeof(*entity),
1285a993507STvrtko Ursulin GFP_KERNEL);
1295a993507STvrtko Ursulin KUNIT_ASSERT_NOT_NULL(test, entity);
1305a993507STvrtko Ursulin
1315a993507STvrtko Ursulin for (i = 0; i < params->num_entities; i++)
1325a993507STvrtko Ursulin entity[i] = drm_mock_sched_entity_new(test,
1335a993507STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL,
1345a993507STvrtko Ursulin sched);
1355a993507STvrtko Ursulin
1365a993507STvrtko Ursulin for (i = 0; i < params->queue_depth; i++) {
1375a993507STvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]);
1385a993507STvrtko Ursulin cur_ent %= params->num_entities;
1395a993507STvrtko Ursulin drm_mock_sched_job_set_duration_us(job, params->job_us);
1405a993507STvrtko Ursulin if (params->dep_chain && prev)
1415a993507STvrtko Ursulin drm_sched_job_add_dependency(&job->base,
1425a993507STvrtko Ursulin dma_fence_get(&prev->base.s_fence->finished));
1435a993507STvrtko Ursulin drm_mock_sched_job_submit(job);
1445a993507STvrtko Ursulin prev = job;
1455a993507STvrtko Ursulin }
1465a993507STvrtko Ursulin
1475a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ);
1485a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
1495a993507STvrtko Ursulin
1505a993507STvrtko Ursulin for (i = 0; i < params->num_entities; i++)
1515a993507STvrtko Ursulin drm_mock_sched_entity_free(entity[i]);
1525a993507STvrtko Ursulin }
1535a993507STvrtko Ursulin
drm_sched_basic_entity_cleanup(struct kunit * test)1545a993507STvrtko Ursulin static void drm_sched_basic_entity_cleanup(struct kunit *test)
1555a993507STvrtko Ursulin {
1565a993507STvrtko Ursulin struct drm_mock_sched_job *job, *mid, *prev = NULL;
1575a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
1585a993507STvrtko Ursulin struct drm_mock_sched_entity *entity[4];
1595a993507STvrtko Ursulin const unsigned int qd = 100;
1605a993507STvrtko Ursulin unsigned int i, cur_ent = 0;
1615a993507STvrtko Ursulin bool done;
1625a993507STvrtko Ursulin
1635a993507STvrtko Ursulin /*
1645a993507STvrtko Ursulin * Submit a queue of jobs across different entities with an explicit
1655a993507STvrtko Ursulin * chain of dependencies between them and trigger entity cleanup while
1665a993507STvrtko Ursulin * the queue is still being processed.
1675a993507STvrtko Ursulin */
1685a993507STvrtko Ursulin
1695a993507STvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++)
1705a993507STvrtko Ursulin entity[i] = drm_mock_sched_entity_new(test,
1715a993507STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL,
1725a993507STvrtko Ursulin sched);
1735a993507STvrtko Ursulin
1745a993507STvrtko Ursulin for (i = 0; i < qd; i++) {
1755a993507STvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]);
1765a993507STvrtko Ursulin cur_ent %= ARRAY_SIZE(entity);
1775a993507STvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000);
1785a993507STvrtko Ursulin if (prev)
1795a993507STvrtko Ursulin drm_sched_job_add_dependency(&job->base,
1805a993507STvrtko Ursulin dma_fence_get(&prev->base.s_fence->finished));
1815a993507STvrtko Ursulin drm_mock_sched_job_submit(job);
1825a993507STvrtko Ursulin if (i == qd / 2)
1835a993507STvrtko Ursulin mid = job;
1845a993507STvrtko Ursulin prev = job;
1855a993507STvrtko Ursulin }
1865a993507STvrtko Ursulin
1875a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(mid, HZ);
1885a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
1895a993507STvrtko Ursulin
1905a993507STvrtko Ursulin /* Exit with half of the queue still pending to be executed. */
1915a993507STvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++)
1925a993507STvrtko Ursulin drm_mock_sched_entity_free(entity[i]);
1935a993507STvrtko Ursulin }
1945a993507STvrtko Ursulin
1955a993507STvrtko Ursulin static struct kunit_case drm_sched_basic_tests[] = {
1965a993507STvrtko Ursulin KUNIT_CASE(drm_sched_basic_submit),
1975a993507STvrtko Ursulin KUNIT_CASE_PARAM(drm_sched_basic_test, drm_sched_basic_gen_params),
1985a993507STvrtko Ursulin KUNIT_CASE(drm_sched_basic_entity_cleanup),
1995a993507STvrtko Ursulin {}
2005a993507STvrtko Ursulin };
2015a993507STvrtko Ursulin
2025a993507STvrtko Ursulin static struct kunit_suite drm_sched_basic = {
2035a993507STvrtko Ursulin .name = "drm_sched_basic_tests",
2045a993507STvrtko Ursulin .init = drm_sched_basic_init,
2055a993507STvrtko Ursulin .exit = drm_sched_basic_exit,
2065a993507STvrtko Ursulin .test_cases = drm_sched_basic_tests,
2075a993507STvrtko Ursulin };
2085a993507STvrtko Ursulin
drm_sched_basic_cancel(struct kunit * test)209c2668a0eSPhilipp Stanner static void drm_sched_basic_cancel(struct kunit *test)
210c2668a0eSPhilipp Stanner {
211c2668a0eSPhilipp Stanner struct drm_mock_sched_entity *entity;
212c2668a0eSPhilipp Stanner struct drm_mock_scheduler *sched;
213c2668a0eSPhilipp Stanner struct drm_mock_sched_job *job;
214c2668a0eSPhilipp Stanner bool done;
215c2668a0eSPhilipp Stanner
216c2668a0eSPhilipp Stanner /*
217c2668a0eSPhilipp Stanner * Check that drm_sched_fini() uses the cancel_job() callback to cancel
218c2668a0eSPhilipp Stanner * jobs that are still pending.
219c2668a0eSPhilipp Stanner */
220c2668a0eSPhilipp Stanner
221c2668a0eSPhilipp Stanner sched = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT);
222c2668a0eSPhilipp Stanner entity = drm_mock_sched_entity_new(test, DRM_SCHED_PRIORITY_NORMAL,
223c2668a0eSPhilipp Stanner sched);
224c2668a0eSPhilipp Stanner
225c2668a0eSPhilipp Stanner job = drm_mock_sched_job_new(test, entity);
226c2668a0eSPhilipp Stanner
227c2668a0eSPhilipp Stanner drm_mock_sched_job_submit(job);
228c2668a0eSPhilipp Stanner
229c2668a0eSPhilipp Stanner done = drm_mock_sched_job_wait_scheduled(job, HZ);
230c2668a0eSPhilipp Stanner KUNIT_ASSERT_TRUE(test, done);
231c2668a0eSPhilipp Stanner
232c2668a0eSPhilipp Stanner drm_mock_sched_entity_free(entity);
233c2668a0eSPhilipp Stanner drm_mock_sched_fini(sched);
234c2668a0eSPhilipp Stanner
235c2668a0eSPhilipp Stanner KUNIT_ASSERT_EQ(test, job->hw_fence.error, -ECANCELED);
236c2668a0eSPhilipp Stanner }
237c2668a0eSPhilipp Stanner
238c2668a0eSPhilipp Stanner static struct kunit_case drm_sched_cancel_tests[] = {
239c2668a0eSPhilipp Stanner KUNIT_CASE(drm_sched_basic_cancel),
240c2668a0eSPhilipp Stanner {}
241c2668a0eSPhilipp Stanner };
242c2668a0eSPhilipp Stanner
243c2668a0eSPhilipp Stanner static struct kunit_suite drm_sched_cancel = {
244c2668a0eSPhilipp Stanner .name = "drm_sched_basic_cancel_tests",
245c2668a0eSPhilipp Stanner .init = drm_sched_basic_init,
246c2668a0eSPhilipp Stanner .exit = drm_sched_basic_exit,
247c2668a0eSPhilipp Stanner .test_cases = drm_sched_cancel_tests,
248c2668a0eSPhilipp Stanner };
249c2668a0eSPhilipp Stanner
drm_sched_basic_timeout(struct kunit * test)25053e65974STvrtko Ursulin static void drm_sched_basic_timeout(struct kunit *test)
25153e65974STvrtko Ursulin {
25253e65974STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
25353e65974STvrtko Ursulin struct drm_mock_sched_entity *entity;
25453e65974STvrtko Ursulin struct drm_mock_sched_job *job;
25553e65974STvrtko Ursulin bool done;
25653e65974STvrtko Ursulin
25753e65974STvrtko Ursulin /*
25853e65974STvrtko Ursulin * Submit a single job against a scheduler with the timeout configured
25953e65974STvrtko Ursulin * and verify that the timeout handling will run if the backend fails
26053e65974STvrtko Ursulin * to complete it in time.
26153e65974STvrtko Ursulin */
26253e65974STvrtko Ursulin
26353e65974STvrtko Ursulin entity = drm_mock_sched_entity_new(test,
26453e65974STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL,
26553e65974STvrtko Ursulin sched);
26653e65974STvrtko Ursulin job = drm_mock_sched_job_new(test, entity);
26753e65974STvrtko Ursulin
26853e65974STvrtko Ursulin drm_mock_sched_job_submit(job);
26953e65974STvrtko Ursulin
27053e65974STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job, HZ);
27153e65974STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
27253e65974STvrtko Ursulin
2739b9b5a36SMaíra Canal done = drm_mock_sched_job_wait_finished(job, MOCK_TIMEOUT / 2);
27453e65974STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done);
27553e65974STvrtko Ursulin
27653e65974STvrtko Ursulin KUNIT_ASSERT_EQ(test,
27753e65974STvrtko Ursulin job->flags & DRM_MOCK_SCHED_JOB_TIMEDOUT,
27853e65974STvrtko Ursulin 0);
27953e65974STvrtko Ursulin
2809b9b5a36SMaíra Canal done = drm_mock_sched_job_wait_finished(job, MOCK_TIMEOUT);
28153e65974STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done);
28253e65974STvrtko Ursulin
28353e65974STvrtko Ursulin KUNIT_ASSERT_EQ(test,
28453e65974STvrtko Ursulin job->flags & DRM_MOCK_SCHED_JOB_TIMEDOUT,
28553e65974STvrtko Ursulin DRM_MOCK_SCHED_JOB_TIMEDOUT);
28653e65974STvrtko Ursulin
28753e65974STvrtko Ursulin drm_mock_sched_entity_free(entity);
28853e65974STvrtko Ursulin }
28953e65974STvrtko Ursulin
drm_sched_skip_reset(struct kunit * test)290*1472e754SMaíra Canal static void drm_sched_skip_reset(struct kunit *test)
291*1472e754SMaíra Canal {
292*1472e754SMaíra Canal struct drm_mock_scheduler *sched = test->priv;
293*1472e754SMaíra Canal struct drm_mock_sched_entity *entity;
294*1472e754SMaíra Canal struct drm_mock_sched_job *job;
295*1472e754SMaíra Canal unsigned int i;
296*1472e754SMaíra Canal bool done;
297*1472e754SMaíra Canal
298*1472e754SMaíra Canal /*
299*1472e754SMaíra Canal * Submit a single job against a scheduler with the timeout configured
300*1472e754SMaíra Canal * and verify that if the job is still running, the timeout handler
301*1472e754SMaíra Canal * will skip the reset and allow the job to complete.
302*1472e754SMaíra Canal */
303*1472e754SMaíra Canal
304*1472e754SMaíra Canal entity = drm_mock_sched_entity_new(test,
305*1472e754SMaíra Canal DRM_SCHED_PRIORITY_NORMAL,
306*1472e754SMaíra Canal sched);
307*1472e754SMaíra Canal job = drm_mock_sched_job_new(test, entity);
308*1472e754SMaíra Canal
309*1472e754SMaíra Canal job->flags = DRM_MOCK_SCHED_JOB_DONT_RESET;
310*1472e754SMaíra Canal
311*1472e754SMaíra Canal drm_mock_sched_job_submit(job);
312*1472e754SMaíra Canal
313*1472e754SMaíra Canal done = drm_mock_sched_job_wait_scheduled(job, HZ);
314*1472e754SMaíra Canal KUNIT_ASSERT_TRUE(test, done);
315*1472e754SMaíra Canal
316*1472e754SMaíra Canal done = drm_mock_sched_job_wait_finished(job, 2 * MOCK_TIMEOUT);
317*1472e754SMaíra Canal KUNIT_ASSERT_FALSE(test, done);
318*1472e754SMaíra Canal
319*1472e754SMaíra Canal KUNIT_ASSERT_EQ(test,
320*1472e754SMaíra Canal job->flags & DRM_MOCK_SCHED_JOB_DONT_RESET,
321*1472e754SMaíra Canal 0);
322*1472e754SMaíra Canal
323*1472e754SMaíra Canal i = drm_mock_sched_advance(sched, 1);
324*1472e754SMaíra Canal KUNIT_ASSERT_EQ(test, i, 1);
325*1472e754SMaíra Canal
326*1472e754SMaíra Canal done = drm_mock_sched_job_wait_finished(job, HZ);
327*1472e754SMaíra Canal KUNIT_ASSERT_TRUE(test, done);
328*1472e754SMaíra Canal
329*1472e754SMaíra Canal drm_mock_sched_entity_free(entity);
330*1472e754SMaíra Canal }
331*1472e754SMaíra Canal
33253e65974STvrtko Ursulin static struct kunit_case drm_sched_timeout_tests[] = {
33353e65974STvrtko Ursulin KUNIT_CASE(drm_sched_basic_timeout),
334*1472e754SMaíra Canal KUNIT_CASE(drm_sched_skip_reset),
33553e65974STvrtko Ursulin {}
33653e65974STvrtko Ursulin };
33753e65974STvrtko Ursulin
33853e65974STvrtko Ursulin static struct kunit_suite drm_sched_timeout = {
33953e65974STvrtko Ursulin .name = "drm_sched_basic_timeout_tests",
34053e65974STvrtko Ursulin .init = drm_sched_timeout_init,
34153e65974STvrtko Ursulin .exit = drm_sched_basic_exit,
34253e65974STvrtko Ursulin .test_cases = drm_sched_timeout_tests,
34353e65974STvrtko Ursulin };
34453e65974STvrtko Ursulin
drm_sched_priorities(struct kunit * test)3457b765cdaSTvrtko Ursulin static void drm_sched_priorities(struct kunit *test)
3467b765cdaSTvrtko Ursulin {
3477b765cdaSTvrtko Ursulin struct drm_mock_sched_entity *entity[DRM_SCHED_PRIORITY_COUNT];
3487b765cdaSTvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
3497b765cdaSTvrtko Ursulin struct drm_mock_sched_job *job;
3507b765cdaSTvrtko Ursulin const unsigned int qd = 100;
3517b765cdaSTvrtko Ursulin unsigned int i, cur_ent = 0;
3527b765cdaSTvrtko Ursulin enum drm_sched_priority p;
3537b765cdaSTvrtko Ursulin bool done;
3547b765cdaSTvrtko Ursulin
3557b765cdaSTvrtko Ursulin /*
3567b765cdaSTvrtko Ursulin * Submit a bunch of jobs against entities configured with different
3577b765cdaSTvrtko Ursulin * priorities.
3587b765cdaSTvrtko Ursulin */
3597b765cdaSTvrtko Ursulin
3607b765cdaSTvrtko Ursulin BUILD_BUG_ON(DRM_SCHED_PRIORITY_KERNEL > DRM_SCHED_PRIORITY_LOW);
3617b765cdaSTvrtko Ursulin BUILD_BUG_ON(ARRAY_SIZE(entity) != DRM_SCHED_PRIORITY_COUNT);
3627b765cdaSTvrtko Ursulin
3637b765cdaSTvrtko Ursulin for (p = DRM_SCHED_PRIORITY_KERNEL; p <= DRM_SCHED_PRIORITY_LOW; p++)
3647b765cdaSTvrtko Ursulin entity[p] = drm_mock_sched_entity_new(test, p, sched);
3657b765cdaSTvrtko Ursulin
3667b765cdaSTvrtko Ursulin for (i = 0; i < qd; i++) {
3677b765cdaSTvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]);
3687b765cdaSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity);
3697b765cdaSTvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000);
3707b765cdaSTvrtko Ursulin drm_mock_sched_job_submit(job);
3717b765cdaSTvrtko Ursulin }
3727b765cdaSTvrtko Ursulin
3737b765cdaSTvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ);
3747b765cdaSTvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
3757b765cdaSTvrtko Ursulin
3767b765cdaSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++)
3777b765cdaSTvrtko Ursulin drm_mock_sched_entity_free(entity[i]);
3787b765cdaSTvrtko Ursulin }
3797b765cdaSTvrtko Ursulin
drm_sched_change_priority(struct kunit * test)3807b765cdaSTvrtko Ursulin static void drm_sched_change_priority(struct kunit *test)
3817b765cdaSTvrtko Ursulin {
3827b765cdaSTvrtko Ursulin struct drm_mock_sched_entity *entity[DRM_SCHED_PRIORITY_COUNT];
3837b765cdaSTvrtko Ursulin struct drm_mock_scheduler *sched = test->priv;
3847b765cdaSTvrtko Ursulin struct drm_mock_sched_job *job;
3857b765cdaSTvrtko Ursulin const unsigned int qd = 1000;
3867b765cdaSTvrtko Ursulin unsigned int i, cur_ent = 0;
3877b765cdaSTvrtko Ursulin enum drm_sched_priority p;
3887b765cdaSTvrtko Ursulin
3897b765cdaSTvrtko Ursulin /*
3907b765cdaSTvrtko Ursulin * Submit a bunch of jobs against entities configured with different
3917b765cdaSTvrtko Ursulin * priorities and while waiting for them to complete, periodically keep
3927b765cdaSTvrtko Ursulin * changing their priorities.
3937b765cdaSTvrtko Ursulin *
3947b765cdaSTvrtko Ursulin * We set up the queue-depth (qd) and job duration so the priority
3957b765cdaSTvrtko Ursulin * changing loop has some time to interact with submissions to the
3967b765cdaSTvrtko Ursulin * backend and job completions as they progress.
3977b765cdaSTvrtko Ursulin */
3987b765cdaSTvrtko Ursulin
3997b765cdaSTvrtko Ursulin for (p = DRM_SCHED_PRIORITY_KERNEL; p <= DRM_SCHED_PRIORITY_LOW; p++)
4007b765cdaSTvrtko Ursulin entity[p] = drm_mock_sched_entity_new(test, p, sched);
4017b765cdaSTvrtko Ursulin
4027b765cdaSTvrtko Ursulin for (i = 0; i < qd; i++) {
4037b765cdaSTvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]);
4047b765cdaSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity);
4057b765cdaSTvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000);
4067b765cdaSTvrtko Ursulin drm_mock_sched_job_submit(job);
4077b765cdaSTvrtko Ursulin }
4087b765cdaSTvrtko Ursulin
4097b765cdaSTvrtko Ursulin do {
4107b765cdaSTvrtko Ursulin drm_sched_entity_set_priority(&entity[cur_ent]->base,
4117b765cdaSTvrtko Ursulin (entity[cur_ent]->base.priority + 1) %
4127b765cdaSTvrtko Ursulin DRM_SCHED_PRIORITY_COUNT);
4137b765cdaSTvrtko Ursulin cur_ent++;
4147b765cdaSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity);
4157b765cdaSTvrtko Ursulin usleep_range(200, 500);
4167b765cdaSTvrtko Ursulin } while (!drm_mock_sched_job_is_finished(job));
4177b765cdaSTvrtko Ursulin
4187b765cdaSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++)
4197b765cdaSTvrtko Ursulin drm_mock_sched_entity_free(entity[i]);
4207b765cdaSTvrtko Ursulin }
4217b765cdaSTvrtko Ursulin
4227b765cdaSTvrtko Ursulin static struct kunit_case drm_sched_priority_tests[] = {
4237b765cdaSTvrtko Ursulin KUNIT_CASE(drm_sched_priorities),
4247b765cdaSTvrtko Ursulin KUNIT_CASE(drm_sched_change_priority),
4257b765cdaSTvrtko Ursulin {}
4267b765cdaSTvrtko Ursulin };
4277b765cdaSTvrtko Ursulin
4287b765cdaSTvrtko Ursulin static struct kunit_suite drm_sched_priority = {
4297b765cdaSTvrtko Ursulin .name = "drm_sched_basic_priority_tests",
4307b765cdaSTvrtko Ursulin .init = drm_sched_basic_init,
4317b765cdaSTvrtko Ursulin .exit = drm_sched_basic_exit,
4327b765cdaSTvrtko Ursulin .test_cases = drm_sched_priority_tests,
4337b765cdaSTvrtko Ursulin };
4347b765cdaSTvrtko Ursulin
drm_sched_test_modify_sched(struct kunit * test)435c85fc5dbSTvrtko Ursulin static void drm_sched_test_modify_sched(struct kunit *test)
436c85fc5dbSTvrtko Ursulin {
437c85fc5dbSTvrtko Ursulin unsigned int i, cur_ent = 0, cur_sched = 0;
438c85fc5dbSTvrtko Ursulin struct drm_mock_sched_entity *entity[13];
439c85fc5dbSTvrtko Ursulin struct drm_mock_scheduler *sched[3];
440c85fc5dbSTvrtko Ursulin struct drm_mock_sched_job *job;
441c85fc5dbSTvrtko Ursulin const unsigned int qd = 1000;
442c85fc5dbSTvrtko Ursulin
443c85fc5dbSTvrtko Ursulin /*
444c85fc5dbSTvrtko Ursulin * Submit a bunch of jobs against entities configured with different
445c85fc5dbSTvrtko Ursulin * schedulers and while waiting for them to complete, periodically keep
446c85fc5dbSTvrtko Ursulin * changing schedulers associated with each entity.
447c85fc5dbSTvrtko Ursulin *
448c85fc5dbSTvrtko Ursulin * We set up the queue-depth (qd) and job duration so the sched modify
449c85fc5dbSTvrtko Ursulin * loop has some time to interact with submissions to the backend and
450c85fc5dbSTvrtko Ursulin * job completions as they progress.
451c85fc5dbSTvrtko Ursulin *
452c85fc5dbSTvrtko Ursulin * For the number of schedulers and entities we use primes in order to
453c85fc5dbSTvrtko Ursulin * perturb the entity->sched assignments with less of a regular pattern.
454c85fc5dbSTvrtko Ursulin */
455c85fc5dbSTvrtko Ursulin
456c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(sched); i++)
457c85fc5dbSTvrtko Ursulin sched[i] = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT);
458c85fc5dbSTvrtko Ursulin
459c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++)
460c85fc5dbSTvrtko Ursulin entity[i] = drm_mock_sched_entity_new(test,
461c85fc5dbSTvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL,
462c85fc5dbSTvrtko Ursulin sched[i % ARRAY_SIZE(sched)]);
463c85fc5dbSTvrtko Ursulin
464c85fc5dbSTvrtko Ursulin for (i = 0; i < qd; i++) {
465c85fc5dbSTvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]);
466c85fc5dbSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity);
467c85fc5dbSTvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000);
468c85fc5dbSTvrtko Ursulin drm_mock_sched_job_submit(job);
469c85fc5dbSTvrtko Ursulin }
470c85fc5dbSTvrtko Ursulin
471c85fc5dbSTvrtko Ursulin do {
472c85fc5dbSTvrtko Ursulin struct drm_gpu_scheduler *modify;
473c85fc5dbSTvrtko Ursulin
474c85fc5dbSTvrtko Ursulin usleep_range(200, 500);
475c85fc5dbSTvrtko Ursulin cur_ent++;
476c85fc5dbSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity);
477c85fc5dbSTvrtko Ursulin cur_sched++;
478c85fc5dbSTvrtko Ursulin cur_sched %= ARRAY_SIZE(sched);
479c85fc5dbSTvrtko Ursulin modify = &sched[cur_sched]->base;
480c85fc5dbSTvrtko Ursulin drm_sched_entity_modify_sched(&entity[cur_ent]->base, &modify,
481c85fc5dbSTvrtko Ursulin 1);
482c85fc5dbSTvrtko Ursulin } while (!drm_mock_sched_job_is_finished(job));
483c85fc5dbSTvrtko Ursulin
484c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++)
485c85fc5dbSTvrtko Ursulin drm_mock_sched_entity_free(entity[i]);
486c85fc5dbSTvrtko Ursulin
487c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(sched); i++)
488c85fc5dbSTvrtko Ursulin drm_mock_sched_fini(sched[i]);
489c85fc5dbSTvrtko Ursulin }
490c85fc5dbSTvrtko Ursulin
491c85fc5dbSTvrtko Ursulin static struct kunit_case drm_sched_modify_sched_tests[] = {
492c85fc5dbSTvrtko Ursulin KUNIT_CASE(drm_sched_test_modify_sched),
493c85fc5dbSTvrtko Ursulin {}
494c85fc5dbSTvrtko Ursulin };
495c85fc5dbSTvrtko Ursulin
496c85fc5dbSTvrtko Ursulin static struct kunit_suite drm_sched_modify_sched = {
497c85fc5dbSTvrtko Ursulin .name = "drm_sched_basic_modify_sched_tests",
498c85fc5dbSTvrtko Ursulin .test_cases = drm_sched_modify_sched_tests,
499c85fc5dbSTvrtko Ursulin };
500c85fc5dbSTvrtko Ursulin
drm_sched_test_credits(struct kunit * test)501909bda22STvrtko Ursulin static void drm_sched_test_credits(struct kunit *test)
502909bda22STvrtko Ursulin {
503909bda22STvrtko Ursulin struct drm_mock_sched_entity *entity;
504909bda22STvrtko Ursulin struct drm_mock_scheduler *sched;
505909bda22STvrtko Ursulin struct drm_mock_sched_job *job[2];
506909bda22STvrtko Ursulin bool done;
507909bda22STvrtko Ursulin int i;
508909bda22STvrtko Ursulin
509909bda22STvrtko Ursulin /*
510909bda22STvrtko Ursulin * Check that the configured credit limit is respected.
511909bda22STvrtko Ursulin */
512909bda22STvrtko Ursulin
513909bda22STvrtko Ursulin sched = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT);
514909bda22STvrtko Ursulin sched->base.credit_limit = 1;
515909bda22STvrtko Ursulin
516909bda22STvrtko Ursulin entity = drm_mock_sched_entity_new(test,
517909bda22STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL,
518909bda22STvrtko Ursulin sched);
519909bda22STvrtko Ursulin
520909bda22STvrtko Ursulin job[0] = drm_mock_sched_job_new(test, entity);
521909bda22STvrtko Ursulin job[1] = drm_mock_sched_job_new(test, entity);
522909bda22STvrtko Ursulin
523909bda22STvrtko Ursulin drm_mock_sched_job_submit(job[0]);
524909bda22STvrtko Ursulin drm_mock_sched_job_submit(job[1]);
525909bda22STvrtko Ursulin
526909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job[0], HZ);
527909bda22STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
528909bda22STvrtko Ursulin
529909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job[1], HZ);
530909bda22STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done);
531909bda22STvrtko Ursulin
532909bda22STvrtko Ursulin i = drm_mock_sched_advance(sched, 1);
533909bda22STvrtko Ursulin KUNIT_ASSERT_EQ(test, i, 1);
534909bda22STvrtko Ursulin
535909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job[1], HZ);
536909bda22STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
537909bda22STvrtko Ursulin
538909bda22STvrtko Ursulin i = drm_mock_sched_advance(sched, 1);
539909bda22STvrtko Ursulin KUNIT_ASSERT_EQ(test, i, 1);
540909bda22STvrtko Ursulin
541909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job[1], HZ);
542909bda22STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done);
543909bda22STvrtko Ursulin
544909bda22STvrtko Ursulin drm_mock_sched_entity_free(entity);
545909bda22STvrtko Ursulin drm_mock_sched_fini(sched);
546909bda22STvrtko Ursulin }
547909bda22STvrtko Ursulin
548909bda22STvrtko Ursulin static struct kunit_case drm_sched_credits_tests[] = {
549909bda22STvrtko Ursulin KUNIT_CASE(drm_sched_test_credits),
550909bda22STvrtko Ursulin {}
551909bda22STvrtko Ursulin };
552909bda22STvrtko Ursulin
553909bda22STvrtko Ursulin static struct kunit_suite drm_sched_credits = {
554909bda22STvrtko Ursulin .name = "drm_sched_basic_credits_tests",
555909bda22STvrtko Ursulin .test_cases = drm_sched_credits_tests,
556909bda22STvrtko Ursulin };
557909bda22STvrtko Ursulin
55853e65974STvrtko Ursulin kunit_test_suites(&drm_sched_basic,
5597b765cdaSTvrtko Ursulin &drm_sched_timeout,
560c2668a0eSPhilipp Stanner &drm_sched_cancel,
561c85fc5dbSTvrtko Ursulin &drm_sched_priority,
562909bda22STvrtko Ursulin &drm_sched_modify_sched,
563909bda22STvrtko Ursulin &drm_sched_credits);
564