blob: 38efefd22dcefa83c8289a8fd74d8ea81e5bf1ea [file] [log] [blame]
Chris Wilsone2f34962018-10-01 15:47:54 +01001/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright © 2018 Intel Corporation
5 */
6
7#include <linux/mutex.h>
8
9#include "i915_drv.h"
10#include "i915_request.h"
11#include "i915_scheduler.h"
12
13static DEFINE_SPINLOCK(schedule_lock);
14
15static const struct i915_request *
16node_to_request(const struct i915_sched_node *node)
17{
18 return container_of(node, const struct i915_request, sched);
19}
20
Chris Wilsonbabfb1b2019-02-26 10:23:54 +000021static inline bool node_started(const struct i915_sched_node *node)
22{
23 return i915_request_started(node_to_request(node));
24}
25
Chris Wilsone2f34962018-10-01 15:47:54 +010026static inline bool node_signaled(const struct i915_sched_node *node)
27{
28 return i915_request_completed(node_to_request(node));
29}
30
31void i915_sched_node_init(struct i915_sched_node *node)
32{
33 INIT_LIST_HEAD(&node->signalers_list);
34 INIT_LIST_HEAD(&node->waiters_list);
35 INIT_LIST_HEAD(&node->link);
36 node->attr.priority = I915_PRIORITY_INVALID;
37}
38
39static struct i915_dependency *
40i915_dependency_alloc(struct drm_i915_private *i915)
41{
42 return kmem_cache_alloc(i915->dependencies, GFP_KERNEL);
43}
44
45static void
46i915_dependency_free(struct drm_i915_private *i915,
47 struct i915_dependency *dep)
48{
49 kmem_cache_free(i915->dependencies, dep);
50}
51
52bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
53 struct i915_sched_node *signal,
54 struct i915_dependency *dep,
55 unsigned long flags)
56{
57 bool ret = false;
58
59 spin_lock(&schedule_lock);
60
61 if (!node_signaled(signal)) {
62 INIT_LIST_HEAD(&dep->dfs_link);
63 list_add(&dep->wait_link, &signal->waiters_list);
64 list_add(&dep->signal_link, &node->signalers_list);
65 dep->signaler = signal;
66 dep->flags = flags;
67
68 ret = true;
69 }
70
71 spin_unlock(&schedule_lock);
72
73 return ret;
74}
75
76int i915_sched_node_add_dependency(struct drm_i915_private *i915,
77 struct i915_sched_node *node,
78 struct i915_sched_node *signal)
79{
80 struct i915_dependency *dep;
81
82 dep = i915_dependency_alloc(i915);
83 if (!dep)
84 return -ENOMEM;
85
86 if (!__i915_sched_node_add_dependency(node, signal, dep,
87 I915_DEPENDENCY_ALLOC))
88 i915_dependency_free(i915, dep);
89
90 return 0;
91}
92
93void i915_sched_node_fini(struct drm_i915_private *i915,
94 struct i915_sched_node *node)
95{
96 struct i915_dependency *dep, *tmp;
97
98 GEM_BUG_ON(!list_empty(&node->link));
99
100 spin_lock(&schedule_lock);
101
102 /*
103 * Everyone we depended upon (the fences we wait to be signaled)
104 * should retire before us and remove themselves from our list.
105 * However, retirement is run independently on each timeline and
106 * so we may be called out-of-order.
107 */
108 list_for_each_entry_safe(dep, tmp, &node->signalers_list, signal_link) {
109 GEM_BUG_ON(!node_signaled(dep->signaler));
110 GEM_BUG_ON(!list_empty(&dep->dfs_link));
111
112 list_del(&dep->wait_link);
113 if (dep->flags & I915_DEPENDENCY_ALLOC)
114 i915_dependency_free(i915, dep);
115 }
116
117 /* Remove ourselves from everyone who depends upon us */
118 list_for_each_entry_safe(dep, tmp, &node->waiters_list, wait_link) {
119 GEM_BUG_ON(dep->signaler != node);
120 GEM_BUG_ON(!list_empty(&dep->dfs_link));
121
122 list_del(&dep->signal_link);
123 if (dep->flags & I915_DEPENDENCY_ALLOC)
124 i915_dependency_free(i915, dep);
125 }
126
127 spin_unlock(&schedule_lock);
128}
129
130static inline struct i915_priolist *to_priolist(struct rb_node *rb)
131{
132 return rb_entry(rb, struct i915_priolist, node);
133}
134
Chris Wilson4d97cbe02019-01-29 18:54:51 +0000135static void assert_priolists(struct intel_engine_execlists * const execlists)
Chris Wilsone2f34962018-10-01 15:47:54 +0100136{
137 struct rb_node *rb;
138 long last_prio, i;
139
140 if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
141 return;
142
143 GEM_BUG_ON(rb_first_cached(&execlists->queue) !=
144 rb_first(&execlists->queue.rb_root));
145
Chris Wilson4d97cbe02019-01-29 18:54:51 +0000146 last_prio = (INT_MAX >> I915_USER_PRIORITY_SHIFT) + 1;
Chris Wilsone2f34962018-10-01 15:47:54 +0100147 for (rb = rb_first_cached(&execlists->queue); rb; rb = rb_next(rb)) {
148 const struct i915_priolist *p = to_priolist(rb);
149
150 GEM_BUG_ON(p->priority >= last_prio);
151 last_prio = p->priority;
152
153 GEM_BUG_ON(!p->used);
154 for (i = 0; i < ARRAY_SIZE(p->requests); i++) {
155 if (list_empty(&p->requests[i]))
156 continue;
157
158 GEM_BUG_ON(!(p->used & BIT(i)));
159 }
160 }
161}
162
163struct list_head *
164i915_sched_lookup_priolist(struct intel_engine_cs *engine, int prio)
165{
166 struct intel_engine_execlists * const execlists = &engine->execlists;
167 struct i915_priolist *p;
168 struct rb_node **parent, *rb;
169 bool first = true;
170 int idx, i;
171
172 lockdep_assert_held(&engine->timeline.lock);
Chris Wilson4d97cbe02019-01-29 18:54:51 +0000173 assert_priolists(execlists);
Chris Wilsone2f34962018-10-01 15:47:54 +0100174
175 /* buckets sorted from highest [in slot 0] to lowest priority */
176 idx = I915_PRIORITY_COUNT - (prio & I915_PRIORITY_MASK) - 1;
177 prio >>= I915_USER_PRIORITY_SHIFT;
178 if (unlikely(execlists->no_priolist))
179 prio = I915_PRIORITY_NORMAL;
180
181find_priolist:
182 /* most positive priority is scheduled first, equal priorities fifo */
183 rb = NULL;
184 parent = &execlists->queue.rb_root.rb_node;
185 while (*parent) {
186 rb = *parent;
187 p = to_priolist(rb);
188 if (prio > p->priority) {
189 parent = &rb->rb_left;
190 } else if (prio < p->priority) {
191 parent = &rb->rb_right;
192 first = false;
193 } else {
194 goto out;
195 }
196 }
197
198 if (prio == I915_PRIORITY_NORMAL) {
199 p = &execlists->default_priolist;
200 } else {
201 p = kmem_cache_alloc(engine->i915->priorities, GFP_ATOMIC);
202 /* Convert an allocation failure to a priority bump */
203 if (unlikely(!p)) {
204 prio = I915_PRIORITY_NORMAL; /* recurses just once */
205
206 /* To maintain ordering with all rendering, after an
207 * allocation failure we have to disable all scheduling.
208 * Requests will then be executed in fifo, and schedule
209 * will ensure that dependencies are emitted in fifo.
210 * There will be still some reordering with existing
211 * requests, so if userspace lied about their
212 * dependencies that reordering may be visible.
213 */
214 execlists->no_priolist = true;
215 goto find_priolist;
216 }
217 }
218
219 p->priority = prio;
220 for (i = 0; i < ARRAY_SIZE(p->requests); i++)
221 INIT_LIST_HEAD(&p->requests[i]);
222 rb_link_node(&p->node, rb, parent);
223 rb_insert_color_cached(&p->node, &execlists->queue, first);
224 p->used = 0;
225
226out:
227 p->used |= BIT(idx);
228 return &p->requests[idx];
229}
230
Chris Wilsoned7dc672019-02-11 20:46:47 +0000231struct sched_cache {
232 struct list_head *priolist;
233};
234
Chris Wilsone2f34962018-10-01 15:47:54 +0100235static struct intel_engine_cs *
Chris Wilsoned7dc672019-02-11 20:46:47 +0000236sched_lock_engine(const struct i915_sched_node *node,
237 struct intel_engine_cs *locked,
238 struct sched_cache *cache)
Chris Wilsone2f34962018-10-01 15:47:54 +0100239{
240 struct intel_engine_cs *engine = node_to_request(node)->engine;
241
242 GEM_BUG_ON(!locked);
243
244 if (engine != locked) {
245 spin_unlock(&locked->timeline.lock);
Chris Wilsoned7dc672019-02-11 20:46:47 +0000246 memset(cache, 0, sizeof(*cache));
Chris Wilsone2f34962018-10-01 15:47:54 +0100247 spin_lock(&engine->timeline.lock);
248 }
249
250 return engine;
251}
252
Chris Wilsonc9a64622019-01-29 18:54:52 +0000253static bool inflight(const struct i915_request *rq,
254 const struct intel_engine_cs *engine)
255{
256 const struct i915_request *active;
257
Chris Wilson52c0fdb2019-01-29 20:52:29 +0000258 if (!i915_request_is_active(rq))
Chris Wilsonc9a64622019-01-29 18:54:52 +0000259 return false;
260
261 active = port_request(engine->execlists.port);
262 return active->hw_context == rq->hw_context;
263}
264
Chris Wilsone9eaf822018-10-01 15:47:55 +0100265static void __i915_schedule(struct i915_request *rq,
266 const struct i915_sched_attr *attr)
Chris Wilsone2f34962018-10-01 15:47:54 +0100267{
Chris Wilsoned7dc672019-02-11 20:46:47 +0000268 struct intel_engine_cs *engine;
Chris Wilsone2f34962018-10-01 15:47:54 +0100269 struct i915_dependency *dep, *p;
270 struct i915_dependency stack;
271 const int prio = attr->priority;
Chris Wilsoned7dc672019-02-11 20:46:47 +0000272 struct sched_cache cache;
Chris Wilsone2f34962018-10-01 15:47:54 +0100273 LIST_HEAD(dfs);
274
Chris Wilsone9eaf822018-10-01 15:47:55 +0100275 /* Needed in order to use the temporary link inside i915_dependency */
276 lockdep_assert_held(&schedule_lock);
Chris Wilsone2f34962018-10-01 15:47:54 +0100277 GEM_BUG_ON(prio == I915_PRIORITY_INVALID);
278
279 if (i915_request_completed(rq))
280 return;
281
282 if (prio <= READ_ONCE(rq->sched.attr.priority))
283 return;
284
Chris Wilsone2f34962018-10-01 15:47:54 +0100285 stack.signaler = &rq->sched;
286 list_add(&stack.dfs_link, &dfs);
287
288 /*
289 * Recursively bump all dependent priorities to match the new request.
290 *
291 * A naive approach would be to use recursion:
292 * static void update_priorities(struct i915_sched_node *node, prio) {
293 * list_for_each_entry(dep, &node->signalers_list, signal_link)
294 * update_priorities(dep->signal, prio)
295 * queue_request(node);
296 * }
297 * but that may have unlimited recursion depth and so runs a very
298 * real risk of overunning the kernel stack. Instead, we build
299 * a flat list of all dependencies starting with the current request.
300 * As we walk the list of dependencies, we add all of its dependencies
301 * to the end of the list (this may include an already visited
302 * request) and continue to walk onwards onto the new dependencies. The
303 * end result is a topological list of requests in reverse order, the
304 * last element in the list is the request we must execute first.
305 */
306 list_for_each_entry(dep, &dfs, dfs_link) {
307 struct i915_sched_node *node = dep->signaler;
308
Chris Wilsonbabfb1b2019-02-26 10:23:54 +0000309 /* If we are already flying, we know we have no signalers */
310 if (node_started(node))
311 continue;
312
Chris Wilsone2f34962018-10-01 15:47:54 +0100313 /*
314 * Within an engine, there can be no cycle, but we may
315 * refer to the same dependency chain multiple times
316 * (redundant dependencies are not eliminated) and across
317 * engines.
318 */
319 list_for_each_entry(p, &node->signalers_list, signal_link) {
320 GEM_BUG_ON(p == dep); /* no cycles! */
321
322 if (node_signaled(p->signaler))
323 continue;
324
325 GEM_BUG_ON(p->signaler->attr.priority < node->attr.priority);
326 if (prio > READ_ONCE(p->signaler->attr.priority))
327 list_move_tail(&p->dfs_link, &dfs);
328 }
329 }
330
331 /*
332 * If we didn't need to bump any existing priorities, and we haven't
333 * yet submitted this request (i.e. there is no potential race with
334 * execlists_submit_request()), we can set our own priority and skip
335 * acquiring the engine locks.
336 */
337 if (rq->sched.attr.priority == I915_PRIORITY_INVALID) {
338 GEM_BUG_ON(!list_empty(&rq->sched.link));
339 rq->sched.attr = *attr;
340
341 if (stack.dfs_link.next == stack.dfs_link.prev)
Chris Wilsone9eaf822018-10-01 15:47:55 +0100342 return;
Chris Wilsone2f34962018-10-01 15:47:54 +0100343
344 __list_del_entry(&stack.dfs_link);
345 }
346
Chris Wilsoned7dc672019-02-11 20:46:47 +0000347 memset(&cache, 0, sizeof(cache));
Chris Wilsone2f34962018-10-01 15:47:54 +0100348 engine = rq->engine;
349 spin_lock_irq(&engine->timeline.lock);
350
351 /* Fifo and depth-first replacement ensure our deps execute before us */
352 list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) {
353 struct i915_sched_node *node = dep->signaler;
354
355 INIT_LIST_HEAD(&dep->dfs_link);
356
Chris Wilsoned7dc672019-02-11 20:46:47 +0000357 engine = sched_lock_engine(node, engine, &cache);
Chris Wilsonc9a64622019-01-29 18:54:52 +0000358 lockdep_assert_held(&engine->timeline.lock);
Chris Wilsone2f34962018-10-01 15:47:54 +0100359
360 /* Recheck after acquiring the engine->timeline.lock */
361 if (prio <= node->attr.priority || node_signaled(node))
362 continue;
363
364 node->attr.priority = prio;
365 if (!list_empty(&node->link)) {
Chris Wilsoned7dc672019-02-11 20:46:47 +0000366 if (!cache.priolist)
367 cache.priolist =
368 i915_sched_lookup_priolist(engine,
369 prio);
370 list_move_tail(&node->link, cache.priolist);
Chris Wilsone2f34962018-10-01 15:47:54 +0100371 } else {
372 /*
373 * If the request is not in the priolist queue because
374 * it is not yet runnable, then it doesn't contribute
375 * to our preemption decisions. On the other hand,
376 * if the request is on the HW, it too is not in the
377 * queue; but in that case we may still need to reorder
378 * the inflight requests.
379 */
380 if (!i915_sw_fence_done(&node_to_request(node)->submit))
381 continue;
382 }
383
Chris Wilson4d97cbe02019-01-29 18:54:51 +0000384 if (prio <= engine->execlists.queue_priority_hint)
Chris Wilsone2f34962018-10-01 15:47:54 +0100385 continue;
386
Chris Wilsonc9a64622019-01-29 18:54:52 +0000387 engine->execlists.queue_priority_hint = prio;
388
Chris Wilsone2f34962018-10-01 15:47:54 +0100389 /*
390 * If we are already the currently executing context, don't
391 * bother evaluating if we should preempt ourselves.
392 */
Chris Wilsonc9a64622019-01-29 18:54:52 +0000393 if (inflight(node_to_request(node), engine))
Chris Wilsone2f34962018-10-01 15:47:54 +0100394 continue;
395
396 /* Defer (tasklet) submission until after all of our updates. */
Chris Wilsone2f34962018-10-01 15:47:54 +0100397 tasklet_hi_schedule(&engine->execlists.tasklet);
398 }
399
400 spin_unlock_irq(&engine->timeline.lock);
Chris Wilsone9eaf822018-10-01 15:47:55 +0100401}
Chris Wilsone2f34962018-10-01 15:47:54 +0100402
Chris Wilsone9eaf822018-10-01 15:47:55 +0100403void i915_schedule(struct i915_request *rq, const struct i915_sched_attr *attr)
404{
405 spin_lock(&schedule_lock);
406 __i915_schedule(rq, attr);
Chris Wilsone2f34962018-10-01 15:47:54 +0100407 spin_unlock(&schedule_lock);
408}
Chris Wilsone9eaf822018-10-01 15:47:55 +0100409
410void i915_schedule_bump_priority(struct i915_request *rq, unsigned int bump)
411{
412 struct i915_sched_attr attr;
413
414 GEM_BUG_ON(bump & ~I915_PRIORITY_MASK);
415
416 if (READ_ONCE(rq->sched.attr.priority) == I915_PRIORITY_INVALID)
417 return;
418
419 spin_lock_bh(&schedule_lock);
420
421 attr = rq->sched.attr;
422 attr.priority |= bump;
423 __i915_schedule(rq, &attr);
424
425 spin_unlock_bh(&schedule_lock);
426}