18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright © 2008-2015 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 * Authors: 248c2ecf20Sopenharmony_ci * Eric Anholt <eric@anholt.net> 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <drm/drm_vma_manager.h> 298c2ecf20Sopenharmony_ci#include <linux/dma-fence-array.h> 308c2ecf20Sopenharmony_ci#include <linux/kthread.h> 318c2ecf20Sopenharmony_ci#include <linux/dma-resv.h> 328c2ecf20Sopenharmony_ci#include <linux/shmem_fs.h> 338c2ecf20Sopenharmony_ci#include <linux/slab.h> 348c2ecf20Sopenharmony_ci#include <linux/stop_machine.h> 358c2ecf20Sopenharmony_ci#include <linux/swap.h> 368c2ecf20Sopenharmony_ci#include <linux/pci.h> 378c2ecf20Sopenharmony_ci#include <linux/dma-buf.h> 388c2ecf20Sopenharmony_ci#include <linux/mman.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "display/intel_display.h" 418c2ecf20Sopenharmony_ci#include "display/intel_frontbuffer.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "gem/i915_gem_clflush.h" 448c2ecf20Sopenharmony_ci#include "gem/i915_gem_context.h" 458c2ecf20Sopenharmony_ci#include "gem/i915_gem_ioctls.h" 468c2ecf20Sopenharmony_ci#include "gem/i915_gem_mman.h" 478c2ecf20Sopenharmony_ci#include "gem/i915_gem_region.h" 488c2ecf20Sopenharmony_ci#include "gt/intel_engine_user.h" 498c2ecf20Sopenharmony_ci#include "gt/intel_gt.h" 508c2ecf20Sopenharmony_ci#include "gt/intel_gt_pm.h" 518c2ecf20Sopenharmony_ci#include "gt/intel_workarounds.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include "i915_drv.h" 548c2ecf20Sopenharmony_ci#include "i915_trace.h" 558c2ecf20Sopenharmony_ci#include "i915_vgpu.h" 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include "intel_pm.h" 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int 608c2ecf20Sopenharmony_ciinsert_mappable_node(struct i915_ggtt *ggtt, struct drm_mm_node *node, u32 size) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci int err; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci err = mutex_lock_interruptible(&ggtt->vm.mutex); 658c2ecf20Sopenharmony_ci if (err) 668c2ecf20Sopenharmony_ci return err; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci memset(node, 0, sizeof(*node)); 698c2ecf20Sopenharmony_ci err = drm_mm_insert_node_in_range(&ggtt->vm.mm, node, 708c2ecf20Sopenharmony_ci size, 0, I915_COLOR_UNEVICTABLE, 718c2ecf20Sopenharmony_ci 0, ggtt->mappable_end, 728c2ecf20Sopenharmony_ci DRM_MM_INSERT_LOW); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci mutex_unlock(&ggtt->vm.mutex); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return err; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void 808c2ecf20Sopenharmony_ciremove_mappable_node(struct i915_ggtt *ggtt, struct drm_mm_node *node) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci mutex_lock(&ggtt->vm.mutex); 838c2ecf20Sopenharmony_ci drm_mm_remove_node(node); 848c2ecf20Sopenharmony_ci mutex_unlock(&ggtt->vm.mutex); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciint 888c2ecf20Sopenharmony_cii915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, 898c2ecf20Sopenharmony_ci struct drm_file *file) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct i915_ggtt *ggtt = &to_i915(dev)->ggtt; 928c2ecf20Sopenharmony_ci struct drm_i915_gem_get_aperture *args = data; 938c2ecf20Sopenharmony_ci struct i915_vma *vma; 948c2ecf20Sopenharmony_ci u64 pinned; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ggtt->vm.mutex)) 978c2ecf20Sopenharmony_ci return -EINTR; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci pinned = ggtt->vm.reserved; 1008c2ecf20Sopenharmony_ci list_for_each_entry(vma, &ggtt->vm.bound_list, vm_link) 1018c2ecf20Sopenharmony_ci if (i915_vma_is_pinned(vma)) 1028c2ecf20Sopenharmony_ci pinned += vma->node.size; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci mutex_unlock(&ggtt->vm.mutex); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci args->aper_size = ggtt->vm.total; 1078c2ecf20Sopenharmony_ci args->aper_available_size = args->aper_size - pinned; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint i915_gem_object_unbind(struct drm_i915_gem_object *obj, 1138c2ecf20Sopenharmony_ci unsigned long flags) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct intel_runtime_pm *rpm = &to_i915(obj->base.dev)->runtime_pm; 1168c2ecf20Sopenharmony_ci LIST_HEAD(still_in_list); 1178c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 1188c2ecf20Sopenharmony_ci struct i915_vma *vma; 1198c2ecf20Sopenharmony_ci int ret; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (list_empty(&obj->vma.list)) 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * As some machines use ACPI to handle runtime-resume callbacks, and 1268c2ecf20Sopenharmony_ci * ACPI is quite kmalloc happy, we cannot resume beneath the vm->mutex 1278c2ecf20Sopenharmony_ci * as they are required by the shrinker. Ergo, we wake the device up 1288c2ecf20Sopenharmony_ci * first just in case. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(rpm); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_citry_again: 1338c2ecf20Sopenharmony_ci ret = 0; 1348c2ecf20Sopenharmony_ci spin_lock(&obj->vma.lock); 1358c2ecf20Sopenharmony_ci while (!ret && (vma = list_first_entry_or_null(&obj->vma.list, 1368c2ecf20Sopenharmony_ci struct i915_vma, 1378c2ecf20Sopenharmony_ci obj_link))) { 1388c2ecf20Sopenharmony_ci struct i915_address_space *vm = vma->vm; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci list_move_tail(&vma->obj_link, &still_in_list); 1418c2ecf20Sopenharmony_ci if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK)) 1428c2ecf20Sopenharmony_ci continue; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (flags & I915_GEM_OBJECT_UNBIND_TEST) { 1458c2ecf20Sopenharmony_ci ret = -EBUSY; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ret = -EAGAIN; 1508c2ecf20Sopenharmony_ci if (!i915_vm_tryopen(vm)) 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Prevent vma being freed by i915_vma_parked as we unbind */ 1548c2ecf20Sopenharmony_ci vma = __i915_vma_get(vma); 1558c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (vma) { 1588c2ecf20Sopenharmony_ci ret = -EBUSY; 1598c2ecf20Sopenharmony_ci if (flags & I915_GEM_OBJECT_UNBIND_ACTIVE || 1608c2ecf20Sopenharmony_ci !i915_vma_is_active(vma)) 1618c2ecf20Sopenharmony_ci ret = i915_vma_unbind(vma); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci __i915_vma_put(vma); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci i915_vm_close(vm); 1678c2ecf20Sopenharmony_ci spin_lock(&obj->vma.lock); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci list_splice_init(&still_in_list, &obj->vma.list); 1708c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (ret == -EAGAIN && flags & I915_GEM_OBJECT_UNBIND_BARRIER) { 1738c2ecf20Sopenharmony_ci rcu_barrier(); /* flush the i915_vm_release() */ 1748c2ecf20Sopenharmony_ci goto try_again; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci intel_runtime_pm_put(rpm, wakeref); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return ret; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic int 1838c2ecf20Sopenharmony_cii915_gem_create(struct drm_file *file, 1848c2ecf20Sopenharmony_ci struct intel_memory_region *mr, 1858c2ecf20Sopenharmony_ci u64 *size_p, 1868c2ecf20Sopenharmony_ci u32 *handle_p) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 1898c2ecf20Sopenharmony_ci u32 handle; 1908c2ecf20Sopenharmony_ci u64 size; 1918c2ecf20Sopenharmony_ci int ret; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci GEM_BUG_ON(!is_power_of_2(mr->min_page_size)); 1948c2ecf20Sopenharmony_ci size = round_up(*size_p, mr->min_page_size); 1958c2ecf20Sopenharmony_ci if (size == 0) 1968c2ecf20Sopenharmony_ci return -EINVAL; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* For most of the ABI (e.g. mmap) we think in system pages */ 1998c2ecf20Sopenharmony_ci GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE)); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* Allocate the new object */ 2028c2ecf20Sopenharmony_ci obj = i915_gem_object_create_region(mr, size, 0); 2038c2ecf20Sopenharmony_ci if (IS_ERR(obj)) 2048c2ecf20Sopenharmony_ci return PTR_ERR(obj); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ret = drm_gem_handle_create(file, &obj->base, &handle); 2078c2ecf20Sopenharmony_ci /* drop reference from allocate - handle holds it now */ 2088c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 2098c2ecf20Sopenharmony_ci if (ret) 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci *handle_p = handle; 2138c2ecf20Sopenharmony_ci *size_p = size; 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint 2188c2ecf20Sopenharmony_cii915_gem_dumb_create(struct drm_file *file, 2198c2ecf20Sopenharmony_ci struct drm_device *dev, 2208c2ecf20Sopenharmony_ci struct drm_mode_create_dumb *args) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci enum intel_memory_type mem_type; 2238c2ecf20Sopenharmony_ci int cpp = DIV_ROUND_UP(args->bpp, 8); 2248c2ecf20Sopenharmony_ci u32 format; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci switch (cpp) { 2278c2ecf20Sopenharmony_ci case 1: 2288c2ecf20Sopenharmony_ci format = DRM_FORMAT_C8; 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci case 2: 2318c2ecf20Sopenharmony_ci format = DRM_FORMAT_RGB565; 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci case 4: 2348c2ecf20Sopenharmony_ci format = DRM_FORMAT_XRGB8888; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci default: 2378c2ecf20Sopenharmony_ci return -EINVAL; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* have to work out size/pitch and return them */ 2418c2ecf20Sopenharmony_ci args->pitch = ALIGN(args->width * cpp, 64); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* align stride to page size so that we can remap */ 2448c2ecf20Sopenharmony_ci if (args->pitch > intel_plane_fb_max_stride(to_i915(dev), format, 2458c2ecf20Sopenharmony_ci DRM_FORMAT_MOD_LINEAR)) 2468c2ecf20Sopenharmony_ci args->pitch = ALIGN(args->pitch, 4096); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (args->pitch < args->width) 2498c2ecf20Sopenharmony_ci return -EINVAL; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci args->size = mul_u32_u32(args->pitch, args->height); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci mem_type = INTEL_MEMORY_SYSTEM; 2548c2ecf20Sopenharmony_ci if (HAS_LMEM(to_i915(dev))) 2558c2ecf20Sopenharmony_ci mem_type = INTEL_MEMORY_LOCAL; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return i915_gem_create(file, 2588c2ecf20Sopenharmony_ci intel_memory_region_by_type(to_i915(dev), 2598c2ecf20Sopenharmony_ci mem_type), 2608c2ecf20Sopenharmony_ci &args->size, &args->handle); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * Creates a new mm object and returns a handle to it. 2658c2ecf20Sopenharmony_ci * @dev: drm device pointer 2668c2ecf20Sopenharmony_ci * @data: ioctl data blob 2678c2ecf20Sopenharmony_ci * @file: drm file pointer 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ciint 2708c2ecf20Sopenharmony_cii915_gem_create_ioctl(struct drm_device *dev, void *data, 2718c2ecf20Sopenharmony_ci struct drm_file *file) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 2748c2ecf20Sopenharmony_ci struct drm_i915_gem_create *args = data; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci i915_gem_flush_free_objects(i915); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return i915_gem_create(file, 2798c2ecf20Sopenharmony_ci intel_memory_region_by_type(i915, 2808c2ecf20Sopenharmony_ci INTEL_MEMORY_SYSTEM), 2818c2ecf20Sopenharmony_ci &args->size, &args->handle); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int 2858c2ecf20Sopenharmony_cishmem_pread(struct page *page, int offset, int len, char __user *user_data, 2868c2ecf20Sopenharmony_ci bool needs_clflush) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci char *vaddr; 2898c2ecf20Sopenharmony_ci int ret; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci vaddr = kmap(page); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (needs_clflush) 2948c2ecf20Sopenharmony_ci drm_clflush_virt_range(vaddr + offset, len); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ret = __copy_to_user(user_data, vaddr + offset, len); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci kunmap(page); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return ret ? -EFAULT : 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int 3048c2ecf20Sopenharmony_cii915_gem_shmem_pread(struct drm_i915_gem_object *obj, 3058c2ecf20Sopenharmony_ci struct drm_i915_gem_pread *args) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci unsigned int needs_clflush; 3088c2ecf20Sopenharmony_ci unsigned int idx, offset; 3098c2ecf20Sopenharmony_ci struct dma_fence *fence; 3108c2ecf20Sopenharmony_ci char __user *user_data; 3118c2ecf20Sopenharmony_ci u64 remain; 3128c2ecf20Sopenharmony_ci int ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ret = i915_gem_object_lock_interruptible(obj, NULL); 3158c2ecf20Sopenharmony_ci if (ret) 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci ret = i915_gem_object_prepare_read(obj, &needs_clflush); 3198c2ecf20Sopenharmony_ci if (ret) { 3208c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci fence = i915_gem_object_lock_fence(obj); 3258c2ecf20Sopenharmony_ci i915_gem_object_finish_access(obj); 3268c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (!fence) 3298c2ecf20Sopenharmony_ci return -ENOMEM; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci remain = args->size; 3328c2ecf20Sopenharmony_ci user_data = u64_to_user_ptr(args->data_ptr); 3338c2ecf20Sopenharmony_ci offset = offset_in_page(args->offset); 3348c2ecf20Sopenharmony_ci for (idx = args->offset >> PAGE_SHIFT; remain; idx++) { 3358c2ecf20Sopenharmony_ci struct page *page = i915_gem_object_get_page(obj, idx); 3368c2ecf20Sopenharmony_ci unsigned int length = min_t(u64, remain, PAGE_SIZE - offset); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = shmem_pread(page, offset, length, user_data, 3398c2ecf20Sopenharmony_ci needs_clflush); 3408c2ecf20Sopenharmony_ci if (ret) 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci remain -= length; 3448c2ecf20Sopenharmony_ci user_data += length; 3458c2ecf20Sopenharmony_ci offset = 0; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci i915_gem_object_unlock_fence(obj, fence); 3498c2ecf20Sopenharmony_ci return ret; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic inline bool 3538c2ecf20Sopenharmony_cigtt_user_read(struct io_mapping *mapping, 3548c2ecf20Sopenharmony_ci loff_t base, int offset, 3558c2ecf20Sopenharmony_ci char __user *user_data, int length) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci void __iomem *vaddr; 3588c2ecf20Sopenharmony_ci unsigned long unwritten; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* We can use the cpu mem copy function because this is X86. */ 3618c2ecf20Sopenharmony_ci vaddr = io_mapping_map_atomic_wc(mapping, base); 3628c2ecf20Sopenharmony_ci unwritten = __copy_to_user_inatomic(user_data, 3638c2ecf20Sopenharmony_ci (void __force *)vaddr + offset, 3648c2ecf20Sopenharmony_ci length); 3658c2ecf20Sopenharmony_ci io_mapping_unmap_atomic(vaddr); 3668c2ecf20Sopenharmony_ci if (unwritten) { 3678c2ecf20Sopenharmony_ci vaddr = io_mapping_map_wc(mapping, base, PAGE_SIZE); 3688c2ecf20Sopenharmony_ci unwritten = copy_to_user(user_data, 3698c2ecf20Sopenharmony_ci (void __force *)vaddr + offset, 3708c2ecf20Sopenharmony_ci length); 3718c2ecf20Sopenharmony_ci io_mapping_unmap(vaddr); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci return unwritten; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int 3778c2ecf20Sopenharmony_cii915_gem_gtt_pread(struct drm_i915_gem_object *obj, 3788c2ecf20Sopenharmony_ci const struct drm_i915_gem_pread *args) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(obj->base.dev); 3818c2ecf20Sopenharmony_ci struct i915_ggtt *ggtt = &i915->ggtt; 3828c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 3838c2ecf20Sopenharmony_ci struct drm_mm_node node; 3848c2ecf20Sopenharmony_ci struct dma_fence *fence; 3858c2ecf20Sopenharmony_ci void __user *user_data; 3868c2ecf20Sopenharmony_ci struct i915_vma *vma; 3878c2ecf20Sopenharmony_ci u64 remain, offset; 3888c2ecf20Sopenharmony_ci int ret; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(&i915->runtime_pm); 3918c2ecf20Sopenharmony_ci vma = ERR_PTR(-ENODEV); 3928c2ecf20Sopenharmony_ci if (!i915_gem_object_is_tiled(obj)) 3938c2ecf20Sopenharmony_ci vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 3948c2ecf20Sopenharmony_ci PIN_MAPPABLE | 3958c2ecf20Sopenharmony_ci PIN_NONBLOCK /* NOWARN */ | 3968c2ecf20Sopenharmony_ci PIN_NOEVICT); 3978c2ecf20Sopenharmony_ci if (!IS_ERR(vma)) { 3988c2ecf20Sopenharmony_ci node.start = i915_ggtt_offset(vma); 3998c2ecf20Sopenharmony_ci node.flags = 0; 4008c2ecf20Sopenharmony_ci } else { 4018c2ecf20Sopenharmony_ci ret = insert_mappable_node(ggtt, &node, PAGE_SIZE); 4028c2ecf20Sopenharmony_ci if (ret) 4038c2ecf20Sopenharmony_ci goto out_rpm; 4048c2ecf20Sopenharmony_ci GEM_BUG_ON(!drm_mm_node_allocated(&node)); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = i915_gem_object_lock_interruptible(obj, NULL); 4088c2ecf20Sopenharmony_ci if (ret) 4098c2ecf20Sopenharmony_ci goto out_unpin; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ret = i915_gem_object_set_to_gtt_domain(obj, false); 4128c2ecf20Sopenharmony_ci if (ret) { 4138c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 4148c2ecf20Sopenharmony_ci goto out_unpin; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci fence = i915_gem_object_lock_fence(obj); 4188c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 4198c2ecf20Sopenharmony_ci if (!fence) { 4208c2ecf20Sopenharmony_ci ret = -ENOMEM; 4218c2ecf20Sopenharmony_ci goto out_unpin; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci user_data = u64_to_user_ptr(args->data_ptr); 4258c2ecf20Sopenharmony_ci remain = args->size; 4268c2ecf20Sopenharmony_ci offset = args->offset; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci while (remain > 0) { 4298c2ecf20Sopenharmony_ci /* Operation in this page 4308c2ecf20Sopenharmony_ci * 4318c2ecf20Sopenharmony_ci * page_base = page offset within aperture 4328c2ecf20Sopenharmony_ci * page_offset = offset within page 4338c2ecf20Sopenharmony_ci * page_length = bytes to copy for this page 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci u32 page_base = node.start; 4368c2ecf20Sopenharmony_ci unsigned page_offset = offset_in_page(offset); 4378c2ecf20Sopenharmony_ci unsigned page_length = PAGE_SIZE - page_offset; 4388c2ecf20Sopenharmony_ci page_length = remain < page_length ? remain : page_length; 4398c2ecf20Sopenharmony_ci if (drm_mm_node_allocated(&node)) { 4408c2ecf20Sopenharmony_ci ggtt->vm.insert_page(&ggtt->vm, 4418c2ecf20Sopenharmony_ci i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT), 4428c2ecf20Sopenharmony_ci node.start, I915_CACHE_NONE, 0); 4438c2ecf20Sopenharmony_ci } else { 4448c2ecf20Sopenharmony_ci page_base += offset & PAGE_MASK; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (gtt_user_read(&ggtt->iomap, page_base, page_offset, 4488c2ecf20Sopenharmony_ci user_data, page_length)) { 4498c2ecf20Sopenharmony_ci ret = -EFAULT; 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci remain -= page_length; 4548c2ecf20Sopenharmony_ci user_data += page_length; 4558c2ecf20Sopenharmony_ci offset += page_length; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci i915_gem_object_unlock_fence(obj, fence); 4598c2ecf20Sopenharmony_ciout_unpin: 4608c2ecf20Sopenharmony_ci if (drm_mm_node_allocated(&node)) { 4618c2ecf20Sopenharmony_ci ggtt->vm.clear_range(&ggtt->vm, node.start, node.size); 4628c2ecf20Sopenharmony_ci remove_mappable_node(ggtt, &node); 4638c2ecf20Sopenharmony_ci } else { 4648c2ecf20Sopenharmony_ci i915_vma_unpin(vma); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ciout_rpm: 4678c2ecf20Sopenharmony_ci intel_runtime_pm_put(&i915->runtime_pm, wakeref); 4688c2ecf20Sopenharmony_ci return ret; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/** 4728c2ecf20Sopenharmony_ci * Reads data from the object referenced by handle. 4738c2ecf20Sopenharmony_ci * @dev: drm device pointer 4748c2ecf20Sopenharmony_ci * @data: ioctl data blob 4758c2ecf20Sopenharmony_ci * @file: drm file pointer 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * On error, the contents of *data are undefined. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ciint 4808c2ecf20Sopenharmony_cii915_gem_pread_ioctl(struct drm_device *dev, void *data, 4818c2ecf20Sopenharmony_ci struct drm_file *file) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct drm_i915_gem_pread *args = data; 4848c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 4858c2ecf20Sopenharmony_ci int ret; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (args->size == 0) 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!access_ok(u64_to_user_ptr(args->data_ptr), 4918c2ecf20Sopenharmony_ci args->size)) 4928c2ecf20Sopenharmony_ci return -EFAULT; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci obj = i915_gem_object_lookup(file, args->handle); 4958c2ecf20Sopenharmony_ci if (!obj) 4968c2ecf20Sopenharmony_ci return -ENOENT; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* Bounds check source. */ 4998c2ecf20Sopenharmony_ci if (range_overflows_t(u64, args->offset, args->size, obj->base.size)) { 5008c2ecf20Sopenharmony_ci ret = -EINVAL; 5018c2ecf20Sopenharmony_ci goto out; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci trace_i915_gem_object_pread(obj, args->offset, args->size); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci ret = -ENODEV; 5078c2ecf20Sopenharmony_ci if (obj->ops->pread) 5088c2ecf20Sopenharmony_ci ret = obj->ops->pread(obj, args); 5098c2ecf20Sopenharmony_ci if (ret != -ENODEV) 5108c2ecf20Sopenharmony_ci goto out; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci ret = i915_gem_object_wait(obj, 5138c2ecf20Sopenharmony_ci I915_WAIT_INTERRUPTIBLE, 5148c2ecf20Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 5158c2ecf20Sopenharmony_ci if (ret) 5168c2ecf20Sopenharmony_ci goto out; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ret = i915_gem_object_pin_pages(obj); 5198c2ecf20Sopenharmony_ci if (ret) 5208c2ecf20Sopenharmony_ci goto out; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci ret = i915_gem_shmem_pread(obj, args); 5238c2ecf20Sopenharmony_ci if (ret == -EFAULT || ret == -ENODEV) 5248c2ecf20Sopenharmony_ci ret = i915_gem_gtt_pread(obj, args); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci i915_gem_object_unpin_pages(obj); 5278c2ecf20Sopenharmony_ciout: 5288c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 5298c2ecf20Sopenharmony_ci return ret; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* This is the fast write path which cannot handle 5338c2ecf20Sopenharmony_ci * page faults in the source data 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic inline bool 5378c2ecf20Sopenharmony_ciggtt_write(struct io_mapping *mapping, 5388c2ecf20Sopenharmony_ci loff_t base, int offset, 5398c2ecf20Sopenharmony_ci char __user *user_data, int length) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci void __iomem *vaddr; 5428c2ecf20Sopenharmony_ci unsigned long unwritten; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* We can use the cpu mem copy function because this is X86. */ 5458c2ecf20Sopenharmony_ci vaddr = io_mapping_map_atomic_wc(mapping, base); 5468c2ecf20Sopenharmony_ci unwritten = __copy_from_user_inatomic_nocache((void __force *)vaddr + offset, 5478c2ecf20Sopenharmony_ci user_data, length); 5488c2ecf20Sopenharmony_ci io_mapping_unmap_atomic(vaddr); 5498c2ecf20Sopenharmony_ci if (unwritten) { 5508c2ecf20Sopenharmony_ci vaddr = io_mapping_map_wc(mapping, base, PAGE_SIZE); 5518c2ecf20Sopenharmony_ci unwritten = copy_from_user((void __force *)vaddr + offset, 5528c2ecf20Sopenharmony_ci user_data, length); 5538c2ecf20Sopenharmony_ci io_mapping_unmap(vaddr); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return unwritten; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * This is the fast pwrite path, where we copy the data directly from the 5618c2ecf20Sopenharmony_ci * user into the GTT, uncached. 5628c2ecf20Sopenharmony_ci * @obj: i915 GEM object 5638c2ecf20Sopenharmony_ci * @args: pwrite arguments structure 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_cistatic int 5668c2ecf20Sopenharmony_cii915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, 5678c2ecf20Sopenharmony_ci const struct drm_i915_gem_pwrite *args) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(obj->base.dev); 5708c2ecf20Sopenharmony_ci struct i915_ggtt *ggtt = &i915->ggtt; 5718c2ecf20Sopenharmony_ci struct intel_runtime_pm *rpm = &i915->runtime_pm; 5728c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 5738c2ecf20Sopenharmony_ci struct drm_mm_node node; 5748c2ecf20Sopenharmony_ci struct dma_fence *fence; 5758c2ecf20Sopenharmony_ci struct i915_vma *vma; 5768c2ecf20Sopenharmony_ci u64 remain, offset; 5778c2ecf20Sopenharmony_ci void __user *user_data; 5788c2ecf20Sopenharmony_ci int ret; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (i915_gem_object_has_struct_page(obj)) { 5818c2ecf20Sopenharmony_ci /* 5828c2ecf20Sopenharmony_ci * Avoid waking the device up if we can fallback, as 5838c2ecf20Sopenharmony_ci * waking/resuming is very slow (worst-case 10-100 ms 5848c2ecf20Sopenharmony_ci * depending on PCI sleeps and our own resume time). 5858c2ecf20Sopenharmony_ci * This easily dwarfs any performance advantage from 5868c2ecf20Sopenharmony_ci * using the cache bypass of indirect GGTT access. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get_if_in_use(rpm); 5898c2ecf20Sopenharmony_ci if (!wakeref) 5908c2ecf20Sopenharmony_ci return -EFAULT; 5918c2ecf20Sopenharmony_ci } else { 5928c2ecf20Sopenharmony_ci /* No backing pages, no fallback, we must force GGTT access */ 5938c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(rpm); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci vma = ERR_PTR(-ENODEV); 5978c2ecf20Sopenharmony_ci if (!i915_gem_object_is_tiled(obj)) 5988c2ecf20Sopenharmony_ci vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 5998c2ecf20Sopenharmony_ci PIN_MAPPABLE | 6008c2ecf20Sopenharmony_ci PIN_NONBLOCK /* NOWARN */ | 6018c2ecf20Sopenharmony_ci PIN_NOEVICT); 6028c2ecf20Sopenharmony_ci if (!IS_ERR(vma)) { 6038c2ecf20Sopenharmony_ci node.start = i915_ggtt_offset(vma); 6048c2ecf20Sopenharmony_ci node.flags = 0; 6058c2ecf20Sopenharmony_ci } else { 6068c2ecf20Sopenharmony_ci ret = insert_mappable_node(ggtt, &node, PAGE_SIZE); 6078c2ecf20Sopenharmony_ci if (ret) 6088c2ecf20Sopenharmony_ci goto out_rpm; 6098c2ecf20Sopenharmony_ci GEM_BUG_ON(!drm_mm_node_allocated(&node)); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ret = i915_gem_object_lock_interruptible(obj, NULL); 6138c2ecf20Sopenharmony_ci if (ret) 6148c2ecf20Sopenharmony_ci goto out_unpin; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ret = i915_gem_object_set_to_gtt_domain(obj, true); 6178c2ecf20Sopenharmony_ci if (ret) { 6188c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 6198c2ecf20Sopenharmony_ci goto out_unpin; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci fence = i915_gem_object_lock_fence(obj); 6238c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 6248c2ecf20Sopenharmony_ci if (!fence) { 6258c2ecf20Sopenharmony_ci ret = -ENOMEM; 6268c2ecf20Sopenharmony_ci goto out_unpin; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci user_data = u64_to_user_ptr(args->data_ptr); 6328c2ecf20Sopenharmony_ci offset = args->offset; 6338c2ecf20Sopenharmony_ci remain = args->size; 6348c2ecf20Sopenharmony_ci while (remain) { 6358c2ecf20Sopenharmony_ci /* Operation in this page 6368c2ecf20Sopenharmony_ci * 6378c2ecf20Sopenharmony_ci * page_base = page offset within aperture 6388c2ecf20Sopenharmony_ci * page_offset = offset within page 6398c2ecf20Sopenharmony_ci * page_length = bytes to copy for this page 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ci u32 page_base = node.start; 6428c2ecf20Sopenharmony_ci unsigned int page_offset = offset_in_page(offset); 6438c2ecf20Sopenharmony_ci unsigned int page_length = PAGE_SIZE - page_offset; 6448c2ecf20Sopenharmony_ci page_length = remain < page_length ? remain : page_length; 6458c2ecf20Sopenharmony_ci if (drm_mm_node_allocated(&node)) { 6468c2ecf20Sopenharmony_ci /* flush the write before we modify the GGTT */ 6478c2ecf20Sopenharmony_ci intel_gt_flush_ggtt_writes(ggtt->vm.gt); 6488c2ecf20Sopenharmony_ci ggtt->vm.insert_page(&ggtt->vm, 6498c2ecf20Sopenharmony_ci i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT), 6508c2ecf20Sopenharmony_ci node.start, I915_CACHE_NONE, 0); 6518c2ecf20Sopenharmony_ci wmb(); /* flush modifications to the GGTT (insert_page) */ 6528c2ecf20Sopenharmony_ci } else { 6538c2ecf20Sopenharmony_ci page_base += offset & PAGE_MASK; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci /* If we get a fault while copying data, then (presumably) our 6568c2ecf20Sopenharmony_ci * source page isn't available. Return the error and we'll 6578c2ecf20Sopenharmony_ci * retry in the slow path. 6588c2ecf20Sopenharmony_ci * If the object is non-shmem backed, we retry again with the 6598c2ecf20Sopenharmony_ci * path that handles page fault. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci if (ggtt_write(&ggtt->iomap, page_base, page_offset, 6628c2ecf20Sopenharmony_ci user_data, page_length)) { 6638c2ecf20Sopenharmony_ci ret = -EFAULT; 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci remain -= page_length; 6688c2ecf20Sopenharmony_ci user_data += page_length; 6698c2ecf20Sopenharmony_ci offset += page_length; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci intel_gt_flush_ggtt_writes(ggtt->vm.gt); 6738c2ecf20Sopenharmony_ci i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci i915_gem_object_unlock_fence(obj, fence); 6768c2ecf20Sopenharmony_ciout_unpin: 6778c2ecf20Sopenharmony_ci if (drm_mm_node_allocated(&node)) { 6788c2ecf20Sopenharmony_ci ggtt->vm.clear_range(&ggtt->vm, node.start, node.size); 6798c2ecf20Sopenharmony_ci remove_mappable_node(ggtt, &node); 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci i915_vma_unpin(vma); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ciout_rpm: 6848c2ecf20Sopenharmony_ci intel_runtime_pm_put(rpm, wakeref); 6858c2ecf20Sopenharmony_ci return ret; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci/* Per-page copy function for the shmem pwrite fastpath. 6898c2ecf20Sopenharmony_ci * Flushes invalid cachelines before writing to the target if 6908c2ecf20Sopenharmony_ci * needs_clflush_before is set and flushes out any written cachelines after 6918c2ecf20Sopenharmony_ci * writing if needs_clflush is set. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_cistatic int 6948c2ecf20Sopenharmony_cishmem_pwrite(struct page *page, int offset, int len, char __user *user_data, 6958c2ecf20Sopenharmony_ci bool needs_clflush_before, 6968c2ecf20Sopenharmony_ci bool needs_clflush_after) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci char *vaddr; 6998c2ecf20Sopenharmony_ci int ret; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci vaddr = kmap(page); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (needs_clflush_before) 7048c2ecf20Sopenharmony_ci drm_clflush_virt_range(vaddr + offset, len); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci ret = __copy_from_user(vaddr + offset, user_data, len); 7078c2ecf20Sopenharmony_ci if (!ret && needs_clflush_after) 7088c2ecf20Sopenharmony_ci drm_clflush_virt_range(vaddr + offset, len); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci kunmap(page); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return ret ? -EFAULT : 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int 7168c2ecf20Sopenharmony_cii915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, 7178c2ecf20Sopenharmony_ci const struct drm_i915_gem_pwrite *args) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci unsigned int partial_cacheline_write; 7208c2ecf20Sopenharmony_ci unsigned int needs_clflush; 7218c2ecf20Sopenharmony_ci unsigned int offset, idx; 7228c2ecf20Sopenharmony_ci struct dma_fence *fence; 7238c2ecf20Sopenharmony_ci void __user *user_data; 7248c2ecf20Sopenharmony_ci u64 remain; 7258c2ecf20Sopenharmony_ci int ret; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci ret = i915_gem_object_lock_interruptible(obj, NULL); 7288c2ecf20Sopenharmony_ci if (ret) 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci ret = i915_gem_object_prepare_write(obj, &needs_clflush); 7328c2ecf20Sopenharmony_ci if (ret) { 7338c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 7348c2ecf20Sopenharmony_ci return ret; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci fence = i915_gem_object_lock_fence(obj); 7388c2ecf20Sopenharmony_ci i915_gem_object_finish_access(obj); 7398c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!fence) 7428c2ecf20Sopenharmony_ci return -ENOMEM; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* If we don't overwrite a cacheline completely we need to be 7458c2ecf20Sopenharmony_ci * careful to have up-to-date data by first clflushing. Don't 7468c2ecf20Sopenharmony_ci * overcomplicate things and flush the entire patch. 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_ci partial_cacheline_write = 0; 7498c2ecf20Sopenharmony_ci if (needs_clflush & CLFLUSH_BEFORE) 7508c2ecf20Sopenharmony_ci partial_cacheline_write = boot_cpu_data.x86_clflush_size - 1; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci user_data = u64_to_user_ptr(args->data_ptr); 7538c2ecf20Sopenharmony_ci remain = args->size; 7548c2ecf20Sopenharmony_ci offset = offset_in_page(args->offset); 7558c2ecf20Sopenharmony_ci for (idx = args->offset >> PAGE_SHIFT; remain; idx++) { 7568c2ecf20Sopenharmony_ci struct page *page = i915_gem_object_get_page(obj, idx); 7578c2ecf20Sopenharmony_ci unsigned int length = min_t(u64, remain, PAGE_SIZE - offset); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci ret = shmem_pwrite(page, offset, length, user_data, 7608c2ecf20Sopenharmony_ci (offset | length) & partial_cacheline_write, 7618c2ecf20Sopenharmony_ci needs_clflush & CLFLUSH_AFTER); 7628c2ecf20Sopenharmony_ci if (ret) 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci remain -= length; 7668c2ecf20Sopenharmony_ci user_data += length; 7678c2ecf20Sopenharmony_ci offset = 0; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU); 7718c2ecf20Sopenharmony_ci i915_gem_object_unlock_fence(obj, fence); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return ret; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci/** 7778c2ecf20Sopenharmony_ci * Writes data to the object referenced by handle. 7788c2ecf20Sopenharmony_ci * @dev: drm device 7798c2ecf20Sopenharmony_ci * @data: ioctl data blob 7808c2ecf20Sopenharmony_ci * @file: drm file 7818c2ecf20Sopenharmony_ci * 7828c2ecf20Sopenharmony_ci * On error, the contents of the buffer that were to be modified are undefined. 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_ciint 7858c2ecf20Sopenharmony_cii915_gem_pwrite_ioctl(struct drm_device *dev, void *data, 7868c2ecf20Sopenharmony_ci struct drm_file *file) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct drm_i915_gem_pwrite *args = data; 7898c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 7908c2ecf20Sopenharmony_ci int ret; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (args->size == 0) 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (!access_ok(u64_to_user_ptr(args->data_ptr), args->size)) 7968c2ecf20Sopenharmony_ci return -EFAULT; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci obj = i915_gem_object_lookup(file, args->handle); 7998c2ecf20Sopenharmony_ci if (!obj) 8008c2ecf20Sopenharmony_ci return -ENOENT; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* Bounds check destination. */ 8038c2ecf20Sopenharmony_ci if (range_overflows_t(u64, args->offset, args->size, obj->base.size)) { 8048c2ecf20Sopenharmony_ci ret = -EINVAL; 8058c2ecf20Sopenharmony_ci goto err; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Writes not allowed into this read-only object */ 8098c2ecf20Sopenharmony_ci if (i915_gem_object_is_readonly(obj)) { 8108c2ecf20Sopenharmony_ci ret = -EINVAL; 8118c2ecf20Sopenharmony_ci goto err; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci trace_i915_gem_object_pwrite(obj, args->offset, args->size); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci ret = -ENODEV; 8178c2ecf20Sopenharmony_ci if (obj->ops->pwrite) 8188c2ecf20Sopenharmony_ci ret = obj->ops->pwrite(obj, args); 8198c2ecf20Sopenharmony_ci if (ret != -ENODEV) 8208c2ecf20Sopenharmony_ci goto err; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci ret = i915_gem_object_wait(obj, 8238c2ecf20Sopenharmony_ci I915_WAIT_INTERRUPTIBLE | 8248c2ecf20Sopenharmony_ci I915_WAIT_ALL, 8258c2ecf20Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 8268c2ecf20Sopenharmony_ci if (ret) 8278c2ecf20Sopenharmony_ci goto err; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci ret = i915_gem_object_pin_pages(obj); 8308c2ecf20Sopenharmony_ci if (ret) 8318c2ecf20Sopenharmony_ci goto err; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ret = -EFAULT; 8348c2ecf20Sopenharmony_ci /* We can only do the GTT pwrite on untiled buffers, as otherwise 8358c2ecf20Sopenharmony_ci * it would end up going through the fenced access, and we'll get 8368c2ecf20Sopenharmony_ci * different detiling behavior between reading and writing. 8378c2ecf20Sopenharmony_ci * pread/pwrite currently are reading and writing from the CPU 8388c2ecf20Sopenharmony_ci * perspective, requiring manual detiling by the client. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci if (!i915_gem_object_has_struct_page(obj) || 8418c2ecf20Sopenharmony_ci cpu_write_needs_clflush(obj)) 8428c2ecf20Sopenharmony_ci /* Note that the gtt paths might fail with non-page-backed user 8438c2ecf20Sopenharmony_ci * pointers (e.g. gtt mappings when moving data between 8448c2ecf20Sopenharmony_ci * textures). Fallback to the shmem path in that case. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci ret = i915_gem_gtt_pwrite_fast(obj, args); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (ret == -EFAULT || ret == -ENOSPC) { 8498c2ecf20Sopenharmony_ci if (i915_gem_object_has_struct_page(obj)) 8508c2ecf20Sopenharmony_ci ret = i915_gem_shmem_pwrite(obj, args); 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci i915_gem_object_unpin_pages(obj); 8548c2ecf20Sopenharmony_cierr: 8558c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 8568c2ecf20Sopenharmony_ci return ret; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci/** 8608c2ecf20Sopenharmony_ci * Called when user space has done writes to this buffer 8618c2ecf20Sopenharmony_ci * @dev: drm device 8628c2ecf20Sopenharmony_ci * @data: ioctl data blob 8638c2ecf20Sopenharmony_ci * @file: drm file 8648c2ecf20Sopenharmony_ci */ 8658c2ecf20Sopenharmony_ciint 8668c2ecf20Sopenharmony_cii915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, 8678c2ecf20Sopenharmony_ci struct drm_file *file) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct drm_i915_gem_sw_finish *args = data; 8708c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci obj = i915_gem_object_lookup(file, args->handle); 8738c2ecf20Sopenharmony_ci if (!obj) 8748c2ecf20Sopenharmony_ci return -ENOENT; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* 8778c2ecf20Sopenharmony_ci * Proxy objects are barred from CPU access, so there is no 8788c2ecf20Sopenharmony_ci * need to ban sw_finish as it is a nop. 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* Pinned buffers may be scanout, so flush the cache */ 8828c2ecf20Sopenharmony_ci i915_gem_object_flush_if_display(obj); 8838c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return 0; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_civoid i915_gem_runtime_suspend(struct drm_i915_private *i915) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj, *on; 8918c2ecf20Sopenharmony_ci int i; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* 8948c2ecf20Sopenharmony_ci * Only called during RPM suspend. All users of the userfault_list 8958c2ecf20Sopenharmony_ci * must be holding an RPM wakeref to ensure that this can not 8968c2ecf20Sopenharmony_ci * run concurrently with themselves (and use the struct_mutex for 8978c2ecf20Sopenharmony_ci * protection between themselves). 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci list_for_each_entry_safe(obj, on, 9018c2ecf20Sopenharmony_ci &i915->ggtt.userfault_list, userfault_link) 9028c2ecf20Sopenharmony_ci __i915_gem_object_release_mmap_gtt(obj); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* 9058c2ecf20Sopenharmony_ci * The fence will be lost when the device powers down. If any were 9068c2ecf20Sopenharmony_ci * in use by hardware (i.e. they are pinned), we should not be powering 9078c2ecf20Sopenharmony_ci * down! All other fences will be reacquired by the user upon waking. 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_ci for (i = 0; i < i915->ggtt.num_fences; i++) { 9108c2ecf20Sopenharmony_ci struct i915_fence_reg *reg = &i915->ggtt.fence_regs[i]; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* 9138c2ecf20Sopenharmony_ci * Ideally we want to assert that the fence register is not 9148c2ecf20Sopenharmony_ci * live at this point (i.e. that no piece of code will be 9158c2ecf20Sopenharmony_ci * trying to write through fence + GTT, as that both violates 9168c2ecf20Sopenharmony_ci * our tracking of activity and associated locking/barriers, 9178c2ecf20Sopenharmony_ci * but also is illegal given that the hw is powered down). 9188c2ecf20Sopenharmony_ci * 9198c2ecf20Sopenharmony_ci * Previously we used reg->pin_count as a "liveness" indicator. 9208c2ecf20Sopenharmony_ci * That is not sufficient, and we need a more fine-grained 9218c2ecf20Sopenharmony_ci * tool if we want to have a sanity check here. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (!reg->vma) 9258c2ecf20Sopenharmony_ci continue; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci GEM_BUG_ON(i915_vma_has_userfault(reg->vma)); 9288c2ecf20Sopenharmony_ci reg->dirty = true; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void discard_ggtt_vma(struct i915_vma *vma) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj = vma->obj; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci spin_lock(&obj->vma.lock); 9378c2ecf20Sopenharmony_ci if (!RB_EMPTY_NODE(&vma->obj_node)) { 9388c2ecf20Sopenharmony_ci rb_erase(&vma->obj_node, &obj->vma.tree); 9398c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&vma->obj_node); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci spin_unlock(&obj->vma.lock); 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistruct i915_vma * 9458c2ecf20Sopenharmony_cii915_gem_object_ggtt_pin_ww(struct drm_i915_gem_object *obj, 9468c2ecf20Sopenharmony_ci struct i915_gem_ww_ctx *ww, 9478c2ecf20Sopenharmony_ci const struct i915_ggtt_view *view, 9488c2ecf20Sopenharmony_ci u64 size, u64 alignment, u64 flags) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(obj->base.dev); 9518c2ecf20Sopenharmony_ci struct i915_ggtt *ggtt = &i915->ggtt; 9528c2ecf20Sopenharmony_ci struct i915_vma *vma; 9538c2ecf20Sopenharmony_ci int ret; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (flags & PIN_MAPPABLE && 9568c2ecf20Sopenharmony_ci (!view || view->type == I915_GGTT_VIEW_NORMAL)) { 9578c2ecf20Sopenharmony_ci /* 9588c2ecf20Sopenharmony_ci * If the required space is larger than the available 9598c2ecf20Sopenharmony_ci * aperture, we will not able to find a slot for the 9608c2ecf20Sopenharmony_ci * object and unbinding the object now will be in 9618c2ecf20Sopenharmony_ci * vain. Worse, doing so may cause us to ping-pong 9628c2ecf20Sopenharmony_ci * the object in and out of the Global GTT and 9638c2ecf20Sopenharmony_ci * waste a lot of cycles under the mutex. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_ci if (obj->base.size > ggtt->mappable_end) 9668c2ecf20Sopenharmony_ci return ERR_PTR(-E2BIG); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* 9698c2ecf20Sopenharmony_ci * If NONBLOCK is set the caller is optimistically 9708c2ecf20Sopenharmony_ci * trying to cache the full object within the mappable 9718c2ecf20Sopenharmony_ci * aperture, and *must* have a fallback in place for 9728c2ecf20Sopenharmony_ci * situations where we cannot bind the object. We 9738c2ecf20Sopenharmony_ci * can be a little more lax here and use the fallback 9748c2ecf20Sopenharmony_ci * more often to avoid costly migrations of ourselves 9758c2ecf20Sopenharmony_ci * and other objects within the aperture. 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * Half-the-aperture is used as a simple heuristic. 9788c2ecf20Sopenharmony_ci * More interesting would to do search for a free 9798c2ecf20Sopenharmony_ci * block prior to making the commitment to unbind. 9808c2ecf20Sopenharmony_ci * That caters for the self-harm case, and with a 9818c2ecf20Sopenharmony_ci * little more heuristics (e.g. NOFAULT, NOEVICT) 9828c2ecf20Sopenharmony_ci * we could try to minimise harm to others. 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_ci if (flags & PIN_NONBLOCK && 9858c2ecf20Sopenharmony_ci obj->base.size > ggtt->mappable_end / 2) 9868c2ecf20Sopenharmony_ci return ERR_PTR(-ENOSPC); 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cinew_vma: 9908c2ecf20Sopenharmony_ci vma = i915_vma_instance(obj, &ggtt->vm, view); 9918c2ecf20Sopenharmony_ci if (IS_ERR(vma)) 9928c2ecf20Sopenharmony_ci return vma; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (i915_vma_misplaced(vma, size, alignment, flags)) { 9958c2ecf20Sopenharmony_ci if (flags & PIN_NONBLOCK) { 9968c2ecf20Sopenharmony_ci if (i915_vma_is_pinned(vma) || i915_vma_is_active(vma)) 9978c2ecf20Sopenharmony_ci return ERR_PTR(-ENOSPC); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (flags & PIN_MAPPABLE && 10008c2ecf20Sopenharmony_ci vma->fence_size > ggtt->mappable_end / 2) 10018c2ecf20Sopenharmony_ci return ERR_PTR(-ENOSPC); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (i915_vma_is_pinned(vma) || i915_vma_is_active(vma)) { 10058c2ecf20Sopenharmony_ci discard_ggtt_vma(vma); 10068c2ecf20Sopenharmony_ci goto new_vma; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci ret = i915_vma_unbind(vma); 10108c2ecf20Sopenharmony_ci if (ret) 10118c2ecf20Sopenharmony_ci return ERR_PTR(ret); 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci ret = i915_vma_pin_ww(vma, ww, size, alignment, flags | PIN_GLOBAL); 10158c2ecf20Sopenharmony_ci if (ret) 10168c2ecf20Sopenharmony_ci return ERR_PTR(ret); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (vma->fence && !i915_gem_object_is_tiled(obj)) { 10198c2ecf20Sopenharmony_ci mutex_lock(&ggtt->vm.mutex); 10208c2ecf20Sopenharmony_ci i915_vma_revoke_fence(vma); 10218c2ecf20Sopenharmony_ci mutex_unlock(&ggtt->vm.mutex); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci ret = i915_vma_wait_for_bind(vma); 10258c2ecf20Sopenharmony_ci if (ret) { 10268c2ecf20Sopenharmony_ci i915_vma_unpin(vma); 10278c2ecf20Sopenharmony_ci return ERR_PTR(ret); 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci return vma; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ciint 10348c2ecf20Sopenharmony_cii915_gem_madvise_ioctl(struct drm_device *dev, void *data, 10358c2ecf20Sopenharmony_ci struct drm_file *file_priv) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = to_i915(dev); 10388c2ecf20Sopenharmony_ci struct drm_i915_gem_madvise *args = data; 10398c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 10408c2ecf20Sopenharmony_ci int err; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci switch (args->madv) { 10438c2ecf20Sopenharmony_ci case I915_MADV_DONTNEED: 10448c2ecf20Sopenharmony_ci case I915_MADV_WILLNEED: 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci default: 10478c2ecf20Sopenharmony_ci return -EINVAL; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci obj = i915_gem_object_lookup(file_priv, args->handle); 10518c2ecf20Sopenharmony_ci if (!obj) 10528c2ecf20Sopenharmony_ci return -ENOENT; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci err = mutex_lock_interruptible(&obj->mm.lock); 10558c2ecf20Sopenharmony_ci if (err) 10568c2ecf20Sopenharmony_ci goto out; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (i915_gem_object_has_pages(obj) && 10598c2ecf20Sopenharmony_ci i915_gem_object_is_tiled(obj) && 10608c2ecf20Sopenharmony_ci i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) { 10618c2ecf20Sopenharmony_ci if (obj->mm.madv == I915_MADV_WILLNEED) { 10628c2ecf20Sopenharmony_ci GEM_BUG_ON(!obj->mm.quirked); 10638c2ecf20Sopenharmony_ci __i915_gem_object_unpin_pages(obj); 10648c2ecf20Sopenharmony_ci obj->mm.quirked = false; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci if (args->madv == I915_MADV_WILLNEED) { 10678c2ecf20Sopenharmony_ci GEM_BUG_ON(obj->mm.quirked); 10688c2ecf20Sopenharmony_ci __i915_gem_object_pin_pages(obj); 10698c2ecf20Sopenharmony_ci obj->mm.quirked = true; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (obj->mm.madv != __I915_MADV_PURGED) 10748c2ecf20Sopenharmony_ci obj->mm.madv = args->madv; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (i915_gem_object_has_pages(obj)) { 10778c2ecf20Sopenharmony_ci struct list_head *list; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (i915_gem_object_is_shrinkable(obj)) { 10808c2ecf20Sopenharmony_ci unsigned long flags; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci spin_lock_irqsave(&i915->mm.obj_lock, flags); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (obj->mm.madv != I915_MADV_WILLNEED) 10858c2ecf20Sopenharmony_ci list = &i915->mm.purge_list; 10868c2ecf20Sopenharmony_ci else 10878c2ecf20Sopenharmony_ci list = &i915->mm.shrink_list; 10888c2ecf20Sopenharmony_ci list_move_tail(&obj->mm.link, list); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i915->mm.obj_lock, flags); 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* if the object is no longer attached, discard its backing storage */ 10958c2ecf20Sopenharmony_ci if (obj->mm.madv == I915_MADV_DONTNEED && 10968c2ecf20Sopenharmony_ci !i915_gem_object_has_pages(obj)) 10978c2ecf20Sopenharmony_ci i915_gem_object_truncate(obj); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci args->retained = obj->mm.madv != __I915_MADV_PURGED; 11008c2ecf20Sopenharmony_ci mutex_unlock(&obj->mm.lock); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ciout: 11038c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 11048c2ecf20Sopenharmony_ci return err; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ciint i915_gem_init(struct drm_i915_private *dev_priv) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci int ret; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* We need to fallback to 4K pages if host doesn't support huge gtt. */ 11128c2ecf20Sopenharmony_ci if (intel_vgpu_active(dev_priv) && !intel_vgpu_has_huge_gtt(dev_priv)) 11138c2ecf20Sopenharmony_ci mkwrite_device_info(dev_priv)->page_sizes = 11148c2ecf20Sopenharmony_ci I915_GTT_PAGE_SIZE_4K; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci ret = i915_gem_init_userptr(dev_priv); 11178c2ecf20Sopenharmony_ci if (ret) 11188c2ecf20Sopenharmony_ci return ret; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci intel_uc_fetch_firmwares(&dev_priv->gt.uc); 11218c2ecf20Sopenharmony_ci intel_wopcm_init(&dev_priv->wopcm); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci ret = i915_init_ggtt(dev_priv); 11248c2ecf20Sopenharmony_ci if (ret) { 11258c2ecf20Sopenharmony_ci GEM_BUG_ON(ret == -EIO); 11268c2ecf20Sopenharmony_ci goto err_unlock; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* 11308c2ecf20Sopenharmony_ci * Despite its name intel_init_clock_gating applies both display 11318c2ecf20Sopenharmony_ci * clock gating workarounds; GT mmio workarounds and the occasional 11328c2ecf20Sopenharmony_ci * GT power context workaround. Worse, sometimes it includes a context 11338c2ecf20Sopenharmony_ci * register workaround which we need to apply before we record the 11348c2ecf20Sopenharmony_ci * default HW state for all contexts. 11358c2ecf20Sopenharmony_ci * 11368c2ecf20Sopenharmony_ci * FIXME: break up the workarounds and apply them at the right time! 11378c2ecf20Sopenharmony_ci */ 11388c2ecf20Sopenharmony_ci intel_init_clock_gating(dev_priv); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci ret = intel_gt_init(&dev_priv->gt); 11418c2ecf20Sopenharmony_ci if (ret) 11428c2ecf20Sopenharmony_ci goto err_unlock; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return 0; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* 11478c2ecf20Sopenharmony_ci * Unwinding is complicated by that we want to handle -EIO to mean 11488c2ecf20Sopenharmony_ci * disable GPU submission but keep KMS alive. We want to mark the 11498c2ecf20Sopenharmony_ci * HW as irrevisibly wedged, but keep enough state around that the 11508c2ecf20Sopenharmony_ci * driver doesn't explode during runtime. 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_cierr_unlock: 11538c2ecf20Sopenharmony_ci i915_gem_drain_workqueue(dev_priv); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (ret != -EIO) { 11568c2ecf20Sopenharmony_ci intel_uc_cleanup_firmwares(&dev_priv->gt.uc); 11578c2ecf20Sopenharmony_ci i915_gem_cleanup_userptr(dev_priv); 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (ret == -EIO) { 11618c2ecf20Sopenharmony_ci /* 11628c2ecf20Sopenharmony_ci * Allow engines or uC initialisation to fail by marking the GPU 11638c2ecf20Sopenharmony_ci * as wedged. But we only want to do this when the GPU is angry, 11648c2ecf20Sopenharmony_ci * for all other failure, such as an allocation failure, bail. 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_ci if (!intel_gt_is_wedged(&dev_priv->gt)) { 11678c2ecf20Sopenharmony_ci i915_probe_error(dev_priv, 11688c2ecf20Sopenharmony_ci "Failed to initialize GPU, declaring it wedged!\n"); 11698c2ecf20Sopenharmony_ci intel_gt_set_wedged(&dev_priv->gt); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Minimal basic recovery for KMS */ 11738c2ecf20Sopenharmony_ci ret = i915_ggtt_enable_hw(dev_priv); 11748c2ecf20Sopenharmony_ci i915_ggtt_resume(&dev_priv->ggtt); 11758c2ecf20Sopenharmony_ci intel_init_clock_gating(dev_priv); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 11798c2ecf20Sopenharmony_ci return ret; 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_civoid i915_gem_driver_register(struct drm_i915_private *i915) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci i915_gem_driver_register__shrinker(i915); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci intel_engines_driver_register(i915); 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_civoid i915_gem_driver_unregister(struct drm_i915_private *i915) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci i915_gem_driver_unregister__shrinker(i915); 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_civoid i915_gem_driver_remove(struct drm_i915_private *dev_priv) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci intel_wakeref_auto_fini(&dev_priv->ggtt.userfault_wakeref); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci i915_gem_suspend_late(dev_priv); 11998c2ecf20Sopenharmony_ci intel_gt_driver_remove(&dev_priv->gt); 12008c2ecf20Sopenharmony_ci dev_priv->uabi_engines = RB_ROOT; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* Flush any outstanding unpin_work. */ 12038c2ecf20Sopenharmony_ci i915_gem_drain_workqueue(dev_priv); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_civoid i915_gem_driver_release(struct drm_i915_private *dev_priv) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci i915_gem_driver_release__contexts(dev_priv); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci intel_gt_driver_release(&dev_priv->gt); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci intel_wa_list_free(&dev_priv->gt_wa_list); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci intel_uc_cleanup_firmwares(&dev_priv->gt.uc); 12178c2ecf20Sopenharmony_ci i915_gem_cleanup_userptr(dev_priv); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !list_empty(&dev_priv->gem.contexts.list)); 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic void i915_gem_init__mm(struct drm_i915_private *i915) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci spin_lock_init(&i915->mm.obj_lock); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci init_llist_head(&i915->mm.free_list); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&i915->mm.purge_list); 12318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&i915->mm.shrink_list); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci i915_gem_init__objects(i915); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_civoid i915_gem_init_early(struct drm_i915_private *dev_priv) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci i915_gem_init__mm(dev_priv); 12398c2ecf20Sopenharmony_ci i915_gem_init__contexts(dev_priv); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci spin_lock_init(&dev_priv->fb_tracking.lock); 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_civoid i915_gem_cleanup_early(struct drm_i915_private *dev_priv) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci i915_gem_drain_freed_objects(dev_priv); 12478c2ecf20Sopenharmony_ci GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list)); 12488c2ecf20Sopenharmony_ci GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count)); 12498c2ecf20Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, dev_priv->mm.shrink_count); 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ciint i915_gem_freeze(struct drm_i915_private *dev_priv) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci /* Discard all purgeable objects, let userspace recover those as 12558c2ecf20Sopenharmony_ci * required after resuming. 12568c2ecf20Sopenharmony_ci */ 12578c2ecf20Sopenharmony_ci i915_gem_shrink_all(dev_priv); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ciint i915_gem_freeze_late(struct drm_i915_private *i915) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 12658c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* 12688c2ecf20Sopenharmony_ci * Called just before we write the hibernation image. 12698c2ecf20Sopenharmony_ci * 12708c2ecf20Sopenharmony_ci * We need to update the domain tracking to reflect that the CPU 12718c2ecf20Sopenharmony_ci * will be accessing all the pages to create and restore from the 12728c2ecf20Sopenharmony_ci * hibernation, and so upon restoration those pages will be in the 12738c2ecf20Sopenharmony_ci * CPU domain. 12748c2ecf20Sopenharmony_ci * 12758c2ecf20Sopenharmony_ci * To make sure the hibernation image contains the latest state, 12768c2ecf20Sopenharmony_ci * we update that state just before writing out the image. 12778c2ecf20Sopenharmony_ci * 12788c2ecf20Sopenharmony_ci * To try and reduce the hibernation image, we manually shrink 12798c2ecf20Sopenharmony_ci * the objects as well, see i915_gem_freeze() 12808c2ecf20Sopenharmony_ci */ 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(&i915->runtime_pm); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci i915_gem_shrink(i915, -1UL, NULL, ~0); 12858c2ecf20Sopenharmony_ci i915_gem_drain_freed_objects(i915); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci list_for_each_entry(obj, &i915->mm.shrink_list, mm.link) { 12888c2ecf20Sopenharmony_ci i915_gem_object_lock(obj, NULL); 12898c2ecf20Sopenharmony_ci drm_WARN_ON(&i915->drm, 12908c2ecf20Sopenharmony_ci i915_gem_object_set_to_cpu_domain(obj, true)); 12918c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci intel_runtime_pm_put(&i915->runtime_pm, wakeref); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return 0; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ciint i915_gem_open(struct drm_i915_private *i915, struct drm_file *file) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci struct drm_i915_file_private *file_priv; 13028c2ecf20Sopenharmony_ci int ret; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci DRM_DEBUG("\n"); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); 13078c2ecf20Sopenharmony_ci if (!file_priv) 13088c2ecf20Sopenharmony_ci return -ENOMEM; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci file->driver_priv = file_priv; 13118c2ecf20Sopenharmony_ci file_priv->dev_priv = i915; 13128c2ecf20Sopenharmony_ci file_priv->file = file; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci file_priv->bsd_engine = -1; 13158c2ecf20Sopenharmony_ci file_priv->hang_timestamp = jiffies; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci ret = i915_gem_context_open(i915, file); 13188c2ecf20Sopenharmony_ci if (ret) 13198c2ecf20Sopenharmony_ci kfree(file_priv); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return ret; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_civoid i915_gem_ww_ctx_init(struct i915_gem_ww_ctx *ww, bool intr) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci ww_acquire_init(&ww->ctx, &reservation_ww_class); 13278c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ww->obj_list); 13288c2ecf20Sopenharmony_ci ww->intr = intr; 13298c2ecf20Sopenharmony_ci ww->contended = NULL; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic void i915_gem_ww_ctx_unlock_all(struct i915_gem_ww_ctx *ww) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci while ((obj = list_first_entry_or_null(&ww->obj_list, struct drm_i915_gem_object, obj_link))) { 13378c2ecf20Sopenharmony_ci list_del(&obj->obj_link); 13388c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_civoid i915_gem_ww_unlock_single(struct drm_i915_gem_object *obj) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci list_del(&obj->obj_link); 13458c2ecf20Sopenharmony_ci i915_gem_object_unlock(obj); 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_civoid i915_gem_ww_ctx_fini(struct i915_gem_ww_ctx *ww) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci i915_gem_ww_ctx_unlock_all(ww); 13518c2ecf20Sopenharmony_ci WARN_ON(ww->contended); 13528c2ecf20Sopenharmony_ci ww_acquire_fini(&ww->ctx); 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ciint __must_check i915_gem_ww_ctx_backoff(struct i915_gem_ww_ctx *ww) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci int ret = 0; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (WARN_ON(!ww->contended)) 13608c2ecf20Sopenharmony_ci return -EINVAL; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci i915_gem_ww_ctx_unlock_all(ww); 13638c2ecf20Sopenharmony_ci if (ww->intr) 13648c2ecf20Sopenharmony_ci ret = dma_resv_lock_slow_interruptible(ww->contended->base.resv, &ww->ctx); 13658c2ecf20Sopenharmony_ci else 13668c2ecf20Sopenharmony_ci dma_resv_lock_slow(ww->contended->base.resv, &ww->ctx); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (!ret) 13698c2ecf20Sopenharmony_ci list_add_tail(&ww->contended->obj_link, &ww->obj_list); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci ww->contended = NULL; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci return ret; 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 13778c2ecf20Sopenharmony_ci#include "selftests/mock_gem_device.c" 13788c2ecf20Sopenharmony_ci#include "selftests/i915_gem.c" 13798c2ecf20Sopenharmony_ci#endif 1380