Commit | Line | Data |
---|---|---|
1b1f42d8 LS |
1 | /* |
2 | * Copyright 2015 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | */ | |
23 | ||
24 | #ifndef _DRM_GPU_SCHEDULER_H_ | |
25 | #define _DRM_GPU_SCHEDULER_H_ | |
26 | ||
27 | #include <drm/spsc_queue.h> | |
28 | #include <linux/dma-fence.h> | |
dc10218d | 29 | #include <linux/completion.h> |
ebd5f742 | 30 | #include <linux/xarray.h> |
7d64c40a | 31 | #include <linux/workqueue.h> |
1b1f42d8 | 32 | |
741f01e6 AG |
33 | #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) |
34 | ||
7b476aff | 35 | /** |
1e436f4f | 36 | * DRM_SCHED_FENCE_DONT_PIPELINE - Prevent dependency pipelining |
7b476aff CK |
37 | * |
38 | * Setting this flag on a scheduler fence prevents pipelining of jobs depending | |
39 | * on this fence. In other words we always insert a full CPU round trip before | |
1e436f4f | 40 | * dependent jobs are pushed to the hw queue. |
7b476aff CK |
41 | */ |
42 | #define DRM_SCHED_FENCE_DONT_PIPELINE DMA_FENCE_FLAG_USER_BITS | |
43 | ||
f3823da7 RC |
44 | /** |
45 | * DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT - A fence deadline hint has been set | |
46 | * | |
47 | * Because we could have a deadline hint can be set before the backing hw | |
48 | * fence is created, we need to keep track of whether a deadline has already | |
49 | * been set. | |
50 | */ | |
51 | #define DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT (DMA_FENCE_FLAG_USER_BITS + 1) | |
52 | ||
4d5230b5 CK |
53 | enum dma_resv_usage; |
54 | struct dma_resv; | |
ebd5f742 DV |
55 | struct drm_gem_object; |
56 | ||
1b1f42d8 LS |
57 | struct drm_gpu_scheduler; |
58 | struct drm_sched_rq; | |
59 | ||
c087bbb6 MC |
60 | struct drm_file; |
61 | ||
e2d732fd LT |
62 | /* These are often used as an (initial) index |
63 | * to an array, and as such should start at 0. | |
64 | */ | |
1b1f42d8 | 65 | enum drm_sched_priority { |
1b1f42d8 | 66 | DRM_SCHED_PRIORITY_KERNEL, |
38f922a5 LT |
67 | DRM_SCHED_PRIORITY_HIGH, |
68 | DRM_SCHED_PRIORITY_NORMAL, | |
69 | DRM_SCHED_PRIORITY_LOW, | |
e2d732fd | 70 | |
fa8391ad | 71 | DRM_SCHED_PRIORITY_COUNT |
1b1f42d8 LS |
72 | }; |
73 | ||
74 | /** | |
2d33948e ND |
75 | * struct drm_sched_entity - A wrapper around a job queue (typically |
76 | * attached to the DRM file_priv). | |
77 | * | |
1a61ee07 EA |
78 | * Entities will emit jobs in order to their corresponding hardware |
79 | * ring, and the scheduler will alternate between entities based on | |
80 | * scheduling policy. | |
2d33948e | 81 | */ |
1b1f42d8 | 82 | struct drm_sched_entity { |
981b04d9 DV |
83 | /** |
84 | * @list: | |
85 | * | |
86 | * Used to append this struct to the list of entities in the runqueue | |
87 | * @rq under &drm_sched_rq.entities. | |
88 | * | |
89 | * Protected by &drm_sched_rq.lock of @rq. | |
90 | */ | |
1b1f42d8 | 91 | struct list_head list; |
981b04d9 | 92 | |
f93126f5 TU |
93 | /** |
94 | * @lock: | |
95 | * | |
96 | * Lock protecting the run-queue (@rq) to which this entity belongs, | |
97 | * @priority and the list of schedulers (@sched_list, @num_sched_list). | |
98 | */ | |
99 | spinlock_t lock; | |
100 | ||
981b04d9 DV |
101 | /** |
102 | * @rq: | |
103 | * | |
104 | * Runqueue on which this entity is currently scheduled. | |
105 | * | |
106 | * FIXME: Locking is very unclear for this. Writers are protected by | |
f93126f5 TU |
107 | * @lock, but readers are generally lockless and seem to just race with |
108 | * not even a READ_ONCE. | |
981b04d9 | 109 | */ |
1b1f42d8 | 110 | struct drm_sched_rq *rq; |
981b04d9 DV |
111 | |
112 | /** | |
113 | * @sched_list: | |
114 | * | |
115 | * A list of schedulers (struct drm_gpu_scheduler). Jobs from this entity can | |
116 | * be scheduled on any scheduler on this list. | |
117 | * | |
118 | * This can be modified by calling drm_sched_entity_modify_sched(). | |
119 | * Locking is entirely up to the driver, see the above function for more | |
120 | * details. | |
121 | * | |
122 | * This will be set to NULL if &num_sched_list equals 1 and @rq has been | |
123 | * set already. | |
124 | * | |
125 | * FIXME: This means priority changes through | |
126 | * drm_sched_entity_set_priority() will be lost henceforth in this case. | |
127 | */ | |
b3ac1766 | 128 | struct drm_gpu_scheduler **sched_list; |
981b04d9 DV |
129 | |
130 | /** | |
131 | * @num_sched_list: | |
132 | * | |
133 | * Number of drm_gpu_schedulers in the @sched_list. | |
134 | */ | |
9e3e90c5 | 135 | unsigned int num_sched_list; |
981b04d9 DV |
136 | |
137 | /** | |
138 | * @priority: | |
139 | * | |
140 | * Priority of the entity. This can be modified by calling | |
f93126f5 | 141 | * drm_sched_entity_set_priority(). Protected by @lock. |
981b04d9 | 142 | */ |
b3ac1766 | 143 | enum drm_sched_priority priority; |
981b04d9 | 144 | |
981b04d9 DV |
145 | /** |
146 | * @job_queue: the list of jobs of this entity. | |
147 | */ | |
1b1f42d8 LS |
148 | struct spsc_queue job_queue; |
149 | ||
981b04d9 DV |
150 | /** |
151 | * @fence_seq: | |
152 | * | |
153 | * A linearly increasing seqno incremented with each new | |
154 | * &drm_sched_fence which is part of the entity. | |
155 | * | |
156 | * FIXME: Callers of drm_sched_job_arm() need to ensure correct locking, | |
157 | * this doesn't need to be atomic. | |
158 | */ | |
1b1f42d8 | 159 | atomic_t fence_seq; |
981b04d9 DV |
160 | |
161 | /** | |
162 | * @fence_context: | |
163 | * | |
164 | * A unique context for all the fences which belong to this entity. The | |
165 | * &drm_sched_fence.scheduled uses the fence_context but | |
166 | * &drm_sched_fence.finished uses fence_context + 1. | |
167 | */ | |
1b1f42d8 LS |
168 | uint64_t fence_context; |
169 | ||
981b04d9 DV |
170 | /** |
171 | * @dependency: | |
172 | * | |
173 | * The dependency fence of the job which is on the top of the job queue. | |
174 | */ | |
1b1f42d8 | 175 | struct dma_fence *dependency; |
981b04d9 DV |
176 | |
177 | /** | |
178 | * @cb: | |
179 | * | |
180 | * Callback for the dependency fence above. | |
181 | */ | |
1b1f42d8 | 182 | struct dma_fence_cb cb; |
981b04d9 DV |
183 | |
184 | /** | |
185 | * @guilty: | |
186 | * | |
187 | * Points to entities' guilty. | |
188 | */ | |
2d33948e | 189 | atomic_t *guilty; |
981b04d9 DV |
190 | |
191 | /** | |
192 | * @last_scheduled: | |
193 | * | |
194 | * Points to the finished fence of the last scheduled job. Only written | |
195 | * by the scheduler thread, can be accessed locklessly from | |
1e436f4f | 196 | * drm_sched_job_arm() if the queue is empty. |
981b04d9 | 197 | */ |
70102d77 | 198 | struct dma_fence __rcu *last_scheduled; |
981b04d9 DV |
199 | |
200 | /** | |
201 | * @last_user: last group leader pushing a job into the entity. | |
202 | */ | |
43bce41c | 203 | struct task_struct *last_user; |
981b04d9 DV |
204 | |
205 | /** | |
206 | * @stopped: | |
207 | * | |
208 | * Marks the enity as removed from rq and destined for | |
209 | * termination. This is set by calling drm_sched_entity_flush() and by | |
210 | * drm_sched_fini(). | |
211 | */ | |
62347a33 | 212 | bool stopped; |
981b04d9 DV |
213 | |
214 | /** | |
215 | * @entity_idle: | |
216 | * | |
217 | * Signals when entity is not in use, used to sequence entity cleanup in | |
218 | * drm_sched_entity_fini(). | |
219 | */ | |
83a7772b | 220 | struct completion entity_idle; |
08fb97de AG |
221 | |
222 | /** | |
223 | * @oldest_job_waiting: | |
224 | * | |
225 | * Marks earliest job waiting in SW queue | |
226 | */ | |
227 | ktime_t oldest_job_waiting; | |
228 | ||
229 | /** | |
230 | * @rb_tree_node: | |
231 | * | |
232 | * The node used to insert this entity into time based priority queue | |
233 | */ | |
234 | struct rb_node rb_tree_node; | |
235 | ||
1b1f42d8 LS |
236 | }; |
237 | ||
238 | /** | |
2d33948e ND |
239 | * struct drm_sched_rq - queue of entities to be scheduled. |
240 | * | |
8dc9fbbf | 241 | * @sched: the scheduler to which this rq belongs to. |
a6f46283 | 242 | * @lock: protects @entities, @rb_tree_root and @current_entity. |
2d33948e | 243 | * @current_entity: the entity which is to be scheduled. |
a6f46283 | 244 | * @entities: list of the entities to be scheduled. |
1e436f4f | 245 | * @rb_tree_root: root of time based priority queue of entities for FIFO scheduling |
2d33948e | 246 | * |
1b1f42d8 LS |
247 | * Run queue is a set of entities scheduling command submissions for |
248 | * one specific ring. It implements the scheduling policy that selects | |
249 | * the next entity to emit commands from. | |
2d33948e | 250 | */ |
1b1f42d8 | 251 | struct drm_sched_rq { |
8dc9fbbf | 252 | struct drm_gpu_scheduler *sched; |
a6f46283 TU |
253 | |
254 | spinlock_t lock; | |
255 | /* Following members are protected by the @lock: */ | |
1b1f42d8 | 256 | struct drm_sched_entity *current_entity; |
a6f46283 | 257 | struct list_head entities; |
08fb97de | 258 | struct rb_root_cached rb_tree_root; |
1b1f42d8 LS |
259 | }; |
260 | ||
2d33948e ND |
261 | /** |
262 | * struct drm_sched_fence - fences corresponding to the scheduling of a job. | |
263 | */ | |
1b1f42d8 | 264 | struct drm_sched_fence { |
2d33948e ND |
265 | /** |
266 | * @scheduled: this fence is what will be signaled by the scheduler | |
267 | * when the job is scheduled. | |
268 | */ | |
1b1f42d8 | 269 | struct dma_fence scheduled; |
1a61ee07 | 270 | |
2d33948e ND |
271 | /** |
272 | * @finished: this fence is what will be signaled by the scheduler | |
273 | * when the job is completed. | |
274 | * | |
275 | * When setting up an out fence for the job, you should use | |
276 | * this, since it's available immediately upon | |
277 | * drm_sched_job_init(), and the fence returned by the driver | |
278 | * from run_job() won't be created until the dependencies have | |
279 | * resolved. | |
280 | */ | |
1b1f42d8 | 281 | struct dma_fence finished; |
1a61ee07 | 282 | |
f3823da7 RC |
283 | /** |
284 | * @deadline: deadline set on &drm_sched_fence.finished which | |
285 | * potentially needs to be propagated to &drm_sched_fence.parent | |
286 | */ | |
287 | ktime_t deadline; | |
288 | ||
2d33948e ND |
289 | /** |
290 | * @parent: the fence returned by &drm_sched_backend_ops.run_job | |
291 | * when scheduling the job on hardware. We signal the | |
292 | * &drm_sched_fence.finished fence once parent is signalled. | |
293 | */ | |
1b1f42d8 | 294 | struct dma_fence *parent; |
2d33948e ND |
295 | /** |
296 | * @sched: the scheduler instance to which the job having this struct | |
297 | * belongs to. | |
298 | */ | |
1b1f42d8 | 299 | struct drm_gpu_scheduler *sched; |
2d33948e ND |
300 | /** |
301 | * @lock: the lock used by the scheduled and the finished fences. | |
302 | */ | |
1b1f42d8 | 303 | spinlock_t lock; |
2d33948e ND |
304 | /** |
305 | * @owner: job owner for debugging | |
306 | */ | |
1b1f42d8 LS |
307 | void *owner; |
308 | }; | |
309 | ||
310 | struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f); | |
311 | ||
1a61ee07 | 312 | /** |
2d33948e ND |
313 | * struct drm_sched_job - A job to be run by an entity. |
314 | * | |
315 | * @queue_node: used to append this struct to the queue of jobs in an entity. | |
c365d304 | 316 | * @list: a job participates in a "pending" and "done" lists. |
2d33948e ND |
317 | * @sched: the scheduler instance on which this job is scheduled. |
318 | * @s_fence: contains the fences for the scheduling of job. | |
319 | * @finish_cb: the callback for the finished fence. | |
a78422e9 | 320 | * @credits: the number of credits this job contributes to the scheduler |
1e436f4f | 321 | * @work: Helper to reschedule job kill to different context. |
2d33948e ND |
322 | * @id: a unique id assigned to each job scheduled on the scheduler. |
323 | * @karma: increment on every hang caused by this job. If this exceeds the hang | |
324 | * limit of the scheduler then the job is marked guilty and will not | |
325 | * be scheduled further. | |
326 | * @s_priority: the priority of the job. | |
327 | * @entity: the entity to which this job belongs. | |
3741540e | 328 | * @cb: the callback for the parent fence in s_fence. |
1a61ee07 EA |
329 | * |
330 | * A job is created by the driver using drm_sched_job_init(), and | |
331 | * should call drm_sched_entity_push_job() once it wants the scheduler | |
332 | * to schedule the job. | |
333 | */ | |
1b1f42d8 | 334 | struct drm_sched_job { |
b76f1467 TU |
335 | u64 id; |
336 | ||
337 | /** | |
338 | * @submit_ts: | |
339 | * | |
340 | * When the job was pushed into the entity queue. | |
341 | */ | |
342 | ktime_t submit_ts; | |
3ae80b37 PS |
343 | |
344 | /** | |
345 | * @sched: | |
346 | * | |
347 | * The scheduler this job is or will be scheduled on. Gets set by | |
348 | * drm_sched_job_arm(). Valid until drm_sched_backend_ops.free_job() | |
349 | * has finished. | |
350 | */ | |
1b1f42d8 | 351 | struct drm_gpu_scheduler *sched; |
b76f1467 | 352 | |
1b1f42d8 | 353 | struct drm_sched_fence *s_fence; |
b76f1467 | 354 | struct drm_sched_entity *entity; |
542cff78 | 355 | |
b76f1467 | 356 | enum drm_sched_priority s_priority; |
a78422e9 | 357 | u32 credits; |
b76f1467 TU |
358 | /** @last_dependency: tracks @dependencies as they signal */ |
359 | unsigned int last_dependency; | |
360 | atomic_t karma; | |
361 | ||
362 | struct spsc_node queue_node; | |
363 | struct list_head list; | |
a78422e9 | 364 | |
542cff78 AG |
365 | /* |
366 | * work is used only after finish_cb has been used and will not be | |
367 | * accessed anymore. | |
368 | */ | |
369 | union { | |
b76f1467 TU |
370 | struct dma_fence_cb finish_cb; |
371 | struct work_struct work; | |
542cff78 AG |
372 | }; |
373 | ||
3741540e | 374 | struct dma_fence_cb cb; |
b76f1467 | 375 | |
ebd5f742 DV |
376 | /** |
377 | * @dependencies: | |
378 | * | |
379 | * Contains the dependencies as struct dma_fence for this job, see | |
380 | * drm_sched_job_add_dependency() and | |
381 | * drm_sched_job_add_implicit_dependencies(). | |
382 | */ | |
383 | struct xarray dependencies; | |
1b1f42d8 LS |
384 | }; |
385 | ||
2eeed61d PS |
386 | /** |
387 | * enum drm_gpu_sched_stat - the scheduler's status | |
388 | * | |
389 | * @DRM_GPU_SCHED_STAT_NONE: Reserved. Do not use. | |
390 | * @DRM_GPU_SCHED_STAT_NOMINAL: Operation succeeded. | |
391 | * @DRM_GPU_SCHED_STAT_ENODEV: Error: Device is not available anymore. | |
392 | */ | |
a6a1f036 | 393 | enum drm_gpu_sched_stat { |
2eeed61d | 394 | DRM_GPU_SCHED_STAT_NONE, |
a6a1f036 LT |
395 | DRM_GPU_SCHED_STAT_NOMINAL, |
396 | DRM_GPU_SCHED_STAT_ENODEV, | |
397 | }; | |
398 | ||
1b1f42d8 | 399 | /** |
f8ad757e RD |
400 | * struct drm_sched_backend_ops - Define the backend operations |
401 | * called by the scheduler | |
2d33948e | 402 | * |
f8ad757e | 403 | * These functions should be implemented in the driver side. |
2d33948e | 404 | */ |
1b1f42d8 | 405 | struct drm_sched_backend_ops { |
2d33948e | 406 | /** |
a82f30b0 | 407 | * @prepare_job: |
ebd5f742 DV |
408 | * |
409 | * Called when the scheduler is considering scheduling this job next, to | |
410 | * get another struct dma_fence for this job to block on. Once it | |
411 | * returns NULL, run_job() may be called. | |
412 | * | |
a82f30b0 CK |
413 | * Can be NULL if no additional preparation to the dependencies are |
414 | * necessary. Skipped when jobs are killed instead of run. | |
1a61ee07 | 415 | */ |
a82f30b0 CK |
416 | struct dma_fence *(*prepare_job)(struct drm_sched_job *sched_job, |
417 | struct drm_sched_entity *s_entity); | |
1a61ee07 | 418 | |
2d33948e | 419 | /** |
87edca62 PS |
420 | * @run_job: Called to execute the job once all of the dependencies |
421 | * have been resolved. | |
422 | * | |
423 | * @sched_job: the job to run | |
424 | * | |
425 | * The deprecated drm_sched_resubmit_jobs() (called by &struct | |
426 | * drm_sched_backend_ops.timedout_job) can invoke this again with the | |
427 | * same parameters. Using this is discouraged because it violates | |
428 | * dma_fence rules, notably dma_fence_init() has to be called on | |
429 | * already initialized fences for a second time. Moreover, this is | |
430 | * dangerous because attempts to allocate memory might deadlock with | |
431 | * memory management code waiting for the reset to complete. | |
432 | * | |
433 | * TODO: Document what drivers should do / use instead. | |
434 | * | |
435 | * This method is called in a workqueue context - either from the | |
436 | * submit_wq the driver passed through drm_sched_init(), or, if the | |
437 | * driver passed NULL, a separate, ordered workqueue the scheduler | |
438 | * allocated. | |
439 | * | |
440 | * Note that the scheduler expects to 'inherit' its own reference to | |
441 | * this fence from the callback. It does not invoke an extra | |
442 | * dma_fence_get() on it. Consequently, this callback must take a | |
443 | * reference for the scheduler, and additional ones for the driver's | |
444 | * respective needs. | |
445 | * | |
446 | * Return: | |
447 | * * On success: dma_fence the driver must signal once the hardware has | |
448 | * completed the job ("hardware fence"). | |
449 | * * On failure: NULL or an ERR_PTR. | |
1a61ee07 | 450 | */ |
1b1f42d8 | 451 | struct dma_fence *(*run_job)(struct drm_sched_job *sched_job); |
1a61ee07 | 452 | |
2d33948e | 453 | /** |
a6a1f036 LT |
454 | * @timedout_job: Called when a job has taken too long to execute, |
455 | * to trigger GPU recovery. | |
456 | * | |
2eeed61d PS |
457 | * @sched_job: The job that has timed out |
458 | * | |
459 | * Drivers typically issue a reset to recover from GPU hangs. | |
460 | * This procedure looks very different depending on whether a firmware | |
461 | * or a hardware scheduler is being used. | |
462 | * | |
463 | * For a FIRMWARE SCHEDULER, each ring has one scheduler, and each | |
464 | * scheduler has one entity. Hence, the steps taken typically look as | |
465 | * follows: | |
1fad1b7e | 466 | * |
2eeed61d PS |
467 | * 1. Stop the scheduler using drm_sched_stop(). This will pause the |
468 | * scheduler workqueues and cancel the timeout work, guaranteeing | |
469 | * that nothing is queued while the ring is being removed. | |
470 | * 2. Remove the ring. The firmware will make sure that the | |
471 | * corresponding parts of the hardware are resetted, and that other | |
472 | * rings are not impacted. | |
473 | * 3. Kill the entity and the associated scheduler. | |
1fad1b7e | 474 | * |
2eeed61d PS |
475 | * |
476 | * For a HARDWARE SCHEDULER, a scheduler instance schedules jobs from | |
477 | * one or more entities to one ring. This implies that all entities | |
478 | * associated with the affected scheduler cannot be torn down, because | |
479 | * this would effectively also affect innocent userspace processes which | |
480 | * did not submit faulty jobs (for example). | |
481 | * | |
482 | * Consequently, the procedure to recover with a hardware scheduler | |
483 | * should look like this: | |
484 | * | |
485 | * 1. Stop all schedulers impacted by the reset using drm_sched_stop(). | |
486 | * 2. Kill the entity the faulty job stems from. | |
487 | * 3. Issue a GPU reset on all faulty rings (driver-specific). | |
488 | * 4. Re-submit jobs on all schedulers impacted by re-submitting them to | |
489 | * the entities which are still alive. | |
490 | * 5. Restart all schedulers that were stopped in step #1 using | |
491 | * drm_sched_start(). | |
1fad1b7e | 492 | * |
78efe21b BB |
493 | * Note that some GPUs have distinct hardware queues but need to reset |
494 | * the GPU globally, which requires extra synchronization between the | |
2eeed61d PS |
495 | * timeout handlers of different schedulers. One way to achieve this |
496 | * synchronization is to create an ordered workqueue (using | |
497 | * alloc_ordered_workqueue()) at the driver level, and pass this queue | |
498 | * as drm_sched_init()'s @timeout_wq parameter. This will guarantee | |
499 | * that timeout handlers are executed sequentially. | |
78efe21b | 500 | * |
2eeed61d | 501 | * Return: The scheduler's status, defined by &enum drm_gpu_sched_stat |
a6a1f036 | 502 | * |
1a61ee07 | 503 | */ |
a6a1f036 | 504 | enum drm_gpu_sched_stat (*timedout_job)(struct drm_sched_job *sched_job); |
1a61ee07 | 505 | |
2d33948e ND |
506 | /** |
507 | * @free_job: Called once the job's finished fence has been signaled | |
508 | * and it's time to clean it up. | |
1a61ee07 | 509 | */ |
1b1f42d8 LS |
510 | void (*free_job)(struct drm_sched_job *sched_job); |
511 | }; | |
512 | ||
513 | /** | |
f8ad757e | 514 | * struct drm_gpu_scheduler - scheduler instance-specific data |
2d33948e ND |
515 | * |
516 | * @ops: backend operations provided by the driver. | |
a78422e9 DK |
517 | * @credit_limit: the credit limit of this scheduler |
518 | * @credit_count: the current credit count of this scheduler | |
2d33948e ND |
519 | * @timeout: the time after which a job is removed from the scheduler. |
520 | * @name: name of the ring for which this scheduler is being used. | |
56e44960 LT |
521 | * @num_rqs: Number of run-queues. This is at most DRM_SCHED_PRIORITY_COUNT, |
522 | * as there's usually one run-queue per priority, but could be less. | |
523 | * @sched_rq: An allocated array of run-queues of size @num_rqs; | |
2d33948e ND |
524 | * @job_scheduled: once @drm_sched_entity_do_release is called the scheduler |
525 | * waits on this wait queue until all the scheduled jobs are | |
526 | * finished. | |
2d33948e | 527 | * @job_id_count: used to assign unique id to the each job. |
f7fe64ad | 528 | * @submit_wq: workqueue used to queue @work_run_job and @work_free_job |
78efe21b | 529 | * @timeout_wq: workqueue used to queue @work_tdr |
a6149f03 | 530 | * @work_run_job: work which calls run_job op of each scheduler. |
f7fe64ad | 531 | * @work_free_job: work which calls free_job op of each scheduler. |
6a962430 ND |
532 | * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the |
533 | * timeout interval is over. | |
6efa4b46 LT |
534 | * @pending_list: the list of jobs which are currently in the job queue. |
535 | * @job_list_lock: lock to protect the pending_list. | |
2d33948e | 536 | * @hang_limit: once the hangs by a job crosses this limit then it is marked |
95b2151f | 537 | * guilty and it will no longer be considered for scheduling. |
d41a39dd | 538 | * @score: score to help loadbalancer pick a idle sched |
be318fd8 | 539 | * @_score: score used when the driver doesn't provide one |
faf6e1a8 | 540 | * @ready: marks if the underlying HW is ready to work |
a5343b8a | 541 | * @free_guilty: A hit to time out handler to free the guilty job. |
a6149f03 MB |
542 | * @pause_submit: pause queuing of @work_run_job on @submit_wq |
543 | * @own_submit_wq: scheduler owns allocation of @submit_wq | |
f8ad757e | 544 | * @dev: system &struct device |
2d33948e ND |
545 | * |
546 | * One scheduler is implemented for each hardware ring. | |
547 | */ | |
1b1f42d8 LS |
548 | struct drm_gpu_scheduler { |
549 | const struct drm_sched_backend_ops *ops; | |
a78422e9 DK |
550 | u32 credit_limit; |
551 | atomic_t credit_count; | |
1b1f42d8 LS |
552 | long timeout; |
553 | const char *name; | |
56e44960 LT |
554 | u32 num_rqs; |
555 | struct drm_sched_rq **sched_rq; | |
1b1f42d8 | 556 | wait_queue_head_t job_scheduled; |
1b1f42d8 | 557 | atomic64_t job_id_count; |
a6149f03 | 558 | struct workqueue_struct *submit_wq; |
78efe21b | 559 | struct workqueue_struct *timeout_wq; |
a6149f03 | 560 | struct work_struct work_run_job; |
f7fe64ad | 561 | struct work_struct work_free_job; |
6a962430 | 562 | struct delayed_work work_tdr; |
6efa4b46 | 563 | struct list_head pending_list; |
1b1f42d8 LS |
564 | spinlock_t job_list_lock; |
565 | int hang_limit; | |
f2f12eb9 CK |
566 | atomic_t *score; |
567 | atomic_t _score; | |
d41a39dd | 568 | bool ready; |
a5343b8a | 569 | bool free_guilty; |
a6149f03 MB |
570 | bool pause_submit; |
571 | bool own_submit_wq; | |
8ab62eda | 572 | struct device *dev; |
1b1f42d8 LS |
573 | }; |
574 | ||
796a9f55 PS |
575 | /** |
576 | * struct drm_sched_init_args - parameters for initializing a DRM GPU scheduler | |
577 | * | |
578 | * @ops: backend operations provided by the driver | |
579 | * @submit_wq: workqueue to use for submission. If NULL, an ordered wq is | |
580 | * allocated and used. | |
581 | * @num_rqs: Number of run-queues. This may be at most DRM_SCHED_PRIORITY_COUNT, | |
582 | * as there's usually one run-queue per priority, but may be less. | |
583 | * @credit_limit: the number of credits this scheduler can hold from all jobs | |
584 | * @hang_limit: number of times to allow a job to hang before dropping it. | |
585 | * This mechanism is DEPRECATED. Set it to 0. | |
586 | * @timeout: timeout value in jiffies for submitted jobs. | |
587 | * @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is used. | |
588 | * @score: score atomic shared with other schedulers. May be NULL. | |
589 | * @name: name (typically the driver's name). Used for debugging | |
590 | * @dev: associated device. Used for debugging | |
591 | */ | |
592 | struct drm_sched_init_args { | |
593 | const struct drm_sched_backend_ops *ops; | |
594 | struct workqueue_struct *submit_wq; | |
595 | struct workqueue_struct *timeout_wq; | |
596 | u32 num_rqs; | |
597 | u32 credit_limit; | |
598 | unsigned int hang_limit; | |
599 | long timeout; | |
600 | atomic_t *score; | |
601 | const char *name; | |
602 | struct device *dev; | |
603 | }; | |
604 | ||
27d48151 TU |
605 | /* Scheduler operations */ |
606 | ||
1b1f42d8 | 607 | int drm_sched_init(struct drm_gpu_scheduler *sched, |
796a9f55 | 608 | const struct drm_sched_init_args *args); |
faf6e1a8 | 609 | |
1b1f42d8 | 610 | void drm_sched_fini(struct drm_gpu_scheduler *sched); |
27d48151 TU |
611 | |
612 | unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched); | |
613 | void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched, | |
614 | unsigned long remaining); | |
615 | void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched); | |
616 | bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched); | |
617 | void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched); | |
618 | void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched); | |
619 | void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad); | |
620 | void drm_sched_start(struct drm_gpu_scheduler *sched, int errno); | |
621 | void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); | |
622 | void drm_sched_fault(struct drm_gpu_scheduler *sched); | |
623 | ||
624 | struct drm_gpu_scheduler * | |
625 | drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, | |
626 | unsigned int num_sched_list); | |
627 | ||
628 | /* Jobs */ | |
629 | ||
620e762f CK |
630 | int drm_sched_job_init(struct drm_sched_job *job, |
631 | struct drm_sched_entity *entity, | |
a78422e9 | 632 | u32 credits, void *owner); |
dbe48d03 | 633 | void drm_sched_job_arm(struct drm_sched_job *job); |
27d48151 | 634 | void drm_sched_entity_push_job(struct drm_sched_job *sched_job); |
ebd5f742 DV |
635 | int drm_sched_job_add_dependency(struct drm_sched_job *job, |
636 | struct dma_fence *fence); | |
c087bbb6 MC |
637 | int drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job, |
638 | struct drm_file *file, | |
639 | u32 handle, | |
640 | u32 point); | |
4d5230b5 CK |
641 | int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, |
642 | struct dma_resv *resv, | |
643 | enum dma_resv_usage usage); | |
ebd5f742 DV |
644 | int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, |
645 | struct drm_gem_object *obj, | |
646 | bool write); | |
51678bb9 TU |
647 | bool drm_sched_job_has_dependency(struct drm_sched_job *job, |
648 | struct dma_fence *fence); | |
26efecf9 | 649 | void drm_sched_job_cleanup(struct drm_sched_job *job); |
222b5f04 | 650 | void drm_sched_increase_karma(struct drm_sched_job *bad); |
27d48151 TU |
651 | |
652 | static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, | |
653 | int threshold) | |
654 | { | |
655 | return s_job && atomic_inc_return(&s_job->karma) > threshold; | |
656 | } | |
657 | ||
658 | /* Entities */ | |
620e762f | 659 | |
aa16b6c6 | 660 | int drm_sched_entity_init(struct drm_sched_entity *entity, |
b3ac1766 ND |
661 | enum drm_sched_priority priority, |
662 | struct drm_gpu_scheduler **sched_list, | |
9e3e90c5 | 663 | unsigned int num_sched_list, |
8344c53f | 664 | atomic_t *guilty); |
cdc50176 ND |
665 | long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout); |
666 | void drm_sched_entity_fini(struct drm_sched_entity *entity); | |
667 | void drm_sched_entity_destroy(struct drm_sched_entity *entity); | |
7febe4bf CK |
668 | void drm_sched_entity_set_priority(struct drm_sched_entity *entity, |
669 | enum drm_sched_priority priority); | |
70102d77 | 670 | int drm_sched_entity_error(struct drm_sched_entity *entity); |
27d48151 TU |
671 | void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, |
672 | struct drm_gpu_scheduler **sched_list, | |
673 | unsigned int num_sched_list); | |
1db8c142 | 674 | |
1b1f42d8 | 675 | #endif |