xref: /linux/drivers/gpu/drm/scheduler/tests/sched_tests.h (revision face6a3615a649456eb4549f6d474221d877d604)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (c) 2025 Valve Corporation */
3 
4 #ifndef _SCHED_TESTS_H_
5 #define _SCHED_TESTS_H_
6 
7 #include <kunit/test.h>
8 #include <linux/atomic.h>
9 #include <linux/completion.h>
10 #include <linux/dma-fence.h>
11 #include <linux/hrtimer.h>
12 #include <linux/ktime.h>
13 #include <linux/list.h>
14 #include <linux/mutex.h>
15 #include <linux/types.h>
16 
17 #include <drm/gpu_scheduler.h>
18 
19 /*
20  * DOC: Mock DRM scheduler data structures
21  *
22  * drm_mock_* data structures are used to implement a mock "GPU".
23  *
24  * They subclass the core DRM scheduler objects and add their data on top, which
25  * enables tracking the submitted jobs and simulating their execution with the
26  * attributes as specified by the test case.
27  */
28 
29 /**
30  * struct drm_mock_scheduler - implements a trivial mock GPU execution engine
31  *
32  * @base: DRM scheduler base class
33  * @test: Backpointer to owning the kunit test case
34  * @lock: Lock to protect the simulated @hw_timeline and @job_list
35  * @job_list: List of jobs submitted to the mock GPU
36  * @hw_timeline: Simulated hardware timeline has a @context, @next_seqno and
37  *		 @cur_seqno for implementing a struct dma_fence signaling the
38  *		 simulated job completion.
39  *
40  * Trivial mock GPU execution engine tracks submitted jobs and enables
41  * completing them strictly in submission order.
42  */
43 struct drm_mock_scheduler {
44 	struct drm_gpu_scheduler base;
45 
46 	struct kunit		*test;
47 
48 	spinlock_t		lock;
49 	struct list_head	job_list;
50 
51 	struct {
52 		u64		context;
53 		atomic_t	next_seqno;
54 		unsigned int	cur_seqno;
55 	} hw_timeline;
56 };
57 
58 /**
59  * struct drm_mock_sched_entity - implements a mock GPU sched entity
60  *
61  * @base: DRM scheduler entity base class
62  * @test: Backpointer to owning the kunit test case
63  *
64  * Mock GPU sched entity is used by the test cases to submit jobs to the mock
65  * scheduler.
66  */
67 struct drm_mock_sched_entity {
68 	struct drm_sched_entity base;
69 
70 	struct kunit		*test;
71 };
72 
73 /**
74  * struct drm_mock_sched_job - implements a mock GPU job
75  *
76  * @base: DRM sched job base class
77  * @done: Completion signaling job completion.
78  * @flags: Flags designating job state.
79  * @link: List head element used by job tracking by the drm_mock_scheduler
80  * @timer: Timer used for simulating job execution duration
81  * @duration_us: Simulated job duration in micro seconds, or zero if in manual
82  *		 timeline advance mode
83  * @finish_at: Absolute time when the jobs with set duration will complete
84  * @lock: Lock used for @hw_fence
85  * @hw_fence: Fence returned to DRM scheduler as the hardware fence
86  * @test: Backpointer to owning the kunit test case
87  *
88  * Mock GPU sched job is used by the test cases to submit jobs to the mock
89  * scheduler.
90  */
91 struct drm_mock_sched_job {
92 	struct drm_sched_job	base;
93 
94 	struct completion	done;
95 
96 #define DRM_MOCK_SCHED_JOB_DONE			0x1
97 #define DRM_MOCK_SCHED_JOB_TIMEDOUT		0x2
98 #define DRM_MOCK_SCHED_JOB_DONT_RESET		0x4
99 #define DRM_MOCK_SCHED_JOB_RESET_SKIPPED	0x8
100 	unsigned long		flags;
101 
102 	struct list_head	link;
103 	struct hrtimer		timer;
104 
105 	unsigned int		duration_us;
106 	ktime_t			finish_at;
107 
108 	struct dma_fence	hw_fence;
109 
110 	struct kunit		*test;
111 };
112 
113 static inline struct drm_mock_scheduler *
114 drm_sched_to_mock_sched(struct drm_gpu_scheduler *sched)
115 {
116 	return container_of(sched, struct drm_mock_scheduler, base);
117 };
118 
119 static inline struct drm_mock_sched_entity *
120 drm_sched_entity_to_mock_entity(struct drm_sched_entity *sched_entity)
121 {
122 	return container_of(sched_entity, struct drm_mock_sched_entity, base);
123 };
124 
125 static inline struct drm_mock_sched_job *
126 drm_sched_job_to_mock_job(struct drm_sched_job *sched_job)
127 {
128 	return container_of(sched_job, struct drm_mock_sched_job, base);
129 };
130 
131 struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test,
132 					      long timeout);
133 void drm_mock_sched_fini(struct drm_mock_scheduler *sched);
134 unsigned int drm_mock_sched_advance(struct drm_mock_scheduler *sched,
135 				    unsigned int num);
136 
137 struct drm_mock_sched_entity *
138 drm_mock_sched_entity_new(struct kunit *test,
139 			  enum drm_sched_priority priority,
140 			  struct drm_mock_scheduler *sched);
141 void drm_mock_sched_entity_free(struct drm_mock_sched_entity *entity);
142 
143 struct drm_mock_sched_job *
144 drm_mock_sched_job_new(struct kunit *test,
145 		       struct drm_mock_sched_entity *entity);
146 
147 /**
148  * drm_mock_sched_job_submit - Arm and submit a job in one go
149  *
150  * @job: Job to arm and submit
151  */
152 static inline void drm_mock_sched_job_submit(struct drm_mock_sched_job *job)
153 {
154 	drm_sched_job_arm(&job->base);
155 	drm_sched_entity_push_job(&job->base);
156 }
157 
158 /**
159  * drm_mock_sched_job_set_duration_us - Set a job duration
160  *
161  * @job: Job to set the duration for
162  * @duration_us: Duration in micro seconds
163  *
164  * Jobs with duration set will be automatically completed by the mock scheduler
165  * as the timeline progresses, unless a job without a set duration is
166  * encountered in the timelime in which case calling drm_mock_sched_advance()
167  * will be required to bump the timeline.
168  */
169 static inline void
170 drm_mock_sched_job_set_duration_us(struct drm_mock_sched_job *job,
171 				   unsigned int duration_us)
172 {
173 	job->duration_us = duration_us;
174 }
175 
176 /**
177  * drm_mock_sched_job_is_finished - Check if a job is finished
178  *
179  * @job: Job to check
180  *
181  * Returns: true if finished
182  */
183 static inline bool
184 drm_mock_sched_job_is_finished(struct drm_mock_sched_job *job)
185 {
186 	return job->flags & DRM_MOCK_SCHED_JOB_DONE;
187 }
188 
189 /**
190  * drm_mock_sched_job_wait_finished - Wait until a job is finished
191  *
192  * @job: Job to wait for
193  * @timeout: Wait time in jiffies
194  *
195  * Returns: true if finished within the timeout provided, otherwise false
196  */
197 static inline bool
198 drm_mock_sched_job_wait_finished(struct drm_mock_sched_job *job, long timeout)
199 {
200 	if (job->flags & DRM_MOCK_SCHED_JOB_DONE)
201 		return true;
202 
203 	return wait_for_completion_timeout(&job->done, timeout) != 0;
204 }
205 
206 /**
207  * drm_mock_sched_job_wait_scheduled - Wait until a job is scheduled
208  *
209  * @job: Job to wait for
210  * @timeout: Wait time in jiffies
211  *
212  * Returns: true if scheduled within the timeout provided, otherwise false
213  */
214 static inline bool
215 drm_mock_sched_job_wait_scheduled(struct drm_mock_sched_job *job, long timeout)
216 {
217 	KUNIT_ASSERT_EQ(job->test, job->flags & DRM_MOCK_SCHED_JOB_DONE, 0);
218 
219 	return dma_fence_wait_timeout(&job->base.s_fence->scheduled,
220 				      false,
221 				      timeout) != 0;
222 }
223 
224 #endif
225