18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright © 2016 Intel Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 138c2ecf20Sopenharmony_ci * Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 218c2ecf20Sopenharmony_ci * IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 268c2ecf20Sopenharmony_ci#include <drm/drm_gem.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "display/intel_frontbuffer.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "gt/intel_engine.h" 318c2ecf20Sopenharmony_ci#include "gt/intel_engine_heartbeat.h" 328c2ecf20Sopenharmony_ci#include "gt/intel_gt.h" 338c2ecf20Sopenharmony_ci#include "gt/intel_gt_requests.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "i915_drv.h" 368c2ecf20Sopenharmony_ci#include "i915_globals.h" 378c2ecf20Sopenharmony_ci#include "i915_sw_fence_work.h" 388c2ecf20Sopenharmony_ci#include "i915_trace.h" 398c2ecf20Sopenharmony_ci#include "i915_vma.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct i915_global_vma { 428c2ecf20Sopenharmony_ci struct i915_global base; 438c2ecf20Sopenharmony_ci struct kmem_cache *slab_vmas; 448c2ecf20Sopenharmony_ci} global; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct i915_vma *i915_vma_alloc(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci return kmem_cache_zalloc(global.slab_vmas, GFP_KERNEL); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_civoid i915_vma_free(struct i915_vma *vma) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci return kmem_cache_free(global.slab_vmas, vma); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_ERRLOG_GEM) && IS_ENABLED(CONFIG_DRM_DEBUG_MM) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#include <linux/stackdepot.h> 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void vma_print_allocator(struct i915_vma *vma, const char *reason) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned long *entries; 638c2ecf20Sopenharmony_ci unsigned int nr_entries; 648c2ecf20Sopenharmony_ci char buf[512]; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (!vma->node.stack) { 678c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: unknown owner\n", 688c2ecf20Sopenharmony_ci vma->node.start, vma->node.size, reason); 698c2ecf20Sopenharmony_ci return; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci nr_entries = stack_depot_fetch(vma->node.stack, &entries); 738c2ecf20Sopenharmony_ci stack_trace_snprint(buf, sizeof(buf), entries, nr_entries, 0); 748c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: inserted at %s\n", 758c2ecf20Sopenharmony_ci vma->node.start, vma->node.size, reason, buf); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#else 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void vma_print_allocator(struct i915_vma *vma, const char *reason) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline struct i915_vma *active_to_vma(struct i915_active *ref) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci return container_of(ref, typeof(struct i915_vma), active); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int __i915_vma_active(struct i915_active *ref) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci return i915_vma_tryget(active_to_vma(ref)) ? 0 : -ENOENT; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci__i915_active_call 978c2ecf20Sopenharmony_cistatic void __i915_vma_retire(struct i915_active *ref) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci i915_vma_put(active_to_vma(ref)); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic struct i915_vma * 1038c2ecf20Sopenharmony_civma_create(struct drm_i915_gem_object *obj, 1048c2ecf20Sopenharmony_ci struct i915_address_space *vm, 1058c2ecf20Sopenharmony_ci const struct i915_ggtt_view *view) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct i915_vma *pos = ERR_PTR(-E2BIG); 1088c2ecf20Sopenharmony_ci struct i915_vma *vma; 1098c2ecf20Sopenharmony_ci struct rb_node *rb, **p; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* The aliasing_ppgtt should never be used directly! */ 1128c2ecf20Sopenharmony_ci GEM_BUG_ON(vm == &vm->gt->ggtt->alias->vm); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci vma = i915_vma_alloc(); 1158c2ecf20Sopenharmony_ci if (vma == NULL) 1168c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci kref_init(&vma->ref); 1198c2ecf20Sopenharmony_ci mutex_init(&vma->pages_mutex); 1208c2ecf20Sopenharmony_ci vma->vm = i915_vm_get(vm); 1218c2ecf20Sopenharmony_ci vma->ops = &vm->vma_ops; 1228c2ecf20Sopenharmony_ci vma->obj = obj; 1238c2ecf20Sopenharmony_ci vma->resv = obj->base.resv; 1248c2ecf20Sopenharmony_ci vma->size = obj->base.size; 1258c2ecf20Sopenharmony_ci vma->display_alignment = I915_GTT_MIN_ALIGNMENT; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci i915_active_init(&vma->active, __i915_vma_active, __i915_vma_retire); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Declare ourselves safe for use inside shrinkers */ 1308c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_LOCKDEP)) { 1318c2ecf20Sopenharmony_ci fs_reclaim_acquire(GFP_KERNEL); 1328c2ecf20Sopenharmony_ci might_lock(&vma->active.mutex); 1338c2ecf20Sopenharmony_ci fs_reclaim_release(GFP_KERNEL); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vma->closed_link); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (view && view->type != I915_GGTT_VIEW_NORMAL) { 1398c2ecf20Sopenharmony_ci vma->ggtt_view = *view; 1408c2ecf20Sopenharmony_ci if (view->type == I915_GGTT_VIEW_PARTIAL) { 1418c2ecf20Sopenharmony_ci GEM_BUG_ON(range_overflows_t(u64, 1428c2ecf20Sopenharmony_ci view->partial.offset, 1438c2ecf20Sopenharmony_ci view->partial.size, 1448c2ecf20Sopenharmony_ci obj->base.size >> PAGE_SHIFT)); 1458c2ecf20Sopenharmony_ci vma->size = view->partial.size; 1468c2ecf20Sopenharmony_ci vma->size <<= PAGE_SHIFT; 1478c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->size > obj->base.size); 1488c2ecf20Sopenharmony_ci } else if (view->type == I915_GGTT_VIEW_ROTATED) { 1498c2ecf20Sopenharmony_ci vma->size = intel_rotation_info_size(&view->rotated); 1508c2ecf20Sopenharmony_ci vma->size <<= PAGE_SHIFT; 1518c2ecf20Sopenharmony_ci } else if (view->type == I915_GGTT_VIEW_REMAPPED) { 1528c2ecf20Sopenharmony_ci vma->size = intel_remapped_info_size(&view->remapped); 1538c2ecf20Sopenharmony_ci vma->size <<= PAGE_SHIFT; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (unlikely(vma->size > vm->total)) 1588c2ecf20Sopenharmony_ci goto err_vma; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE)); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spin_lock(&obj->vma.lock); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (i915_is_ggtt(vm)) { 1658c2ecf20Sopenharmony_ci if (unlikely(overflows_type(vma->size, u32))) 1668c2ecf20Sopenharmony_ci goto err_unlock; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci vma->fence_size = i915_gem_fence_size(vm->i915, vma->size, 1698c2ecf20Sopenharmony_ci i915_gem_object_get_tiling(obj), 1708c2ecf20Sopenharmony_ci i915_gem_object_get_stride(obj)); 1718c2ecf20Sopenharmony_ci if (unlikely(vma->fence_size < vma->size || /* overflow */ 1728c2ecf20Sopenharmony_ci vma->fence_size > vm->total)) 1738c2ecf20Sopenharmony_ci goto err_unlock; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(vma->fence_size, I915_GTT_MIN_ALIGNMENT)); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci vma->fence_alignment = i915_gem_fence_alignment(vm->i915, vma->size, 1788c2ecf20Sopenharmony_ci i915_gem_object_get_tiling(obj), 1798c2ecf20Sopenharmony_ci i915_gem_object_get_stride(obj)); 1808c2ecf20Sopenharmony_ci GEM_BUG_ON(!is_power_of_2(vma->fence_alignment)); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci __set_bit(I915_VMA_GGTT_BIT, __i915_vma_flags(vma)); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci rb = NULL; 1868c2ecf20Sopenharmony_ci p = &obj->vma.tree.rb_node; 1878c2ecf20Sopenharmony_ci while (*p) { 1888c2ecf20Sopenharmony_ci long cmp; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci rb = *p; 1918c2ecf20Sopenharmony_ci pos = rb_entry(rb, struct i915_vma, obj_node); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * If the view already exists in the tree, another thread 1958c2ecf20Sopenharmony_ci * already created a matching vma, so return the older instance 1968c2ecf20Sopenharmony_ci * and dispose of ours. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci cmp = i915_vma_compare(pos, vm, view); 1998c2ecf20Sopenharmony_ci if (cmp < 0) 2008c2ecf20Sopenharmony_ci p = &rb->rb_right; 2018c2ecf20Sopenharmony_ci else if (cmp > 0) 2028c2ecf20Sopenharmony_ci p = &rb->rb_left; 2038c2ecf20Sopenharmony_ci else 2048c2ecf20Sopenharmony_ci goto err_unlock; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci rb_link_node(&vma->obj_node, rb, p); 2078c2ecf20Sopenharmony_ci rb_insert_color(&vma->obj_node, &obj->vma.tree); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (i915_vma_is_ggtt(vma)) 2108c2ecf20Sopenharmony_ci /* 2118c2ecf20Sopenharmony_ci * We put the GGTT vma at the start of the vma-list, followed 2128c2ecf20Sopenharmony_ci * by the ppGGTT vma. This allows us to break early when 2138c2ecf20Sopenharmony_ci * iterating over only the GGTT vma for an object, see 2148c2ecf20Sopenharmony_ci * for_each_ggtt_vma() 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci list_add(&vma->obj_link, &obj->vma.list); 2178c2ecf20Sopenharmony_ci else 2188c2ecf20Sopenharmony_ci list_add_tail(&vma->obj_link, &obj->vma.list); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return vma; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cierr_unlock: 2258c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 2268c2ecf20Sopenharmony_cierr_vma: 2278c2ecf20Sopenharmony_ci i915_vm_put(vm); 2288c2ecf20Sopenharmony_ci i915_vma_free(vma); 2298c2ecf20Sopenharmony_ci return pos; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic struct i915_vma * 2338c2ecf20Sopenharmony_civma_lookup(struct drm_i915_gem_object *obj, 2348c2ecf20Sopenharmony_ci struct i915_address_space *vm, 2358c2ecf20Sopenharmony_ci const struct i915_ggtt_view *view) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct rb_node *rb; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci rb = obj->vma.tree.rb_node; 2408c2ecf20Sopenharmony_ci while (rb) { 2418c2ecf20Sopenharmony_ci struct i915_vma *vma = rb_entry(rb, struct i915_vma, obj_node); 2428c2ecf20Sopenharmony_ci long cmp; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci cmp = i915_vma_compare(vma, vm, view); 2458c2ecf20Sopenharmony_ci if (cmp == 0) 2468c2ecf20Sopenharmony_ci return vma; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (cmp < 0) 2498c2ecf20Sopenharmony_ci rb = rb->rb_right; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci rb = rb->rb_left; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return NULL; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * i915_vma_instance - return the singleton instance of the VMA 2598c2ecf20Sopenharmony_ci * @obj: parent &struct drm_i915_gem_object to be mapped 2608c2ecf20Sopenharmony_ci * @vm: address space in which the mapping is located 2618c2ecf20Sopenharmony_ci * @view: additional mapping requirements 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * i915_vma_instance() looks up an existing VMA of the @obj in the @vm with 2648c2ecf20Sopenharmony_ci * the same @view characteristics. If a match is not found, one is created. 2658c2ecf20Sopenharmony_ci * Once created, the VMA is kept until either the object is freed, or the 2668c2ecf20Sopenharmony_ci * address space is closed. 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Returns the vma, or an error pointer. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_cistruct i915_vma * 2718c2ecf20Sopenharmony_cii915_vma_instance(struct drm_i915_gem_object *obj, 2728c2ecf20Sopenharmony_ci struct i915_address_space *vm, 2738c2ecf20Sopenharmony_ci const struct i915_ggtt_view *view) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct i915_vma *vma; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci GEM_BUG_ON(view && !i915_is_ggtt(vm)); 2788c2ecf20Sopenharmony_ci GEM_BUG_ON(!atomic_read(&vm->open)); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci spin_lock(&obj->vma.lock); 2818c2ecf20Sopenharmony_ci vma = vma_lookup(obj, vm, view); 2828c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* vma_create() will resolve the race if another creates the vma */ 2858c2ecf20Sopenharmony_ci if (unlikely(!vma)) 2868c2ecf20Sopenharmony_ci vma = vma_create(obj, vm, view); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ERR(vma) && i915_vma_compare(vma, vm, view)); 2898c2ecf20Sopenharmony_ci return vma; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistruct i915_vma_work { 2938c2ecf20Sopenharmony_ci struct dma_fence_work base; 2948c2ecf20Sopenharmony_ci struct i915_address_space *vm; 2958c2ecf20Sopenharmony_ci struct i915_vm_pt_stash stash; 2968c2ecf20Sopenharmony_ci struct i915_vma *vma; 2978c2ecf20Sopenharmony_ci struct drm_i915_gem_object *pinned; 2988c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb cb; 2998c2ecf20Sopenharmony_ci enum i915_cache_level cache_level; 3008c2ecf20Sopenharmony_ci unsigned int flags; 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int __vma_bind(struct dma_fence_work *work) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct i915_vma_work *vw = container_of(work, typeof(*vw), base); 3068c2ecf20Sopenharmony_ci struct i915_vma *vma = vw->vma; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci vma->ops->bind_vma(vw->vm, &vw->stash, 3098c2ecf20Sopenharmony_ci vma, vw->cache_level, vw->flags); 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic void __vma_release(struct dma_fence_work *work) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct i915_vma_work *vw = container_of(work, typeof(*vw), base); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (vw->pinned) { 3188c2ecf20Sopenharmony_ci __i915_gem_object_unpin_pages(vw->pinned); 3198c2ecf20Sopenharmony_ci i915_gem_object_put(vw->pinned); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci i915_vm_free_pt_stash(vw->vm, &vw->stash); 3238c2ecf20Sopenharmony_ci i915_vm_put(vw->vm); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const struct dma_fence_work_ops bind_ops = { 3278c2ecf20Sopenharmony_ci .name = "bind", 3288c2ecf20Sopenharmony_ci .work = __vma_bind, 3298c2ecf20Sopenharmony_ci .release = __vma_release, 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistruct i915_vma_work *i915_vma_work(void) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct i915_vma_work *vw; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci vw = kzalloc(sizeof(*vw), GFP_KERNEL); 3378c2ecf20Sopenharmony_ci if (!vw) 3388c2ecf20Sopenharmony_ci return NULL; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci dma_fence_work_init(&vw->base, &bind_ops); 3418c2ecf20Sopenharmony_ci vw->base.dma.error = -EAGAIN; /* disable the worker by default */ 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return vw; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ciint i915_vma_wait_for_bind(struct i915_vma *vma) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci int err = 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (rcu_access_pointer(vma->active.excl.fence)) { 3518c2ecf20Sopenharmony_ci struct dma_fence *fence; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci rcu_read_lock(); 3548c2ecf20Sopenharmony_ci fence = dma_fence_get_rcu_safe(&vma->active.excl.fence); 3558c2ecf20Sopenharmony_ci rcu_read_unlock(); 3568c2ecf20Sopenharmony_ci if (fence) { 3578c2ecf20Sopenharmony_ci err = dma_fence_wait(fence, MAX_SCHEDULE_TIMEOUT); 3588c2ecf20Sopenharmony_ci dma_fence_put(fence); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return err; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/** 3668c2ecf20Sopenharmony_ci * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space. 3678c2ecf20Sopenharmony_ci * @vma: VMA to map 3688c2ecf20Sopenharmony_ci * @cache_level: mapping cache level 3698c2ecf20Sopenharmony_ci * @flags: flags like global or local mapping 3708c2ecf20Sopenharmony_ci * @work: preallocated worker for allocating and binding the PTE 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * DMA addresses are taken from the scatter-gather table of this object (or of 3738c2ecf20Sopenharmony_ci * this VMA in case of non-default GGTT views) and PTE entries set up. 3748c2ecf20Sopenharmony_ci * Note that DMA addresses are also the only part of the SG table we care about. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ciint i915_vma_bind(struct i915_vma *vma, 3778c2ecf20Sopenharmony_ci enum i915_cache_level cache_level, 3788c2ecf20Sopenharmony_ci u32 flags, 3798c2ecf20Sopenharmony_ci struct i915_vma_work *work) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci u32 bind_flags; 3828c2ecf20Sopenharmony_ci u32 vma_flags; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); 3858c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->size > vma->node.size); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (GEM_DEBUG_WARN_ON(range_overflows(vma->node.start, 3888c2ecf20Sopenharmony_ci vma->node.size, 3898c2ecf20Sopenharmony_ci vma->vm->total))) 3908c2ecf20Sopenharmony_ci return -ENODEV; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (GEM_DEBUG_WARN_ON(!flags)) 3938c2ecf20Sopenharmony_ci return -EINVAL; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci bind_flags = flags; 3968c2ecf20Sopenharmony_ci bind_flags &= I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci vma_flags = atomic_read(&vma->flags); 3998c2ecf20Sopenharmony_ci vma_flags &= I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci bind_flags &= ~vma_flags; 4028c2ecf20Sopenharmony_ci if (bind_flags == 0) 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci GEM_BUG_ON(!vma->pages); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci trace_i915_vma_bind(vma, bind_flags); 4088c2ecf20Sopenharmony_ci if (work && bind_flags & vma->vm->bind_async_flags) { 4098c2ecf20Sopenharmony_ci struct dma_fence *prev; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci work->vma = vma; 4128c2ecf20Sopenharmony_ci work->cache_level = cache_level; 4138c2ecf20Sopenharmony_ci work->flags = bind_flags; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci * Note we only want to chain up to the migration fence on 4178c2ecf20Sopenharmony_ci * the pages (not the object itself). As we don't track that, 4188c2ecf20Sopenharmony_ci * yet, we have to use the exclusive fence instead. 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * Also note that we do not want to track the async vma as 4218c2ecf20Sopenharmony_ci * part of the obj->resv->excl_fence as it only affects 4228c2ecf20Sopenharmony_ci * execution and not content or object's backing store lifetime. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_ci prev = i915_active_set_exclusive(&vma->active, &work->base.dma); 4258c2ecf20Sopenharmony_ci if (prev) { 4268c2ecf20Sopenharmony_ci __i915_sw_fence_await_dma_fence(&work->base.chain, 4278c2ecf20Sopenharmony_ci prev, 4288c2ecf20Sopenharmony_ci &work->cb); 4298c2ecf20Sopenharmony_ci dma_fence_put(prev); 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci work->base.dma.error = 0; /* enable the queue_work() */ 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (vma->obj) { 4358c2ecf20Sopenharmony_ci __i915_gem_object_pin_pages(vma->obj); 4368c2ecf20Sopenharmony_ci work->pinned = i915_gem_object_get(vma->obj); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci } else { 4398c2ecf20Sopenharmony_ci vma->ops->bind_vma(vma->vm, NULL, vma, cache_level, bind_flags); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (vma->obj) 4438c2ecf20Sopenharmony_ci set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci atomic_or(bind_flags, &vma->flags); 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_civoid __iomem *i915_vma_pin_iomap(struct i915_vma *vma) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci void __iomem *ptr; 4528c2ecf20Sopenharmony_ci int err; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (GEM_WARN_ON(!i915_vma_is_map_and_fenceable(vma))) { 4558c2ecf20Sopenharmony_ci err = -ENODEV; 4568c2ecf20Sopenharmony_ci goto err; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_ggtt(vma)); 4608c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ptr = READ_ONCE(vma->iomap); 4638c2ecf20Sopenharmony_ci if (ptr == NULL) { 4648c2ecf20Sopenharmony_ci ptr = io_mapping_map_wc(&i915_vm_to_ggtt(vma->vm)->iomap, 4658c2ecf20Sopenharmony_ci vma->node.start, 4668c2ecf20Sopenharmony_ci vma->node.size); 4678c2ecf20Sopenharmony_ci if (ptr == NULL) { 4688c2ecf20Sopenharmony_ci err = -ENOMEM; 4698c2ecf20Sopenharmony_ci goto err; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (unlikely(cmpxchg(&vma->iomap, NULL, ptr))) { 4738c2ecf20Sopenharmony_ci io_mapping_unmap(ptr); 4748c2ecf20Sopenharmony_ci ptr = vma->iomap; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci __i915_vma_pin(vma); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci err = i915_vma_pin_fence(vma); 4818c2ecf20Sopenharmony_ci if (err) 4828c2ecf20Sopenharmony_ci goto err_unpin; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci i915_vma_set_ggtt_write(vma); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* NB Access through the GTT requires the device to be awake. */ 4878c2ecf20Sopenharmony_ci return ptr; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cierr_unpin: 4908c2ecf20Sopenharmony_ci __i915_vma_unpin(vma); 4918c2ecf20Sopenharmony_cierr: 4928c2ecf20Sopenharmony_ci return IO_ERR_PTR(err); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_civoid i915_vma_flush_writes(struct i915_vma *vma) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci if (i915_vma_unset_ggtt_write(vma)) 4988c2ecf20Sopenharmony_ci intel_gt_flush_ggtt_writes(vma->vm->gt); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_civoid i915_vma_unpin_iomap(struct i915_vma *vma) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->iomap == NULL); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci i915_vma_flush_writes(vma); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci i915_vma_unpin_fence(vma); 5088c2ecf20Sopenharmony_ci i915_vma_unpin(vma); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_civoid i915_vma_unpin_and_release(struct i915_vma **p_vma, unsigned int flags) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct i915_vma *vma; 5148c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci vma = fetch_and_zero(p_vma); 5178c2ecf20Sopenharmony_ci if (!vma) 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci obj = vma->obj; 5218c2ecf20Sopenharmony_ci GEM_BUG_ON(!obj); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci i915_vma_unpin(vma); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (flags & I915_VMA_RELEASE_MAP) 5268c2ecf20Sopenharmony_ci i915_gem_object_unpin_map(obj); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cibool i915_vma_misplaced(const struct i915_vma *vma, 5328c2ecf20Sopenharmony_ci u64 size, u64 alignment, u64 flags) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci if (!drm_mm_node_allocated(&vma->node)) 5358c2ecf20Sopenharmony_ci return false; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (test_bit(I915_VMA_ERROR_BIT, __i915_vma_flags(vma))) 5388c2ecf20Sopenharmony_ci return true; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (vma->node.size < size) 5418c2ecf20Sopenharmony_ci return true; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci GEM_BUG_ON(alignment && !is_power_of_2(alignment)); 5448c2ecf20Sopenharmony_ci if (alignment && !IS_ALIGNED(vma->node.start, alignment)) 5458c2ecf20Sopenharmony_ci return true; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (flags & PIN_MAPPABLE && !i915_vma_is_map_and_fenceable(vma)) 5488c2ecf20Sopenharmony_ci return true; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (flags & PIN_OFFSET_BIAS && 5518c2ecf20Sopenharmony_ci vma->node.start < (flags & PIN_OFFSET_MASK)) 5528c2ecf20Sopenharmony_ci return true; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (flags & PIN_OFFSET_FIXED && 5558c2ecf20Sopenharmony_ci vma->node.start != (flags & PIN_OFFSET_MASK)) 5568c2ecf20Sopenharmony_ci return true; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return false; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_civoid __i915_vma_set_map_and_fenceable(struct i915_vma *vma) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci bool mappable, fenceable; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_ggtt(vma)); 5668c2ecf20Sopenharmony_ci GEM_BUG_ON(!vma->fence_size); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci fenceable = (vma->node.size >= vma->fence_size && 5698c2ecf20Sopenharmony_ci IS_ALIGNED(vma->node.start, vma->fence_alignment)); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci mappable = vma->node.start + vma->fence_size <= i915_vm_to_ggtt(vma->vm)->mappable_end; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (mappable && fenceable) 5748c2ecf20Sopenharmony_ci set_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(vma)); 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci clear_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(vma)); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cibool i915_gem_valid_gtt_space(struct i915_vma *vma, unsigned long color) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct drm_mm_node *node = &vma->node; 5828c2ecf20Sopenharmony_ci struct drm_mm_node *other; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* 5858c2ecf20Sopenharmony_ci * On some machines we have to be careful when putting differing types 5868c2ecf20Sopenharmony_ci * of snoopable memory together to avoid the prefetcher crossing memory 5878c2ecf20Sopenharmony_ci * domains and dying. During vm initialisation, we decide whether or not 5888c2ecf20Sopenharmony_ci * these constraints apply and set the drm_mm.color_adjust 5898c2ecf20Sopenharmony_ci * appropriately. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci if (!i915_vm_has_cache_coloring(vma->vm)) 5928c2ecf20Sopenharmony_ci return true; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* Only valid to be called on an already inserted vma */ 5958c2ecf20Sopenharmony_ci GEM_BUG_ON(!drm_mm_node_allocated(node)); 5968c2ecf20Sopenharmony_ci GEM_BUG_ON(list_empty(&node->node_list)); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci other = list_prev_entry(node, node_list); 5998c2ecf20Sopenharmony_ci if (i915_node_color_differs(other, color) && 6008c2ecf20Sopenharmony_ci !drm_mm_hole_follows(other)) 6018c2ecf20Sopenharmony_ci return false; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci other = list_next_entry(node, node_list); 6048c2ecf20Sopenharmony_ci if (i915_node_color_differs(other, color) && 6058c2ecf20Sopenharmony_ci !drm_mm_hole_follows(node)) 6068c2ecf20Sopenharmony_ci return false; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return true; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/** 6128c2ecf20Sopenharmony_ci * i915_vma_insert - finds a slot for the vma in its address space 6138c2ecf20Sopenharmony_ci * @vma: the vma 6148c2ecf20Sopenharmony_ci * @size: requested size in bytes (can be larger than the VMA) 6158c2ecf20Sopenharmony_ci * @alignment: required alignment 6168c2ecf20Sopenharmony_ci * @flags: mask of PIN_* flags to use 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * First we try to allocate some free space that meets the requirements for 6198c2ecf20Sopenharmony_ci * the VMA. Failiing that, if the flags permit, it will evict an old VMA, 6208c2ecf20Sopenharmony_ci * preferrably the oldest idle entry to make room for the new VMA. 6218c2ecf20Sopenharmony_ci * 6228c2ecf20Sopenharmony_ci * Returns: 6238c2ecf20Sopenharmony_ci * 0 on success, negative error code otherwise. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_cistatic int 6268c2ecf20Sopenharmony_cii915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci unsigned long color; 6298c2ecf20Sopenharmony_ci u64 start, end; 6308c2ecf20Sopenharmony_ci int ret; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND)); 6338c2ecf20Sopenharmony_ci GEM_BUG_ON(drm_mm_node_allocated(&vma->node)); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci size = max(size, vma->size); 6368c2ecf20Sopenharmony_ci alignment = max(alignment, vma->display_alignment); 6378c2ecf20Sopenharmony_ci if (flags & PIN_MAPPABLE) { 6388c2ecf20Sopenharmony_ci size = max_t(typeof(size), size, vma->fence_size); 6398c2ecf20Sopenharmony_ci alignment = max_t(typeof(alignment), 6408c2ecf20Sopenharmony_ci alignment, vma->fence_alignment); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)); 6448c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(alignment, I915_GTT_MIN_ALIGNMENT)); 6458c2ecf20Sopenharmony_ci GEM_BUG_ON(!is_power_of_2(alignment)); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0; 6488c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(start, I915_GTT_PAGE_SIZE)); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci end = vma->vm->total; 6518c2ecf20Sopenharmony_ci if (flags & PIN_MAPPABLE) 6528c2ecf20Sopenharmony_ci end = min_t(u64, end, i915_vm_to_ggtt(vma->vm)->mappable_end); 6538c2ecf20Sopenharmony_ci if (flags & PIN_ZONE_4G) 6548c2ecf20Sopenharmony_ci end = min_t(u64, end, (1ULL << 32) - I915_GTT_PAGE_SIZE); 6558c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(end, I915_GTT_PAGE_SIZE)); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* If binding the object/GGTT view requires more space than the entire 6588c2ecf20Sopenharmony_ci * aperture has, reject it early before evicting everything in a vain 6598c2ecf20Sopenharmony_ci * attempt to find space. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci if (size > end) { 6628c2ecf20Sopenharmony_ci DRM_DEBUG("Attempting to bind an object larger than the aperture: request=%llu > %s aperture=%llu\n", 6638c2ecf20Sopenharmony_ci size, flags & PIN_MAPPABLE ? "mappable" : "total", 6648c2ecf20Sopenharmony_ci end); 6658c2ecf20Sopenharmony_ci return -ENOSPC; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci color = 0; 6698c2ecf20Sopenharmony_ci if (vma->obj && i915_vm_has_cache_coloring(vma->vm)) 6708c2ecf20Sopenharmony_ci color = vma->obj->cache_level; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (flags & PIN_OFFSET_FIXED) { 6738c2ecf20Sopenharmony_ci u64 offset = flags & PIN_OFFSET_MASK; 6748c2ecf20Sopenharmony_ci if (!IS_ALIGNED(offset, alignment) || 6758c2ecf20Sopenharmony_ci range_overflows(offset, size, end)) 6768c2ecf20Sopenharmony_ci return -EINVAL; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci ret = i915_gem_gtt_reserve(vma->vm, &vma->node, 6798c2ecf20Sopenharmony_ci size, offset, color, 6808c2ecf20Sopenharmony_ci flags); 6818c2ecf20Sopenharmony_ci if (ret) 6828c2ecf20Sopenharmony_ci return ret; 6838c2ecf20Sopenharmony_ci } else { 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * We only support huge gtt pages through the 48b PPGTT, 6868c2ecf20Sopenharmony_ci * however we also don't want to force any alignment for 6878c2ecf20Sopenharmony_ci * objects which need to be tightly packed into the low 32bits. 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * Note that we assume that GGTT are limited to 4GiB for the 6908c2ecf20Sopenharmony_ci * forseeable future. See also i915_ggtt_offset(). 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci if (upper_32_bits(end - 1) && 6938c2ecf20Sopenharmony_ci vma->page_sizes.sg > I915_GTT_PAGE_SIZE) { 6948c2ecf20Sopenharmony_ci /* 6958c2ecf20Sopenharmony_ci * We can't mix 64K and 4K PTEs in the same page-table 6968c2ecf20Sopenharmony_ci * (2M block), and so to avoid the ugliness and 6978c2ecf20Sopenharmony_ci * complexity of coloring we opt for just aligning 64K 6988c2ecf20Sopenharmony_ci * objects to 2M. 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci u64 page_alignment = 7018c2ecf20Sopenharmony_ci rounddown_pow_of_two(vma->page_sizes.sg | 7028c2ecf20Sopenharmony_ci I915_GTT_PAGE_SIZE_2M); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* 7058c2ecf20Sopenharmony_ci * Check we don't expand for the limited Global GTT 7068c2ecf20Sopenharmony_ci * (mappable aperture is even more precious!). This 7078c2ecf20Sopenharmony_ci * also checks that we exclude the aliasing-ppgtt. 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_ggtt(vma)); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci alignment = max(alignment, page_alignment); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K) 7148c2ecf20Sopenharmony_ci size = round_up(size, I915_GTT_PAGE_SIZE_2M); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci ret = i915_gem_gtt_insert(vma->vm, &vma->node, 7188c2ecf20Sopenharmony_ci size, alignment, color, 7198c2ecf20Sopenharmony_ci start, end, flags); 7208c2ecf20Sopenharmony_ci if (ret) 7218c2ecf20Sopenharmony_ci return ret; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->node.start < start); 7248c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->node.start + vma->node.size > end); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); 7278c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color)); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci list_add_tail(&vma->vm_link, &vma->vm->bound_list); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void 7358c2ecf20Sopenharmony_cii915_vma_detach(struct i915_vma *vma) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); 7388c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND)); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* 7418c2ecf20Sopenharmony_ci * And finally now the object is completely decoupled from this 7428c2ecf20Sopenharmony_ci * vma, we can drop its hold on the backing storage and allow 7438c2ecf20Sopenharmony_ci * it to be reaped by the shrinker. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_ci list_del(&vma->vm_link); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic bool try_qad_pin(struct i915_vma *vma, unsigned int flags) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci unsigned int bound; 7518c2ecf20Sopenharmony_ci bool pinned = true; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci bound = atomic_read(&vma->flags); 7548c2ecf20Sopenharmony_ci do { 7558c2ecf20Sopenharmony_ci if (unlikely(flags & ~bound)) 7568c2ecf20Sopenharmony_ci return false; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (unlikely(bound & (I915_VMA_OVERFLOW | I915_VMA_ERROR))) 7598c2ecf20Sopenharmony_ci return false; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!(bound & I915_VMA_PIN_MASK)) 7628c2ecf20Sopenharmony_ci goto unpinned; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci GEM_BUG_ON(((bound + 1) & I915_VMA_PIN_MASK) == 0); 7658c2ecf20Sopenharmony_ci } while (!atomic_try_cmpxchg(&vma->flags, &bound, bound + 1)); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci return true; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ciunpinned: 7708c2ecf20Sopenharmony_ci /* 7718c2ecf20Sopenharmony_ci * If pin_count==0, but we are bound, check under the lock to avoid 7728c2ecf20Sopenharmony_ci * racing with a concurrent i915_vma_unbind(). 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci mutex_lock(&vma->vm->mutex); 7758c2ecf20Sopenharmony_ci do { 7768c2ecf20Sopenharmony_ci if (unlikely(bound & (I915_VMA_OVERFLOW | I915_VMA_ERROR))) { 7778c2ecf20Sopenharmony_ci pinned = false; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (unlikely(flags & ~bound)) { 7828c2ecf20Sopenharmony_ci pinned = false; 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci } while (!atomic_try_cmpxchg(&vma->flags, &bound, bound + 1)); 7868c2ecf20Sopenharmony_ci mutex_unlock(&vma->vm->mutex); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci return pinned; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic int vma_get_pages(struct i915_vma *vma) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci int err = 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (atomic_add_unless(&vma->pages_count, 1, 0)) 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* Allocations ahoy! */ 7998c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&vma->pages_mutex)) 8008c2ecf20Sopenharmony_ci return -EINTR; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (!atomic_read(&vma->pages_count)) { 8038c2ecf20Sopenharmony_ci if (vma->obj) { 8048c2ecf20Sopenharmony_ci err = i915_gem_object_pin_pages(vma->obj); 8058c2ecf20Sopenharmony_ci if (err) 8068c2ecf20Sopenharmony_ci goto unlock; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci err = vma->ops->set_pages(vma); 8108c2ecf20Sopenharmony_ci if (err) { 8118c2ecf20Sopenharmony_ci if (vma->obj) 8128c2ecf20Sopenharmony_ci i915_gem_object_unpin_pages(vma->obj); 8138c2ecf20Sopenharmony_ci goto unlock; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci atomic_inc(&vma->pages_count); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ciunlock: 8198c2ecf20Sopenharmony_ci mutex_unlock(&vma->pages_mutex); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci return err; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic void __vma_put_pages(struct i915_vma *vma, unsigned int count) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci /* We allocate under vma_get_pages, so beware the shrinker */ 8278c2ecf20Sopenharmony_ci mutex_lock_nested(&vma->pages_mutex, SINGLE_DEPTH_NESTING); 8288c2ecf20Sopenharmony_ci GEM_BUG_ON(atomic_read(&vma->pages_count) < count); 8298c2ecf20Sopenharmony_ci if (atomic_sub_return(count, &vma->pages_count) == 0) { 8308c2ecf20Sopenharmony_ci vma->ops->clear_pages(vma); 8318c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->pages); 8328c2ecf20Sopenharmony_ci if (vma->obj) 8338c2ecf20Sopenharmony_ci i915_gem_object_unpin_pages(vma->obj); 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci mutex_unlock(&vma->pages_mutex); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic void vma_put_pages(struct i915_vma *vma) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci if (atomic_add_unless(&vma->pages_count, -1, 1)) 8418c2ecf20Sopenharmony_ci return; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci __vma_put_pages(vma, 1); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic void vma_unbind_pages(struct i915_vma *vma) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci unsigned int count; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci lockdep_assert_held(&vma->vm->mutex); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* The upper portion of pages_count is the number of bindings */ 8538c2ecf20Sopenharmony_ci count = atomic_read(&vma->pages_count); 8548c2ecf20Sopenharmony_ci count >>= I915_VMA_PAGES_BIAS; 8558c2ecf20Sopenharmony_ci GEM_BUG_ON(!count); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci __vma_put_pages(vma, count | count << I915_VMA_PAGES_BIAS); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciint i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, 8618c2ecf20Sopenharmony_ci u64 size, u64 alignment, u64 flags) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct i915_vma_work *work = NULL; 8648c2ecf20Sopenharmony_ci intel_wakeref_t wakeref = 0; 8658c2ecf20Sopenharmony_ci unsigned int bound; 8668c2ecf20Sopenharmony_ci int err; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci#ifdef CONFIG_PROVE_LOCKING 8698c2ecf20Sopenharmony_ci if (debug_locks && lockdep_is_held(&vma->vm->i915->drm.struct_mutex)) 8708c2ecf20Sopenharmony_ci WARN_ON(!ww); 8718c2ecf20Sopenharmony_ci#endif 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci BUILD_BUG_ON(PIN_GLOBAL != I915_VMA_GLOBAL_BIND); 8748c2ecf20Sopenharmony_ci BUILD_BUG_ON(PIN_USER != I915_VMA_LOCAL_BIND); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci GEM_BUG_ON(!(flags & (PIN_USER | PIN_GLOBAL))); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* First try and grab the pin without rebinding the vma */ 8798c2ecf20Sopenharmony_ci if (try_qad_pin(vma, flags & I915_VMA_BIND_MASK)) 8808c2ecf20Sopenharmony_ci return 0; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci err = vma_get_pages(vma); 8838c2ecf20Sopenharmony_ci if (err) 8848c2ecf20Sopenharmony_ci return err; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (flags & PIN_GLOBAL) 8878c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(&vma->vm->i915->runtime_pm); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (flags & vma->vm->bind_async_flags) { 8908c2ecf20Sopenharmony_ci work = i915_vma_work(); 8918c2ecf20Sopenharmony_ci if (!work) { 8928c2ecf20Sopenharmony_ci err = -ENOMEM; 8938c2ecf20Sopenharmony_ci goto err_rpm; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci work->vm = i915_vm_get(vma->vm); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Allocate enough page directories to used PTE */ 8998c2ecf20Sopenharmony_ci if (vma->vm->allocate_va_range) { 9008c2ecf20Sopenharmony_ci err = i915_vm_alloc_pt_stash(vma->vm, 9018c2ecf20Sopenharmony_ci &work->stash, 9028c2ecf20Sopenharmony_ci vma->size); 9038c2ecf20Sopenharmony_ci if (err) 9048c2ecf20Sopenharmony_ci goto err_fence; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci err = i915_vm_pin_pt_stash(vma->vm, 9078c2ecf20Sopenharmony_ci &work->stash); 9088c2ecf20Sopenharmony_ci if (err) 9098c2ecf20Sopenharmony_ci goto err_fence; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* 9148c2ecf20Sopenharmony_ci * Differentiate between user/kernel vma inside the aliasing-ppgtt. 9158c2ecf20Sopenharmony_ci * 9168c2ecf20Sopenharmony_ci * We conflate the Global GTT with the user's vma when using the 9178c2ecf20Sopenharmony_ci * aliasing-ppgtt, but it is still vitally important to try and 9188c2ecf20Sopenharmony_ci * keep the use cases distinct. For example, userptr objects are 9198c2ecf20Sopenharmony_ci * not allowed inside the Global GTT as that will cause lock 9208c2ecf20Sopenharmony_ci * inversions when we have to evict them the mmu_notifier callbacks - 9218c2ecf20Sopenharmony_ci * but they are allowed to be part of the user ppGTT which can never 9228c2ecf20Sopenharmony_ci * be mapped. As such we try to give the distinct users of the same 9238c2ecf20Sopenharmony_ci * mutex, distinct lockclasses [equivalent to how we keep i915_ggtt 9248c2ecf20Sopenharmony_ci * and i915_ppgtt separate]. 9258c2ecf20Sopenharmony_ci * 9268c2ecf20Sopenharmony_ci * NB this may cause us to mask real lock inversions -- while the 9278c2ecf20Sopenharmony_ci * code is safe today, lockdep may not be able to spot future 9288c2ecf20Sopenharmony_ci * transgressions. 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci err = mutex_lock_interruptible_nested(&vma->vm->mutex, 9318c2ecf20Sopenharmony_ci !(flags & PIN_GLOBAL)); 9328c2ecf20Sopenharmony_ci if (err) 9338c2ecf20Sopenharmony_ci goto err_fence; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* No more allocations allowed now we hold vm->mutex */ 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (unlikely(i915_vma_is_closed(vma))) { 9388c2ecf20Sopenharmony_ci err = -ENOENT; 9398c2ecf20Sopenharmony_ci goto err_unlock; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci bound = atomic_read(&vma->flags); 9438c2ecf20Sopenharmony_ci if (unlikely(bound & I915_VMA_ERROR)) { 9448c2ecf20Sopenharmony_ci err = -ENOMEM; 9458c2ecf20Sopenharmony_ci goto err_unlock; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (unlikely(!((bound + 1) & I915_VMA_PIN_MASK))) { 9498c2ecf20Sopenharmony_ci err = -EAGAIN; /* pins are meant to be fairly temporary */ 9508c2ecf20Sopenharmony_ci goto err_unlock; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (unlikely(!(flags & ~bound & I915_VMA_BIND_MASK))) { 9548c2ecf20Sopenharmony_ci __i915_vma_pin(vma); 9558c2ecf20Sopenharmony_ci goto err_unlock; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci err = i915_active_acquire(&vma->active); 9598c2ecf20Sopenharmony_ci if (err) 9608c2ecf20Sopenharmony_ci goto err_unlock; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (!(bound & I915_VMA_BIND_MASK)) { 9638c2ecf20Sopenharmony_ci err = i915_vma_insert(vma, size, alignment, flags); 9648c2ecf20Sopenharmony_ci if (err) 9658c2ecf20Sopenharmony_ci goto err_active; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (i915_is_ggtt(vma->vm)) 9688c2ecf20Sopenharmony_ci __i915_vma_set_map_and_fenceable(vma); 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci GEM_BUG_ON(!vma->pages); 9728c2ecf20Sopenharmony_ci err = i915_vma_bind(vma, 9738c2ecf20Sopenharmony_ci vma->obj ? vma->obj->cache_level : 0, 9748c2ecf20Sopenharmony_ci flags, work); 9758c2ecf20Sopenharmony_ci if (err) 9768c2ecf20Sopenharmony_ci goto err_remove; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* There should only be at most 2 active bindings (user, global) */ 9798c2ecf20Sopenharmony_ci GEM_BUG_ON(bound + I915_VMA_PAGES_ACTIVE < bound); 9808c2ecf20Sopenharmony_ci atomic_add(I915_VMA_PAGES_ACTIVE, &vma->pages_count); 9818c2ecf20Sopenharmony_ci list_move_tail(&vma->vm_link, &vma->vm->bound_list); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci __i915_vma_pin(vma); 9848c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_pinned(vma)); 9858c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_bound(vma, flags)); 9868c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_misplaced(vma, size, alignment, flags)); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cierr_remove: 9898c2ecf20Sopenharmony_ci if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK)) { 9908c2ecf20Sopenharmony_ci i915_vma_detach(vma); 9918c2ecf20Sopenharmony_ci drm_mm_remove_node(&vma->node); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_cierr_active: 9948c2ecf20Sopenharmony_ci i915_active_release(&vma->active); 9958c2ecf20Sopenharmony_cierr_unlock: 9968c2ecf20Sopenharmony_ci mutex_unlock(&vma->vm->mutex); 9978c2ecf20Sopenharmony_cierr_fence: 9988c2ecf20Sopenharmony_ci if (work) 9998c2ecf20Sopenharmony_ci dma_fence_work_commit_imm(&work->base); 10008c2ecf20Sopenharmony_cierr_rpm: 10018c2ecf20Sopenharmony_ci if (wakeref) 10028c2ecf20Sopenharmony_ci intel_runtime_pm_put(&vma->vm->i915->runtime_pm, wakeref); 10038c2ecf20Sopenharmony_ci vma_put_pages(vma); 10048c2ecf20Sopenharmony_ci return err; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic void flush_idle_contexts(struct intel_gt *gt) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci struct intel_engine_cs *engine; 10108c2ecf20Sopenharmony_ci enum intel_engine_id id; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci for_each_engine(engine, gt, id) 10138c2ecf20Sopenharmony_ci intel_engine_flush_barriers(engine); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci intel_gt_wait_for_idle(gt, MAX_SCHEDULE_TIMEOUT); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ciint i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, 10198c2ecf20Sopenharmony_ci u32 align, unsigned int flags) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct i915_address_space *vm = vma->vm; 10228c2ecf20Sopenharmony_ci int err; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_ggtt(vma)); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci do { 10278c2ecf20Sopenharmony_ci err = i915_vma_pin_ww(vma, ww, 0, align, flags | PIN_GLOBAL); 10288c2ecf20Sopenharmony_ci if (err != -ENOSPC) { 10298c2ecf20Sopenharmony_ci if (!err) { 10308c2ecf20Sopenharmony_ci err = i915_vma_wait_for_bind(vma); 10318c2ecf20Sopenharmony_ci if (err) 10328c2ecf20Sopenharmony_ci i915_vma_unpin(vma); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci return err; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Unlike i915_vma_pin, we don't take no for an answer! */ 10388c2ecf20Sopenharmony_ci flush_idle_contexts(vm->gt); 10398c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&vm->mutex) == 0) { 10408c2ecf20Sopenharmony_ci i915_gem_evict_vm(vm); 10418c2ecf20Sopenharmony_ci mutex_unlock(&vm->mutex); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci } while (1); 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic void __vma_close(struct i915_vma *vma, struct intel_gt *gt) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci /* 10498c2ecf20Sopenharmony_ci * We defer actually closing, unbinding and destroying the VMA until 10508c2ecf20Sopenharmony_ci * the next idle point, or if the object is freed in the meantime. By 10518c2ecf20Sopenharmony_ci * postponing the unbind, we allow for it to be resurrected by the 10528c2ecf20Sopenharmony_ci * client, avoiding the work required to rebind the VMA. This is 10538c2ecf20Sopenharmony_ci * advantageous for DRI, where the client/server pass objects 10548c2ecf20Sopenharmony_ci * between themselves, temporarily opening a local VMA to the 10558c2ecf20Sopenharmony_ci * object, and then closing it again. The same object is then reused 10568c2ecf20Sopenharmony_ci * on the next frame (or two, depending on the depth of the swap queue) 10578c2ecf20Sopenharmony_ci * causing us to rebind the VMA once more. This ends up being a lot 10588c2ecf20Sopenharmony_ci * of wasted work for the steady state. 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_closed(vma)); 10618c2ecf20Sopenharmony_ci list_add(&vma->closed_link, >->closed_vma); 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_civoid i915_vma_close(struct i915_vma *vma) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct intel_gt *gt = vma->vm->gt; 10678c2ecf20Sopenharmony_ci unsigned long flags; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (i915_vma_is_ggtt(vma)) 10708c2ecf20Sopenharmony_ci return; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci GEM_BUG_ON(!atomic_read(&vma->open_count)); 10738c2ecf20Sopenharmony_ci if (atomic_dec_and_lock_irqsave(&vma->open_count, 10748c2ecf20Sopenharmony_ci >->closed_lock, 10758c2ecf20Sopenharmony_ci flags)) { 10768c2ecf20Sopenharmony_ci __vma_close(vma, gt); 10778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(>->closed_lock, flags); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic void __i915_vma_remove_closed(struct i915_vma *vma) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct intel_gt *gt = vma->vm->gt; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci spin_lock_irq(>->closed_lock); 10868c2ecf20Sopenharmony_ci list_del_init(&vma->closed_link); 10878c2ecf20Sopenharmony_ci spin_unlock_irq(>->closed_lock); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_civoid i915_vma_reopen(struct i915_vma *vma) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci if (i915_vma_is_closed(vma)) 10938c2ecf20Sopenharmony_ci __i915_vma_remove_closed(vma); 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_civoid i915_vma_release(struct kref *ref) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct i915_vma *vma = container_of(ref, typeof(*vma), ref); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (drm_mm_node_allocated(&vma->node)) { 11018c2ecf20Sopenharmony_ci mutex_lock(&vma->vm->mutex); 11028c2ecf20Sopenharmony_ci atomic_and(~I915_VMA_PIN_MASK, &vma->flags); 11038c2ecf20Sopenharmony_ci WARN_ON(__i915_vma_unbind(vma)); 11048c2ecf20Sopenharmony_ci mutex_unlock(&vma->vm->mutex); 11058c2ecf20Sopenharmony_ci GEM_BUG_ON(drm_mm_node_allocated(&vma->node)); 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_active(vma)); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (vma->obj) { 11108c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj = vma->obj; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci spin_lock(&obj->vma.lock); 11138c2ecf20Sopenharmony_ci list_del(&vma->obj_link); 11148c2ecf20Sopenharmony_ci if (!RB_EMPTY_NODE(&vma->obj_node)) 11158c2ecf20Sopenharmony_ci rb_erase(&vma->obj_node, &obj->vma.tree); 11168c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci __i915_vma_remove_closed(vma); 11208c2ecf20Sopenharmony_ci i915_vm_put(vma->vm); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci i915_active_fini(&vma->active); 11238c2ecf20Sopenharmony_ci i915_vma_free(vma); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_civoid i915_vma_parked(struct intel_gt *gt) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci struct i915_vma *vma, *next; 11298c2ecf20Sopenharmony_ci LIST_HEAD(closed); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci spin_lock_irq(>->closed_lock); 11328c2ecf20Sopenharmony_ci list_for_each_entry_safe(vma, next, >->closed_vma, closed_link) { 11338c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj = vma->obj; 11348c2ecf20Sopenharmony_ci struct i915_address_space *vm = vma->vm; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* XXX All to avoid keeping a reference on i915_vma itself */ 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&obj->base.refcount)) 11398c2ecf20Sopenharmony_ci continue; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (!i915_vm_tryopen(vm)) { 11428c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 11438c2ecf20Sopenharmony_ci continue; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci list_move(&vma->closed_link, &closed); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci spin_unlock_irq(>->closed_lock); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* As the GT is held idle, no vma can be reopened as we destroy them */ 11518c2ecf20Sopenharmony_ci list_for_each_entry_safe(vma, next, &closed, closed_link) { 11528c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj = vma->obj; 11538c2ecf20Sopenharmony_ci struct i915_address_space *vm = vma->vm; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vma->closed_link); 11568c2ecf20Sopenharmony_ci __i915_vma_put(vma); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 11598c2ecf20Sopenharmony_ci i915_vm_close(vm); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic void __i915_vma_iounmap(struct i915_vma *vma) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_pinned(vma)); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (vma->iomap == NULL) 11688c2ecf20Sopenharmony_ci return; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci io_mapping_unmap(vma->iomap); 11718c2ecf20Sopenharmony_ci vma->iomap = NULL; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_civoid i915_vma_revoke_mmap(struct i915_vma *vma) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct drm_vma_offset_node *node; 11778c2ecf20Sopenharmony_ci u64 vma_offset; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (!i915_vma_has_userfault(vma)) 11808c2ecf20Sopenharmony_ci return; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma)); 11838c2ecf20Sopenharmony_ci GEM_BUG_ON(!vma->obj->userfault_count); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci node = &vma->mmo->vma_node; 11868c2ecf20Sopenharmony_ci vma_offset = vma->ggtt_view.partial.offset << PAGE_SHIFT; 11878c2ecf20Sopenharmony_ci unmap_mapping_range(vma->vm->i915->drm.anon_inode->i_mapping, 11888c2ecf20Sopenharmony_ci drm_vma_node_offset_addr(node) + vma_offset, 11898c2ecf20Sopenharmony_ci vma->size, 11908c2ecf20Sopenharmony_ci 1); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci i915_vma_unset_userfault(vma); 11938c2ecf20Sopenharmony_ci if (!--vma->obj->userfault_count) 11948c2ecf20Sopenharmony_ci list_del(&vma->obj->userfault_link); 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cistatic int 11988c2ecf20Sopenharmony_ci__i915_request_await_bind(struct i915_request *rq, struct i915_vma *vma) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci return __i915_request_await_exclusive(rq, &vma->active); 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ciint __i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci int err; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_pinned(vma)); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* Wait for the vma to be bound before we start! */ 12108c2ecf20Sopenharmony_ci err = __i915_request_await_bind(rq, vma); 12118c2ecf20Sopenharmony_ci if (err) 12128c2ecf20Sopenharmony_ci return err; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci return i915_active_add_request(&vma->active, rq); 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ciint i915_vma_move_to_active(struct i915_vma *vma, 12188c2ecf20Sopenharmony_ci struct i915_request *rq, 12198c2ecf20Sopenharmony_ci unsigned int flags) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj = vma->obj; 12228c2ecf20Sopenharmony_ci int err; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci assert_object_held(obj); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci err = __i915_vma_move_to_active(vma, rq); 12278c2ecf20Sopenharmony_ci if (unlikely(err)) 12288c2ecf20Sopenharmony_ci return err; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (flags & EXEC_OBJECT_WRITE) { 12318c2ecf20Sopenharmony_ci struct intel_frontbuffer *front; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci front = __intel_frontbuffer_get(obj); 12348c2ecf20Sopenharmony_ci if (unlikely(front)) { 12358c2ecf20Sopenharmony_ci if (intel_frontbuffer_invalidate(front, ORIGIN_CS)) 12368c2ecf20Sopenharmony_ci i915_active_add_request(&front->write, rq); 12378c2ecf20Sopenharmony_ci intel_frontbuffer_put(front); 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci dma_resv_add_excl_fence(vma->resv, &rq->fence); 12418c2ecf20Sopenharmony_ci obj->write_domain = I915_GEM_DOMAIN_RENDER; 12428c2ecf20Sopenharmony_ci obj->read_domains = 0; 12438c2ecf20Sopenharmony_ci } else { 12448c2ecf20Sopenharmony_ci err = dma_resv_reserve_shared(vma->resv, 1); 12458c2ecf20Sopenharmony_ci if (unlikely(err)) 12468c2ecf20Sopenharmony_ci return err; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci dma_resv_add_shared_fence(vma->resv, &rq->fence); 12498c2ecf20Sopenharmony_ci obj->write_domain = 0; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (flags & EXEC_OBJECT_NEEDS_FENCE && vma->fence) 12538c2ecf20Sopenharmony_ci i915_active_add_request(&vma->fence->active, rq); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci obj->read_domains |= I915_GEM_GPU_DOMAINS; 12568c2ecf20Sopenharmony_ci obj->mm.dirty = true; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci GEM_BUG_ON(!i915_vma_is_active(vma)); 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_civoid __i915_vma_evict(struct i915_vma *vma) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_pinned(vma)); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (i915_vma_is_map_and_fenceable(vma)) { 12678c2ecf20Sopenharmony_ci /* Force a pagefault for domain tracking on next user access */ 12688c2ecf20Sopenharmony_ci i915_vma_revoke_mmap(vma); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* 12718c2ecf20Sopenharmony_ci * Check that we have flushed all writes through the GGTT 12728c2ecf20Sopenharmony_ci * before the unbind, other due to non-strict nature of those 12738c2ecf20Sopenharmony_ci * indirect writes they may end up referencing the GGTT PTE 12748c2ecf20Sopenharmony_ci * after the unbind. 12758c2ecf20Sopenharmony_ci * 12768c2ecf20Sopenharmony_ci * Note that we may be concurrently poking at the GGTT_WRITE 12778c2ecf20Sopenharmony_ci * bit from set-domain, as we mark all GGTT vma associated 12788c2ecf20Sopenharmony_ci * with an object. We know this is for another vma, as we 12798c2ecf20Sopenharmony_ci * are currently unbinding this one -- so if this vma will be 12808c2ecf20Sopenharmony_ci * reused, it will be refaulted and have its dirty bit set 12818c2ecf20Sopenharmony_ci * before the next write. 12828c2ecf20Sopenharmony_ci */ 12838c2ecf20Sopenharmony_ci i915_vma_flush_writes(vma); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* release the fence reg _after_ flushing */ 12868c2ecf20Sopenharmony_ci i915_vma_revoke_fence(vma); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci __i915_vma_iounmap(vma); 12898c2ecf20Sopenharmony_ci clear_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(vma)); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci GEM_BUG_ON(vma->fence); 12928c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_has_userfault(vma)); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (likely(atomic_read(&vma->vm->open))) { 12958c2ecf20Sopenharmony_ci trace_i915_vma_unbind(vma); 12968c2ecf20Sopenharmony_ci vma->ops->unbind_vma(vma->vm, vma); 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci atomic_and(~(I915_VMA_BIND_MASK | I915_VMA_ERROR | I915_VMA_GGTT_WRITE), 12998c2ecf20Sopenharmony_ci &vma->flags); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci i915_vma_detach(vma); 13028c2ecf20Sopenharmony_ci vma_unbind_pages(vma); 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ciint __i915_vma_unbind(struct i915_vma *vma) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci int ret; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci lockdep_assert_held(&vma->vm->mutex); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (!drm_mm_node_allocated(&vma->node)) 13128c2ecf20Sopenharmony_ci return 0; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (i915_vma_is_pinned(vma)) { 13158c2ecf20Sopenharmony_ci vma_print_allocator(vma, "is pinned"); 13168c2ecf20Sopenharmony_ci return -EAGAIN; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* 13208c2ecf20Sopenharmony_ci * After confirming that no one else is pinning this vma, wait for 13218c2ecf20Sopenharmony_ci * any laggards who may have crept in during the wait (through 13228c2ecf20Sopenharmony_ci * a residual pin skipping the vm->mutex) to complete. 13238c2ecf20Sopenharmony_ci */ 13248c2ecf20Sopenharmony_ci ret = i915_vma_sync(vma); 13258c2ecf20Sopenharmony_ci if (ret) 13268c2ecf20Sopenharmony_ci return ret; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_is_active(vma)); 13298c2ecf20Sopenharmony_ci __i915_vma_evict(vma); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci drm_mm_remove_node(&vma->node); /* pairs with i915_vma_release() */ 13328c2ecf20Sopenharmony_ci return 0; 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ciint i915_vma_unbind(struct i915_vma *vma) 13368c2ecf20Sopenharmony_ci{ 13378c2ecf20Sopenharmony_ci struct i915_address_space *vm = vma->vm; 13388c2ecf20Sopenharmony_ci intel_wakeref_t wakeref = 0; 13398c2ecf20Sopenharmony_ci int err; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* Optimistic wait before taking the mutex */ 13428c2ecf20Sopenharmony_ci err = i915_vma_sync(vma); 13438c2ecf20Sopenharmony_ci if (err) 13448c2ecf20Sopenharmony_ci return err; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (!drm_mm_node_allocated(&vma->node)) 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (i915_vma_is_pinned(vma)) { 13508c2ecf20Sopenharmony_ci vma_print_allocator(vma, "is pinned"); 13518c2ecf20Sopenharmony_ci return -EAGAIN; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) 13558c2ecf20Sopenharmony_ci /* XXX not always required: nop_clear_range */ 13568c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(&vm->i915->runtime_pm); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci err = mutex_lock_interruptible_nested(&vma->vm->mutex, !wakeref); 13598c2ecf20Sopenharmony_ci if (err) 13608c2ecf20Sopenharmony_ci goto out_rpm; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci err = __i915_vma_unbind(vma); 13638c2ecf20Sopenharmony_ci mutex_unlock(&vm->mutex); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ciout_rpm: 13668c2ecf20Sopenharmony_ci if (wakeref) 13678c2ecf20Sopenharmony_ci intel_runtime_pm_put(&vm->i915->runtime_pm, wakeref); 13688c2ecf20Sopenharmony_ci return err; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistruct i915_vma *i915_vma_make_unshrinkable(struct i915_vma *vma) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci i915_gem_object_make_unshrinkable(vma->obj); 13748c2ecf20Sopenharmony_ci return vma; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_civoid i915_vma_make_shrinkable(struct i915_vma *vma) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci i915_gem_object_make_shrinkable(vma->obj); 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_civoid i915_vma_make_purgeable(struct i915_vma *vma) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci i915_gem_object_make_purgeable(vma->obj); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 13888c2ecf20Sopenharmony_ci#include "selftests/i915_vma.c" 13898c2ecf20Sopenharmony_ci#endif 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic void i915_global_vma_shrink(void) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci kmem_cache_shrink(global.slab_vmas); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic void i915_global_vma_exit(void) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci kmem_cache_destroy(global.slab_vmas); 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic struct i915_global_vma global = { { 14028c2ecf20Sopenharmony_ci .shrink = i915_global_vma_shrink, 14038c2ecf20Sopenharmony_ci .exit = i915_global_vma_exit, 14048c2ecf20Sopenharmony_ci} }; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ciint __init i915_global_vma_init(void) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci global.slab_vmas = KMEM_CACHE(i915_vma, SLAB_HWCACHE_ALIGN); 14098c2ecf20Sopenharmony_ci if (!global.slab_vmas) 14108c2ecf20Sopenharmony_ci return -ENOMEM; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci i915_global_register(&global.base); 14138c2ecf20Sopenharmony_ci return 0; 14148c2ecf20Sopenharmony_ci} 1415