xref: /dflybsd-src/sys/dev/drm/radeon/radeon_gem.c (revision 926deccb469948128692b7f35b6846e4999c62b5)
1*926deccbSFrançois Tigeot /*
2*926deccbSFrançois Tigeot  * Copyright 2008 Advanced Micro Devices, Inc.
3*926deccbSFrançois Tigeot  * Copyright 2008 Red Hat Inc.
4*926deccbSFrançois Tigeot  * Copyright 2009 Jerome Glisse.
5*926deccbSFrançois Tigeot  *
6*926deccbSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
7*926deccbSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
8*926deccbSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
9*926deccbSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*926deccbSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
11*926deccbSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
12*926deccbSFrançois Tigeot  *
13*926deccbSFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
14*926deccbSFrançois Tigeot  * all copies or substantial portions of the Software.
15*926deccbSFrançois Tigeot  *
16*926deccbSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*926deccbSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*926deccbSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*926deccbSFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20*926deccbSFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21*926deccbSFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22*926deccbSFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
23*926deccbSFrançois Tigeot  *
24*926deccbSFrançois Tigeot  * Authors: Dave Airlie
25*926deccbSFrançois Tigeot  *          Alex Deucher
26*926deccbSFrançois Tigeot  *          Jerome Glisse
27*926deccbSFrançois Tigeot  *
28*926deccbSFrançois Tigeot  * $FreeBSD: head/sys/dev/drm2/radeon/radeon_gem.c 254885 2013-08-25 19:37:15Z dumbbell $
29*926deccbSFrançois Tigeot  */
30*926deccbSFrançois Tigeot 
31*926deccbSFrançois Tigeot #include <drm/drmP.h>
32*926deccbSFrançois Tigeot #include <uapi_drm/radeon_drm.h>
33*926deccbSFrançois Tigeot #include "radeon.h"
34*926deccbSFrançois Tigeot #include "radeon_gem.h"
35*926deccbSFrançois Tigeot 
36*926deccbSFrançois Tigeot int radeon_gem_object_init(struct drm_gem_object *obj)
37*926deccbSFrançois Tigeot {
38*926deccbSFrançois Tigeot 	panic("radeon_gem_object_init() must not be called");
39*926deccbSFrançois Tigeot 
40*926deccbSFrançois Tigeot 	return 0;
41*926deccbSFrançois Tigeot }
42*926deccbSFrançois Tigeot 
43*926deccbSFrançois Tigeot void radeon_gem_object_free(struct drm_gem_object *gobj)
44*926deccbSFrançois Tigeot {
45*926deccbSFrançois Tigeot 	struct radeon_bo *robj = gem_to_radeon_bo(gobj);
46*926deccbSFrançois Tigeot 
47*926deccbSFrançois Tigeot 	if (robj) {
48*926deccbSFrançois Tigeot #ifdef DUMBBELL_WIP
49*926deccbSFrançois Tigeot 		if (robj->gem_base.import_attach)
50*926deccbSFrançois Tigeot 			drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
51*926deccbSFrançois Tigeot #endif /* DUMBBELL_WIP */
52*926deccbSFrançois Tigeot 		radeon_bo_unref(&robj);
53*926deccbSFrançois Tigeot 	}
54*926deccbSFrançois Tigeot }
55*926deccbSFrançois Tigeot 
56*926deccbSFrançois Tigeot int radeon_gem_object_create(struct radeon_device *rdev, int size,
57*926deccbSFrançois Tigeot 				int alignment, int initial_domain,
58*926deccbSFrançois Tigeot 				bool discardable, bool kernel,
59*926deccbSFrançois Tigeot 				struct drm_gem_object **obj)
60*926deccbSFrançois Tigeot {
61*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
62*926deccbSFrançois Tigeot 	unsigned long max_size;
63*926deccbSFrançois Tigeot 	int r;
64*926deccbSFrançois Tigeot 
65*926deccbSFrançois Tigeot 	*obj = NULL;
66*926deccbSFrançois Tigeot 	/* At least align on page size */
67*926deccbSFrançois Tigeot 	if (alignment < PAGE_SIZE) {
68*926deccbSFrançois Tigeot 		alignment = PAGE_SIZE;
69*926deccbSFrançois Tigeot 	}
70*926deccbSFrançois Tigeot 
71*926deccbSFrançois Tigeot 	/* maximun bo size is the minimun btw visible vram and gtt size */
72*926deccbSFrançois Tigeot 	max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size);
73*926deccbSFrançois Tigeot 	if (size > max_size) {
74*926deccbSFrançois Tigeot 		DRM_ERROR("%s:%d alloc size %dMb bigger than %ldMb limit\n",
75*926deccbSFrançois Tigeot 		       __func__, __LINE__, size >> 20, max_size >> 20);
76*926deccbSFrançois Tigeot 		return -ENOMEM;
77*926deccbSFrançois Tigeot 	}
78*926deccbSFrançois Tigeot 
79*926deccbSFrançois Tigeot retry:
80*926deccbSFrançois Tigeot 	r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, NULL, &robj);
81*926deccbSFrançois Tigeot 	if (r) {
82*926deccbSFrançois Tigeot 		if (r != -ERESTART) {
83*926deccbSFrançois Tigeot 			if (initial_domain == RADEON_GEM_DOMAIN_VRAM) {
84*926deccbSFrançois Tigeot 				initial_domain |= RADEON_GEM_DOMAIN_GTT;
85*926deccbSFrançois Tigeot 				goto retry;
86*926deccbSFrançois Tigeot 			}
87*926deccbSFrançois Tigeot 			DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
88*926deccbSFrançois Tigeot 				  size, initial_domain, alignment, r);
89*926deccbSFrançois Tigeot 		}
90*926deccbSFrançois Tigeot 		return r;
91*926deccbSFrançois Tigeot 	}
92*926deccbSFrançois Tigeot 	*obj = &robj->gem_base;
93*926deccbSFrançois Tigeot 
94*926deccbSFrançois Tigeot 	spin_lock(&rdev->gem.mutex);
95*926deccbSFrançois Tigeot 	list_add_tail(&robj->list, &rdev->gem.objects);
96*926deccbSFrançois Tigeot 	spin_unlock(&rdev->gem.mutex);
97*926deccbSFrançois Tigeot 
98*926deccbSFrançois Tigeot 	return 0;
99*926deccbSFrançois Tigeot }
100*926deccbSFrançois Tigeot 
101*926deccbSFrançois Tigeot static int radeon_gem_set_domain(struct drm_gem_object *gobj,
102*926deccbSFrançois Tigeot 			  uint32_t rdomain, uint32_t wdomain)
103*926deccbSFrançois Tigeot {
104*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
105*926deccbSFrançois Tigeot 	uint32_t domain;
106*926deccbSFrançois Tigeot 	int r;
107*926deccbSFrançois Tigeot 
108*926deccbSFrançois Tigeot 	/* FIXME: reeimplement */
109*926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
110*926deccbSFrançois Tigeot 	/* work out where to validate the buffer to */
111*926deccbSFrançois Tigeot 	domain = wdomain;
112*926deccbSFrançois Tigeot 	if (!domain) {
113*926deccbSFrançois Tigeot 		domain = rdomain;
114*926deccbSFrançois Tigeot 	}
115*926deccbSFrançois Tigeot 	if (!domain) {
116*926deccbSFrançois Tigeot 		/* Do nothings */
117*926deccbSFrançois Tigeot 		DRM_ERROR("Set domain without domain !\n");
118*926deccbSFrançois Tigeot 		return 0;
119*926deccbSFrançois Tigeot 	}
120*926deccbSFrançois Tigeot 	if (domain == RADEON_GEM_DOMAIN_CPU) {
121*926deccbSFrançois Tigeot 		/* Asking for cpu access wait for object idle */
122*926deccbSFrançois Tigeot 		r = radeon_bo_wait(robj, NULL, false);
123*926deccbSFrançois Tigeot 		if (r) {
124*926deccbSFrançois Tigeot 			DRM_ERROR("Failed to wait for object !\n");
125*926deccbSFrançois Tigeot 			return r;
126*926deccbSFrançois Tigeot 		}
127*926deccbSFrançois Tigeot 	}
128*926deccbSFrançois Tigeot 	return 0;
129*926deccbSFrançois Tigeot }
130*926deccbSFrançois Tigeot 
131*926deccbSFrançois Tigeot int radeon_gem_init(struct radeon_device *rdev)
132*926deccbSFrançois Tigeot {
133*926deccbSFrançois Tigeot 	INIT_LIST_HEAD(&rdev->gem.objects);
134*926deccbSFrançois Tigeot 	return 0;
135*926deccbSFrançois Tigeot }
136*926deccbSFrançois Tigeot 
137*926deccbSFrançois Tigeot void radeon_gem_fini(struct radeon_device *rdev)
138*926deccbSFrançois Tigeot {
139*926deccbSFrançois Tigeot 	radeon_bo_force_delete(rdev);
140*926deccbSFrançois Tigeot }
141*926deccbSFrançois Tigeot 
142*926deccbSFrançois Tigeot /*
143*926deccbSFrançois Tigeot  * Call from drm_gem_handle_create which appear in both new and open ioctl
144*926deccbSFrançois Tigeot  * case.
145*926deccbSFrançois Tigeot  */
146*926deccbSFrançois Tigeot int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv)
147*926deccbSFrançois Tigeot {
148*926deccbSFrançois Tigeot 	struct radeon_bo *rbo = gem_to_radeon_bo(obj);
149*926deccbSFrançois Tigeot 	struct radeon_device *rdev = rbo->rdev;
150*926deccbSFrançois Tigeot 	struct radeon_fpriv *fpriv = file_priv->driver_priv;
151*926deccbSFrançois Tigeot 	struct radeon_vm *vm = &fpriv->vm;
152*926deccbSFrançois Tigeot 	struct radeon_bo_va *bo_va;
153*926deccbSFrançois Tigeot 	int r;
154*926deccbSFrançois Tigeot 
155*926deccbSFrançois Tigeot 	if (rdev->family < CHIP_CAYMAN) {
156*926deccbSFrançois Tigeot 		return 0;
157*926deccbSFrançois Tigeot 	}
158*926deccbSFrançois Tigeot 
159*926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, false);
160*926deccbSFrançois Tigeot 	if (r) {
161*926deccbSFrançois Tigeot 		return r;
162*926deccbSFrançois Tigeot 	}
163*926deccbSFrançois Tigeot 
164*926deccbSFrançois Tigeot 	bo_va = radeon_vm_bo_find(vm, rbo);
165*926deccbSFrançois Tigeot 	if (!bo_va) {
166*926deccbSFrançois Tigeot 		bo_va = radeon_vm_bo_add(rdev, vm, rbo);
167*926deccbSFrançois Tigeot 	} else {
168*926deccbSFrançois Tigeot 		++bo_va->ref_count;
169*926deccbSFrançois Tigeot 	}
170*926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
171*926deccbSFrançois Tigeot 
172*926deccbSFrançois Tigeot 	return 0;
173*926deccbSFrançois Tigeot }
174*926deccbSFrançois Tigeot 
175*926deccbSFrançois Tigeot void radeon_gem_object_close(struct drm_gem_object *obj,
176*926deccbSFrançois Tigeot 			     struct drm_file *file_priv)
177*926deccbSFrançois Tigeot {
178*926deccbSFrançois Tigeot 	struct radeon_bo *rbo = gem_to_radeon_bo(obj);
179*926deccbSFrançois Tigeot 	struct radeon_device *rdev = rbo->rdev;
180*926deccbSFrançois Tigeot 	struct radeon_fpriv *fpriv = file_priv->driver_priv;
181*926deccbSFrançois Tigeot 	struct radeon_vm *vm = &fpriv->vm;
182*926deccbSFrançois Tigeot 	struct radeon_bo_va *bo_va;
183*926deccbSFrançois Tigeot 	int r;
184*926deccbSFrançois Tigeot 
185*926deccbSFrançois Tigeot 	if (rdev->family < CHIP_CAYMAN) {
186*926deccbSFrançois Tigeot 		return;
187*926deccbSFrançois Tigeot 	}
188*926deccbSFrançois Tigeot 
189*926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, true);
190*926deccbSFrançois Tigeot 	if (r) {
191*926deccbSFrançois Tigeot 		dev_err(rdev->dev, "leaking bo va because "
192*926deccbSFrançois Tigeot 			"we fail to reserve bo (%d)\n", r);
193*926deccbSFrançois Tigeot 		return;
194*926deccbSFrançois Tigeot 	}
195*926deccbSFrançois Tigeot 	bo_va = radeon_vm_bo_find(vm, rbo);
196*926deccbSFrançois Tigeot 	if (bo_va) {
197*926deccbSFrançois Tigeot 		if (--bo_va->ref_count == 0) {
198*926deccbSFrançois Tigeot 			radeon_vm_bo_rmv(rdev, bo_va);
199*926deccbSFrançois Tigeot 		}
200*926deccbSFrançois Tigeot 	}
201*926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
202*926deccbSFrançois Tigeot }
203*926deccbSFrançois Tigeot 
204*926deccbSFrançois Tigeot static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r)
205*926deccbSFrançois Tigeot {
206*926deccbSFrançois Tigeot 	if (r == -EDEADLK) {
207*926deccbSFrançois Tigeot 		r = radeon_gpu_reset(rdev);
208*926deccbSFrançois Tigeot 		if (!r)
209*926deccbSFrançois Tigeot 			r = -EAGAIN;
210*926deccbSFrançois Tigeot 	}
211*926deccbSFrançois Tigeot 	return r;
212*926deccbSFrançois Tigeot }
213*926deccbSFrançois Tigeot 
214*926deccbSFrançois Tigeot /*
215*926deccbSFrançois Tigeot  * GEM ioctls.
216*926deccbSFrançois Tigeot  */
217*926deccbSFrançois Tigeot int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
218*926deccbSFrançois Tigeot 			  struct drm_file *filp)
219*926deccbSFrançois Tigeot {
220*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
221*926deccbSFrançois Tigeot 	struct drm_radeon_gem_info *args = data;
222*926deccbSFrançois Tigeot 	struct ttm_mem_type_manager *man;
223*926deccbSFrançois Tigeot 	unsigned i;
224*926deccbSFrançois Tigeot 
225*926deccbSFrançois Tigeot 	man = &rdev->mman.bdev.man[TTM_PL_VRAM];
226*926deccbSFrançois Tigeot 
227*926deccbSFrançois Tigeot 	args->vram_size = rdev->mc.real_vram_size;
228*926deccbSFrançois Tigeot 	args->vram_visible = (u64)man->size << PAGE_SHIFT;
229*926deccbSFrançois Tigeot 	if (rdev->stollen_vga_memory)
230*926deccbSFrançois Tigeot 		args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory);
231*926deccbSFrançois Tigeot 	args->vram_visible -= radeon_fbdev_total_size(rdev);
232*926deccbSFrançois Tigeot 	args->gart_size = rdev->mc.gtt_size - 4096 - RADEON_IB_POOL_SIZE*64*1024;
233*926deccbSFrançois Tigeot 	for(i = 0; i < RADEON_NUM_RINGS; ++i)
234*926deccbSFrançois Tigeot 		args->gart_size -= rdev->ring[i].ring_size;
235*926deccbSFrançois Tigeot 	return 0;
236*926deccbSFrançois Tigeot }
237*926deccbSFrançois Tigeot 
238*926deccbSFrançois Tigeot int radeon_gem_pread_ioctl(struct drm_device *dev, void *data,
239*926deccbSFrançois Tigeot 			   struct drm_file *filp)
240*926deccbSFrançois Tigeot {
241*926deccbSFrançois Tigeot 	/* TODO: implement */
242*926deccbSFrançois Tigeot 	DRM_ERROR("unimplemented %s\n", __func__);
243*926deccbSFrançois Tigeot 	return -ENOSYS;
244*926deccbSFrançois Tigeot }
245*926deccbSFrançois Tigeot 
246*926deccbSFrançois Tigeot int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data,
247*926deccbSFrançois Tigeot 			    struct drm_file *filp)
248*926deccbSFrançois Tigeot {
249*926deccbSFrançois Tigeot 	/* TODO: implement */
250*926deccbSFrançois Tigeot 	DRM_ERROR("unimplemented %s\n", __func__);
251*926deccbSFrançois Tigeot 	return -ENOSYS;
252*926deccbSFrançois Tigeot }
253*926deccbSFrançois Tigeot 
254*926deccbSFrançois Tigeot int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
255*926deccbSFrançois Tigeot 			    struct drm_file *filp)
256*926deccbSFrançois Tigeot {
257*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
258*926deccbSFrançois Tigeot 	struct drm_radeon_gem_create *args = data;
259*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
260*926deccbSFrançois Tigeot 	uint32_t handle;
261*926deccbSFrançois Tigeot 	int r;
262*926deccbSFrançois Tigeot 
263*926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_SHARED);
264*926deccbSFrançois Tigeot 	/* create a gem object to contain this object in */
265*926deccbSFrançois Tigeot 	args->size = roundup(args->size, PAGE_SIZE);
266*926deccbSFrançois Tigeot 	r = radeon_gem_object_create(rdev, args->size, args->alignment,
267*926deccbSFrançois Tigeot 					args->initial_domain, false,
268*926deccbSFrançois Tigeot 					false, &gobj);
269*926deccbSFrançois Tigeot 	if (r) {
270*926deccbSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
271*926deccbSFrançois Tigeot 		r = radeon_gem_handle_lockup(rdev, r);
272*926deccbSFrançois Tigeot 		return r;
273*926deccbSFrançois Tigeot 	}
274*926deccbSFrançois Tigeot 	handle = 0;
275*926deccbSFrançois Tigeot 	r = drm_gem_handle_create(filp, gobj, &handle);
276*926deccbSFrançois Tigeot 	/* drop reference from allocate - handle holds it now */
277*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
278*926deccbSFrançois Tigeot 	if (r) {
279*926deccbSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
280*926deccbSFrançois Tigeot 		r = radeon_gem_handle_lockup(rdev, r);
281*926deccbSFrançois Tigeot 		return r;
282*926deccbSFrançois Tigeot 	}
283*926deccbSFrançois Tigeot 	args->handle = handle;
284*926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_RELEASE);
285*926deccbSFrançois Tigeot 	return 0;
286*926deccbSFrançois Tigeot }
287*926deccbSFrançois Tigeot 
288*926deccbSFrançois Tigeot int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
289*926deccbSFrançois Tigeot 				struct drm_file *filp)
290*926deccbSFrançois Tigeot {
291*926deccbSFrançois Tigeot 	/* transition the BO to a domain -
292*926deccbSFrançois Tigeot 	 * just validate the BO into a certain domain */
293*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
294*926deccbSFrançois Tigeot 	struct drm_radeon_gem_set_domain *args = data;
295*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
296*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
297*926deccbSFrançois Tigeot 	int r;
298*926deccbSFrançois Tigeot 
299*926deccbSFrançois Tigeot 	/* for now if someone requests domain CPU -
300*926deccbSFrançois Tigeot 	 * just make sure the buffer is finished with */
301*926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_SHARED);
302*926deccbSFrançois Tigeot 
303*926deccbSFrançois Tigeot 	/* just do a BO wait for now */
304*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
305*926deccbSFrançois Tigeot 	if (gobj == NULL) {
306*926deccbSFrançois Tigeot 		lockmgr(&rdev->exclusive_lock, LK_RELEASE);
307*926deccbSFrançois Tigeot 		return -ENOENT;
308*926deccbSFrançois Tigeot 	}
309*926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
310*926deccbSFrançois Tigeot 
311*926deccbSFrançois Tigeot 	r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
312*926deccbSFrançois Tigeot 
313*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
314*926deccbSFrançois Tigeot 	lockmgr(&rdev->exclusive_lock, LK_RELEASE);
315*926deccbSFrançois Tigeot 	r = radeon_gem_handle_lockup(robj->rdev, r);
316*926deccbSFrançois Tigeot 	return r;
317*926deccbSFrançois Tigeot }
318*926deccbSFrançois Tigeot 
319*926deccbSFrançois Tigeot int radeon_mode_dumb_mmap(struct drm_file *filp,
320*926deccbSFrançois Tigeot 			  struct drm_device *dev,
321*926deccbSFrançois Tigeot 			  uint32_t handle, uint64_t *offset_p)
322*926deccbSFrançois Tigeot {
323*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
324*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
325*926deccbSFrançois Tigeot 
326*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, handle);
327*926deccbSFrançois Tigeot 	if (gobj == NULL) {
328*926deccbSFrançois Tigeot 		return -ENOENT;
329*926deccbSFrançois Tigeot 	}
330*926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
331*926deccbSFrançois Tigeot 	*offset_p = radeon_bo_mmap_offset(robj);
332*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
333*926deccbSFrançois Tigeot 	return 0;
334*926deccbSFrançois Tigeot }
335*926deccbSFrançois Tigeot 
336*926deccbSFrançois Tigeot int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
337*926deccbSFrançois Tigeot 			  struct drm_file *filp)
338*926deccbSFrançois Tigeot {
339*926deccbSFrançois Tigeot 	struct drm_radeon_gem_mmap *args = data;
340*926deccbSFrançois Tigeot 
341*926deccbSFrançois Tigeot 	return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr);
342*926deccbSFrançois Tigeot }
343*926deccbSFrançois Tigeot 
344*926deccbSFrançois Tigeot int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
345*926deccbSFrançois Tigeot 			  struct drm_file *filp)
346*926deccbSFrançois Tigeot {
347*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
348*926deccbSFrançois Tigeot 	struct drm_radeon_gem_busy *args = data;
349*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
350*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
351*926deccbSFrançois Tigeot 	int r;
352*926deccbSFrançois Tigeot 	uint32_t cur_placement = 0;
353*926deccbSFrançois Tigeot 
354*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
355*926deccbSFrançois Tigeot 	if (gobj == NULL) {
356*926deccbSFrançois Tigeot 		return -ENOENT;
357*926deccbSFrançois Tigeot 	}
358*926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
359*926deccbSFrançois Tigeot 	r = radeon_bo_wait(robj, &cur_placement, true);
360*926deccbSFrançois Tigeot 	switch (cur_placement) {
361*926deccbSFrançois Tigeot 	case TTM_PL_VRAM:
362*926deccbSFrançois Tigeot 		args->domain = RADEON_GEM_DOMAIN_VRAM;
363*926deccbSFrançois Tigeot 		break;
364*926deccbSFrançois Tigeot 	case TTM_PL_TT:
365*926deccbSFrançois Tigeot 		args->domain = RADEON_GEM_DOMAIN_GTT;
366*926deccbSFrançois Tigeot 		break;
367*926deccbSFrançois Tigeot 	case TTM_PL_SYSTEM:
368*926deccbSFrançois Tigeot 		args->domain = RADEON_GEM_DOMAIN_CPU;
369*926deccbSFrançois Tigeot 	default:
370*926deccbSFrançois Tigeot 		break;
371*926deccbSFrançois Tigeot 	}
372*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
373*926deccbSFrançois Tigeot 	r = radeon_gem_handle_lockup(rdev, r);
374*926deccbSFrançois Tigeot 	return r;
375*926deccbSFrançois Tigeot }
376*926deccbSFrançois Tigeot 
377*926deccbSFrançois Tigeot int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
378*926deccbSFrançois Tigeot 			      struct drm_file *filp)
379*926deccbSFrançois Tigeot {
380*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
381*926deccbSFrançois Tigeot 	struct drm_radeon_gem_wait_idle *args = data;
382*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
383*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
384*926deccbSFrançois Tigeot 	int r;
385*926deccbSFrançois Tigeot 
386*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
387*926deccbSFrançois Tigeot 	if (gobj == NULL) {
388*926deccbSFrançois Tigeot 		return -ENOENT;
389*926deccbSFrançois Tigeot 	}
390*926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
391*926deccbSFrançois Tigeot 	r = radeon_bo_wait(robj, NULL, false);
392*926deccbSFrançois Tigeot 	/* callback hw specific functions if any */
393*926deccbSFrançois Tigeot 	if (rdev->asic->ioctl_wait_idle)
394*926deccbSFrançois Tigeot 		robj->rdev->asic->ioctl_wait_idle(rdev, robj);
395*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
396*926deccbSFrançois Tigeot 	r = radeon_gem_handle_lockup(rdev, r);
397*926deccbSFrançois Tigeot 	return r;
398*926deccbSFrançois Tigeot }
399*926deccbSFrançois Tigeot 
400*926deccbSFrançois Tigeot int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
401*926deccbSFrançois Tigeot 				struct drm_file *filp)
402*926deccbSFrançois Tigeot {
403*926deccbSFrançois Tigeot 	struct drm_radeon_gem_set_tiling *args = data;
404*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
405*926deccbSFrançois Tigeot 	struct radeon_bo *robj;
406*926deccbSFrançois Tigeot 	int r = 0;
407*926deccbSFrançois Tigeot 
408*926deccbSFrançois Tigeot 	DRM_DEBUG("%d \n", args->handle);
409*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
410*926deccbSFrançois Tigeot 	if (gobj == NULL)
411*926deccbSFrançois Tigeot 		return -ENOENT;
412*926deccbSFrançois Tigeot 	robj = gem_to_radeon_bo(gobj);
413*926deccbSFrançois Tigeot 	r = radeon_bo_set_tiling_flags(robj, args->tiling_flags, args->pitch);
414*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
415*926deccbSFrançois Tigeot 	return r;
416*926deccbSFrançois Tigeot }
417*926deccbSFrançois Tigeot 
418*926deccbSFrançois Tigeot int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
419*926deccbSFrançois Tigeot 				struct drm_file *filp)
420*926deccbSFrançois Tigeot {
421*926deccbSFrançois Tigeot 	struct drm_radeon_gem_get_tiling *args = data;
422*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
423*926deccbSFrançois Tigeot 	struct radeon_bo *rbo;
424*926deccbSFrançois Tigeot 	int r = 0;
425*926deccbSFrançois Tigeot 
426*926deccbSFrançois Tigeot 	DRM_DEBUG("\n");
427*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
428*926deccbSFrançois Tigeot 	if (gobj == NULL)
429*926deccbSFrançois Tigeot 		return -ENOENT;
430*926deccbSFrançois Tigeot 	rbo = gem_to_radeon_bo(gobj);
431*926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, false);
432*926deccbSFrançois Tigeot 	if (unlikely(r != 0))
433*926deccbSFrançois Tigeot 		goto out;
434*926deccbSFrançois Tigeot 	radeon_bo_get_tiling_flags(rbo, &args->tiling_flags, &args->pitch);
435*926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
436*926deccbSFrançois Tigeot out:
437*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
438*926deccbSFrançois Tigeot 	return r;
439*926deccbSFrançois Tigeot }
440*926deccbSFrançois Tigeot 
441*926deccbSFrançois Tigeot int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
442*926deccbSFrançois Tigeot 			  struct drm_file *filp)
443*926deccbSFrançois Tigeot {
444*926deccbSFrançois Tigeot 	struct drm_radeon_gem_va *args = data;
445*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
446*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
447*926deccbSFrançois Tigeot 	struct radeon_fpriv *fpriv = filp->driver_priv;
448*926deccbSFrançois Tigeot 	struct radeon_bo *rbo;
449*926deccbSFrançois Tigeot 	struct radeon_bo_va *bo_va;
450*926deccbSFrançois Tigeot 	u32 invalid_flags;
451*926deccbSFrançois Tigeot 	int r = 0;
452*926deccbSFrançois Tigeot 
453*926deccbSFrançois Tigeot 	if (!rdev->vm_manager.enabled) {
454*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
455*926deccbSFrançois Tigeot 		return -ENOTTY;
456*926deccbSFrançois Tigeot 	}
457*926deccbSFrançois Tigeot 
458*926deccbSFrançois Tigeot 	/* !! DONT REMOVE !!
459*926deccbSFrançois Tigeot 	 * We don't support vm_id yet, to be sure we don't have have broken
460*926deccbSFrançois Tigeot 	 * userspace, reject anyone trying to use non 0 value thus moving
461*926deccbSFrançois Tigeot 	 * forward we can use those fields without breaking existant userspace
462*926deccbSFrançois Tigeot 	 */
463*926deccbSFrançois Tigeot 	if (args->vm_id) {
464*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
465*926deccbSFrançois Tigeot 		return -EINVAL;
466*926deccbSFrançois Tigeot 	}
467*926deccbSFrançois Tigeot 
468*926deccbSFrançois Tigeot 	if (args->offset < RADEON_VA_RESERVED_SIZE) {
469*926deccbSFrançois Tigeot 		dev_err(dev->device,
470*926deccbSFrançois Tigeot 			"offset 0x%lX is in reserved area 0x%X\n",
471*926deccbSFrançois Tigeot 			(unsigned long)args->offset,
472*926deccbSFrançois Tigeot 			RADEON_VA_RESERVED_SIZE);
473*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
474*926deccbSFrançois Tigeot 		return -EINVAL;
475*926deccbSFrançois Tigeot 	}
476*926deccbSFrançois Tigeot 
477*926deccbSFrançois Tigeot 	/* don't remove, we need to enforce userspace to set the snooped flag
478*926deccbSFrançois Tigeot 	 * otherwise we will endup with broken userspace and we won't be able
479*926deccbSFrançois Tigeot 	 * to enable this feature without adding new interface
480*926deccbSFrançois Tigeot 	 */
481*926deccbSFrançois Tigeot 	invalid_flags = RADEON_VM_PAGE_VALID | RADEON_VM_PAGE_SYSTEM;
482*926deccbSFrançois Tigeot 	if ((args->flags & invalid_flags)) {
483*926deccbSFrançois Tigeot 		dev_err(dev->device, "invalid flags 0x%08X vs 0x%08X\n",
484*926deccbSFrançois Tigeot 			args->flags, invalid_flags);
485*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
486*926deccbSFrançois Tigeot 		return -EINVAL;
487*926deccbSFrançois Tigeot 	}
488*926deccbSFrançois Tigeot 	if (!(args->flags & RADEON_VM_PAGE_SNOOPED)) {
489*926deccbSFrançois Tigeot 		dev_err(dev->device, "only supported snooped mapping for now\n");
490*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
491*926deccbSFrançois Tigeot 		return -EINVAL;
492*926deccbSFrançois Tigeot 	}
493*926deccbSFrançois Tigeot 
494*926deccbSFrançois Tigeot 	switch (args->operation) {
495*926deccbSFrançois Tigeot 	case RADEON_VA_MAP:
496*926deccbSFrançois Tigeot 	case RADEON_VA_UNMAP:
497*926deccbSFrançois Tigeot 		break;
498*926deccbSFrançois Tigeot 	default:
499*926deccbSFrançois Tigeot 		dev_err(dev->device, "unsupported operation %d\n",
500*926deccbSFrançois Tigeot 			args->operation);
501*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
502*926deccbSFrançois Tigeot 		return -EINVAL;
503*926deccbSFrançois Tigeot 	}
504*926deccbSFrançois Tigeot 
505*926deccbSFrançois Tigeot 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
506*926deccbSFrançois Tigeot 	if (gobj == NULL) {
507*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
508*926deccbSFrançois Tigeot 		return -ENOENT;
509*926deccbSFrançois Tigeot 	}
510*926deccbSFrançois Tigeot 	rbo = gem_to_radeon_bo(gobj);
511*926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rbo, false);
512*926deccbSFrançois Tigeot 	if (r) {
513*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
514*926deccbSFrançois Tigeot 		drm_gem_object_unreference_unlocked(gobj);
515*926deccbSFrançois Tigeot 		return r;
516*926deccbSFrançois Tigeot 	}
517*926deccbSFrançois Tigeot 	bo_va = radeon_vm_bo_find(&fpriv->vm, rbo);
518*926deccbSFrançois Tigeot 	if (!bo_va) {
519*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
520*926deccbSFrançois Tigeot 		drm_gem_object_unreference_unlocked(gobj);
521*926deccbSFrançois Tigeot 		return -ENOENT;
522*926deccbSFrançois Tigeot 	}
523*926deccbSFrançois Tigeot 
524*926deccbSFrançois Tigeot 	switch (args->operation) {
525*926deccbSFrançois Tigeot 	case RADEON_VA_MAP:
526*926deccbSFrançois Tigeot 		if (bo_va->soffset) {
527*926deccbSFrançois Tigeot 			args->operation = RADEON_VA_RESULT_VA_EXIST;
528*926deccbSFrançois Tigeot 			args->offset = bo_va->soffset;
529*926deccbSFrançois Tigeot 			goto out;
530*926deccbSFrançois Tigeot 		}
531*926deccbSFrançois Tigeot 		r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags);
532*926deccbSFrançois Tigeot 		break;
533*926deccbSFrançois Tigeot 	case RADEON_VA_UNMAP:
534*926deccbSFrançois Tigeot 		r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0);
535*926deccbSFrançois Tigeot 		break;
536*926deccbSFrançois Tigeot 	default:
537*926deccbSFrançois Tigeot 		break;
538*926deccbSFrançois Tigeot 	}
539*926deccbSFrançois Tigeot 	args->operation = RADEON_VA_RESULT_OK;
540*926deccbSFrançois Tigeot 	if (r) {
541*926deccbSFrançois Tigeot 		args->operation = RADEON_VA_RESULT_ERROR;
542*926deccbSFrançois Tigeot 	}
543*926deccbSFrançois Tigeot out:
544*926deccbSFrançois Tigeot 	radeon_bo_unreserve(rbo);
545*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
546*926deccbSFrançois Tigeot 	return r;
547*926deccbSFrançois Tigeot }
548*926deccbSFrançois Tigeot 
549*926deccbSFrançois Tigeot int radeon_mode_dumb_create(struct drm_file *file_priv,
550*926deccbSFrançois Tigeot 			    struct drm_device *dev,
551*926deccbSFrançois Tigeot 			    struct drm_mode_create_dumb *args)
552*926deccbSFrançois Tigeot {
553*926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
554*926deccbSFrançois Tigeot 	struct drm_gem_object *gobj;
555*926deccbSFrançois Tigeot 	uint32_t handle;
556*926deccbSFrançois Tigeot 	int r;
557*926deccbSFrançois Tigeot 
558*926deccbSFrançois Tigeot 	args->pitch = radeon_align_pitch(rdev, args->width, args->bpp, 0) * ((args->bpp + 1) / 8);
559*926deccbSFrançois Tigeot 	args->size = args->pitch * args->height;
560*926deccbSFrançois Tigeot 	args->size = roundup2(args->size, PAGE_SIZE);
561*926deccbSFrançois Tigeot 
562*926deccbSFrançois Tigeot 	r = radeon_gem_object_create(rdev, args->size, 0,
563*926deccbSFrançois Tigeot 				     RADEON_GEM_DOMAIN_VRAM,
564*926deccbSFrançois Tigeot 				     false, ttm_bo_type_device,
565*926deccbSFrançois Tigeot 				     &gobj);
566*926deccbSFrançois Tigeot 	if (r)
567*926deccbSFrançois Tigeot 		return -ENOMEM;
568*926deccbSFrançois Tigeot 
569*926deccbSFrançois Tigeot 	r = drm_gem_handle_create(file_priv, gobj, &handle);
570*926deccbSFrançois Tigeot 	/* drop reference from allocate - handle holds it now */
571*926deccbSFrançois Tigeot 	drm_gem_object_unreference_unlocked(gobj);
572*926deccbSFrançois Tigeot 	if (r) {
573*926deccbSFrançois Tigeot 		return r;
574*926deccbSFrançois Tigeot 	}
575*926deccbSFrançois Tigeot 	args->handle = handle;
576*926deccbSFrançois Tigeot 	return 0;
577*926deccbSFrançois Tigeot }
578*926deccbSFrançois Tigeot 
579*926deccbSFrançois Tigeot int radeon_mode_dumb_destroy(struct drm_file *file_priv,
580*926deccbSFrançois Tigeot 			     struct drm_device *dev,
581*926deccbSFrançois Tigeot 			     uint32_t handle)
582*926deccbSFrançois Tigeot {
583*926deccbSFrançois Tigeot 	return drm_gem_handle_delete(file_priv, handle);
584*926deccbSFrançois Tigeot }
585