18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2008 Ben Skeggs.
38c2ecf20Sopenharmony_ci * All Rights Reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
68c2ecf20Sopenharmony_ci * a copy of this software and associated documentation files (the
78c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
88c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
98c2ecf20Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
108c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
118c2ecf20Sopenharmony_ci * the following conditions:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
148c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial
158c2ecf20Sopenharmony_ci * portions of the Software.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
188c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
198c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
208c2ecf20Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
218c2ecf20Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
228c2ecf20Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
238c2ecf20Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "nouveau_drv.h"
288c2ecf20Sopenharmony_ci#include "nouveau_dma.h"
298c2ecf20Sopenharmony_ci#include "nouveau_fence.h"
308c2ecf20Sopenharmony_ci#include "nouveau_abi16.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "nouveau_ttm.h"
338c2ecf20Sopenharmony_ci#include "nouveau_gem.h"
348c2ecf20Sopenharmony_ci#include "nouveau_mem.h"
358c2ecf20Sopenharmony_ci#include "nouveau_vmm.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <nvif/class.h>
388c2ecf20Sopenharmony_ci#include <nvif/push206e.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_civoid
418c2ecf20Sopenharmony_cinouveau_gem_object_del(struct drm_gem_object *gem)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
448c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
458c2ecf20Sopenharmony_ci	struct device *dev = drm->dev->dev;
468c2ecf20Sopenharmony_ci	int ret;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
498c2ecf20Sopenharmony_ci	if (WARN_ON(ret < 0 && ret != -EACCES)) {
508c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(dev);
518c2ecf20Sopenharmony_ci		return;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (gem->import_attach)
558c2ecf20Sopenharmony_ci		drm_prime_gem_destroy(gem, nvbo->bo.sg);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	ttm_bo_put(&nvbo->bo);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
608c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciint
648c2ecf20Sopenharmony_cinouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
678c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
688c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
698c2ecf20Sopenharmony_ci	struct device *dev = drm->dev->dev;
708c2ecf20Sopenharmony_ci	struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
718c2ecf20Sopenharmony_ci	struct nouveau_vma *vma;
728c2ecf20Sopenharmony_ci	int ret;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50)
758c2ecf20Sopenharmony_ci		return 0;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
788c2ecf20Sopenharmony_ci	if (ret)
798c2ecf20Sopenharmony_ci		return ret;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
828c2ecf20Sopenharmony_ci	if (ret < 0 && ret != -EACCES) {
838c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(dev);
848c2ecf20Sopenharmony_ci		goto out;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	ret = nouveau_vma_new(nvbo, vmm, &vma);
888c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
898c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
908c2ecf20Sopenharmony_ciout:
918c2ecf20Sopenharmony_ci	ttm_bo_unreserve(&nvbo->bo);
928c2ecf20Sopenharmony_ci	return ret;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistruct nouveau_gem_object_unmap {
968c2ecf20Sopenharmony_ci	struct nouveau_cli_work work;
978c2ecf20Sopenharmony_ci	struct nouveau_vma *vma;
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void
1018c2ecf20Sopenharmony_cinouveau_gem_object_delete(struct nouveau_vma *vma)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	nouveau_fence_unref(&vma->fence);
1048c2ecf20Sopenharmony_ci	nouveau_vma_del(&vma);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic void
1088c2ecf20Sopenharmony_cinouveau_gem_object_delete_work(struct nouveau_cli_work *w)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct nouveau_gem_object_unmap *work =
1118c2ecf20Sopenharmony_ci		container_of(w, typeof(*work), work);
1128c2ecf20Sopenharmony_ci	nouveau_gem_object_delete(work->vma);
1138c2ecf20Sopenharmony_ci	kfree(work);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic void
1178c2ecf20Sopenharmony_cinouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct dma_fence *fence = vma->fence ? &vma->fence->base : NULL;
1208c2ecf20Sopenharmony_ci	struct nouveau_gem_object_unmap *work;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	list_del_init(&vma->head);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (!fence) {
1258c2ecf20Sopenharmony_ci		nouveau_gem_object_delete(vma);
1268c2ecf20Sopenharmony_ci		return;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (!(work = kmalloc(sizeof(*work), GFP_KERNEL))) {
1308c2ecf20Sopenharmony_ci		WARN_ON(dma_fence_wait_timeout(fence, false, 2 * HZ) <= 0);
1318c2ecf20Sopenharmony_ci		nouveau_gem_object_delete(vma);
1328c2ecf20Sopenharmony_ci		return;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	work->work.func = nouveau_gem_object_delete_work;
1368c2ecf20Sopenharmony_ci	work->vma = vma;
1378c2ecf20Sopenharmony_ci	nouveau_cli_work_queue(vma->vmm->cli, fence, &work->work);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_civoid
1418c2ecf20Sopenharmony_cinouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
1448c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
1458c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
1468c2ecf20Sopenharmony_ci	struct device *dev = drm->dev->dev;
1478c2ecf20Sopenharmony_ci	struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : & cli->vmm;
1488c2ecf20Sopenharmony_ci	struct nouveau_vma *vma;
1498c2ecf20Sopenharmony_ci	int ret;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50)
1528c2ecf20Sopenharmony_ci		return;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
1558c2ecf20Sopenharmony_ci	if (ret)
1568c2ecf20Sopenharmony_ci		return;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	vma = nouveau_vma_find(nvbo, vmm);
1598c2ecf20Sopenharmony_ci	if (vma) {
1608c2ecf20Sopenharmony_ci		if (--vma->refs == 0) {
1618c2ecf20Sopenharmony_ci			ret = pm_runtime_get_sync(dev);
1628c2ecf20Sopenharmony_ci			if (!WARN_ON(ret < 0 && ret != -EACCES)) {
1638c2ecf20Sopenharmony_ci				nouveau_gem_object_unmap(nvbo, vma);
1648c2ecf20Sopenharmony_ci				pm_runtime_mark_last_busy(dev);
1658c2ecf20Sopenharmony_ci			}
1668c2ecf20Sopenharmony_ci			pm_runtime_put_autosuspend(dev);
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci	ttm_bo_unreserve(&nvbo->bo);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciint
1738c2ecf20Sopenharmony_cinouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain,
1748c2ecf20Sopenharmony_ci		uint32_t tile_mode, uint32_t tile_flags,
1758c2ecf20Sopenharmony_ci		struct nouveau_bo **pnvbo)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = cli->drm;
1788c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo;
1798c2ecf20Sopenharmony_ci	int ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (!(domain & (NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART)))
1828c2ecf20Sopenharmony_ci		domain |= NOUVEAU_GEM_DOMAIN_CPU;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode,
1858c2ecf20Sopenharmony_ci				tile_flags);
1868c2ecf20Sopenharmony_ci	if (IS_ERR(nvbo))
1878c2ecf20Sopenharmony_ci		return PTR_ERR(nvbo);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* Initialize the embedded gem-object. We return a single gem-reference
1908c2ecf20Sopenharmony_ci	 * to the caller, instead of a normal nouveau_bo ttm reference. */
1918c2ecf20Sopenharmony_ci	ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, size);
1928c2ecf20Sopenharmony_ci	if (ret) {
1938c2ecf20Sopenharmony_ci		drm_gem_object_release(&nvbo->bo.base);
1948c2ecf20Sopenharmony_ci		kfree(nvbo);
1958c2ecf20Sopenharmony_ci		return ret;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	ret = nouveau_bo_init(nvbo, size, align, domain, NULL, NULL);
1998c2ecf20Sopenharmony_ci	if (ret)
2008c2ecf20Sopenharmony_ci		return ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* we restrict allowed domains on nv50+ to only the types
2038c2ecf20Sopenharmony_ci	 * that were requested at creation time.  not possibly on
2048c2ecf20Sopenharmony_ci	 * earlier chips without busting the ABI.
2058c2ecf20Sopenharmony_ci	 */
2068c2ecf20Sopenharmony_ci	nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM |
2078c2ecf20Sopenharmony_ci			      NOUVEAU_GEM_DOMAIN_GART;
2088c2ecf20Sopenharmony_ci	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
2098c2ecf20Sopenharmony_ci		nvbo->valid_domains &= domain;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	nvbo->bo.persistent_swap_storage = nvbo->bo.base.filp;
2128c2ecf20Sopenharmony_ci	*pnvbo = nvbo;
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int
2178c2ecf20Sopenharmony_cinouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
2188c2ecf20Sopenharmony_ci		 struct drm_nouveau_gem_info *rep)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
2218c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
2228c2ecf20Sopenharmony_ci	struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
2238c2ecf20Sopenharmony_ci	struct nouveau_vma *vma;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (is_power_of_2(nvbo->valid_domains))
2268c2ecf20Sopenharmony_ci		rep->domain = nvbo->valid_domains;
2278c2ecf20Sopenharmony_ci	else if (nvbo->bo.mem.mem_type == TTM_PL_TT)
2288c2ecf20Sopenharmony_ci		rep->domain = NOUVEAU_GEM_DOMAIN_GART;
2298c2ecf20Sopenharmony_ci	else
2308c2ecf20Sopenharmony_ci		rep->domain = NOUVEAU_GEM_DOMAIN_VRAM;
2318c2ecf20Sopenharmony_ci	rep->offset = nvbo->offset;
2328c2ecf20Sopenharmony_ci	if (vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
2338c2ecf20Sopenharmony_ci		vma = nouveau_vma_find(nvbo, vmm);
2348c2ecf20Sopenharmony_ci		if (!vma)
2358c2ecf20Sopenharmony_ci			return -EINVAL;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		rep->offset = vma->addr;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT;
2418c2ecf20Sopenharmony_ci	rep->map_handle = drm_vma_node_offset_addr(&nvbo->bo.base.vma_node);
2428c2ecf20Sopenharmony_ci	rep->tile_mode = nvbo->mode;
2438c2ecf20Sopenharmony_ci	rep->tile_flags = nvbo->contig ? 0 : NOUVEAU_GEM_TILE_NONCONTIG;
2448c2ecf20Sopenharmony_ci	if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI)
2458c2ecf20Sopenharmony_ci		rep->tile_flags |= nvbo->kind << 8;
2468c2ecf20Sopenharmony_ci	else
2478c2ecf20Sopenharmony_ci	if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
2488c2ecf20Sopenharmony_ci		rep->tile_flags |= nvbo->kind << 8 | nvbo->comp << 16;
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci		rep->tile_flags |= nvbo->zeta;
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ciint
2558c2ecf20Sopenharmony_cinouveau_gem_ioctl_new(struct drm_device *dev, void *data,
2568c2ecf20Sopenharmony_ci		      struct drm_file *file_priv)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
2598c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_new *req = data;
2608c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo = NULL;
2618c2ecf20Sopenharmony_ci	int ret = 0;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	ret = nouveau_gem_new(cli, req->info.size, req->align,
2648c2ecf20Sopenharmony_ci			      req->info.domain, req->info.tile_mode,
2658c2ecf20Sopenharmony_ci			      req->info.tile_flags, &nvbo);
2668c2ecf20Sopenharmony_ci	if (ret)
2678c2ecf20Sopenharmony_ci		return ret;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	ret = drm_gem_handle_create(file_priv, &nvbo->bo.base,
2708c2ecf20Sopenharmony_ci				    &req->info.handle);
2718c2ecf20Sopenharmony_ci	if (ret == 0) {
2728c2ecf20Sopenharmony_ci		ret = nouveau_gem_info(file_priv, &nvbo->bo.base, &req->info);
2738c2ecf20Sopenharmony_ci		if (ret)
2748c2ecf20Sopenharmony_ci			drm_gem_handle_delete(file_priv, req->info.handle);
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* drop reference from allocate - handle holds it now */
2788c2ecf20Sopenharmony_ci	drm_gem_object_put(&nvbo->bo.base);
2798c2ecf20Sopenharmony_ci	return ret;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int
2838c2ecf20Sopenharmony_cinouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
2848c2ecf20Sopenharmony_ci		       uint32_t write_domains, uint32_t valid_domains)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
2878c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo = &nvbo->bo;
2888c2ecf20Sopenharmony_ci	uint32_t domains = valid_domains & nvbo->valid_domains &
2898c2ecf20Sopenharmony_ci		(write_domains ? write_domains : read_domains);
2908c2ecf20Sopenharmony_ci	uint32_t pref_domains = 0;;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (!domains)
2938c2ecf20Sopenharmony_ci		return -EINVAL;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	valid_domains &= ~(NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
2988c2ecf20Sopenharmony_ci	    bo->mem.mem_type == TTM_PL_VRAM)
2998c2ecf20Sopenharmony_ci		pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	else if ((domains & NOUVEAU_GEM_DOMAIN_GART) &&
3028c2ecf20Sopenharmony_ci		 bo->mem.mem_type == TTM_PL_TT)
3038c2ecf20Sopenharmony_ci		pref_domains |= NOUVEAU_GEM_DOMAIN_GART;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	else if (domains & NOUVEAU_GEM_DOMAIN_VRAM)
3068c2ecf20Sopenharmony_ci		pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	else
3098c2ecf20Sopenharmony_ci		pref_domains |= NOUVEAU_GEM_DOMAIN_GART;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	nouveau_bo_placement_set(nvbo, pref_domains, valid_domains);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return 0;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistruct validate_op {
3178c2ecf20Sopenharmony_ci	struct list_head list;
3188c2ecf20Sopenharmony_ci	struct ww_acquire_ctx ticket;
3198c2ecf20Sopenharmony_ci};
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void
3228c2ecf20Sopenharmony_civalidate_fini_no_ticket(struct validate_op *op, struct nouveau_channel *chan,
3238c2ecf20Sopenharmony_ci			struct nouveau_fence *fence,
3248c2ecf20Sopenharmony_ci			struct drm_nouveau_gem_pushbuf_bo *pbbo)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo;
3278c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_pushbuf_bo *b;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	while (!list_empty(&op->list)) {
3308c2ecf20Sopenharmony_ci		nvbo = list_entry(op->list.next, struct nouveau_bo, entry);
3318c2ecf20Sopenharmony_ci		b = &pbbo[nvbo->pbbo_index];
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		if (likely(fence)) {
3348c2ecf20Sopenharmony_ci			nouveau_bo_fence(nvbo, fence, !!b->write_domains);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci			if (chan->vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
3378c2ecf20Sopenharmony_ci				struct nouveau_vma *vma =
3388c2ecf20Sopenharmony_ci					(void *)(unsigned long)b->user_priv;
3398c2ecf20Sopenharmony_ci				nouveau_fence_unref(&vma->fence);
3408c2ecf20Sopenharmony_ci				dma_fence_get(&fence->base);
3418c2ecf20Sopenharmony_ci				vma->fence = fence;
3428c2ecf20Sopenharmony_ci			}
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		if (unlikely(nvbo->validate_mapped)) {
3468c2ecf20Sopenharmony_ci			ttm_bo_kunmap(&nvbo->kmap);
3478c2ecf20Sopenharmony_ci			nvbo->validate_mapped = false;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		list_del(&nvbo->entry);
3518c2ecf20Sopenharmony_ci		nvbo->reserved_by = NULL;
3528c2ecf20Sopenharmony_ci		ttm_bo_unreserve(&nvbo->bo);
3538c2ecf20Sopenharmony_ci		drm_gem_object_put(&nvbo->bo.base);
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic void
3588c2ecf20Sopenharmony_civalidate_fini(struct validate_op *op, struct nouveau_channel *chan,
3598c2ecf20Sopenharmony_ci	      struct nouveau_fence *fence,
3608c2ecf20Sopenharmony_ci	      struct drm_nouveau_gem_pushbuf_bo *pbbo)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	validate_fini_no_ticket(op, chan, fence, pbbo);
3638c2ecf20Sopenharmony_ci	ww_acquire_fini(&op->ticket);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic int
3678c2ecf20Sopenharmony_civalidate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
3688c2ecf20Sopenharmony_ci	      struct drm_nouveau_gem_pushbuf_bo *pbbo,
3698c2ecf20Sopenharmony_ci	      int nr_buffers, struct validate_op *op)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
3728c2ecf20Sopenharmony_ci	int trycnt = 0;
3738c2ecf20Sopenharmony_ci	int ret = -EINVAL, i;
3748c2ecf20Sopenharmony_ci	struct nouveau_bo *res_bo = NULL;
3758c2ecf20Sopenharmony_ci	LIST_HEAD(gart_list);
3768c2ecf20Sopenharmony_ci	LIST_HEAD(vram_list);
3778c2ecf20Sopenharmony_ci	LIST_HEAD(both_list);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ww_acquire_init(&op->ticket, &reservation_ww_class);
3808c2ecf20Sopenharmony_ciretry:
3818c2ecf20Sopenharmony_ci	if (++trycnt > 100000) {
3828c2ecf20Sopenharmony_ci		NV_PRINTK(err, cli, "%s failed and gave up.\n", __func__);
3838c2ecf20Sopenharmony_ci		return -EINVAL;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	for (i = 0; i < nr_buffers; i++) {
3878c2ecf20Sopenharmony_ci		struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[i];
3888c2ecf20Sopenharmony_ci		struct drm_gem_object *gem;
3898c2ecf20Sopenharmony_ci		struct nouveau_bo *nvbo;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		gem = drm_gem_object_lookup(file_priv, b->handle);
3928c2ecf20Sopenharmony_ci		if (!gem) {
3938c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "Unknown handle 0x%08x\n", b->handle);
3948c2ecf20Sopenharmony_ci			ret = -ENOENT;
3958c2ecf20Sopenharmony_ci			break;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci		nvbo = nouveau_gem_object(gem);
3988c2ecf20Sopenharmony_ci		if (nvbo == res_bo) {
3998c2ecf20Sopenharmony_ci			res_bo = NULL;
4008c2ecf20Sopenharmony_ci			drm_gem_object_put(gem);
4018c2ecf20Sopenharmony_ci			continue;
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		if (nvbo->reserved_by && nvbo->reserved_by == file_priv) {
4058c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "multiple instances of buffer %d on "
4068c2ecf20Sopenharmony_ci				      "validation list\n", b->handle);
4078c2ecf20Sopenharmony_ci			drm_gem_object_put(gem);
4088c2ecf20Sopenharmony_ci			ret = -EINVAL;
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		ret = ttm_bo_reserve(&nvbo->bo, true, false, &op->ticket);
4138c2ecf20Sopenharmony_ci		if (ret) {
4148c2ecf20Sopenharmony_ci			list_splice_tail_init(&vram_list, &op->list);
4158c2ecf20Sopenharmony_ci			list_splice_tail_init(&gart_list, &op->list);
4168c2ecf20Sopenharmony_ci			list_splice_tail_init(&both_list, &op->list);
4178c2ecf20Sopenharmony_ci			validate_fini_no_ticket(op, chan, NULL, NULL);
4188c2ecf20Sopenharmony_ci			if (unlikely(ret == -EDEADLK)) {
4198c2ecf20Sopenharmony_ci				ret = ttm_bo_reserve_slowpath(&nvbo->bo, true,
4208c2ecf20Sopenharmony_ci							      &op->ticket);
4218c2ecf20Sopenharmony_ci				if (!ret)
4228c2ecf20Sopenharmony_ci					res_bo = nvbo;
4238c2ecf20Sopenharmony_ci			}
4248c2ecf20Sopenharmony_ci			if (unlikely(ret)) {
4258c2ecf20Sopenharmony_ci				if (ret != -ERESTARTSYS)
4268c2ecf20Sopenharmony_ci					NV_PRINTK(err, cli, "fail reserve\n");
4278c2ecf20Sopenharmony_ci				break;
4288c2ecf20Sopenharmony_ci			}
4298c2ecf20Sopenharmony_ci		}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		if (chan->vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) {
4328c2ecf20Sopenharmony_ci			struct nouveau_vmm *vmm = chan->vmm;
4338c2ecf20Sopenharmony_ci			struct nouveau_vma *vma = nouveau_vma_find(nvbo, vmm);
4348c2ecf20Sopenharmony_ci			if (!vma) {
4358c2ecf20Sopenharmony_ci				NV_PRINTK(err, cli, "vma not found!\n");
4368c2ecf20Sopenharmony_ci				ret = -EINVAL;
4378c2ecf20Sopenharmony_ci				break;
4388c2ecf20Sopenharmony_ci			}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci			b->user_priv = (uint64_t)(unsigned long)vma;
4418c2ecf20Sopenharmony_ci		} else {
4428c2ecf20Sopenharmony_ci			b->user_priv = (uint64_t)(unsigned long)nvbo;
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		nvbo->reserved_by = file_priv;
4468c2ecf20Sopenharmony_ci		nvbo->pbbo_index = i;
4478c2ecf20Sopenharmony_ci		if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
4488c2ecf20Sopenharmony_ci		    (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART))
4498c2ecf20Sopenharmony_ci			list_add_tail(&nvbo->entry, &both_list);
4508c2ecf20Sopenharmony_ci		else
4518c2ecf20Sopenharmony_ci		if (b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM)
4528c2ecf20Sopenharmony_ci			list_add_tail(&nvbo->entry, &vram_list);
4538c2ecf20Sopenharmony_ci		else
4548c2ecf20Sopenharmony_ci		if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)
4558c2ecf20Sopenharmony_ci			list_add_tail(&nvbo->entry, &gart_list);
4568c2ecf20Sopenharmony_ci		else {
4578c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "invalid valid domains: 0x%08x\n",
4588c2ecf20Sopenharmony_ci				 b->valid_domains);
4598c2ecf20Sopenharmony_ci			list_add_tail(&nvbo->entry, &both_list);
4608c2ecf20Sopenharmony_ci			ret = -EINVAL;
4618c2ecf20Sopenharmony_ci			break;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci		if (nvbo == res_bo)
4648c2ecf20Sopenharmony_ci			goto retry;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	ww_acquire_done(&op->ticket);
4688c2ecf20Sopenharmony_ci	list_splice_tail(&vram_list, &op->list);
4698c2ecf20Sopenharmony_ci	list_splice_tail(&gart_list, &op->list);
4708c2ecf20Sopenharmony_ci	list_splice_tail(&both_list, &op->list);
4718c2ecf20Sopenharmony_ci	if (ret)
4728c2ecf20Sopenharmony_ci		validate_fini(op, chan, NULL, NULL);
4738c2ecf20Sopenharmony_ci	return ret;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistatic int
4788c2ecf20Sopenharmony_civalidate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
4798c2ecf20Sopenharmony_ci	      struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = chan->drm;
4828c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo;
4838c2ecf20Sopenharmony_ci	int ret, relocs = 0;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	list_for_each_entry(nvbo, list, entry) {
4868c2ecf20Sopenharmony_ci		struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		ret = nouveau_gem_set_domain(&nvbo->bo.base, b->read_domains,
4898c2ecf20Sopenharmony_ci					     b->write_domains,
4908c2ecf20Sopenharmony_ci					     b->valid_domains);
4918c2ecf20Sopenharmony_ci		if (unlikely(ret)) {
4928c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "fail set_domain\n");
4938c2ecf20Sopenharmony_ci			return ret;
4948c2ecf20Sopenharmony_ci		}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		ret = nouveau_bo_validate(nvbo, true, false);
4978c2ecf20Sopenharmony_ci		if (unlikely(ret)) {
4988c2ecf20Sopenharmony_ci			if (ret != -ERESTARTSYS)
4998c2ecf20Sopenharmony_ci				NV_PRINTK(err, cli, "fail ttm_validate\n");
5008c2ecf20Sopenharmony_ci			return ret;
5018c2ecf20Sopenharmony_ci		}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true);
5048c2ecf20Sopenharmony_ci		if (unlikely(ret)) {
5058c2ecf20Sopenharmony_ci			if (ret != -ERESTARTSYS)
5068c2ecf20Sopenharmony_ci				NV_PRINTK(err, cli, "fail post-validate sync\n");
5078c2ecf20Sopenharmony_ci			return ret;
5088c2ecf20Sopenharmony_ci		}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
5118c2ecf20Sopenharmony_ci			if (nvbo->offset == b->presumed.offset &&
5128c2ecf20Sopenharmony_ci			    ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
5138c2ecf20Sopenharmony_ci			      b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
5148c2ecf20Sopenharmony_ci			     (nvbo->bo.mem.mem_type == TTM_PL_TT &&
5158c2ecf20Sopenharmony_ci			      b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART)))
5168c2ecf20Sopenharmony_ci				continue;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci			if (nvbo->bo.mem.mem_type == TTM_PL_TT)
5198c2ecf20Sopenharmony_ci				b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
5208c2ecf20Sopenharmony_ci			else
5218c2ecf20Sopenharmony_ci				b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
5228c2ecf20Sopenharmony_ci			b->presumed.offset = nvbo->offset;
5238c2ecf20Sopenharmony_ci			b->presumed.valid = 0;
5248c2ecf20Sopenharmony_ci			relocs++;
5258c2ecf20Sopenharmony_ci		}
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return relocs;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int
5328c2ecf20Sopenharmony_cinouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
5338c2ecf20Sopenharmony_ci			     struct drm_file *file_priv,
5348c2ecf20Sopenharmony_ci			     struct drm_nouveau_gem_pushbuf_bo *pbbo,
5358c2ecf20Sopenharmony_ci			     int nr_buffers,
5368c2ecf20Sopenharmony_ci			     struct validate_op *op, bool *apply_relocs)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
5398c2ecf20Sopenharmony_ci	int ret;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&op->list);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (nr_buffers == 0)
5448c2ecf20Sopenharmony_ci		return 0;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
5478c2ecf20Sopenharmony_ci	if (unlikely(ret)) {
5488c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
5498c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "validate_init\n");
5508c2ecf20Sopenharmony_ci		return ret;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	ret = validate_list(chan, cli, &op->list, pbbo);
5548c2ecf20Sopenharmony_ci	if (unlikely(ret < 0)) {
5558c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
5568c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "validating bo list\n");
5578c2ecf20Sopenharmony_ci		validate_fini(op, chan, NULL, NULL);
5588c2ecf20Sopenharmony_ci		return ret;
5598c2ecf20Sopenharmony_ci	} else if (ret > 0) {
5608c2ecf20Sopenharmony_ci		*apply_relocs = true;
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	return 0;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic inline void
5678c2ecf20Sopenharmony_ciu_free(void *addr)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	kvfree(addr);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic inline void *
5738c2ecf20Sopenharmony_ciu_memcpya(uint64_t user, unsigned nmemb, unsigned size)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	void *mem;
5768c2ecf20Sopenharmony_ci	void __user *userptr = (void __force __user *)(uintptr_t)user;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	size *= nmemb;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	mem = kvmalloc(size, GFP_KERNEL);
5818c2ecf20Sopenharmony_ci	if (!mem)
5828c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (copy_from_user(mem, userptr, size)) {
5858c2ecf20Sopenharmony_ci		u_free(mem);
5868c2ecf20Sopenharmony_ci		return ERR_PTR(-EFAULT);
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return mem;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic int
5938c2ecf20Sopenharmony_cinouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
5948c2ecf20Sopenharmony_ci				struct drm_nouveau_gem_pushbuf *req,
5958c2ecf20Sopenharmony_ci				struct drm_nouveau_gem_pushbuf_reloc *reloc,
5968c2ecf20Sopenharmony_ci				struct drm_nouveau_gem_pushbuf_bo *bo)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	int ret = 0;
5998c2ecf20Sopenharmony_ci	unsigned i;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	for (i = 0; i < req->nr_relocs; i++) {
6028c2ecf20Sopenharmony_ci		struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i];
6038c2ecf20Sopenharmony_ci		struct drm_nouveau_gem_pushbuf_bo *b;
6048c2ecf20Sopenharmony_ci		struct nouveau_bo *nvbo;
6058c2ecf20Sopenharmony_ci		uint32_t data;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci		if (unlikely(r->bo_index >= req->nr_buffers)) {
6088c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "reloc bo index invalid\n");
6098c2ecf20Sopenharmony_ci			ret = -EINVAL;
6108c2ecf20Sopenharmony_ci			break;
6118c2ecf20Sopenharmony_ci		}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci		b = &bo[r->bo_index];
6148c2ecf20Sopenharmony_ci		if (b->presumed.valid)
6158c2ecf20Sopenharmony_ci			continue;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci		if (unlikely(r->reloc_bo_index >= req->nr_buffers)) {
6188c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "reloc container bo index invalid\n");
6198c2ecf20Sopenharmony_ci			ret = -EINVAL;
6208c2ecf20Sopenharmony_ci			break;
6218c2ecf20Sopenharmony_ci		}
6228c2ecf20Sopenharmony_ci		nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		if (unlikely(r->reloc_bo_offset + 4 >
6258c2ecf20Sopenharmony_ci			     nvbo->bo.mem.num_pages << PAGE_SHIFT)) {
6268c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "reloc outside of bo\n");
6278c2ecf20Sopenharmony_ci			ret = -EINVAL;
6288c2ecf20Sopenharmony_ci			break;
6298c2ecf20Sopenharmony_ci		}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci		if (!nvbo->kmap.virtual) {
6328c2ecf20Sopenharmony_ci			ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
6338c2ecf20Sopenharmony_ci					  &nvbo->kmap);
6348c2ecf20Sopenharmony_ci			if (ret) {
6358c2ecf20Sopenharmony_ci				NV_PRINTK(err, cli, "failed kmap for reloc\n");
6368c2ecf20Sopenharmony_ci				break;
6378c2ecf20Sopenharmony_ci			}
6388c2ecf20Sopenharmony_ci			nvbo->validate_mapped = true;
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		if (r->flags & NOUVEAU_GEM_RELOC_LOW)
6428c2ecf20Sopenharmony_ci			data = b->presumed.offset + r->data;
6438c2ecf20Sopenharmony_ci		else
6448c2ecf20Sopenharmony_ci		if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
6458c2ecf20Sopenharmony_ci			data = (b->presumed.offset + r->data) >> 32;
6468c2ecf20Sopenharmony_ci		else
6478c2ecf20Sopenharmony_ci			data = r->data;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		if (r->flags & NOUVEAU_GEM_RELOC_OR) {
6508c2ecf20Sopenharmony_ci			if (b->presumed.domain == NOUVEAU_GEM_DOMAIN_GART)
6518c2ecf20Sopenharmony_ci				data |= r->tor;
6528c2ecf20Sopenharmony_ci			else
6538c2ecf20Sopenharmony_ci				data |= r->vor;
6548c2ecf20Sopenharmony_ci		}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci		ret = ttm_bo_wait(&nvbo->bo, false, false);
6578c2ecf20Sopenharmony_ci		if (ret) {
6588c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret);
6598c2ecf20Sopenharmony_ci			break;
6608c2ecf20Sopenharmony_ci		}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	return ret;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ciint
6698c2ecf20Sopenharmony_cinouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
6708c2ecf20Sopenharmony_ci			  struct drm_file *file_priv)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
6738c2ecf20Sopenharmony_ci	struct nouveau_cli *cli = nouveau_cli(file_priv);
6748c2ecf20Sopenharmony_ci	struct nouveau_abi16_chan *temp;
6758c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
6768c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_pushbuf *req = data;
6778c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_pushbuf_push *push;
6788c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
6798c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_pushbuf_bo *bo;
6808c2ecf20Sopenharmony_ci	struct nouveau_channel *chan = NULL;
6818c2ecf20Sopenharmony_ci	struct validate_op op;
6828c2ecf20Sopenharmony_ci	struct nouveau_fence *fence = NULL;
6838c2ecf20Sopenharmony_ci	int i, j, ret = 0;
6848c2ecf20Sopenharmony_ci	bool do_reloc = false, sync = false;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (unlikely(!abi16))
6878c2ecf20Sopenharmony_ci		return -ENOMEM;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	list_for_each_entry(temp, &abi16->channels, head) {
6908c2ecf20Sopenharmony_ci		if (temp->chan->chid == req->channel) {
6918c2ecf20Sopenharmony_ci			chan = temp->chan;
6928c2ecf20Sopenharmony_ci			break;
6938c2ecf20Sopenharmony_ci		}
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (!chan)
6978c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, -ENOENT);
6988c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&chan->killed)))
6998c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, -ENODEV);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	sync = req->vram_available & NOUVEAU_GEM_PUSHBUF_SYNC;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	req->vram_available = drm->gem.vram_available;
7048c2ecf20Sopenharmony_ci	req->gart_available = drm->gem.gart_available;
7058c2ecf20Sopenharmony_ci	if (unlikely(req->nr_push == 0))
7068c2ecf20Sopenharmony_ci		goto out_next;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) {
7098c2ecf20Sopenharmony_ci		NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n",
7108c2ecf20Sopenharmony_ci			 req->nr_push, NOUVEAU_GEM_MAX_PUSH);
7118c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, -EINVAL);
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) {
7158c2ecf20Sopenharmony_ci		NV_PRINTK(err, cli, "pushbuf bo count exceeds limit: %d max %d\n",
7168c2ecf20Sopenharmony_ci			 req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS);
7178c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, -EINVAL);
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) {
7218c2ecf20Sopenharmony_ci		NV_PRINTK(err, cli, "pushbuf reloc count exceeds limit: %d max %d\n",
7228c2ecf20Sopenharmony_ci			 req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS);
7238c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, -EINVAL);
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	push = u_memcpya(req->push, req->nr_push, sizeof(*push));
7278c2ecf20Sopenharmony_ci	if (IS_ERR(push))
7288c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, PTR_ERR(push));
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
7318c2ecf20Sopenharmony_ci	if (IS_ERR(bo)) {
7328c2ecf20Sopenharmony_ci		u_free(push);
7338c2ecf20Sopenharmony_ci		return nouveau_abi16_put(abi16, PTR_ERR(bo));
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/* Ensure all push buffers are on validate list */
7378c2ecf20Sopenharmony_ci	for (i = 0; i < req->nr_push; i++) {
7388c2ecf20Sopenharmony_ci		if (push[i].bo_index >= req->nr_buffers) {
7398c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "push %d buffer not in list\n", i);
7408c2ecf20Sopenharmony_ci			ret = -EINVAL;
7418c2ecf20Sopenharmony_ci			goto out_prevalid;
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	/* Validate buffer list */
7468c2ecf20Sopenharmony_cirevalidate:
7478c2ecf20Sopenharmony_ci	ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo,
7488c2ecf20Sopenharmony_ci					   req->nr_buffers, &op, &do_reloc);
7498c2ecf20Sopenharmony_ci	if (ret) {
7508c2ecf20Sopenharmony_ci		if (ret != -ERESTARTSYS)
7518c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "validate: %d\n", ret);
7528c2ecf20Sopenharmony_ci		goto out_prevalid;
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/* Apply any relocations that are required */
7568c2ecf20Sopenharmony_ci	if (do_reloc) {
7578c2ecf20Sopenharmony_ci		if (!reloc) {
7588c2ecf20Sopenharmony_ci			validate_fini(&op, chan, NULL, bo);
7598c2ecf20Sopenharmony_ci			reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc));
7608c2ecf20Sopenharmony_ci			if (IS_ERR(reloc)) {
7618c2ecf20Sopenharmony_ci				ret = PTR_ERR(reloc);
7628c2ecf20Sopenharmony_ci				goto out_prevalid;
7638c2ecf20Sopenharmony_ci			}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci			goto revalidate;
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		ret = nouveau_gem_pushbuf_reloc_apply(cli, req, reloc, bo);
7698c2ecf20Sopenharmony_ci		if (ret) {
7708c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "reloc apply: %d\n", ret);
7718c2ecf20Sopenharmony_ci			goto out;
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (chan->dma.ib_max) {
7768c2ecf20Sopenharmony_ci		ret = nouveau_dma_wait(chan, req->nr_push + 1, 16);
7778c2ecf20Sopenharmony_ci		if (ret) {
7788c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "nv50cal_space: %d\n", ret);
7798c2ecf20Sopenharmony_ci			goto out;
7808c2ecf20Sopenharmony_ci		}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		for (i = 0; i < req->nr_push; i++) {
7838c2ecf20Sopenharmony_ci			struct nouveau_vma *vma = (void *)(unsigned long)
7848c2ecf20Sopenharmony_ci				bo[push[i].bo_index].user_priv;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci			nv50_dma_push(chan, vma->addr + push[i].offset,
7878c2ecf20Sopenharmony_ci				      push[i].length);
7888c2ecf20Sopenharmony_ci		}
7898c2ecf20Sopenharmony_ci	} else
7908c2ecf20Sopenharmony_ci	if (drm->client.device.info.chipset >= 0x25) {
7918c2ecf20Sopenharmony_ci		ret = PUSH_WAIT(chan->chan.push, req->nr_push * 2);
7928c2ecf20Sopenharmony_ci		if (ret) {
7938c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "cal_space: %d\n", ret);
7948c2ecf20Sopenharmony_ci			goto out;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		for (i = 0; i < req->nr_push; i++) {
7988c2ecf20Sopenharmony_ci			struct nouveau_bo *nvbo = (void *)(unsigned long)
7998c2ecf20Sopenharmony_ci				bo[push[i].bo_index].user_priv;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci			PUSH_CALL(chan->chan.push, nvbo->offset + push[i].offset);
8028c2ecf20Sopenharmony_ci			PUSH_DATA(chan->chan.push, 0);
8038c2ecf20Sopenharmony_ci		}
8048c2ecf20Sopenharmony_ci	} else {
8058c2ecf20Sopenharmony_ci		ret = PUSH_WAIT(chan->chan.push, req->nr_push * (2 + NOUVEAU_DMA_SKIPS));
8068c2ecf20Sopenharmony_ci		if (ret) {
8078c2ecf20Sopenharmony_ci			NV_PRINTK(err, cli, "jmp_space: %d\n", ret);
8088c2ecf20Sopenharmony_ci			goto out;
8098c2ecf20Sopenharmony_ci		}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		for (i = 0; i < req->nr_push; i++) {
8128c2ecf20Sopenharmony_ci			struct nouveau_bo *nvbo = (void *)(unsigned long)
8138c2ecf20Sopenharmony_ci				bo[push[i].bo_index].user_priv;
8148c2ecf20Sopenharmony_ci			uint32_t cmd;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci			cmd = chan->push.addr + ((chan->dma.cur + 2) << 2);
8178c2ecf20Sopenharmony_ci			cmd |= 0x20000000;
8188c2ecf20Sopenharmony_ci			if (unlikely(cmd != req->suffix0)) {
8198c2ecf20Sopenharmony_ci				if (!nvbo->kmap.virtual) {
8208c2ecf20Sopenharmony_ci					ret = ttm_bo_kmap(&nvbo->bo, 0,
8218c2ecf20Sopenharmony_ci							  nvbo->bo.mem.
8228c2ecf20Sopenharmony_ci							  num_pages,
8238c2ecf20Sopenharmony_ci							  &nvbo->kmap);
8248c2ecf20Sopenharmony_ci					if (ret) {
8258c2ecf20Sopenharmony_ci						WIND_RING(chan);
8268c2ecf20Sopenharmony_ci						goto out;
8278c2ecf20Sopenharmony_ci					}
8288c2ecf20Sopenharmony_ci					nvbo->validate_mapped = true;
8298c2ecf20Sopenharmony_ci				}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci				nouveau_bo_wr32(nvbo, (push[i].offset +
8328c2ecf20Sopenharmony_ci						push[i].length - 8) / 4, cmd);
8338c2ecf20Sopenharmony_ci			}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci			PUSH_JUMP(chan->chan.push, nvbo->offset + push[i].offset);
8368c2ecf20Sopenharmony_ci			PUSH_DATA(chan->chan.push, 0);
8378c2ecf20Sopenharmony_ci			for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
8388c2ecf20Sopenharmony_ci				PUSH_DATA(chan->chan.push, 0);
8398c2ecf20Sopenharmony_ci		}
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	ret = nouveau_fence_new(chan, false, &fence);
8438c2ecf20Sopenharmony_ci	if (ret) {
8448c2ecf20Sopenharmony_ci		NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret);
8458c2ecf20Sopenharmony_ci		WIND_RING(chan);
8468c2ecf20Sopenharmony_ci		goto out;
8478c2ecf20Sopenharmony_ci	}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (sync) {
8508c2ecf20Sopenharmony_ci		if (!(ret = nouveau_fence_wait(fence, false, false))) {
8518c2ecf20Sopenharmony_ci			if ((ret = dma_fence_get_status(&fence->base)) == 1)
8528c2ecf20Sopenharmony_ci				ret = 0;
8538c2ecf20Sopenharmony_ci		}
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ciout:
8578c2ecf20Sopenharmony_ci	validate_fini(&op, chan, fence, bo);
8588c2ecf20Sopenharmony_ci	nouveau_fence_unref(&fence);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	if (do_reloc) {
8618c2ecf20Sopenharmony_ci		struct drm_nouveau_gem_pushbuf_bo __user *upbbo =
8628c2ecf20Sopenharmony_ci			u64_to_user_ptr(req->buffers);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		for (i = 0; i < req->nr_buffers; i++) {
8658c2ecf20Sopenharmony_ci			if (bo[i].presumed.valid)
8668c2ecf20Sopenharmony_ci				continue;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci			if (copy_to_user(&upbbo[i].presumed, &bo[i].presumed,
8698c2ecf20Sopenharmony_ci					 sizeof(bo[i].presumed))) {
8708c2ecf20Sopenharmony_ci				ret = -EFAULT;
8718c2ecf20Sopenharmony_ci				break;
8728c2ecf20Sopenharmony_ci			}
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ciout_prevalid:
8768c2ecf20Sopenharmony_ci	if (!IS_ERR(reloc))
8778c2ecf20Sopenharmony_ci		u_free(reloc);
8788c2ecf20Sopenharmony_ci	u_free(bo);
8798c2ecf20Sopenharmony_ci	u_free(push);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ciout_next:
8828c2ecf20Sopenharmony_ci	if (chan->dma.ib_max) {
8838c2ecf20Sopenharmony_ci		req->suffix0 = 0x00000000;
8848c2ecf20Sopenharmony_ci		req->suffix1 = 0x00000000;
8858c2ecf20Sopenharmony_ci	} else
8868c2ecf20Sopenharmony_ci	if (drm->client.device.info.chipset >= 0x25) {
8878c2ecf20Sopenharmony_ci		req->suffix0 = 0x00020000;
8888c2ecf20Sopenharmony_ci		req->suffix1 = 0x00000000;
8898c2ecf20Sopenharmony_ci	} else {
8908c2ecf20Sopenharmony_ci		req->suffix0 = 0x20000000 |
8918c2ecf20Sopenharmony_ci			      (chan->push.addr + ((chan->dma.cur + 2) << 2));
8928c2ecf20Sopenharmony_ci		req->suffix1 = 0x00000000;
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	return nouveau_abi16_put(abi16, ret);
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ciint
8998c2ecf20Sopenharmony_cinouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
9008c2ecf20Sopenharmony_ci			   struct drm_file *file_priv)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_cpu_prep *req = data;
9038c2ecf20Sopenharmony_ci	struct drm_gem_object *gem;
9048c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo;
9058c2ecf20Sopenharmony_ci	bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT);
9068c2ecf20Sopenharmony_ci	bool write = !!(req->flags & NOUVEAU_GEM_CPU_PREP_WRITE);
9078c2ecf20Sopenharmony_ci	long lret;
9088c2ecf20Sopenharmony_ci	int ret;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	gem = drm_gem_object_lookup(file_priv, req->handle);
9118c2ecf20Sopenharmony_ci	if (!gem)
9128c2ecf20Sopenharmony_ci		return -ENOENT;
9138c2ecf20Sopenharmony_ci	nvbo = nouveau_gem_object(gem);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	lret = dma_resv_wait_timeout_rcu(nvbo->bo.base.resv, write, true,
9168c2ecf20Sopenharmony_ci						   no_wait ? 0 : 30 * HZ);
9178c2ecf20Sopenharmony_ci	if (!lret)
9188c2ecf20Sopenharmony_ci		ret = -EBUSY;
9198c2ecf20Sopenharmony_ci	else if (lret > 0)
9208c2ecf20Sopenharmony_ci		ret = 0;
9218c2ecf20Sopenharmony_ci	else
9228c2ecf20Sopenharmony_ci		ret = lret;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	nouveau_bo_sync_for_cpu(nvbo);
9258c2ecf20Sopenharmony_ci	drm_gem_object_put(gem);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return ret;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ciint
9318c2ecf20Sopenharmony_cinouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
9328c2ecf20Sopenharmony_ci			   struct drm_file *file_priv)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_cpu_fini *req = data;
9358c2ecf20Sopenharmony_ci	struct drm_gem_object *gem;
9368c2ecf20Sopenharmony_ci	struct nouveau_bo *nvbo;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	gem = drm_gem_object_lookup(file_priv, req->handle);
9398c2ecf20Sopenharmony_ci	if (!gem)
9408c2ecf20Sopenharmony_ci		return -ENOENT;
9418c2ecf20Sopenharmony_ci	nvbo = nouveau_gem_object(gem);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	nouveau_bo_sync_for_device(nvbo);
9448c2ecf20Sopenharmony_ci	drm_gem_object_put(gem);
9458c2ecf20Sopenharmony_ci	return 0;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ciint
9498c2ecf20Sopenharmony_cinouveau_gem_ioctl_info(struct drm_device *dev, void *data,
9508c2ecf20Sopenharmony_ci		       struct drm_file *file_priv)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	struct drm_nouveau_gem_info *req = data;
9538c2ecf20Sopenharmony_ci	struct drm_gem_object *gem;
9548c2ecf20Sopenharmony_ci	int ret;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	gem = drm_gem_object_lookup(file_priv, req->handle);
9578c2ecf20Sopenharmony_ci	if (!gem)
9588c2ecf20Sopenharmony_ci		return -ENOENT;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	ret = nouveau_gem_info(file_priv, gem, req);
9618c2ecf20Sopenharmony_ci	drm_gem_object_put(gem);
9628c2ecf20Sopenharmony_ci	return ret;
9638c2ecf20Sopenharmony_ci}
9648c2ecf20Sopenharmony_ci
965