xref: /dflybsd-src/sys/dev/drm/radeon/radeon_gem.c (revision f77dbd6cf5d4851131af043d5fdc50567da4be12)
1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot  * Copyright 2008 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot  * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot  * Copyright 2009 Jerome Glisse.
5926deccbSFrançois Tigeot  *
6926deccbSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
7926deccbSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
8926deccbSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
9926deccbSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10926deccbSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
11926deccbSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
12926deccbSFrançois Tigeot  *
13926deccbSFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
14926deccbSFrançois Tigeot  * all copies or substantial portions of the Software.
15926deccbSFrançois Tigeot  *
16926deccbSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17926deccbSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18926deccbSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19926deccbSFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20926deccbSFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21926deccbSFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22926deccbSFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
23926deccbSFrançois Tigeot  *
24926deccbSFrançois Tigeot  * Authors: Dave Airlie
25926deccbSFrançois Tigeot  *          Alex Deucher
26926deccbSFrançois Tigeot  *          Jerome Glisse
27926deccbSFrançois Tigeot  *
28926deccbSFrançois Tigeot  * $FreeBSD: head/sys/dev/drm2/radeon/radeon_gem.c 254885 2013-08-25 19:37:15Z dumbbell $
29926deccbSFrançois Tigeot  */
30926deccbSFrançois Tigeot 
31926deccbSFrançois Tigeot #include <drm/drmP.h>
32926deccbSFrançois Tigeot #include <uapi_drm/radeon_drm.h>
33926deccbSFrançois Tigeot #include "radeon.h"
34926deccbSFrançois Tigeot #include "radeon_gem.h"
35926deccbSFrançois Tigeot 
36926deccbSFrançois Tigeot void radeon_gem_object_free(struct drm_gem_object *gobj)
37926deccbSFrançois Tigeot {
38926deccbSFrançois Tigeot 	struct radeon_bo *robj = gem_to_radeon_bo(gobj);
39926deccbSFrançois Tigeot 
40926deccbSFrançois Tigeot 	if (robj) {
41926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
42926deccbSFrançois Tigeot 		if (robj->gem_base.import_attach)
43926deccbSFrançois Tigeot 			drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
44926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
45926deccbSFrançois Tigeot 		radeon_bo_unref(&robj);
46926deccbSFrançois Tigeot 	}
47926deccbSFrançois Tigeot }
48926deccbSFrançois Tigeot 
49c6f73aabSFrançois Tigeot int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size,
50926deccbSFrançois Tigeot 				int alignment, int initial_domain,
51c6f73aabSFrançois Tigeot 				u32 flags, bool kernel,
52926deccbSFrançois Tigeot 				struct drm_gem_object **obj)
53926deccbSFrançois Tigeot {
54926deccbSFrançois Tigeot 	struct radeon_bo *robj;
55926deccbSFrançois Tigeot 	unsigned long max_size;
56926deccbSFrançois Tigeot 	int r;
57926deccbSFrançois Tigeot 
58926deccbSFrançois Tigeot 	*obj = NULL;
59926deccbSFrançois Tigeot 	/* At least align on page size */
60926deccbSFrançois Tigeot 	if (alignment < PAGE_SIZE) {
61926deccbSFrançois Tigeot 		alignment = PAGE_SIZE;
62926deccbSFrançois Tigeot 	}
63926deccbSFrançois Tigeot 
64c6f73aabSFrançois Tigeot 	/* Maximum bo size is the unpinned gtt size since we use the gtt to
65c6f73aabSFrançois Tigeot 	 * handle vram to system pool migrations.
66c6f73aabSFrançois Tigeot 	 */
67c6f73aabSFrançois Tigeot 	max_size = rdev->mc.gtt_size - rdev->gart_pin_size;
68926deccbSFrançois Tigeot 	if (size > max_size) {
69c6f73aabSFrançois Tigeot 		DRM_DEBUG("Allocation size %ldMb bigger than %ldMb limit\n",
70c6f73aabSFrançois Tigeot 			  size >> 20, max_size >> 20);
71926deccbSFrançois Tigeot 		return -ENOMEM;
72926deccbSFrançois Tigeot 	}
73926deccbSFrançois Tigeot 
74926deccbSFrançois Tigeot retry:
75c6f73aabSFrançois Tigeot 	r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain,
76c6f73aabSFrançois Tigeot 			     flags, NULL, &robj);
77926deccbSFrançois Tigeot 	if (r) {
78797013cfSFrançois Tigeot 		if (r != -ERESTARTSYS) {
79926deccbSFrançois Tigeot 			if (initial_domain == RADEON_GEM_DOMAIN_VRAM) {
80926deccbSFrançois Tigeot 				initial_domain |= RADEON_GEM_DOMAIN_GTT;
81926deccbSFrançois Tigeot 				goto retry;
82926deccbSFrançois Tigeot 			}
83c6f73aabSFrançois Tigeot 			DRM_ERROR("Failed to allocate GEM object (%ld, %d, %u, %d)\n",
84926deccbSFrançois Tigeot 				  size, initial_domain, alignment, r);
85926deccbSFrançois Tigeot 		}
86926deccbSFrançois Tigeot 		return r;
87926deccbSFrançois Tigeot 	}
88926deccbSFrançois Tigeot 	*obj = &robj->gem_base;
89f43cf1b1SMichael Neumann 	robj->pid = curproc ? curproc->p_pid : 0;
90926deccbSFrançois Tigeot 
91fefad7a7SFrançois Tigeot 	mutex_lock(&rdev->gem.mutex);
92926deccbSFrançois Tigeot 	list_add_tail(&robj->list, &rdev->gem.objects);
93fefad7a7SFrançois Tigeot 	mutex_unlock(&rdev->gem.mutex);
94926deccbSFrançois Tigeot 
95926deccbSFrançois Tigeot 	return 0;
96926deccbSFrançois Tigeot }
97926deccbSFrançois Tigeot 
98926deccbSFrançois Tigeot static int radeon_gem_set_domain(struct drm_gem_object *gobj,
99926deccbSFrançois Tigeot 			  uint32_t rdomain, uint32_t wdomain)
100926deccbSFrançois Tigeot {
101926deccbSFrançois Tigeot 	struct radeon_bo *robj;
102926deccbSFrançois Tigeot 	uint32_t domain;
103926deccbSFrançois Tigeot 	int r;
104926deccbSFrançois Tigeot 
105926deccbSFrançois Tigeot 	/* FIXME: reeimplement */
106926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
107926deccbSFrançois Tigeot 	/* work out where to validate the buffer to */
108926deccbSFrançois Tigeot 	domain = wdomain;
109926deccbSFrançois Tigeot 	if (!domain) {
110926deccbSFrançois Tigeot 		domain = rdomain;
111926deccbSFrançois Tigeot 	}
112926deccbSFrançois Tigeot 	if (!domain) {
113926deccbSFrançois Tigeot 		/* Do nothings */
114c4ef309bSzrj 		printk(KERN_WARNING "Set domain without domain !\n");
115926deccbSFrançois Tigeot 		return 0;
116926deccbSFrançois Tigeot 	}
117926deccbSFrançois Tigeot 	if (domain == RADEON_GEM_DOMAIN_CPU) {
118926deccbSFrançois Tigeot 		/* Asking for cpu access wait for object idle */
119926deccbSFrançois Tigeot 		r = radeon_bo_wait(robj, NULL, false);
120926deccbSFrançois Tigeot 		if (r) {
121c4ef309bSzrj 			printk(KERN_ERR "Failed to wait for object !\n");
122926deccbSFrançois Tigeot 			return r;
123926deccbSFrançois Tigeot 		}
124926deccbSFrançois Tigeot 	}
125926deccbSFrançois Tigeot 	return 0;
126926deccbSFrançois Tigeot }
127926deccbSFrançois Tigeot 
128926deccbSFrançois Tigeot int radeon_gem_init(struct radeon_device *rdev)
129926deccbSFrançois Tigeot {
130926deccbSFrançois Tigeot 	INIT_LIST_HEAD(&rdev->gem.objects);
131926deccbSFrançois Tigeot 	return 0;
132926deccbSFrançois Tigeot }
133926deccbSFrançois Tigeot 
134926deccbSFrançois Tigeot void radeon_gem_fini(struct radeon_device *rdev)
135926deccbSFrançois Tigeot {
136926deccbSFrançois Tigeot 	radeon_bo_force_delete(rdev);
137926deccbSFrançois Tigeot }
138926deccbSFrançois Tigeot 
139926deccbSFrançois Tigeot /*
140926deccbSFrançois Tigeot  * Call from drm_gem_handle_create which appear in both new and open ioctl
141926deccbSFrançois Tigeot  * case.
142926deccbSFrançois Tigeot  */
143926deccbSFrançois Tigeot int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv)
144926deccbSFrançois Tigeot {
145926deccbSFrançois Tigeot 	struct radeon_bo *rbo = gem_to_radeon_bo(obj);
146926deccbSFrançois Tigeot 	struct radeon_device *rdev = rbo->rdev;
147926deccbSFrançois Tigeot 	struct radeon_fpriv *fpriv = file_priv->driver_priv;
148926deccbSFrançois Tigeot 	struct radeon_vm *vm = &fpriv->vm;
149926deccbSFrançois Tigeot 	struct radeon_bo_va *bo_va;
150926deccbSFrançois Tigeot 	int r;
151926deccbSFrançois Tigeot 
152926deccbSFrançois Tigeot 	if (rdev->family < CHIP_CAYMAN) {
153926deccbSFrançois Tigeot 		return 0;
154926deccbSFrançois Tigeot 	}
155926deccbSFrançois Tigeot 
156926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, false);
157926deccbSFrançois Tigeot 	if (r) {
158926deccbSFrançois Tigeot 		return r;
159926deccbSFrançois Tigeot 	}
160926deccbSFrançois Tigeot 
161926deccbSFrançois Tigeot 	bo_va = radeon_vm_bo_find(vm, rbo);
162926deccbSFrançois Tigeot 	if (!bo_va) {
163926deccbSFrançois Tigeot 		bo_va = radeon_vm_bo_add(rdev, vm, rbo);
164926deccbSFrançois Tigeot 	} else {
165926deccbSFrançois Tigeot 		++bo_va->ref_count;
166926deccbSFrançois Tigeot 	}
167926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
168926deccbSFrançois Tigeot 
169926deccbSFrançois Tigeot 	return 0;
170926deccbSFrançois Tigeot }
171926deccbSFrançois Tigeot 
172926deccbSFrançois Tigeot void radeon_gem_object_close(struct drm_gem_object *obj,
173926deccbSFrançois Tigeot 			     struct drm_file *file_priv)
174926deccbSFrançois Tigeot {
175926deccbSFrançois Tigeot 	struct radeon_bo *rbo = gem_to_radeon_bo(obj);
176926deccbSFrançois Tigeot 	struct radeon_device *rdev = rbo->rdev;
177926deccbSFrançois Tigeot 	struct radeon_fpriv *fpriv = file_priv->driver_priv;
178926deccbSFrançois Tigeot 	struct radeon_vm *vm = &fpriv->vm;
179926deccbSFrançois Tigeot 	struct radeon_bo_va *bo_va;
180926deccbSFrançois Tigeot 	int r;
181926deccbSFrançois Tigeot 
182926deccbSFrançois Tigeot 	if (rdev->family < CHIP_CAYMAN) {
183926deccbSFrançois Tigeot 		return;
184926deccbSFrançois Tigeot 	}
185926deccbSFrançois Tigeot 
186926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, true);
187926deccbSFrançois Tigeot 	if (r) {
188926deccbSFrançois Tigeot 		dev_err(rdev->dev, "leaking bo va because "
189926deccbSFrançois Tigeot 			"we fail to reserve bo (%d)\n", r);
190926deccbSFrançois Tigeot 		return;
191926deccbSFrançois Tigeot 	}
192926deccbSFrançois Tigeot 	bo_va = radeon_vm_bo_find(vm, rbo);
193926deccbSFrançois Tigeot 	if (bo_va) {
194926deccbSFrançois Tigeot 		if (--bo_va->ref_count == 0) {
195926deccbSFrançois Tigeot 			radeon_vm_bo_rmv(rdev, bo_va);
196926deccbSFrançois Tigeot 		}
197926deccbSFrançois Tigeot 	}
198926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
199926deccbSFrançois Tigeot }
200926deccbSFrançois Tigeot 
201926deccbSFrançois Tigeot static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r)
202926deccbSFrançois Tigeot {
203926deccbSFrançois Tigeot 	if (r == -EDEADLK) {
204926deccbSFrançois Tigeot 		r = radeon_gpu_reset(rdev);
205926deccbSFrançois Tigeot 		if (!r)
206926deccbSFrançois Tigeot 			r = -EAGAIN;
207926deccbSFrançois Tigeot 	}
208926deccbSFrançois Tigeot 	return r;
209926deccbSFrançois Tigeot }
210926deccbSFrançois Tigeot 
211926deccbSFrançois Tigeot /*
212926deccbSFrançois Tigeot  * GEM ioctls.
213926deccbSFrançois Tigeot  */
214926deccbSFrançois Tigeot int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
215926deccbSFrançois Tigeot 			  struct drm_file *filp)
216926deccbSFrançois Tigeot {
217926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
218926deccbSFrançois Tigeot 	struct drm_radeon_gem_info *args = data;
219926deccbSFrançois Tigeot 	struct ttm_mem_type_manager *man;
220926deccbSFrançois Tigeot 
221926deccbSFrançois Tigeot 	man = &rdev->mman.bdev.man[TTM_PL_VRAM];
222926deccbSFrançois Tigeot 
223926deccbSFrançois Tigeot 	args->vram_size = rdev->mc.real_vram_size;
224926deccbSFrançois Tigeot 	args->vram_visible = (u64)man->size << PAGE_SHIFT;
225c6f73aabSFrançois Tigeot 	args->vram_visible -= rdev->vram_pin_size;
226c6f73aabSFrançois Tigeot 	args->gart_size = rdev->mc.gtt_size;
227c6f73aabSFrançois Tigeot 	args->gart_size -= rdev->gart_pin_size;
228c6f73aabSFrançois Tigeot 
229926deccbSFrançois Tigeot 	return 0;
230926deccbSFrançois Tigeot }
231926deccbSFrançois Tigeot 
232926deccbSFrançois Tigeot int radeon_gem_pread_ioctl(struct drm_device *dev, void *data,
233926deccbSFrançois Tigeot 			   struct drm_file *filp)
234926deccbSFrançois Tigeot {
235926deccbSFrançois Tigeot 	/* TODO: implement */
236926deccbSFrançois Tigeot 	DRM_ERROR("unimplemented %s\n", __func__);
237926deccbSFrançois Tigeot 	return -ENOSYS;
238926deccbSFrançois Tigeot }
239926deccbSFrançois Tigeot 
240926deccbSFrançois Tigeot int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data,
241926deccbSFrançois Tigeot 			    struct drm_file *filp)
242926deccbSFrançois Tigeot {
243926deccbSFrançois Tigeot 	/* TODO: implement */
244926deccbSFrançois Tigeot 	DRM_ERROR("unimplemented %s\n", __func__);
245926deccbSFrançois Tigeot 	return -ENOSYS;
246926deccbSFrançois Tigeot }
247926deccbSFrançois Tigeot 
248926deccbSFrançois Tigeot int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
249926deccbSFrançois Tigeot 			    struct drm_file *filp)
250926deccbSFrançois Tigeot {
251926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
252926deccbSFrançois Tigeot 	struct drm_radeon_gem_create *args = data;
253926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
254926deccbSFrançois Tigeot 	uint32_t handle;
255926deccbSFrançois Tigeot 	int r;
256926deccbSFrançois Tigeot 
257926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_SHARED);
258926deccbSFrançois Tigeot 	/* create a gem object to contain this object in */
259926deccbSFrançois Tigeot 	args->size = roundup(args->size, PAGE_SIZE);
260926deccbSFrançois Tigeot 	r = radeon_gem_object_create(rdev, args->size, args->alignment,
261c6f73aabSFrançois Tigeot 				     args->initial_domain, args->flags,
262926deccbSFrançois Tigeot 				     false, &gobj);
263926deccbSFrançois Tigeot 	if (r) {
26463c3939fSImre Vadasz 		if (r == -ERESTARTSYS)
26563c3939fSImre Vadasz 			r = -EINTR;
266926deccbSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
267926deccbSFrançois Tigeot 		r = radeon_gem_handle_lockup(rdev, r);
268926deccbSFrançois Tigeot 		return r;
269926deccbSFrançois Tigeot 	}
270926deccbSFrançois Tigeot 	handle = 0;
271926deccbSFrançois Tigeot 	r = drm_gem_handle_create(filp, gobj, &handle);
272926deccbSFrançois Tigeot 	/* drop reference from allocate - handle holds it now */
273926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
274926deccbSFrançois Tigeot 	if (r) {
275926deccbSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
276926deccbSFrançois Tigeot 		r = radeon_gem_handle_lockup(rdev, r);
277926deccbSFrançois Tigeot 		return r;
278926deccbSFrançois Tigeot 	}
279926deccbSFrançois Tigeot 	args->handle = handle;
280926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_RELEASE);
281926deccbSFrançois Tigeot 	return 0;
282926deccbSFrançois Tigeot }
283926deccbSFrançois Tigeot 
284926deccbSFrançois Tigeot int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
285926deccbSFrançois Tigeot 				struct drm_file *filp)
286926deccbSFrançois Tigeot {
287926deccbSFrançois Tigeot 	/* transition the BO to a domain -
288926deccbSFrançois Tigeot 	 * just validate the BO into a certain domain */
289926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
290926deccbSFrançois Tigeot 	struct drm_radeon_gem_set_domain *args = data;
291926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
292926deccbSFrançois Tigeot 	struct radeon_bo *robj;
293926deccbSFrançois Tigeot 	int r;
294926deccbSFrançois Tigeot 
295926deccbSFrançois Tigeot 	/* for now if someone requests domain CPU -
296926deccbSFrançois Tigeot 	 * just make sure the buffer is finished with */
297926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_SHARED);
298926deccbSFrançois Tigeot 
299926deccbSFrançois Tigeot 	/* just do a BO wait for now */
300926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
301926deccbSFrançois Tigeot 	if (gobj == NULL) {
302926deccbSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
303926deccbSFrançois Tigeot 		return -ENOENT;
304926deccbSFrançois Tigeot 	}
305926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
306926deccbSFrançois Tigeot 
307926deccbSFrançois Tigeot 	r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
308926deccbSFrançois Tigeot 
309926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
310926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_RELEASE);
311926deccbSFrançois Tigeot 	r = radeon_gem_handle_lockup(robj->rdev, r);
312926deccbSFrançois Tigeot 	return r;
313926deccbSFrançois Tigeot }
314926deccbSFrançois Tigeot 
315926deccbSFrançois Tigeot int radeon_mode_dumb_mmap(struct drm_file *filp,
316926deccbSFrançois Tigeot 			  struct drm_device *dev,
317926deccbSFrançois Tigeot 			  uint32_t handle, uint64_t *offset_p)
318926deccbSFrançois Tigeot {
319926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
320926deccbSFrançois Tigeot 	struct radeon_bo *robj;
321926deccbSFrançois Tigeot 
322926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, handle);
323926deccbSFrançois Tigeot 	if (gobj == NULL) {
324926deccbSFrançois Tigeot 		return -ENOENT;
325926deccbSFrançois Tigeot 	}
326926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
327926deccbSFrançois Tigeot 	*offset_p = radeon_bo_mmap_offset(robj);
328926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
329926deccbSFrançois Tigeot 	return 0;
330926deccbSFrançois Tigeot }
331926deccbSFrançois Tigeot 
332926deccbSFrançois Tigeot int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
333926deccbSFrançois Tigeot 			  struct drm_file *filp)
334926deccbSFrançois Tigeot {
335926deccbSFrançois Tigeot 	struct drm_radeon_gem_mmap *args = data;
336926deccbSFrançois Tigeot 
337*f77dbd6cSFrançois Tigeot 	return radeon_mode_dumb_mmap(filp, dev, args->handle, (uint64_t *)&args->addr_ptr);
338926deccbSFrançois Tigeot }
339926deccbSFrançois Tigeot 
340926deccbSFrançois Tigeot int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
341926deccbSFrançois Tigeot 			  struct drm_file *filp)
342926deccbSFrançois Tigeot {
343926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
344926deccbSFrançois Tigeot 	struct drm_radeon_gem_busy *args = data;
345926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
346926deccbSFrançois Tigeot 	struct radeon_bo *robj;
347926deccbSFrançois Tigeot 	int r;
348926deccbSFrançois Tigeot 	uint32_t cur_placement = 0;
349926deccbSFrançois Tigeot 
350926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
351926deccbSFrançois Tigeot 	if (gobj == NULL) {
352926deccbSFrançois Tigeot 		return -ENOENT;
353926deccbSFrançois Tigeot 	}
354926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
355926deccbSFrançois Tigeot 	r = radeon_bo_wait(robj, &cur_placement, true);
356c6f73aabSFrançois Tigeot 	args->domain = radeon_mem_type_to_domain(cur_placement);
357926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
358926deccbSFrançois Tigeot 	r = radeon_gem_handle_lockup(rdev, r);
359926deccbSFrançois Tigeot 	return r;
360926deccbSFrançois Tigeot }
361926deccbSFrançois Tigeot 
362926deccbSFrançois Tigeot int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
363926deccbSFrançois Tigeot 			      struct drm_file *filp)
364926deccbSFrançois Tigeot {
365926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
366926deccbSFrançois Tigeot 	struct drm_radeon_gem_wait_idle *args = data;
367926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
368926deccbSFrançois Tigeot 	struct radeon_bo *robj;
369926deccbSFrançois Tigeot 	int r;
370c6f73aabSFrançois Tigeot 	uint32_t cur_placement = 0;
371926deccbSFrançois Tigeot 
372926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
373926deccbSFrançois Tigeot 	if (gobj == NULL) {
374926deccbSFrançois Tigeot 		return -ENOENT;
375926deccbSFrançois Tigeot 	}
376926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
377c6f73aabSFrançois Tigeot 	r = radeon_bo_wait(robj, &cur_placement, false);
378c6f73aabSFrançois Tigeot 	/* Flush HDP cache via MMIO if necessary */
379c6f73aabSFrançois Tigeot 	if (rdev->asic->mmio_hdp_flush &&
380c6f73aabSFrançois Tigeot 	    radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM)
381c6f73aabSFrançois Tigeot 		robj->rdev->asic->mmio_hdp_flush(rdev);
382926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
38363c3939fSImre Vadasz 	if (r == -ERESTARTSYS)
38463c3939fSImre Vadasz 		r = -EINTR;
385926deccbSFrançois Tigeot 	r = radeon_gem_handle_lockup(rdev, r);
386926deccbSFrançois Tigeot 	return r;
387926deccbSFrançois Tigeot }
388926deccbSFrançois Tigeot 
389926deccbSFrançois Tigeot int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
390926deccbSFrançois Tigeot 				struct drm_file *filp)
391926deccbSFrançois Tigeot {
392926deccbSFrançois Tigeot 	struct drm_radeon_gem_set_tiling *args = data;
393926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
394926deccbSFrançois Tigeot 	struct radeon_bo *robj;
395926deccbSFrançois Tigeot 	int r = 0;
396926deccbSFrançois Tigeot 
397926deccbSFrançois Tigeot 	DRM_DEBUG("%d \n", args->handle);
398926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
399926deccbSFrançois Tigeot 	if (gobj == NULL)
400926deccbSFrançois Tigeot 		return -ENOENT;
401926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
402926deccbSFrançois Tigeot 	r = radeon_bo_set_tiling_flags(robj, args->tiling_flags, args->pitch);
403926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
404926deccbSFrançois Tigeot 	return r;
405926deccbSFrançois Tigeot }
406926deccbSFrançois Tigeot 
407926deccbSFrançois Tigeot int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
408926deccbSFrançois Tigeot 				struct drm_file *filp)
409926deccbSFrançois Tigeot {
410926deccbSFrançois Tigeot 	struct drm_radeon_gem_get_tiling *args = data;
411926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
412926deccbSFrançois Tigeot 	struct radeon_bo *rbo;
413926deccbSFrançois Tigeot 	int r = 0;
414926deccbSFrançois Tigeot 
415926deccbSFrançois Tigeot 	DRM_DEBUG("\n");
416926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
417926deccbSFrançois Tigeot 	if (gobj == NULL)
418926deccbSFrançois Tigeot 		return -ENOENT;
419926deccbSFrançois Tigeot 	rbo = gem_to_radeon_bo(gobj);
420926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, false);
421926deccbSFrançois Tigeot 	if (unlikely(r != 0))
422926deccbSFrançois Tigeot 		goto out;
423926deccbSFrançois Tigeot 	radeon_bo_get_tiling_flags(rbo, &args->tiling_flags, &args->pitch);
424926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
425926deccbSFrançois Tigeot out:
426926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
427926deccbSFrançois Tigeot 	return r;
428926deccbSFrançois Tigeot }
429926deccbSFrançois Tigeot 
430926deccbSFrançois Tigeot int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
431926deccbSFrançois Tigeot 			  struct drm_file *filp)
432926deccbSFrançois Tigeot {
433926deccbSFrançois Tigeot 	struct drm_radeon_gem_va *args = data;
434926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
435926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
436926deccbSFrançois Tigeot 	struct radeon_fpriv *fpriv = filp->driver_priv;
437926deccbSFrançois Tigeot 	struct radeon_bo *rbo;
438926deccbSFrançois Tigeot 	struct radeon_bo_va *bo_va;
439926deccbSFrançois Tigeot 	u32 invalid_flags;
440926deccbSFrançois Tigeot 	int r = 0;
441926deccbSFrançois Tigeot 
442926deccbSFrançois Tigeot 	if (!rdev->vm_manager.enabled) {
443926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
444926deccbSFrançois Tigeot 		return -ENOTTY;
445926deccbSFrançois Tigeot 	}
446926deccbSFrançois Tigeot 
447926deccbSFrançois Tigeot 	/* !! DONT REMOVE !!
448926deccbSFrançois Tigeot 	 * We don't support vm_id yet, to be sure we don't have have broken
449926deccbSFrançois Tigeot 	 * userspace, reject anyone trying to use non 0 value thus moving
450926deccbSFrançois Tigeot 	 * forward we can use those fields without breaking existant userspace
451926deccbSFrançois Tigeot 	 */
452926deccbSFrançois Tigeot 	if (args->vm_id) {
453926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
454926deccbSFrançois Tigeot 		return -EINVAL;
455926deccbSFrançois Tigeot 	}
456926deccbSFrançois Tigeot 
457926deccbSFrançois Tigeot 	if (args->offset < RADEON_VA_RESERVED_SIZE) {
458fb572d17SFrançois Tigeot 		dev_err(&dev->pdev->dev,
459926deccbSFrançois Tigeot 			"offset 0x%lX is in reserved area 0x%X\n",
460926deccbSFrançois Tigeot 			(unsigned long)args->offset,
461926deccbSFrançois Tigeot 			RADEON_VA_RESERVED_SIZE);
462926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
463926deccbSFrançois Tigeot 		return -EINVAL;
464926deccbSFrançois Tigeot 	}
465926deccbSFrançois Tigeot 
466926deccbSFrançois Tigeot 	/* don't remove, we need to enforce userspace to set the snooped flag
467926deccbSFrançois Tigeot 	 * otherwise we will endup with broken userspace and we won't be able
468926deccbSFrançois Tigeot 	 * to enable this feature without adding new interface
469926deccbSFrançois Tigeot 	 */
470926deccbSFrançois Tigeot 	invalid_flags = RADEON_VM_PAGE_VALID | RADEON_VM_PAGE_SYSTEM;
471926deccbSFrançois Tigeot 	if ((args->flags & invalid_flags)) {
472fb572d17SFrançois Tigeot 		dev_err(&dev->pdev->dev, "invalid flags 0x%08X vs 0x%08X\n",
473926deccbSFrançois Tigeot 			args->flags, invalid_flags);
474926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
475926deccbSFrançois Tigeot 		return -EINVAL;
476926deccbSFrançois Tigeot 	}
477926deccbSFrançois Tigeot 
478926deccbSFrançois Tigeot 	switch (args->operation) {
479926deccbSFrançois Tigeot 	case RADEON_VA_MAP:
480926deccbSFrançois Tigeot 	case RADEON_VA_UNMAP:
481926deccbSFrançois Tigeot 		break;
482926deccbSFrançois Tigeot 	default:
483fb572d17SFrançois Tigeot 		dev_err(&dev->pdev->dev, "unsupported operation %d\n",
484926deccbSFrançois Tigeot 			args->operation);
485926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
486926deccbSFrançois Tigeot 		return -EINVAL;
487926deccbSFrançois Tigeot 	}
488926deccbSFrançois Tigeot 
489926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
490926deccbSFrançois Tigeot 	if (gobj == NULL) {
491926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
492926deccbSFrançois Tigeot 		return -ENOENT;
493926deccbSFrançois Tigeot 	}
494926deccbSFrançois Tigeot 	rbo = gem_to_radeon_bo(gobj);
495926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, false);
496926deccbSFrançois Tigeot 	if (r) {
497926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
498926deccbSFrançois Tigeot 		drm_gem_object_unreference_unlocked(gobj);
499926deccbSFrançois Tigeot 		return r;
500926deccbSFrançois Tigeot 	}
501926deccbSFrançois Tigeot 	bo_va = radeon_vm_bo_find(&fpriv->vm, rbo);
502926deccbSFrançois Tigeot 	if (!bo_va) {
503926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
504926deccbSFrançois Tigeot 		drm_gem_object_unreference_unlocked(gobj);
505926deccbSFrançois Tigeot 		return -ENOENT;
506926deccbSFrançois Tigeot 	}
507926deccbSFrançois Tigeot 
508926deccbSFrançois Tigeot 	switch (args->operation) {
509926deccbSFrançois Tigeot 	case RADEON_VA_MAP:
510926deccbSFrançois Tigeot 		if (bo_va->soffset) {
511926deccbSFrançois Tigeot 			args->operation = RADEON_VA_RESULT_VA_EXIST;
512926deccbSFrançois Tigeot 			args->offset = bo_va->soffset;
513926deccbSFrançois Tigeot 			goto out;
514926deccbSFrançois Tigeot 		}
515926deccbSFrançois Tigeot 		r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags);
516926deccbSFrançois Tigeot 		break;
517926deccbSFrançois Tigeot 	case RADEON_VA_UNMAP:
518926deccbSFrançois Tigeot 		r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0);
519926deccbSFrançois Tigeot 		break;
520926deccbSFrançois Tigeot 	default:
521926deccbSFrançois Tigeot 		break;
522926deccbSFrançois Tigeot 	}
523926deccbSFrançois Tigeot 	args->operation = RADEON_VA_RESULT_OK;
524926deccbSFrançois Tigeot 	if (r) {
525926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
526926deccbSFrançois Tigeot 	}
527926deccbSFrançois Tigeot out:
528926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
529926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
530926deccbSFrançois Tigeot 	return r;
531926deccbSFrançois Tigeot }
532926deccbSFrançois Tigeot 
533c6f73aabSFrançois Tigeot int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
534c6f73aabSFrançois Tigeot 			struct drm_file *filp)
535c6f73aabSFrançois Tigeot {
536c6f73aabSFrançois Tigeot 	struct drm_radeon_gem_op *args = data;
537c6f73aabSFrançois Tigeot 	struct drm_gem_object *gobj;
538c6f73aabSFrançois Tigeot 	struct radeon_bo *robj;
539c6f73aabSFrançois Tigeot 	int r;
540c6f73aabSFrançois Tigeot 
541c6f73aabSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
542c6f73aabSFrançois Tigeot 	if (gobj == NULL) {
543c6f73aabSFrançois Tigeot 		return -ENOENT;
544c6f73aabSFrançois Tigeot 	}
545c6f73aabSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
546c6f73aabSFrançois Tigeot 	r = radeon_bo_reserve(robj, false);
547c6f73aabSFrançois Tigeot 	if (unlikely(r))
548c6f73aabSFrançois Tigeot 		goto out;
549c6f73aabSFrançois Tigeot 
550c6f73aabSFrançois Tigeot 	switch (args->op) {
551c6f73aabSFrançois Tigeot 	case RADEON_GEM_OP_GET_INITIAL_DOMAIN:
552c6f73aabSFrançois Tigeot 		args->value = robj->initial_domain;
553c6f73aabSFrançois Tigeot 		break;
554c6f73aabSFrançois Tigeot 	case RADEON_GEM_OP_SET_INITIAL_DOMAIN:
555c6f73aabSFrançois Tigeot 		robj->initial_domain = args->value & (RADEON_GEM_DOMAIN_VRAM |
556c6f73aabSFrançois Tigeot 						      RADEON_GEM_DOMAIN_GTT |
557c6f73aabSFrançois Tigeot 						      RADEON_GEM_DOMAIN_CPU);
558c6f73aabSFrançois Tigeot 		break;
559c6f73aabSFrançois Tigeot 	default:
560c6f73aabSFrançois Tigeot 		r = -EINVAL;
561c6f73aabSFrançois Tigeot 	}
562c6f73aabSFrançois Tigeot 
563c6f73aabSFrançois Tigeot 	radeon_bo_unreserve(robj);
564c6f73aabSFrançois Tigeot out:
565c6f73aabSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
566c6f73aabSFrançois Tigeot 	return r;
567c6f73aabSFrançois Tigeot }
568c6f73aabSFrançois Tigeot 
569926deccbSFrançois Tigeot int radeon_mode_dumb_create(struct drm_file *file_priv,
570926deccbSFrançois Tigeot 			    struct drm_device *dev,
571926deccbSFrançois Tigeot 			    struct drm_mode_create_dumb *args)
572926deccbSFrançois Tigeot {
573926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
574926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
575926deccbSFrançois Tigeot 	uint32_t handle;
576926deccbSFrançois Tigeot 	int r;
577926deccbSFrançois Tigeot 
578926deccbSFrançois Tigeot 	args->pitch = radeon_align_pitch(rdev, args->width, args->bpp, 0) * ((args->bpp + 1) / 8);
579926deccbSFrançois Tigeot 	args->size = args->pitch * args->height;
580c4ef309bSzrj 	args->size = ALIGN(args->size, PAGE_SIZE);
581926deccbSFrançois Tigeot 
582926deccbSFrançois Tigeot 	r = radeon_gem_object_create(rdev, args->size, 0,
583c6f73aabSFrançois Tigeot 				     RADEON_GEM_DOMAIN_VRAM, 0,
584c6f73aabSFrançois Tigeot 				     false, &gobj);
585926deccbSFrançois Tigeot 	if (r)
586926deccbSFrançois Tigeot 		return -ENOMEM;
587926deccbSFrançois Tigeot 
588926deccbSFrançois Tigeot 	r = drm_gem_handle_create(file_priv, gobj, &handle);
589926deccbSFrançois Tigeot 	/* drop reference from allocate - handle holds it now */
590926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
591926deccbSFrançois Tigeot 	if (r) {
592926deccbSFrançois Tigeot 		return r;
593926deccbSFrançois Tigeot 	}
594926deccbSFrançois Tigeot 	args->handle = handle;
595926deccbSFrançois Tigeot 	return 0;
596926deccbSFrançois Tigeot }
597926deccbSFrançois Tigeot 
598f43cf1b1SMichael Neumann #if defined(CONFIG_DEBUG_FS)
599f43cf1b1SMichael Neumann static int radeon_debugfs_gem_info(struct seq_file *m, void *data)
600f43cf1b1SMichael Neumann {
601f43cf1b1SMichael Neumann 	struct drm_info_node *node = (struct drm_info_node *)m->private;
602f43cf1b1SMichael Neumann 	struct drm_device *dev = node->minor->dev;
603f43cf1b1SMichael Neumann 	struct radeon_device *rdev = dev->dev_private;
604f43cf1b1SMichael Neumann 	struct radeon_bo *rbo;
605f43cf1b1SMichael Neumann 	unsigned i = 0;
606f43cf1b1SMichael Neumann 
607f43cf1b1SMichael Neumann 	mutex_lock(&rdev->gem.mutex);
608f43cf1b1SMichael Neumann 	list_for_each_entry(rbo, &rdev->gem.objects, list) {
609f43cf1b1SMichael Neumann 		unsigned domain;
610f43cf1b1SMichael Neumann 		const char *placement;
611f43cf1b1SMichael Neumann 
612f43cf1b1SMichael Neumann 		domain = radeon_mem_type_to_domain(rbo->tbo.mem.mem_type);
613f43cf1b1SMichael Neumann 		switch (domain) {
614f43cf1b1SMichael Neumann 		case RADEON_GEM_DOMAIN_VRAM:
615f43cf1b1SMichael Neumann 			placement = "VRAM";
616f43cf1b1SMichael Neumann 			break;
617f43cf1b1SMichael Neumann 		case RADEON_GEM_DOMAIN_GTT:
618f43cf1b1SMichael Neumann 			placement = " GTT";
619f43cf1b1SMichael Neumann 			break;
620f43cf1b1SMichael Neumann 		case RADEON_GEM_DOMAIN_CPU:
621f43cf1b1SMichael Neumann 		default:
622f43cf1b1SMichael Neumann 			placement = " CPU";
623f43cf1b1SMichael Neumann 			break;
624f43cf1b1SMichael Neumann 		}
625f43cf1b1SMichael Neumann 		seq_printf(m, "bo[0x%08x] %8ldkB %8ldMB %s pid %8ld\n",
626f43cf1b1SMichael Neumann 			   i, radeon_bo_size(rbo) >> 10, radeon_bo_size(rbo) >> 20,
627f43cf1b1SMichael Neumann 			   placement, (unsigned long)rbo->pid);
628f43cf1b1SMichael Neumann 		i++;
629f43cf1b1SMichael Neumann 	}
630f43cf1b1SMichael Neumann 	mutex_unlock(&rdev->gem.mutex);
631f43cf1b1SMichael Neumann 	return 0;
632f43cf1b1SMichael Neumann }
633f43cf1b1SMichael Neumann 
634f43cf1b1SMichael Neumann static struct drm_info_list radeon_debugfs_gem_list[] = {
635f43cf1b1SMichael Neumann 	{"radeon_gem_info", &radeon_debugfs_gem_info, 0, NULL},
636f43cf1b1SMichael Neumann };
637f43cf1b1SMichael Neumann #endif
638f43cf1b1SMichael Neumann 
639f43cf1b1SMichael Neumann int radeon_gem_debugfs_init(struct radeon_device *rdev)
640f43cf1b1SMichael Neumann {
641f43cf1b1SMichael Neumann #if defined(CONFIG_DEBUG_FS)
642f43cf1b1SMichael Neumann 	return radeon_debugfs_add_files(rdev, radeon_debugfs_gem_list, 1);
643f43cf1b1SMichael Neumann #endif
644f43cf1b1SMichael Neumann 	return 0;
645f43cf1b1SMichael Neumann }
646