1 1.8 tnn /* $NetBSD: i915_scheduler.c,v 1.8 2021/12/21 12:06:29 tnn Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * SPDX-License-Identifier: MIT 5 1.1 riastrad * 6 1.1 riastrad * Copyright 2018 Intel Corporation 7 1.1 riastrad */ 8 1.1 riastrad 9 1.1 riastrad #include <sys/cdefs.h> 10 1.8 tnn __KERNEL_RCSID(0, "$NetBSD: i915_scheduler.c,v 1.8 2021/12/21 12:06:29 tnn Exp $"); 11 1.1 riastrad 12 1.1 riastrad #include <linux/mutex.h> 13 1.1 riastrad 14 1.1 riastrad #include "i915_drv.h" 15 1.1 riastrad #include "i915_globals.h" 16 1.1 riastrad #include "i915_request.h" 17 1.1 riastrad #include "i915_scheduler.h" 18 1.1 riastrad 19 1.4 riastrad #include <linux/nbsd-namespace.h> 20 1.4 riastrad 21 1.1 riastrad static struct i915_global_scheduler { 22 1.1 riastrad struct i915_global base; 23 1.1 riastrad struct kmem_cache *slab_dependencies; 24 1.1 riastrad struct kmem_cache *slab_priorities; 25 1.1 riastrad } global; 26 1.1 riastrad 27 1.3 riastrad #ifdef __NetBSD__ 28 1.3 riastrad static spinlock_t schedule_lock; 29 1.3 riastrad spinlock_t *const i915_schedule_lock = &schedule_lock; 30 1.3 riastrad #else 31 1.1 riastrad static DEFINE_SPINLOCK(schedule_lock); 32 1.3 riastrad #endif 33 1.1 riastrad 34 1.1 riastrad static const struct i915_request * 35 1.1 riastrad node_to_request(const struct i915_sched_node *node) 36 1.1 riastrad { 37 1.8 tnn return const_container_of(node, struct i915_request, sched); 38 1.1 riastrad } 39 1.1 riastrad 40 1.1 riastrad static inline bool node_started(const struct i915_sched_node *node) 41 1.1 riastrad { 42 1.1 riastrad return i915_request_started(node_to_request(node)); 43 1.1 riastrad } 44 1.1 riastrad 45 1.1 riastrad static inline bool node_signaled(const struct i915_sched_node *node) 46 1.1 riastrad { 47 1.1 riastrad return i915_request_completed(node_to_request(node)); 48 1.1 riastrad } 49 1.1 riastrad 50 1.1 riastrad static inline struct i915_priolist *to_priolist(struct rb_node *rb) 51 1.1 riastrad { 52 1.1 riastrad return rb_entry(rb, struct i915_priolist, node); 53 1.1 riastrad } 54 1.1 riastrad 55 1.1 riastrad static void assert_priolists(struct intel_engine_execlists * const execlists) 56 1.1 riastrad { 57 1.1 riastrad struct rb_node *rb; 58 1.1 riastrad long last_prio, i; 59 1.1 riastrad 60 1.1 riastrad if (!IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) 61 1.1 riastrad return; 62 1.1 riastrad 63 1.1 riastrad GEM_BUG_ON(rb_first_cached(&execlists->queue) != 64 1.1 riastrad rb_first(&execlists->queue.rb_root)); 65 1.1 riastrad 66 1.1 riastrad last_prio = (INT_MAX >> I915_USER_PRIORITY_SHIFT) + 1; 67 1.4 riastrad for (rb = rb_first_cached(&execlists->queue); 68 1.4 riastrad rb; 69 1.4 riastrad rb = rb_next2(&execlists->queue.rb_root, rb)) { 70 1.1 riastrad const struct i915_priolist *p = to_priolist(rb); 71 1.1 riastrad 72 1.1 riastrad GEM_BUG_ON(p->priority >= last_prio); 73 1.1 riastrad last_prio = p->priority; 74 1.1 riastrad 75 1.1 riastrad GEM_BUG_ON(!p->used); 76 1.1 riastrad for (i = 0; i < ARRAY_SIZE(p->requests); i++) { 77 1.1 riastrad if (list_empty(&p->requests[i])) 78 1.1 riastrad continue; 79 1.1 riastrad 80 1.1 riastrad GEM_BUG_ON(!(p->used & BIT(i))); 81 1.1 riastrad } 82 1.1 riastrad } 83 1.1 riastrad } 84 1.1 riastrad 85 1.5 riastrad #ifdef __NetBSD__ 86 1.5 riastrad 87 1.5 riastrad static int 88 1.5 riastrad compare_priolists(void *cookie, const void *va, const void *vb) 89 1.5 riastrad { 90 1.5 riastrad const struct i915_priolist *a = va; 91 1.5 riastrad const struct i915_priolist *b = vb; 92 1.5 riastrad 93 1.7 riastrad if (a->priority > b->priority) 94 1.7 riastrad return -1; 95 1.5 riastrad if (a->priority < b->priority) 96 1.5 riastrad return +1; 97 1.5 riastrad return 0; 98 1.5 riastrad } 99 1.5 riastrad 100 1.5 riastrad static int 101 1.5 riastrad compare_priolist_key(void *cookie, const void *vp, const void *vk) 102 1.5 riastrad { 103 1.5 riastrad const struct i915_priolist *p = vp; 104 1.5 riastrad const int *priorityp = vk, priority = *priorityp; 105 1.5 riastrad 106 1.5 riastrad if (p->priority > priority) 107 1.5 riastrad return -1; 108 1.7 riastrad if (p->priority < priority) 109 1.7 riastrad return +1; 110 1.5 riastrad return 0; 111 1.5 riastrad } 112 1.5 riastrad 113 1.5 riastrad static const rb_tree_ops_t i915_priolist_rb_ops = { 114 1.5 riastrad .rbto_compare_nodes = compare_priolists, 115 1.5 riastrad .rbto_compare_key = compare_priolist_key, 116 1.5 riastrad .rbto_node_offset = offsetof(struct i915_priolist, node), 117 1.5 riastrad }; 118 1.5 riastrad 119 1.6 riastrad #endif 120 1.6 riastrad 121 1.5 riastrad void 122 1.5 riastrad i915_sched_init(struct intel_engine_execlists *execlists) 123 1.5 riastrad { 124 1.5 riastrad 125 1.6 riastrad #ifdef __NetBSD__ 126 1.5 riastrad rb_tree_init(&execlists->queue.rb_root.rbr_tree, 127 1.5 riastrad &i915_priolist_rb_ops); 128 1.6 riastrad #else 129 1.6 riastrad execlists->queue = RB_ROOT_CACHED; 130 1.6 riastrad #endif 131 1.5 riastrad } 132 1.5 riastrad 133 1.1 riastrad struct list_head * 134 1.1 riastrad i915_sched_lookup_priolist(struct intel_engine_cs *engine, int prio) 135 1.1 riastrad { 136 1.1 riastrad struct intel_engine_execlists * const execlists = &engine->execlists; 137 1.1 riastrad struct i915_priolist *p; 138 1.1 riastrad struct rb_node **parent, *rb; 139 1.1 riastrad bool first = true; 140 1.1 riastrad int idx, i; 141 1.1 riastrad 142 1.1 riastrad lockdep_assert_held(&engine->active.lock); 143 1.1 riastrad assert_priolists(execlists); 144 1.1 riastrad 145 1.1 riastrad /* buckets sorted from highest [in slot 0] to lowest priority */ 146 1.1 riastrad idx = I915_PRIORITY_COUNT - (prio & I915_PRIORITY_MASK) - 1; 147 1.1 riastrad prio >>= I915_USER_PRIORITY_SHIFT; 148 1.1 riastrad if (unlikely(execlists->no_priolist)) 149 1.1 riastrad prio = I915_PRIORITY_NORMAL; 150 1.1 riastrad 151 1.1 riastrad find_priolist: 152 1.4 riastrad #ifdef __NetBSD__ 153 1.4 riastrad /* XXX */ 154 1.4 riastrad __USE(first); 155 1.4 riastrad __USE(parent); 156 1.4 riastrad __USE(rb); 157 1.4 riastrad p = rb_tree_find_node(&execlists->queue.rb_root.rbr_tree, &prio); 158 1.4 riastrad if (p) 159 1.4 riastrad goto out; 160 1.4 riastrad #else 161 1.1 riastrad /* most positive priority is scheduled first, equal priorities fifo */ 162 1.1 riastrad rb = NULL; 163 1.1 riastrad parent = &execlists->queue.rb_root.rb_node; 164 1.1 riastrad while (*parent) { 165 1.1 riastrad rb = *parent; 166 1.1 riastrad p = to_priolist(rb); 167 1.1 riastrad if (prio > p->priority) { 168 1.1 riastrad parent = &rb->rb_left; 169 1.1 riastrad } else if (prio < p->priority) { 170 1.1 riastrad parent = &rb->rb_right; 171 1.1 riastrad first = false; 172 1.1 riastrad } else { 173 1.1 riastrad goto out; 174 1.1 riastrad } 175 1.1 riastrad } 176 1.4 riastrad #endif 177 1.1 riastrad 178 1.1 riastrad if (prio == I915_PRIORITY_NORMAL) { 179 1.1 riastrad p = &execlists->default_priolist; 180 1.1 riastrad } else { 181 1.1 riastrad p = kmem_cache_alloc(global.slab_priorities, GFP_ATOMIC); 182 1.1 riastrad /* Convert an allocation failure to a priority bump */ 183 1.1 riastrad if (unlikely(!p)) { 184 1.1 riastrad prio = I915_PRIORITY_NORMAL; /* recurses just once */ 185 1.1 riastrad 186 1.1 riastrad /* To maintain ordering with all rendering, after an 187 1.1 riastrad * allocation failure we have to disable all scheduling. 188 1.1 riastrad * Requests will then be executed in fifo, and schedule 189 1.1 riastrad * will ensure that dependencies are emitted in fifo. 190 1.1 riastrad * There will be still some reordering with existing 191 1.1 riastrad * requests, so if userspace lied about their 192 1.1 riastrad * dependencies that reordering may be visible. 193 1.1 riastrad */ 194 1.1 riastrad execlists->no_priolist = true; 195 1.1 riastrad goto find_priolist; 196 1.1 riastrad } 197 1.1 riastrad } 198 1.1 riastrad 199 1.1 riastrad p->priority = prio; 200 1.1 riastrad for (i = 0; i < ARRAY_SIZE(p->requests); i++) 201 1.1 riastrad INIT_LIST_HEAD(&p->requests[i]); 202 1.4 riastrad #ifdef __NetBSD__ 203 1.4 riastrad struct i915_priolist *collision __diagused; 204 1.4 riastrad collision = rb_tree_insert_node(&execlists->queue.rb_root.rbr_tree, 205 1.4 riastrad p); 206 1.4 riastrad KASSERT(collision == p); 207 1.4 riastrad #else 208 1.1 riastrad rb_link_node(&p->node, rb, parent); 209 1.1 riastrad rb_insert_color_cached(&p->node, &execlists->queue, first); 210 1.4 riastrad #endif 211 1.1 riastrad p->used = 0; 212 1.1 riastrad 213 1.1 riastrad out: 214 1.1 riastrad p->used |= BIT(idx); 215 1.1 riastrad return &p->requests[idx]; 216 1.1 riastrad } 217 1.1 riastrad 218 1.1 riastrad void __i915_priolist_free(struct i915_priolist *p) 219 1.1 riastrad { 220 1.1 riastrad kmem_cache_free(global.slab_priorities, p); 221 1.1 riastrad } 222 1.1 riastrad 223 1.1 riastrad struct sched_cache { 224 1.1 riastrad struct list_head *priolist; 225 1.1 riastrad }; 226 1.1 riastrad 227 1.1 riastrad static struct intel_engine_cs * 228 1.1 riastrad sched_lock_engine(const struct i915_sched_node *node, 229 1.1 riastrad struct intel_engine_cs *locked, 230 1.1 riastrad struct sched_cache *cache) 231 1.1 riastrad { 232 1.1 riastrad const struct i915_request *rq = node_to_request(node); 233 1.1 riastrad struct intel_engine_cs *engine; 234 1.1 riastrad 235 1.1 riastrad GEM_BUG_ON(!locked); 236 1.1 riastrad 237 1.1 riastrad /* 238 1.1 riastrad * Virtual engines complicate acquiring the engine timeline lock, 239 1.1 riastrad * as their rq->engine pointer is not stable until under that 240 1.1 riastrad * engine lock. The simple ploy we use is to take the lock then 241 1.1 riastrad * check that the rq still belongs to the newly locked engine. 242 1.1 riastrad */ 243 1.1 riastrad while (locked != (engine = READ_ONCE(rq->engine))) { 244 1.1 riastrad spin_unlock(&locked->active.lock); 245 1.1 riastrad memset(cache, 0, sizeof(*cache)); 246 1.1 riastrad spin_lock(&engine->active.lock); 247 1.1 riastrad locked = engine; 248 1.1 riastrad } 249 1.1 riastrad 250 1.1 riastrad GEM_BUG_ON(locked != engine); 251 1.1 riastrad return locked; 252 1.1 riastrad } 253 1.1 riastrad 254 1.1 riastrad static inline int rq_prio(const struct i915_request *rq) 255 1.1 riastrad { 256 1.1 riastrad return rq->sched.attr.priority | __NO_PREEMPTION; 257 1.1 riastrad } 258 1.1 riastrad 259 1.1 riastrad static inline bool need_preempt(int prio, int active) 260 1.1 riastrad { 261 1.1 riastrad /* 262 1.1 riastrad * Allow preemption of low -> normal -> high, but we do 263 1.1 riastrad * not allow low priority tasks to preempt other low priority 264 1.1 riastrad * tasks under the impression that latency for low priority 265 1.1 riastrad * tasks does not matter (as much as background throughput), 266 1.1 riastrad * so kiss. 267 1.1 riastrad */ 268 1.1 riastrad return prio >= max(I915_PRIORITY_NORMAL, active); 269 1.1 riastrad } 270 1.1 riastrad 271 1.1 riastrad static void kick_submission(struct intel_engine_cs *engine, 272 1.1 riastrad const struct i915_request *rq, 273 1.1 riastrad int prio) 274 1.1 riastrad { 275 1.1 riastrad const struct i915_request *inflight; 276 1.1 riastrad 277 1.1 riastrad /* 278 1.1 riastrad * We only need to kick the tasklet once for the high priority 279 1.1 riastrad * new context we add into the queue. 280 1.1 riastrad */ 281 1.1 riastrad if (prio <= engine->execlists.queue_priority_hint) 282 1.1 riastrad return; 283 1.1 riastrad 284 1.1 riastrad rcu_read_lock(); 285 1.1 riastrad 286 1.1 riastrad /* Nothing currently active? We're overdue for a submission! */ 287 1.1 riastrad inflight = execlists_active(&engine->execlists); 288 1.1 riastrad if (!inflight) 289 1.1 riastrad goto unlock; 290 1.1 riastrad 291 1.1 riastrad /* 292 1.1 riastrad * If we are already the currently executing context, don't 293 1.1 riastrad * bother evaluating if we should preempt ourselves. 294 1.1 riastrad */ 295 1.1 riastrad if (inflight->context == rq->context) 296 1.1 riastrad goto unlock; 297 1.1 riastrad 298 1.1 riastrad engine->execlists.queue_priority_hint = prio; 299 1.1 riastrad if (need_preempt(prio, rq_prio(inflight))) 300 1.1 riastrad tasklet_hi_schedule(&engine->execlists.tasklet); 301 1.1 riastrad 302 1.1 riastrad unlock: 303 1.1 riastrad rcu_read_unlock(); 304 1.1 riastrad } 305 1.1 riastrad 306 1.1 riastrad static void __i915_schedule(struct i915_sched_node *node, 307 1.1 riastrad const struct i915_sched_attr *attr) 308 1.1 riastrad { 309 1.1 riastrad struct intel_engine_cs *engine; 310 1.1 riastrad struct i915_dependency *dep, *p; 311 1.1 riastrad struct i915_dependency stack; 312 1.1 riastrad const int prio = attr->priority; 313 1.1 riastrad struct sched_cache cache; 314 1.1 riastrad LIST_HEAD(dfs); 315 1.1 riastrad 316 1.1 riastrad /* Needed in order to use the temporary link inside i915_dependency */ 317 1.1 riastrad lockdep_assert_held(&schedule_lock); 318 1.1 riastrad GEM_BUG_ON(prio == I915_PRIORITY_INVALID); 319 1.1 riastrad 320 1.1 riastrad if (prio <= READ_ONCE(node->attr.priority)) 321 1.1 riastrad return; 322 1.1 riastrad 323 1.1 riastrad if (node_signaled(node)) 324 1.1 riastrad return; 325 1.1 riastrad 326 1.1 riastrad stack.signaler = node; 327 1.1 riastrad list_add(&stack.dfs_link, &dfs); 328 1.1 riastrad 329 1.1 riastrad /* 330 1.1 riastrad * Recursively bump all dependent priorities to match the new request. 331 1.1 riastrad * 332 1.1 riastrad * A naive approach would be to use recursion: 333 1.1 riastrad * static void update_priorities(struct i915_sched_node *node, prio) { 334 1.1 riastrad * list_for_each_entry(dep, &node->signalers_list, signal_link) 335 1.1 riastrad * update_priorities(dep->signal, prio) 336 1.1 riastrad * queue_request(node); 337 1.1 riastrad * } 338 1.1 riastrad * but that may have unlimited recursion depth and so runs a very 339 1.1 riastrad * real risk of overunning the kernel stack. Instead, we build 340 1.1 riastrad * a flat list of all dependencies starting with the current request. 341 1.1 riastrad * As we walk the list of dependencies, we add all of its dependencies 342 1.1 riastrad * to the end of the list (this may include an already visited 343 1.1 riastrad * request) and continue to walk onwards onto the new dependencies. The 344 1.1 riastrad * end result is a topological list of requests in reverse order, the 345 1.1 riastrad * last element in the list is the request we must execute first. 346 1.1 riastrad */ 347 1.1 riastrad list_for_each_entry(dep, &dfs, dfs_link) { 348 1.1 riastrad struct i915_sched_node *node = dep->signaler; 349 1.1 riastrad 350 1.1 riastrad /* If we are already flying, we know we have no signalers */ 351 1.1 riastrad if (node_started(node)) 352 1.1 riastrad continue; 353 1.1 riastrad 354 1.1 riastrad /* 355 1.1 riastrad * Within an engine, there can be no cycle, but we may 356 1.1 riastrad * refer to the same dependency chain multiple times 357 1.1 riastrad * (redundant dependencies are not eliminated) and across 358 1.1 riastrad * engines. 359 1.1 riastrad */ 360 1.1 riastrad list_for_each_entry(p, &node->signalers_list, signal_link) { 361 1.1 riastrad GEM_BUG_ON(p == dep); /* no cycles! */ 362 1.1 riastrad 363 1.1 riastrad if (node_signaled(p->signaler)) 364 1.1 riastrad continue; 365 1.1 riastrad 366 1.1 riastrad if (prio > READ_ONCE(p->signaler->attr.priority)) 367 1.1 riastrad list_move_tail(&p->dfs_link, &dfs); 368 1.1 riastrad } 369 1.1 riastrad } 370 1.1 riastrad 371 1.1 riastrad /* 372 1.1 riastrad * If we didn't need to bump any existing priorities, and we haven't 373 1.1 riastrad * yet submitted this request (i.e. there is no potential race with 374 1.1 riastrad * execlists_submit_request()), we can set our own priority and skip 375 1.1 riastrad * acquiring the engine locks. 376 1.1 riastrad */ 377 1.1 riastrad if (node->attr.priority == I915_PRIORITY_INVALID) { 378 1.1 riastrad GEM_BUG_ON(!list_empty(&node->link)); 379 1.1 riastrad node->attr = *attr; 380 1.1 riastrad 381 1.1 riastrad if (stack.dfs_link.next == stack.dfs_link.prev) 382 1.1 riastrad return; 383 1.1 riastrad 384 1.1 riastrad __list_del_entry(&stack.dfs_link); 385 1.1 riastrad } 386 1.1 riastrad 387 1.1 riastrad memset(&cache, 0, sizeof(cache)); 388 1.1 riastrad engine = node_to_request(node)->engine; 389 1.1 riastrad spin_lock(&engine->active.lock); 390 1.1 riastrad 391 1.1 riastrad /* Fifo and depth-first replacement ensure our deps execute before us */ 392 1.1 riastrad engine = sched_lock_engine(node, engine, &cache); 393 1.1 riastrad list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) { 394 1.1 riastrad INIT_LIST_HEAD(&dep->dfs_link); 395 1.1 riastrad 396 1.1 riastrad node = dep->signaler; 397 1.1 riastrad engine = sched_lock_engine(node, engine, &cache); 398 1.1 riastrad lockdep_assert_held(&engine->active.lock); 399 1.1 riastrad 400 1.1 riastrad /* Recheck after acquiring the engine->timeline.lock */ 401 1.1 riastrad if (prio <= node->attr.priority || node_signaled(node)) 402 1.1 riastrad continue; 403 1.1 riastrad 404 1.1 riastrad GEM_BUG_ON(node_to_request(node)->engine != engine); 405 1.1 riastrad 406 1.1 riastrad node->attr.priority = prio; 407 1.1 riastrad 408 1.1 riastrad /* 409 1.1 riastrad * Once the request is ready, it will be placed into the 410 1.1 riastrad * priority lists and then onto the HW runlist. Before the 411 1.1 riastrad * request is ready, it does not contribute to our preemption 412 1.1 riastrad * decisions and we can safely ignore it, as it will, and 413 1.1 riastrad * any preemption required, be dealt with upon submission. 414 1.1 riastrad * See engine->submit_request() 415 1.1 riastrad */ 416 1.1 riastrad if (list_empty(&node->link)) 417 1.1 riastrad continue; 418 1.1 riastrad 419 1.1 riastrad if (i915_request_in_priority_queue(node_to_request(node))) { 420 1.1 riastrad if (!cache.priolist) 421 1.1 riastrad cache.priolist = 422 1.1 riastrad i915_sched_lookup_priolist(engine, 423 1.1 riastrad prio); 424 1.1 riastrad list_move_tail(&node->link, cache.priolist); 425 1.1 riastrad } 426 1.1 riastrad 427 1.1 riastrad /* Defer (tasklet) submission until after all of our updates. */ 428 1.1 riastrad kick_submission(engine, node_to_request(node), prio); 429 1.1 riastrad } 430 1.1 riastrad 431 1.1 riastrad spin_unlock(&engine->active.lock); 432 1.1 riastrad } 433 1.1 riastrad 434 1.1 riastrad void i915_schedule(struct i915_request *rq, const struct i915_sched_attr *attr) 435 1.1 riastrad { 436 1.1 riastrad spin_lock_irq(&schedule_lock); 437 1.1 riastrad __i915_schedule(&rq->sched, attr); 438 1.1 riastrad spin_unlock_irq(&schedule_lock); 439 1.1 riastrad } 440 1.1 riastrad 441 1.1 riastrad static void __bump_priority(struct i915_sched_node *node, unsigned int bump) 442 1.1 riastrad { 443 1.1 riastrad struct i915_sched_attr attr = node->attr; 444 1.1 riastrad 445 1.1 riastrad attr.priority |= bump; 446 1.1 riastrad __i915_schedule(node, &attr); 447 1.1 riastrad } 448 1.1 riastrad 449 1.1 riastrad void i915_schedule_bump_priority(struct i915_request *rq, unsigned int bump) 450 1.1 riastrad { 451 1.1 riastrad unsigned long flags; 452 1.1 riastrad 453 1.1 riastrad GEM_BUG_ON(bump & ~I915_PRIORITY_MASK); 454 1.1 riastrad if (READ_ONCE(rq->sched.attr.priority) & bump) 455 1.1 riastrad return; 456 1.1 riastrad 457 1.1 riastrad spin_lock_irqsave(&schedule_lock, flags); 458 1.1 riastrad __bump_priority(&rq->sched, bump); 459 1.1 riastrad spin_unlock_irqrestore(&schedule_lock, flags); 460 1.1 riastrad } 461 1.1 riastrad 462 1.1 riastrad void i915_sched_node_init(struct i915_sched_node *node) 463 1.1 riastrad { 464 1.1 riastrad INIT_LIST_HEAD(&node->signalers_list); 465 1.1 riastrad INIT_LIST_HEAD(&node->waiters_list); 466 1.1 riastrad INIT_LIST_HEAD(&node->link); 467 1.1 riastrad 468 1.1 riastrad i915_sched_node_reinit(node); 469 1.1 riastrad } 470 1.1 riastrad 471 1.1 riastrad void i915_sched_node_reinit(struct i915_sched_node *node) 472 1.1 riastrad { 473 1.1 riastrad node->attr.priority = I915_PRIORITY_INVALID; 474 1.1 riastrad node->semaphores = 0; 475 1.1 riastrad node->flags = 0; 476 1.1 riastrad 477 1.1 riastrad GEM_BUG_ON(!list_empty(&node->signalers_list)); 478 1.1 riastrad GEM_BUG_ON(!list_empty(&node->waiters_list)); 479 1.1 riastrad GEM_BUG_ON(!list_empty(&node->link)); 480 1.1 riastrad } 481 1.1 riastrad 482 1.1 riastrad static struct i915_dependency * 483 1.1 riastrad i915_dependency_alloc(void) 484 1.1 riastrad { 485 1.1 riastrad return kmem_cache_alloc(global.slab_dependencies, GFP_KERNEL); 486 1.1 riastrad } 487 1.1 riastrad 488 1.1 riastrad static void 489 1.1 riastrad i915_dependency_free(struct i915_dependency *dep) 490 1.1 riastrad { 491 1.1 riastrad kmem_cache_free(global.slab_dependencies, dep); 492 1.1 riastrad } 493 1.1 riastrad 494 1.1 riastrad bool __i915_sched_node_add_dependency(struct i915_sched_node *node, 495 1.1 riastrad struct i915_sched_node *signal, 496 1.1 riastrad struct i915_dependency *dep, 497 1.1 riastrad unsigned long flags) 498 1.1 riastrad { 499 1.1 riastrad bool ret = false; 500 1.1 riastrad 501 1.1 riastrad spin_lock_irq(&schedule_lock); 502 1.1 riastrad 503 1.1 riastrad if (!node_signaled(signal)) { 504 1.1 riastrad INIT_LIST_HEAD(&dep->dfs_link); 505 1.1 riastrad dep->signaler = signal; 506 1.1 riastrad dep->waiter = node; 507 1.1 riastrad dep->flags = flags; 508 1.1 riastrad 509 1.1 riastrad /* Keep track of whether anyone on this chain has a semaphore */ 510 1.1 riastrad if (signal->flags & I915_SCHED_HAS_SEMAPHORE_CHAIN && 511 1.1 riastrad !node_started(signal)) 512 1.1 riastrad node->flags |= I915_SCHED_HAS_SEMAPHORE_CHAIN; 513 1.1 riastrad 514 1.1 riastrad /* All set, now publish. Beware the lockless walkers. */ 515 1.1 riastrad list_add(&dep->signal_link, &node->signalers_list); 516 1.1 riastrad list_add_rcu(&dep->wait_link, &signal->waiters_list); 517 1.1 riastrad 518 1.1 riastrad /* 519 1.1 riastrad * As we do not allow WAIT to preempt inflight requests, 520 1.1 riastrad * once we have executed a request, along with triggering 521 1.1 riastrad * any execution callbacks, we must preserve its ordering 522 1.1 riastrad * within the non-preemptible FIFO. 523 1.1 riastrad */ 524 1.1 riastrad BUILD_BUG_ON(__NO_PREEMPTION & ~I915_PRIORITY_MASK); 525 1.1 riastrad if (flags & I915_DEPENDENCY_EXTERNAL) 526 1.1 riastrad __bump_priority(signal, __NO_PREEMPTION); 527 1.1 riastrad 528 1.1 riastrad ret = true; 529 1.1 riastrad } 530 1.1 riastrad 531 1.1 riastrad spin_unlock_irq(&schedule_lock); 532 1.1 riastrad 533 1.1 riastrad return ret; 534 1.1 riastrad } 535 1.1 riastrad 536 1.1 riastrad int i915_sched_node_add_dependency(struct i915_sched_node *node, 537 1.1 riastrad struct i915_sched_node *signal) 538 1.1 riastrad { 539 1.1 riastrad struct i915_dependency *dep; 540 1.1 riastrad 541 1.1 riastrad dep = i915_dependency_alloc(); 542 1.1 riastrad if (!dep) 543 1.1 riastrad return -ENOMEM; 544 1.1 riastrad 545 1.1 riastrad if (!__i915_sched_node_add_dependency(node, signal, dep, 546 1.1 riastrad I915_DEPENDENCY_EXTERNAL | 547 1.1 riastrad I915_DEPENDENCY_ALLOC)) 548 1.1 riastrad i915_dependency_free(dep); 549 1.1 riastrad 550 1.1 riastrad return 0; 551 1.1 riastrad } 552 1.1 riastrad 553 1.1 riastrad void i915_sched_node_fini(struct i915_sched_node *node) 554 1.1 riastrad { 555 1.1 riastrad struct i915_dependency *dep, *tmp; 556 1.1 riastrad 557 1.1 riastrad spin_lock_irq(&schedule_lock); 558 1.1 riastrad 559 1.1 riastrad /* 560 1.1 riastrad * Everyone we depended upon (the fences we wait to be signaled) 561 1.1 riastrad * should retire before us and remove themselves from our list. 562 1.1 riastrad * However, retirement is run independently on each timeline and 563 1.1 riastrad * so we may be called out-of-order. 564 1.1 riastrad */ 565 1.1 riastrad list_for_each_entry_safe(dep, tmp, &node->signalers_list, signal_link) { 566 1.1 riastrad GEM_BUG_ON(!list_empty(&dep->dfs_link)); 567 1.1 riastrad 568 1.1 riastrad list_del(&dep->wait_link); 569 1.1 riastrad if (dep->flags & I915_DEPENDENCY_ALLOC) 570 1.1 riastrad i915_dependency_free(dep); 571 1.1 riastrad } 572 1.1 riastrad INIT_LIST_HEAD(&node->signalers_list); 573 1.1 riastrad 574 1.1 riastrad /* Remove ourselves from everyone who depends upon us */ 575 1.1 riastrad list_for_each_entry_safe(dep, tmp, &node->waiters_list, wait_link) { 576 1.1 riastrad GEM_BUG_ON(dep->signaler != node); 577 1.1 riastrad GEM_BUG_ON(!list_empty(&dep->dfs_link)); 578 1.1 riastrad 579 1.1 riastrad list_del(&dep->signal_link); 580 1.1 riastrad if (dep->flags & I915_DEPENDENCY_ALLOC) 581 1.1 riastrad i915_dependency_free(dep); 582 1.1 riastrad } 583 1.1 riastrad INIT_LIST_HEAD(&node->waiters_list); 584 1.1 riastrad 585 1.1 riastrad spin_unlock_irq(&schedule_lock); 586 1.1 riastrad } 587 1.1 riastrad 588 1.1 riastrad static void i915_global_scheduler_shrink(void) 589 1.1 riastrad { 590 1.1 riastrad kmem_cache_shrink(global.slab_dependencies); 591 1.1 riastrad kmem_cache_shrink(global.slab_priorities); 592 1.1 riastrad } 593 1.1 riastrad 594 1.1 riastrad static void i915_global_scheduler_exit(void) 595 1.1 riastrad { 596 1.1 riastrad kmem_cache_destroy(global.slab_dependencies); 597 1.1 riastrad kmem_cache_destroy(global.slab_priorities); 598 1.1 riastrad } 599 1.1 riastrad 600 1.1 riastrad static struct i915_global_scheduler global = { { 601 1.1 riastrad .shrink = i915_global_scheduler_shrink, 602 1.1 riastrad .exit = i915_global_scheduler_exit, 603 1.1 riastrad } }; 604 1.1 riastrad 605 1.1 riastrad int __init i915_global_scheduler_init(void) 606 1.1 riastrad { 607 1.1 riastrad global.slab_dependencies = KMEM_CACHE(i915_dependency, 608 1.1 riastrad SLAB_HWCACHE_ALIGN); 609 1.1 riastrad if (!global.slab_dependencies) 610 1.1 riastrad return -ENOMEM; 611 1.1 riastrad 612 1.1 riastrad global.slab_priorities = KMEM_CACHE(i915_priolist, 613 1.1 riastrad SLAB_HWCACHE_ALIGN); 614 1.1 riastrad if (!global.slab_priorities) 615 1.1 riastrad goto err_priorities; 616 1.1 riastrad 617 1.1 riastrad i915_global_register(&global.base); 618 1.1 riastrad return 0; 619 1.1 riastrad 620 1.1 riastrad err_priorities: 621 1.1 riastrad kmem_cache_destroy(global.slab_priorities); 622 1.1 riastrad return -ENOMEM; 623 1.1 riastrad } 624