LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915 - i915_scheduler.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 7 213 3.3 %
Date: 2022-03-28 15:32:58 Functions: 1 14 7.1 %
Branches: 2 82 2.4 %

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

Generated by: LCOV version 1.14