LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915 - i915_gem_evict.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 122 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 3 0.0 %
Branches: 0 96 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright © 2008-2010 Intel Corporation
       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 (including the next
      12                 :            :  * paragraph) shall be included in all copies or substantial portions of the
      13                 :            :  * Software.
      14                 :            :  *
      15                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      18                 :            :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      20                 :            :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      21                 :            :  * IN THE SOFTWARE.
      22                 :            :  *
      23                 :            :  * Authors:
      24                 :            :  *    Eric Anholt <eric@anholt.net>
      25                 :            :  *    Chris Wilson <chris@chris-wilson.co.uuk>
      26                 :            :  *
      27                 :            :  */
      28                 :            : 
      29                 :            : #include <drm/i915_drm.h>
      30                 :            : 
      31                 :            : #include "gem/i915_gem_context.h"
      32                 :            : #include "gt/intel_gt_requests.h"
      33                 :            : 
      34                 :            : #include "i915_drv.h"
      35                 :            : #include "i915_trace.h"
      36                 :            : 
      37                 :            : I915_SELFTEST_DECLARE(static struct igt_evict_ctl {
      38                 :            :         bool fail_if_busy:1;
      39                 :            : } igt_evict_ctl;)
      40                 :            : 
      41                 :          0 : static int ggtt_flush(struct intel_gt *gt)
      42                 :            : {
      43                 :            :         /*
      44                 :            :          * Not everything in the GGTT is tracked via vma (otherwise we
      45                 :            :          * could evict as required with minimal stalling) so we are forced
      46                 :            :          * to idle the GPU and explicitly retire outstanding requests in
      47                 :            :          * the hopes that we can then remove contexts and the like only
      48                 :            :          * bound by their active reference.
      49                 :            :          */
      50                 :          0 :         return intel_gt_wait_for_idle(gt, MAX_SCHEDULE_TIMEOUT);
      51                 :            : }
      52                 :            : 
      53                 :            : static bool
      54                 :            : mark_free(struct drm_mm_scan *scan,
      55                 :            :           struct i915_vma *vma,
      56                 :            :           unsigned int flags,
      57                 :            :           struct list_head *unwind)
      58                 :            : {
      59                 :            :         if (i915_vma_is_pinned(vma))
      60                 :            :                 return false;
      61                 :            : 
      62                 :            :         list_add(&vma->evict_link, unwind);
      63                 :            :         return drm_mm_scan_add_block(scan, &vma->node);
      64                 :            : }
      65                 :            : 
      66                 :            : /**
      67                 :            :  * i915_gem_evict_something - Evict vmas to make room for binding a new one
      68                 :            :  * @vm: address space to evict from
      69                 :            :  * @min_size: size of the desired free space
      70                 :            :  * @alignment: alignment constraint of the desired free space
      71                 :            :  * @color: color for the desired space
      72                 :            :  * @start: start (inclusive) of the range from which to evict objects
      73                 :            :  * @end: end (exclusive) of the range from which to evict objects
      74                 :            :  * @flags: additional flags to control the eviction algorithm
      75                 :            :  *
      76                 :            :  * This function will try to evict vmas until a free space satisfying the
      77                 :            :  * requirements is found. Callers must check first whether any such hole exists
      78                 :            :  * already before calling this function.
      79                 :            :  *
      80                 :            :  * This function is used by the object/vma binding code.
      81                 :            :  *
      82                 :            :  * Since this function is only used to free up virtual address space it only
      83                 :            :  * ignores pinned vmas, and not object where the backing storage itself is
      84                 :            :  * pinned. Hence obj->pages_pin_count does not protect against eviction.
      85                 :            :  *
      86                 :            :  * To clarify: This is for freeing up virtual address space, not for freeing
      87                 :            :  * memory in e.g. the shrinker.
      88                 :            :  */
      89                 :            : int
      90                 :          0 : i915_gem_evict_something(struct i915_address_space *vm,
      91                 :            :                          u64 min_size, u64 alignment,
      92                 :            :                          unsigned long color,
      93                 :            :                          u64 start, u64 end,
      94                 :            :                          unsigned flags)
      95                 :            : {
      96                 :          0 :         struct drm_mm_scan scan;
      97                 :          0 :         struct list_head eviction_list;
      98                 :          0 :         struct i915_vma *vma, *next;
      99                 :          0 :         struct drm_mm_node *node;
     100                 :          0 :         enum drm_mm_insert_mode mode;
     101                 :          0 :         struct i915_vma *active;
     102                 :          0 :         int ret;
     103                 :            : 
     104                 :          0 :         lockdep_assert_held(&vm->mutex);
     105                 :          0 :         trace_i915_gem_evict(vm, min_size, alignment, flags);
     106                 :            : 
     107                 :            :         /*
     108                 :            :          * The goal is to evict objects and amalgamate space in rough LRU order.
     109                 :            :          * Since both active and inactive objects reside on the same list,
     110                 :            :          * in a mix of creation and last scanned order, as we process the list
     111                 :            :          * we sort it into inactive/active, which keeps the active portion
     112                 :            :          * in a rough MRU order.
     113                 :            :          *
     114                 :            :          * The retirement sequence is thus:
     115                 :            :          *   1. Inactive objects (already retired, random order)
     116                 :            :          *   2. Active objects (will stall on unbinding, oldest scanned first)
     117                 :            :          */
     118                 :          0 :         mode = DRM_MM_INSERT_BEST;
     119         [ #  # ]:          0 :         if (flags & PIN_HIGH)
     120                 :          0 :                 mode = DRM_MM_INSERT_HIGH;
     121         [ #  # ]:          0 :         if (flags & PIN_MAPPABLE)
     122                 :          0 :                 mode = DRM_MM_INSERT_LOW;
     123                 :          0 :         drm_mm_scan_init_with_range(&scan, &vm->mm,
     124                 :            :                                     min_size, alignment, color,
     125                 :            :                                     start, end, mode);
     126                 :            : 
     127                 :          0 :         intel_gt_retire_requests(vm->gt);
     128                 :            : 
     129                 :          0 : search_again:
     130                 :          0 :         active = NULL;
     131                 :          0 :         INIT_LIST_HEAD(&eviction_list);
     132         [ #  # ]:          0 :         list_for_each_entry_safe(vma, next, &vm->bound_list, vm_link) {
     133                 :            :                 /*
     134                 :            :                  * We keep this list in a rough least-recently scanned order
     135                 :            :                  * of active elements (inactive elements are cheap to reap).
     136                 :            :                  * New entries are added to the end, and we move anything we
     137                 :            :                  * scan to the end. The assumption is that the working set
     138                 :            :                  * of applications is either steady state (and thanks to the
     139                 :            :                  * userspace bo cache it almost always is) or volatile and
     140                 :            :                  * frequently replaced after a frame, which are self-evicting!
     141                 :            :                  * Given that assumption, the MRU order of the scan list is
     142                 :            :                  * fairly static, and keeping it in least-recently scan order
     143                 :            :                  * is suitable.
     144                 :            :                  *
     145                 :            :                  * To notice when we complete one full cycle, we record the
     146                 :            :                  * first active element seen, before moving it to the tail.
     147                 :            :                  */
     148         [ #  # ]:          0 :                 if (i915_vma_is_active(vma)) {
     149         [ #  # ]:          0 :                         if (vma == active) {
     150         [ #  # ]:          0 :                                 if (flags & PIN_NONBLOCK)
     151                 :            :                                         break;
     152                 :            : 
     153                 :            :                                 active = ERR_PTR(-EAGAIN);
     154                 :            :                         }
     155                 :            : 
     156         [ #  # ]:          0 :                         if (active != ERR_PTR(-EAGAIN)) {
     157         [ #  # ]:          0 :                                 if (!active)
     158                 :          0 :                                         active = vma;
     159                 :            : 
     160                 :          0 :                                 list_move_tail(&vma->vm_link, &vm->bound_list);
     161                 :          0 :                                 continue;
     162                 :            :                         }
     163                 :            :                 }
     164                 :            : 
     165         [ #  # ]:          0 :                 if (mark_free(&scan, vma, flags, &eviction_list))
     166                 :          0 :                         goto found;
     167                 :            :         }
     168                 :            : 
     169                 :            :         /* Nothing found, clean up and bail out! */
     170         [ #  # ]:          0 :         list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
     171                 :          0 :                 ret = drm_mm_scan_remove_block(&scan, &vma->node);
     172         [ #  # ]:          0 :                 BUG_ON(ret);
     173                 :            :         }
     174                 :            : 
     175                 :            :         /*
     176                 :            :          * Can we unpin some objects such as idle hw contents,
     177                 :            :          * or pending flips? But since only the GGTT has global entries
     178                 :            :          * such as scanouts, rinbuffers and contexts, we can skip the
     179                 :            :          * purge when inspecting per-process local address spaces.
     180                 :            :          */
     181   [ #  #  #  # ]:          0 :         if (!i915_is_ggtt(vm) || flags & PIN_NONBLOCK)
     182                 :            :                 return -ENOSPC;
     183                 :            : 
     184                 :            :         /*
     185                 :            :          * Not everything in the GGTT is tracked via VMA using
     186                 :            :          * i915_vma_move_to_active(), otherwise we could evict as required
     187                 :            :          * with minimal stalling. Instead we are forced to idle the GPU and
     188                 :            :          * explicitly retire outstanding requests which will then remove
     189                 :            :          * the pinning for active objects such as contexts and ring,
     190                 :            :          * enabling us to evict them on the next iteration.
     191                 :            :          *
     192                 :            :          * To ensure that all user contexts are evictable, we perform
     193                 :            :          * a switch to the perma-pinned kernel context. This all also gives
     194                 :            :          * us a termination condition, when the last retired context is
     195                 :            :          * the kernel's there is no more we can evict.
     196                 :            :          */
     197                 :          0 :         if (I915_SELFTEST_ONLY(igt_evict_ctl.fail_if_busy))
     198                 :            :                 return -EBUSY;
     199                 :            : 
     200                 :          0 :         ret = ggtt_flush(vm->gt);
     201         [ #  # ]:          0 :         if (ret)
     202                 :          0 :                 return ret;
     203                 :            : 
     204                 :          0 :         cond_resched();
     205                 :            : 
     206                 :          0 :         flags |= PIN_NONBLOCK;
     207                 :          0 :         goto search_again;
     208                 :            : 
     209                 :            : found:
     210                 :            :         /* drm_mm doesn't allow any other other operations while
     211                 :            :          * scanning, therefore store to-be-evicted objects on a
     212                 :            :          * temporary list and take a reference for all before
     213                 :            :          * calling unbind (which may remove the active reference
     214                 :            :          * of any of our objects, thus corrupting the list).
     215                 :            :          */
     216         [ #  # ]:          0 :         list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
     217         [ #  # ]:          0 :                 if (drm_mm_scan_remove_block(&scan, &vma->node))
     218                 :          0 :                         __i915_vma_pin(vma);
     219                 :            :                 else
     220                 :          0 :                         list_del(&vma->evict_link);
     221                 :            :         }
     222                 :            : 
     223                 :            :         /* Unbinding will emit any required flushes */
     224                 :          0 :         ret = 0;
     225         [ #  # ]:          0 :         list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
     226                 :          0 :                 __i915_vma_unpin(vma);
     227         [ #  # ]:          0 :                 if (ret == 0)
     228                 :          0 :                         ret = __i915_vma_unbind(vma);
     229                 :            :         }
     230                 :            : 
     231   [ #  #  #  # ]:          0 :         while (ret == 0 && (node = drm_mm_scan_color_evict(&scan))) {
     232                 :          0 :                 vma = container_of(node, struct i915_vma, node);
     233                 :          0 :                 ret = __i915_vma_unbind(vma);
     234                 :            :         }
     235                 :            : 
     236                 :            :         return ret;
     237                 :            : }
     238                 :            : 
     239                 :            : /**
     240                 :            :  * i915_gem_evict_for_vma - Evict vmas to make room for binding a new one
     241                 :            :  * @vm: address space to evict from
     242                 :            :  * @target: range (and color) to evict for
     243                 :            :  * @flags: additional flags to control the eviction algorithm
     244                 :            :  *
     245                 :            :  * This function will try to evict vmas that overlap the target node.
     246                 :            :  *
     247                 :            :  * To clarify: This is for freeing up virtual address space, not for freeing
     248                 :            :  * memory in e.g. the shrinker.
     249                 :            :  */
     250                 :          0 : int i915_gem_evict_for_node(struct i915_address_space *vm,
     251                 :            :                             struct drm_mm_node *target,
     252                 :            :                             unsigned int flags)
     253                 :            : {
     254                 :          0 :         LIST_HEAD(eviction_list);
     255                 :          0 :         struct drm_mm_node *node;
     256                 :          0 :         u64 start = target->start;
     257                 :          0 :         u64 end = start + target->size;
     258                 :          0 :         struct i915_vma *vma, *next;
     259                 :          0 :         int ret = 0;
     260                 :            : 
     261                 :          0 :         lockdep_assert_held(&vm->mutex);
     262                 :          0 :         GEM_BUG_ON(!IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
     263                 :          0 :         GEM_BUG_ON(!IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
     264                 :            : 
     265                 :          0 :         trace_i915_gem_evict_node(vm, target, flags);
     266                 :            : 
     267                 :            :         /*
     268                 :            :          * Retire before we search the active list. Although we have
     269                 :            :          * reasonable accuracy in our retirement lists, we may have
     270                 :            :          * a stray pin (preventing eviction) that can only be resolved by
     271                 :            :          * retiring.
     272                 :            :          */
     273                 :          0 :         intel_gt_retire_requests(vm->gt);
     274                 :            : 
     275   [ #  #  #  # ]:          0 :         if (i915_vm_has_cache_coloring(vm)) {
     276                 :            :                 /* Expand search to cover neighbouring guard pages (or lack!) */
     277         [ #  # ]:          0 :                 if (start)
     278                 :          0 :                         start -= I915_GTT_PAGE_SIZE;
     279                 :            : 
     280                 :            :                 /* Always look at the page afterwards to avoid the end-of-GTT */
     281                 :          0 :                 end += I915_GTT_PAGE_SIZE;
     282                 :            :         }
     283                 :          0 :         GEM_BUG_ON(start >= end);
     284                 :            : 
     285         [ #  # ]:          0 :         drm_mm_for_each_node_in_range(node, &vm->mm, start, end) {
     286                 :            :                 /* If we find any non-objects (!vma), we cannot evict them */
     287         [ #  # ]:          0 :                 if (node->color == I915_COLOR_UNEVICTABLE) {
     288                 :            :                         ret = -ENOSPC;
     289                 :            :                         break;
     290                 :            :                 }
     291                 :            : 
     292                 :          0 :                 GEM_BUG_ON(!drm_mm_node_allocated(node));
     293                 :          0 :                 vma = container_of(node, typeof(*vma), node);
     294                 :            : 
     295                 :            :                 /* If we are using coloring to insert guard pages between
     296                 :            :                  * different cache domains within the address space, we have
     297                 :            :                  * to check whether the objects on either side of our range
     298                 :            :                  * abutt and conflict. If they are in conflict, then we evict
     299                 :            :                  * those as well to make room for our guard pages.
     300                 :            :                  */
     301   [ #  #  #  # ]:          0 :                 if (i915_vm_has_cache_coloring(vm)) {
     302         [ #  # ]:          0 :                         if (node->start + node->size == target->start) {
     303         [ #  # ]:          0 :                                 if (node->color == target->color)
     304                 :          0 :                                         continue;
     305                 :            :                         }
     306         [ #  # ]:          0 :                         if (node->start == target->start + target->size) {
     307         [ #  # ]:          0 :                                 if (node->color == target->color)
     308                 :          0 :                                         continue;
     309                 :            :                         }
     310                 :            :                 }
     311                 :            : 
     312   [ #  #  #  # ]:          0 :                 if (flags & PIN_NONBLOCK &&
     313         [ #  # ]:          0 :                     (i915_vma_is_pinned(vma) || i915_vma_is_active(vma))) {
     314                 :            :                         ret = -ENOSPC;
     315                 :            :                         break;
     316                 :            :                 }
     317                 :            : 
     318                 :            :                 /* Overlap of objects in the same batch? */
     319         [ #  # ]:          0 :                 if (i915_vma_is_pinned(vma)) {
     320                 :          0 :                         ret = -ENOSPC;
     321         [ #  # ]:          0 :                         if (vma->exec_flags &&
     322         [ #  # ]:          0 :                             *vma->exec_flags & EXEC_OBJECT_PINNED)
     323                 :          0 :                                 ret = -EINVAL;
     324                 :            :                         break;
     325                 :            :                 }
     326                 :            : 
     327                 :            :                 /* Never show fear in the face of dragons!
     328                 :            :                  *
     329                 :            :                  * We cannot directly remove this node from within this
     330                 :            :                  * iterator and as with i915_gem_evict_something() we employ
     331                 :            :                  * the vma pin_count in order to prevent the action of
     332                 :            :                  * unbinding one vma from freeing (by dropping its active
     333                 :            :                  * reference) another in our eviction list.
     334                 :            :                  */
     335                 :          0 :                 __i915_vma_pin(vma);
     336                 :          0 :                 list_add(&vma->evict_link, &eviction_list);
     337                 :            :         }
     338                 :            : 
     339         [ #  # ]:          0 :         list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
     340                 :          0 :                 __i915_vma_unpin(vma);
     341         [ #  # ]:          0 :                 if (ret == 0)
     342                 :          0 :                         ret = __i915_vma_unbind(vma);
     343                 :            :         }
     344                 :            : 
     345                 :          0 :         return ret;
     346                 :            : }
     347                 :            : 
     348                 :            : /**
     349                 :            :  * i915_gem_evict_vm - Evict all idle vmas from a vm
     350                 :            :  * @vm: Address space to cleanse
     351                 :            :  *
     352                 :            :  * This function evicts all vmas from a vm.
     353                 :            :  *
     354                 :            :  * This is used by the execbuf code as a last-ditch effort to defragment the
     355                 :            :  * address space.
     356                 :            :  *
     357                 :            :  * To clarify: This is for freeing up virtual address space, not for freeing
     358                 :            :  * memory in e.g. the shrinker.
     359                 :            :  */
     360                 :          0 : int i915_gem_evict_vm(struct i915_address_space *vm)
     361                 :            : {
     362                 :          0 :         int ret = 0;
     363                 :            : 
     364                 :          0 :         lockdep_assert_held(&vm->mutex);
     365                 :          0 :         trace_i915_gem_evict_vm(vm);
     366                 :            : 
     367                 :            :         /* Switch back to the default context in order to unpin
     368                 :            :          * the existing context objects. However, such objects only
     369                 :            :          * pin themselves inside the global GTT and performing the
     370                 :            :          * switch otherwise is ineffective.
     371                 :            :          */
     372         [ #  # ]:          0 :         if (i915_is_ggtt(vm)) {
     373                 :          0 :                 ret = ggtt_flush(vm->gt);
     374         [ #  # ]:          0 :                 if (ret)
     375                 :            :                         return ret;
     376                 :            :         }
     377                 :            : 
     378                 :          0 :         do {
     379                 :          0 :                 struct i915_vma *vma, *vn;
     380                 :          0 :                 LIST_HEAD(eviction_list);
     381                 :            : 
     382         [ #  # ]:          0 :                 list_for_each_entry(vma, &vm->bound_list, vm_link) {
     383         [ #  # ]:          0 :                         if (i915_vma_is_pinned(vma))
     384                 :          0 :                                 continue;
     385                 :            : 
     386                 :          0 :                         __i915_vma_pin(vma);
     387                 :          0 :                         list_add(&vma->evict_link, &eviction_list);
     388                 :            :                 }
     389         [ #  # ]:          0 :                 if (list_empty(&eviction_list))
     390                 :            :                         break;
     391                 :            : 
     392                 :          0 :                 ret = 0;
     393         [ #  # ]:          0 :                 list_for_each_entry_safe(vma, vn, &eviction_list, evict_link) {
     394                 :          0 :                         __i915_vma_unpin(vma);
     395         [ #  # ]:          0 :                         if (ret == 0)
     396                 :          0 :                                 ret = __i915_vma_unbind(vma);
     397         [ #  # ]:          0 :                         if (ret != -EINTR) /* "Get me out of here!" */
     398                 :          0 :                                 ret = 0;
     399                 :            :                 }
     400         [ #  # ]:          0 :         } while (ret == 0);
     401                 :            : 
     402                 :            :         return ret;
     403                 :            : }
     404                 :            : 
     405                 :            : #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
     406                 :            : #include "selftests/i915_gem_evict.c"
     407                 :            : #endif

Generated by: LCOV version 1.14