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