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