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 85a993507STvrtko Ursulin /* 95a993507STvrtko Ursulin * DRM scheduler basic tests should check the basic functional correctness of 105a993507STvrtko Ursulin * the scheduler, including some very light smoke testing. More targeted tests, 115a993507STvrtko Ursulin * for example focusing on testing specific bugs and other more complicated test 125a993507STvrtko Ursulin * scenarios, should be implemented in separate source units. 135a993507STvrtko Ursulin */ 145a993507STvrtko Ursulin 155a993507STvrtko Ursulin static int drm_sched_basic_init(struct kunit *test) 165a993507STvrtko Ursulin { 1753e65974STvrtko Ursulin test->priv = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT); 185a993507STvrtko Ursulin 195a993507STvrtko Ursulin return 0; 205a993507STvrtko Ursulin } 215a993507STvrtko Ursulin 225a993507STvrtko Ursulin static void drm_sched_basic_exit(struct kunit *test) 235a993507STvrtko Ursulin { 245a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 255a993507STvrtko Ursulin 265a993507STvrtko Ursulin drm_mock_sched_fini(sched); 275a993507STvrtko Ursulin } 285a993507STvrtko Ursulin 2953e65974STvrtko Ursulin static int drm_sched_timeout_init(struct kunit *test) 3053e65974STvrtko Ursulin { 3153e65974STvrtko Ursulin test->priv = drm_mock_sched_new(test, HZ); 3253e65974STvrtko Ursulin 3353e65974STvrtko Ursulin return 0; 3453e65974STvrtko Ursulin } 3553e65974STvrtko Ursulin 365a993507STvrtko Ursulin static void drm_sched_basic_submit(struct kunit *test) 375a993507STvrtko Ursulin { 385a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 395a993507STvrtko Ursulin struct drm_mock_sched_entity *entity; 405a993507STvrtko Ursulin struct drm_mock_sched_job *job; 415a993507STvrtko Ursulin unsigned int i; 425a993507STvrtko Ursulin bool done; 435a993507STvrtko Ursulin 445a993507STvrtko Ursulin /* 455a993507STvrtko Ursulin * Submit one job to the scheduler and verify that it gets scheduled 465a993507STvrtko Ursulin * and completed only when the mock hw backend processes it. 475a993507STvrtko Ursulin */ 485a993507STvrtko Ursulin 495a993507STvrtko Ursulin entity = drm_mock_sched_entity_new(test, 505a993507STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL, 515a993507STvrtko Ursulin sched); 525a993507STvrtko Ursulin job = drm_mock_sched_job_new(test, entity); 535a993507STvrtko Ursulin 545a993507STvrtko Ursulin drm_mock_sched_job_submit(job); 555a993507STvrtko Ursulin 565a993507STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job, HZ); 575a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 585a993507STvrtko Ursulin 595a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ / 2); 605a993507STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done); 615a993507STvrtko Ursulin 625a993507STvrtko Ursulin i = drm_mock_sched_advance(sched, 1); 635a993507STvrtko Ursulin KUNIT_ASSERT_EQ(test, i, 1); 645a993507STvrtko Ursulin 655a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ); 665a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 675a993507STvrtko Ursulin 685a993507STvrtko Ursulin drm_mock_sched_entity_free(entity); 695a993507STvrtko Ursulin } 705a993507STvrtko Ursulin 715a993507STvrtko Ursulin struct drm_sched_basic_params { 725a993507STvrtko Ursulin const char *description; 735a993507STvrtko Ursulin unsigned int queue_depth; 745a993507STvrtko Ursulin unsigned int num_entities; 755a993507STvrtko Ursulin unsigned int job_us; 765a993507STvrtko Ursulin bool dep_chain; 775a993507STvrtko Ursulin }; 785a993507STvrtko Ursulin 795a993507STvrtko Ursulin static const struct drm_sched_basic_params drm_sched_basic_cases[] = { 805a993507STvrtko Ursulin { 815a993507STvrtko Ursulin .description = "A queue of jobs in a single entity", 825a993507STvrtko Ursulin .queue_depth = 100, 835a993507STvrtko Ursulin .job_us = 1000, 845a993507STvrtko Ursulin .num_entities = 1, 855a993507STvrtko Ursulin }, 865a993507STvrtko Ursulin { 875a993507STvrtko Ursulin .description = "A chain of dependent jobs across multiple entities", 885a993507STvrtko Ursulin .queue_depth = 100, 895a993507STvrtko Ursulin .job_us = 1000, 905a993507STvrtko Ursulin .num_entities = 1, 915a993507STvrtko Ursulin .dep_chain = true, 925a993507STvrtko Ursulin }, 935a993507STvrtko Ursulin { 945a993507STvrtko Ursulin .description = "Multiple independent job queues", 955a993507STvrtko Ursulin .queue_depth = 100, 965a993507STvrtko Ursulin .job_us = 1000, 975a993507STvrtko Ursulin .num_entities = 4, 985a993507STvrtko Ursulin }, 995a993507STvrtko Ursulin { 1005a993507STvrtko Ursulin .description = "Multiple inter-dependent job queues", 1015a993507STvrtko Ursulin .queue_depth = 100, 1025a993507STvrtko Ursulin .job_us = 1000, 1035a993507STvrtko Ursulin .num_entities = 4, 1045a993507STvrtko Ursulin .dep_chain = true, 1055a993507STvrtko Ursulin }, 1065a993507STvrtko Ursulin }; 1075a993507STvrtko Ursulin 1085a993507STvrtko Ursulin static void 1095a993507STvrtko Ursulin drm_sched_basic_desc(const struct drm_sched_basic_params *params, char *desc) 1105a993507STvrtko Ursulin { 1115a993507STvrtko Ursulin strscpy(desc, params->description, KUNIT_PARAM_DESC_SIZE); 1125a993507STvrtko Ursulin } 1135a993507STvrtko Ursulin 1145a993507STvrtko Ursulin KUNIT_ARRAY_PARAM(drm_sched_basic, drm_sched_basic_cases, drm_sched_basic_desc); 1155a993507STvrtko Ursulin 1165a993507STvrtko Ursulin static void drm_sched_basic_test(struct kunit *test) 1175a993507STvrtko Ursulin { 1185a993507STvrtko Ursulin const struct drm_sched_basic_params *params = test->param_value; 1195a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 1205a993507STvrtko Ursulin struct drm_mock_sched_job *job, *prev = NULL; 1215a993507STvrtko Ursulin struct drm_mock_sched_entity **entity; 1225a993507STvrtko Ursulin unsigned int i, cur_ent = 0; 1235a993507STvrtko Ursulin bool done; 1245a993507STvrtko Ursulin 1255a993507STvrtko Ursulin entity = kunit_kcalloc(test, params->num_entities, sizeof(*entity), 1265a993507STvrtko Ursulin GFP_KERNEL); 1275a993507STvrtko Ursulin KUNIT_ASSERT_NOT_NULL(test, entity); 1285a993507STvrtko Ursulin 1295a993507STvrtko Ursulin for (i = 0; i < params->num_entities; i++) 1305a993507STvrtko Ursulin entity[i] = drm_mock_sched_entity_new(test, 1315a993507STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL, 1325a993507STvrtko Ursulin sched); 1335a993507STvrtko Ursulin 1345a993507STvrtko Ursulin for (i = 0; i < params->queue_depth; i++) { 1355a993507STvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]); 1365a993507STvrtko Ursulin cur_ent %= params->num_entities; 1375a993507STvrtko Ursulin drm_mock_sched_job_set_duration_us(job, params->job_us); 1385a993507STvrtko Ursulin if (params->dep_chain && prev) 1395a993507STvrtko Ursulin drm_sched_job_add_dependency(&job->base, 1405a993507STvrtko Ursulin dma_fence_get(&prev->base.s_fence->finished)); 1415a993507STvrtko Ursulin drm_mock_sched_job_submit(job); 1425a993507STvrtko Ursulin prev = job; 1435a993507STvrtko Ursulin } 1445a993507STvrtko Ursulin 1455a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ); 1465a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 1475a993507STvrtko Ursulin 1485a993507STvrtko Ursulin for (i = 0; i < params->num_entities; i++) 1495a993507STvrtko Ursulin drm_mock_sched_entity_free(entity[i]); 1505a993507STvrtko Ursulin } 1515a993507STvrtko Ursulin 1525a993507STvrtko Ursulin static void drm_sched_basic_entity_cleanup(struct kunit *test) 1535a993507STvrtko Ursulin { 1545a993507STvrtko Ursulin struct drm_mock_sched_job *job, *mid, *prev = NULL; 1555a993507STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 1565a993507STvrtko Ursulin struct drm_mock_sched_entity *entity[4]; 1575a993507STvrtko Ursulin const unsigned int qd = 100; 1585a993507STvrtko Ursulin unsigned int i, cur_ent = 0; 1595a993507STvrtko Ursulin bool done; 1605a993507STvrtko Ursulin 1615a993507STvrtko Ursulin /* 1625a993507STvrtko Ursulin * Submit a queue of jobs across different entities with an explicit 1635a993507STvrtko Ursulin * chain of dependencies between them and trigger entity cleanup while 1645a993507STvrtko Ursulin * the queue is still being processed. 1655a993507STvrtko Ursulin */ 1665a993507STvrtko Ursulin 1675a993507STvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++) 1685a993507STvrtko Ursulin entity[i] = drm_mock_sched_entity_new(test, 1695a993507STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL, 1705a993507STvrtko Ursulin sched); 1715a993507STvrtko Ursulin 1725a993507STvrtko Ursulin for (i = 0; i < qd; i++) { 1735a993507STvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]); 1745a993507STvrtko Ursulin cur_ent %= ARRAY_SIZE(entity); 1755a993507STvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000); 1765a993507STvrtko Ursulin if (prev) 1775a993507STvrtko Ursulin drm_sched_job_add_dependency(&job->base, 1785a993507STvrtko Ursulin dma_fence_get(&prev->base.s_fence->finished)); 1795a993507STvrtko Ursulin drm_mock_sched_job_submit(job); 1805a993507STvrtko Ursulin if (i == qd / 2) 1815a993507STvrtko Ursulin mid = job; 1825a993507STvrtko Ursulin prev = job; 1835a993507STvrtko Ursulin } 1845a993507STvrtko Ursulin 1855a993507STvrtko Ursulin done = drm_mock_sched_job_wait_finished(mid, HZ); 1865a993507STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 1875a993507STvrtko Ursulin 1885a993507STvrtko Ursulin /* Exit with half of the queue still pending to be executed. */ 1895a993507STvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++) 1905a993507STvrtko Ursulin drm_mock_sched_entity_free(entity[i]); 1915a993507STvrtko Ursulin } 1925a993507STvrtko Ursulin 1935a993507STvrtko Ursulin static struct kunit_case drm_sched_basic_tests[] = { 1945a993507STvrtko Ursulin KUNIT_CASE(drm_sched_basic_submit), 1955a993507STvrtko Ursulin KUNIT_CASE_PARAM(drm_sched_basic_test, drm_sched_basic_gen_params), 1965a993507STvrtko Ursulin KUNIT_CASE(drm_sched_basic_entity_cleanup), 1975a993507STvrtko Ursulin {} 1985a993507STvrtko Ursulin }; 1995a993507STvrtko Ursulin 2005a993507STvrtko Ursulin static struct kunit_suite drm_sched_basic = { 2015a993507STvrtko Ursulin .name = "drm_sched_basic_tests", 2025a993507STvrtko Ursulin .init = drm_sched_basic_init, 2035a993507STvrtko Ursulin .exit = drm_sched_basic_exit, 2045a993507STvrtko Ursulin .test_cases = drm_sched_basic_tests, 2055a993507STvrtko Ursulin }; 2065a993507STvrtko Ursulin 20753e65974STvrtko Ursulin static void drm_sched_basic_timeout(struct kunit *test) 20853e65974STvrtko Ursulin { 20953e65974STvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 21053e65974STvrtko Ursulin struct drm_mock_sched_entity *entity; 21153e65974STvrtko Ursulin struct drm_mock_sched_job *job; 21253e65974STvrtko Ursulin bool done; 21353e65974STvrtko Ursulin 21453e65974STvrtko Ursulin /* 21553e65974STvrtko Ursulin * Submit a single job against a scheduler with the timeout configured 21653e65974STvrtko Ursulin * and verify that the timeout handling will run if the backend fails 21753e65974STvrtko Ursulin * to complete it in time. 21853e65974STvrtko Ursulin */ 21953e65974STvrtko Ursulin 22053e65974STvrtko Ursulin entity = drm_mock_sched_entity_new(test, 22153e65974STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL, 22253e65974STvrtko Ursulin sched); 22353e65974STvrtko Ursulin job = drm_mock_sched_job_new(test, entity); 22453e65974STvrtko Ursulin 22553e65974STvrtko Ursulin drm_mock_sched_job_submit(job); 22653e65974STvrtko Ursulin 22753e65974STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job, HZ); 22853e65974STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 22953e65974STvrtko Ursulin 23053e65974STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ / 2); 23153e65974STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done); 23253e65974STvrtko Ursulin 23353e65974STvrtko Ursulin KUNIT_ASSERT_EQ(test, 23453e65974STvrtko Ursulin job->flags & DRM_MOCK_SCHED_JOB_TIMEDOUT, 23553e65974STvrtko Ursulin 0); 23653e65974STvrtko Ursulin 23753e65974STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ); 23853e65974STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done); 23953e65974STvrtko Ursulin 24053e65974STvrtko Ursulin KUNIT_ASSERT_EQ(test, 24153e65974STvrtko Ursulin job->flags & DRM_MOCK_SCHED_JOB_TIMEDOUT, 24253e65974STvrtko Ursulin DRM_MOCK_SCHED_JOB_TIMEDOUT); 24353e65974STvrtko Ursulin 24453e65974STvrtko Ursulin drm_mock_sched_entity_free(entity); 24553e65974STvrtko Ursulin } 24653e65974STvrtko Ursulin 24753e65974STvrtko Ursulin static struct kunit_case drm_sched_timeout_tests[] = { 24853e65974STvrtko Ursulin KUNIT_CASE(drm_sched_basic_timeout), 24953e65974STvrtko Ursulin {} 25053e65974STvrtko Ursulin }; 25153e65974STvrtko Ursulin 25253e65974STvrtko Ursulin static struct kunit_suite drm_sched_timeout = { 25353e65974STvrtko Ursulin .name = "drm_sched_basic_timeout_tests", 25453e65974STvrtko Ursulin .init = drm_sched_timeout_init, 25553e65974STvrtko Ursulin .exit = drm_sched_basic_exit, 25653e65974STvrtko Ursulin .test_cases = drm_sched_timeout_tests, 25753e65974STvrtko Ursulin }; 25853e65974STvrtko Ursulin 2597b765cdaSTvrtko Ursulin static void drm_sched_priorities(struct kunit *test) 2607b765cdaSTvrtko Ursulin { 2617b765cdaSTvrtko Ursulin struct drm_mock_sched_entity *entity[DRM_SCHED_PRIORITY_COUNT]; 2627b765cdaSTvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 2637b765cdaSTvrtko Ursulin struct drm_mock_sched_job *job; 2647b765cdaSTvrtko Ursulin const unsigned int qd = 100; 2657b765cdaSTvrtko Ursulin unsigned int i, cur_ent = 0; 2667b765cdaSTvrtko Ursulin enum drm_sched_priority p; 2677b765cdaSTvrtko Ursulin bool done; 2687b765cdaSTvrtko Ursulin 2697b765cdaSTvrtko Ursulin /* 2707b765cdaSTvrtko Ursulin * Submit a bunch of jobs against entities configured with different 2717b765cdaSTvrtko Ursulin * priorities. 2727b765cdaSTvrtko Ursulin */ 2737b765cdaSTvrtko Ursulin 2747b765cdaSTvrtko Ursulin BUILD_BUG_ON(DRM_SCHED_PRIORITY_KERNEL > DRM_SCHED_PRIORITY_LOW); 2757b765cdaSTvrtko Ursulin BUILD_BUG_ON(ARRAY_SIZE(entity) != DRM_SCHED_PRIORITY_COUNT); 2767b765cdaSTvrtko Ursulin 2777b765cdaSTvrtko Ursulin for (p = DRM_SCHED_PRIORITY_KERNEL; p <= DRM_SCHED_PRIORITY_LOW; p++) 2787b765cdaSTvrtko Ursulin entity[p] = drm_mock_sched_entity_new(test, p, sched); 2797b765cdaSTvrtko Ursulin 2807b765cdaSTvrtko Ursulin for (i = 0; i < qd; i++) { 2817b765cdaSTvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]); 2827b765cdaSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity); 2837b765cdaSTvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000); 2847b765cdaSTvrtko Ursulin drm_mock_sched_job_submit(job); 2857b765cdaSTvrtko Ursulin } 2867b765cdaSTvrtko Ursulin 2877b765cdaSTvrtko Ursulin done = drm_mock_sched_job_wait_finished(job, HZ); 2887b765cdaSTvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 2897b765cdaSTvrtko Ursulin 2907b765cdaSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++) 2917b765cdaSTvrtko Ursulin drm_mock_sched_entity_free(entity[i]); 2927b765cdaSTvrtko Ursulin } 2937b765cdaSTvrtko Ursulin 2947b765cdaSTvrtko Ursulin static void drm_sched_change_priority(struct kunit *test) 2957b765cdaSTvrtko Ursulin { 2967b765cdaSTvrtko Ursulin struct drm_mock_sched_entity *entity[DRM_SCHED_PRIORITY_COUNT]; 2977b765cdaSTvrtko Ursulin struct drm_mock_scheduler *sched = test->priv; 2987b765cdaSTvrtko Ursulin struct drm_mock_sched_job *job; 2997b765cdaSTvrtko Ursulin const unsigned int qd = 1000; 3007b765cdaSTvrtko Ursulin unsigned int i, cur_ent = 0; 3017b765cdaSTvrtko Ursulin enum drm_sched_priority p; 3027b765cdaSTvrtko Ursulin 3037b765cdaSTvrtko Ursulin /* 3047b765cdaSTvrtko Ursulin * Submit a bunch of jobs against entities configured with different 3057b765cdaSTvrtko Ursulin * priorities and while waiting for them to complete, periodically keep 3067b765cdaSTvrtko Ursulin * changing their priorities. 3077b765cdaSTvrtko Ursulin * 3087b765cdaSTvrtko Ursulin * We set up the queue-depth (qd) and job duration so the priority 3097b765cdaSTvrtko Ursulin * changing loop has some time to interact with submissions to the 3107b765cdaSTvrtko Ursulin * backend and job completions as they progress. 3117b765cdaSTvrtko Ursulin */ 3127b765cdaSTvrtko Ursulin 3137b765cdaSTvrtko Ursulin for (p = DRM_SCHED_PRIORITY_KERNEL; p <= DRM_SCHED_PRIORITY_LOW; p++) 3147b765cdaSTvrtko Ursulin entity[p] = drm_mock_sched_entity_new(test, p, sched); 3157b765cdaSTvrtko Ursulin 3167b765cdaSTvrtko Ursulin for (i = 0; i < qd; i++) { 3177b765cdaSTvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]); 3187b765cdaSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity); 3197b765cdaSTvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000); 3207b765cdaSTvrtko Ursulin drm_mock_sched_job_submit(job); 3217b765cdaSTvrtko Ursulin } 3227b765cdaSTvrtko Ursulin 3237b765cdaSTvrtko Ursulin do { 3247b765cdaSTvrtko Ursulin drm_sched_entity_set_priority(&entity[cur_ent]->base, 3257b765cdaSTvrtko Ursulin (entity[cur_ent]->base.priority + 1) % 3267b765cdaSTvrtko Ursulin DRM_SCHED_PRIORITY_COUNT); 3277b765cdaSTvrtko Ursulin cur_ent++; 3287b765cdaSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity); 3297b765cdaSTvrtko Ursulin usleep_range(200, 500); 3307b765cdaSTvrtko Ursulin } while (!drm_mock_sched_job_is_finished(job)); 3317b765cdaSTvrtko Ursulin 3327b765cdaSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++) 3337b765cdaSTvrtko Ursulin drm_mock_sched_entity_free(entity[i]); 3347b765cdaSTvrtko Ursulin } 3357b765cdaSTvrtko Ursulin 3367b765cdaSTvrtko Ursulin static struct kunit_case drm_sched_priority_tests[] = { 3377b765cdaSTvrtko Ursulin KUNIT_CASE(drm_sched_priorities), 3387b765cdaSTvrtko Ursulin KUNIT_CASE(drm_sched_change_priority), 3397b765cdaSTvrtko Ursulin {} 3407b765cdaSTvrtko Ursulin }; 3417b765cdaSTvrtko Ursulin 3427b765cdaSTvrtko Ursulin static struct kunit_suite drm_sched_priority = { 3437b765cdaSTvrtko Ursulin .name = "drm_sched_basic_priority_tests", 3447b765cdaSTvrtko Ursulin .init = drm_sched_basic_init, 3457b765cdaSTvrtko Ursulin .exit = drm_sched_basic_exit, 3467b765cdaSTvrtko Ursulin .test_cases = drm_sched_priority_tests, 3477b765cdaSTvrtko Ursulin }; 3487b765cdaSTvrtko Ursulin 349c85fc5dbSTvrtko Ursulin static void drm_sched_test_modify_sched(struct kunit *test) 350c85fc5dbSTvrtko Ursulin { 351c85fc5dbSTvrtko Ursulin unsigned int i, cur_ent = 0, cur_sched = 0; 352c85fc5dbSTvrtko Ursulin struct drm_mock_sched_entity *entity[13]; 353c85fc5dbSTvrtko Ursulin struct drm_mock_scheduler *sched[3]; 354c85fc5dbSTvrtko Ursulin struct drm_mock_sched_job *job; 355c85fc5dbSTvrtko Ursulin const unsigned int qd = 1000; 356c85fc5dbSTvrtko Ursulin 357c85fc5dbSTvrtko Ursulin /* 358c85fc5dbSTvrtko Ursulin * Submit a bunch of jobs against entities configured with different 359c85fc5dbSTvrtko Ursulin * schedulers and while waiting for them to complete, periodically keep 360c85fc5dbSTvrtko Ursulin * changing schedulers associated with each entity. 361c85fc5dbSTvrtko Ursulin * 362c85fc5dbSTvrtko Ursulin * We set up the queue-depth (qd) and job duration so the sched modify 363c85fc5dbSTvrtko Ursulin * loop has some time to interact with submissions to the backend and 364c85fc5dbSTvrtko Ursulin * job completions as they progress. 365c85fc5dbSTvrtko Ursulin * 366c85fc5dbSTvrtko Ursulin * For the number of schedulers and entities we use primes in order to 367c85fc5dbSTvrtko Ursulin * perturb the entity->sched assignments with less of a regular pattern. 368c85fc5dbSTvrtko Ursulin */ 369c85fc5dbSTvrtko Ursulin 370c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(sched); i++) 371c85fc5dbSTvrtko Ursulin sched[i] = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT); 372c85fc5dbSTvrtko Ursulin 373c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++) 374c85fc5dbSTvrtko Ursulin entity[i] = drm_mock_sched_entity_new(test, 375c85fc5dbSTvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL, 376c85fc5dbSTvrtko Ursulin sched[i % ARRAY_SIZE(sched)]); 377c85fc5dbSTvrtko Ursulin 378c85fc5dbSTvrtko Ursulin for (i = 0; i < qd; i++) { 379c85fc5dbSTvrtko Ursulin job = drm_mock_sched_job_new(test, entity[cur_ent++]); 380c85fc5dbSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity); 381c85fc5dbSTvrtko Ursulin drm_mock_sched_job_set_duration_us(job, 1000); 382c85fc5dbSTvrtko Ursulin drm_mock_sched_job_submit(job); 383c85fc5dbSTvrtko Ursulin } 384c85fc5dbSTvrtko Ursulin 385c85fc5dbSTvrtko Ursulin do { 386c85fc5dbSTvrtko Ursulin struct drm_gpu_scheduler *modify; 387c85fc5dbSTvrtko Ursulin 388c85fc5dbSTvrtko Ursulin usleep_range(200, 500); 389c85fc5dbSTvrtko Ursulin cur_ent++; 390c85fc5dbSTvrtko Ursulin cur_ent %= ARRAY_SIZE(entity); 391c85fc5dbSTvrtko Ursulin cur_sched++; 392c85fc5dbSTvrtko Ursulin cur_sched %= ARRAY_SIZE(sched); 393c85fc5dbSTvrtko Ursulin modify = &sched[cur_sched]->base; 394c85fc5dbSTvrtko Ursulin drm_sched_entity_modify_sched(&entity[cur_ent]->base, &modify, 395c85fc5dbSTvrtko Ursulin 1); 396c85fc5dbSTvrtko Ursulin } while (!drm_mock_sched_job_is_finished(job)); 397c85fc5dbSTvrtko Ursulin 398c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(entity); i++) 399c85fc5dbSTvrtko Ursulin drm_mock_sched_entity_free(entity[i]); 400c85fc5dbSTvrtko Ursulin 401c85fc5dbSTvrtko Ursulin for (i = 0; i < ARRAY_SIZE(sched); i++) 402c85fc5dbSTvrtko Ursulin drm_mock_sched_fini(sched[i]); 403c85fc5dbSTvrtko Ursulin } 404c85fc5dbSTvrtko Ursulin 405c85fc5dbSTvrtko Ursulin static struct kunit_case drm_sched_modify_sched_tests[] = { 406c85fc5dbSTvrtko Ursulin KUNIT_CASE(drm_sched_test_modify_sched), 407c85fc5dbSTvrtko Ursulin {} 408c85fc5dbSTvrtko Ursulin }; 409c85fc5dbSTvrtko Ursulin 410c85fc5dbSTvrtko Ursulin static struct kunit_suite drm_sched_modify_sched = { 411c85fc5dbSTvrtko Ursulin .name = "drm_sched_basic_modify_sched_tests", 412c85fc5dbSTvrtko Ursulin .test_cases = drm_sched_modify_sched_tests, 413c85fc5dbSTvrtko Ursulin }; 414c85fc5dbSTvrtko Ursulin 415*909bda22STvrtko Ursulin static void drm_sched_test_credits(struct kunit *test) 416*909bda22STvrtko Ursulin { 417*909bda22STvrtko Ursulin struct drm_mock_sched_entity *entity; 418*909bda22STvrtko Ursulin struct drm_mock_scheduler *sched; 419*909bda22STvrtko Ursulin struct drm_mock_sched_job *job[2]; 420*909bda22STvrtko Ursulin bool done; 421*909bda22STvrtko Ursulin int i; 422*909bda22STvrtko Ursulin 423*909bda22STvrtko Ursulin /* 424*909bda22STvrtko Ursulin * Check that the configured credit limit is respected. 425*909bda22STvrtko Ursulin */ 426*909bda22STvrtko Ursulin 427*909bda22STvrtko Ursulin sched = drm_mock_sched_new(test, MAX_SCHEDULE_TIMEOUT); 428*909bda22STvrtko Ursulin sched->base.credit_limit = 1; 429*909bda22STvrtko Ursulin 430*909bda22STvrtko Ursulin entity = drm_mock_sched_entity_new(test, 431*909bda22STvrtko Ursulin DRM_SCHED_PRIORITY_NORMAL, 432*909bda22STvrtko Ursulin sched); 433*909bda22STvrtko Ursulin 434*909bda22STvrtko Ursulin job[0] = drm_mock_sched_job_new(test, entity); 435*909bda22STvrtko Ursulin job[1] = drm_mock_sched_job_new(test, entity); 436*909bda22STvrtko Ursulin 437*909bda22STvrtko Ursulin drm_mock_sched_job_submit(job[0]); 438*909bda22STvrtko Ursulin drm_mock_sched_job_submit(job[1]); 439*909bda22STvrtko Ursulin 440*909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job[0], HZ); 441*909bda22STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 442*909bda22STvrtko Ursulin 443*909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job[1], HZ); 444*909bda22STvrtko Ursulin KUNIT_ASSERT_FALSE(test, done); 445*909bda22STvrtko Ursulin 446*909bda22STvrtko Ursulin i = drm_mock_sched_advance(sched, 1); 447*909bda22STvrtko Ursulin KUNIT_ASSERT_EQ(test, i, 1); 448*909bda22STvrtko Ursulin 449*909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_scheduled(job[1], HZ); 450*909bda22STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 451*909bda22STvrtko Ursulin 452*909bda22STvrtko Ursulin i = drm_mock_sched_advance(sched, 1); 453*909bda22STvrtko Ursulin KUNIT_ASSERT_EQ(test, i, 1); 454*909bda22STvrtko Ursulin 455*909bda22STvrtko Ursulin done = drm_mock_sched_job_wait_finished(job[1], HZ); 456*909bda22STvrtko Ursulin KUNIT_ASSERT_TRUE(test, done); 457*909bda22STvrtko Ursulin 458*909bda22STvrtko Ursulin drm_mock_sched_entity_free(entity); 459*909bda22STvrtko Ursulin drm_mock_sched_fini(sched); 460*909bda22STvrtko Ursulin } 461*909bda22STvrtko Ursulin 462*909bda22STvrtko Ursulin static struct kunit_case drm_sched_credits_tests[] = { 463*909bda22STvrtko Ursulin KUNIT_CASE(drm_sched_test_credits), 464*909bda22STvrtko Ursulin {} 465*909bda22STvrtko Ursulin }; 466*909bda22STvrtko Ursulin 467*909bda22STvrtko Ursulin static struct kunit_suite drm_sched_credits = { 468*909bda22STvrtko Ursulin .name = "drm_sched_basic_credits_tests", 469*909bda22STvrtko Ursulin .test_cases = drm_sched_credits_tests, 470*909bda22STvrtko Ursulin }; 471*909bda22STvrtko Ursulin 47253e65974STvrtko Ursulin kunit_test_suites(&drm_sched_basic, 4737b765cdaSTvrtko Ursulin &drm_sched_timeout, 474c85fc5dbSTvrtko Ursulin &drm_sched_priority, 475*909bda22STvrtko Ursulin &drm_sched_modify_sched, 476*909bda22STvrtko Ursulin &drm_sched_credits); 477