xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/v3d/v3d_bo.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /* Copyright (C) 2015-2018 Broadcom */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun /**
5*4882a593Smuzhiyun  * DOC: V3D GEM BO management support
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Compared to VC4 (V3D 2.x), V3D 3.3 introduces an MMU between the
8*4882a593Smuzhiyun  * GPU and the bus, allowing us to use shmem objects for our storage
9*4882a593Smuzhiyun  * instead of CMA.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Physically contiguous objects may still be imported to V3D, but the
12*4882a593Smuzhiyun  * driver doesn't allocate physically contiguous objects on its own.
13*4882a593Smuzhiyun  * Display engines requiring physically contiguous allocations should
14*4882a593Smuzhiyun  * look into Mesa's "renderonly" support (as used by the Mesa pl111
15*4882a593Smuzhiyun  * driver) for an example of how to integrate with V3D.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * Long term, we should support evicting pages from the MMU when under
18*4882a593Smuzhiyun  * memory pressure (thus the v3d_bo_get_pages() refcounting), but
19*4882a593Smuzhiyun  * that's not a high priority since our systems tend to not have swap.
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <linux/dma-buf.h>
23*4882a593Smuzhiyun #include <linux/pfn_t.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include "v3d_drv.h"
26*4882a593Smuzhiyun #include "uapi/drm/v3d_drm.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Called DRM core on the last userspace/kernel unreference of the
29*4882a593Smuzhiyun  * BO.
30*4882a593Smuzhiyun  */
v3d_free_object(struct drm_gem_object * obj)31*4882a593Smuzhiyun void v3d_free_object(struct drm_gem_object *obj)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	struct v3d_dev *v3d = to_v3d_dev(obj->dev);
34*4882a593Smuzhiyun 	struct v3d_bo *bo = to_v3d_bo(obj);
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	v3d_mmu_remove_ptes(bo);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	mutex_lock(&v3d->bo_lock);
39*4882a593Smuzhiyun 	v3d->bo_stats.num_allocated--;
40*4882a593Smuzhiyun 	v3d->bo_stats.pages_allocated -= obj->size >> PAGE_SHIFT;
41*4882a593Smuzhiyun 	mutex_unlock(&v3d->bo_lock);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	spin_lock(&v3d->mm_lock);
44*4882a593Smuzhiyun 	drm_mm_remove_node(&bo->node);
45*4882a593Smuzhiyun 	spin_unlock(&v3d->mm_lock);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	/* GPU execution may have dirtied any pages in the BO. */
48*4882a593Smuzhiyun 	bo->base.pages_mark_dirty_on_put = true;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	drm_gem_shmem_free_object(obj);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static const struct drm_gem_object_funcs v3d_gem_funcs = {
54*4882a593Smuzhiyun 	.free = v3d_free_object,
55*4882a593Smuzhiyun 	.print_info = drm_gem_shmem_print_info,
56*4882a593Smuzhiyun 	.pin = drm_gem_shmem_pin,
57*4882a593Smuzhiyun 	.unpin = drm_gem_shmem_unpin,
58*4882a593Smuzhiyun 	.get_sg_table = drm_gem_shmem_get_sg_table,
59*4882a593Smuzhiyun 	.vmap = drm_gem_shmem_vmap,
60*4882a593Smuzhiyun 	.vunmap = drm_gem_shmem_vunmap,
61*4882a593Smuzhiyun 	.mmap = drm_gem_shmem_mmap,
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /* gem_create_object function for allocating a BO struct and doing
65*4882a593Smuzhiyun  * early setup.
66*4882a593Smuzhiyun  */
v3d_create_object(struct drm_device * dev,size_t size)67*4882a593Smuzhiyun struct drm_gem_object *v3d_create_object(struct drm_device *dev, size_t size)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct v3d_bo *bo;
70*4882a593Smuzhiyun 	struct drm_gem_object *obj;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	if (size == 0)
73*4882a593Smuzhiyun 		return NULL;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
76*4882a593Smuzhiyun 	if (!bo)
77*4882a593Smuzhiyun 		return NULL;
78*4882a593Smuzhiyun 	obj = &bo->base.base;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	obj->funcs = &v3d_gem_funcs;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	INIT_LIST_HEAD(&bo->unref_head);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	return &bo->base.base;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun static int
v3d_bo_create_finish(struct drm_gem_object * obj)88*4882a593Smuzhiyun v3d_bo_create_finish(struct drm_gem_object *obj)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct v3d_dev *v3d = to_v3d_dev(obj->dev);
91*4882a593Smuzhiyun 	struct v3d_bo *bo = to_v3d_bo(obj);
92*4882a593Smuzhiyun 	struct sg_table *sgt;
93*4882a593Smuzhiyun 	int ret;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	/* So far we pin the BO in the MMU for its lifetime, so use
96*4882a593Smuzhiyun 	 * shmem's helper for getting a lifetime sgt.
97*4882a593Smuzhiyun 	 */
98*4882a593Smuzhiyun 	sgt = drm_gem_shmem_get_pages_sgt(&bo->base.base);
99*4882a593Smuzhiyun 	if (IS_ERR(sgt))
100*4882a593Smuzhiyun 		return PTR_ERR(sgt);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	spin_lock(&v3d->mm_lock);
103*4882a593Smuzhiyun 	/* Allocate the object's space in the GPU's page tables.
104*4882a593Smuzhiyun 	 * Inserting PTEs will happen later, but the offset is for the
105*4882a593Smuzhiyun 	 * lifetime of the BO.
106*4882a593Smuzhiyun 	 */
107*4882a593Smuzhiyun 	ret = drm_mm_insert_node_generic(&v3d->mm, &bo->node,
108*4882a593Smuzhiyun 					 obj->size >> PAGE_SHIFT,
109*4882a593Smuzhiyun 					 GMP_GRANULARITY >> PAGE_SHIFT, 0, 0);
110*4882a593Smuzhiyun 	spin_unlock(&v3d->mm_lock);
111*4882a593Smuzhiyun 	if (ret)
112*4882a593Smuzhiyun 		return ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* Track stats for /debug/dri/n/bo_stats. */
115*4882a593Smuzhiyun 	mutex_lock(&v3d->bo_lock);
116*4882a593Smuzhiyun 	v3d->bo_stats.num_allocated++;
117*4882a593Smuzhiyun 	v3d->bo_stats.pages_allocated += obj->size >> PAGE_SHIFT;
118*4882a593Smuzhiyun 	mutex_unlock(&v3d->bo_lock);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	v3d_mmu_insert_ptes(bo);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return 0;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
v3d_bo_create(struct drm_device * dev,struct drm_file * file_priv,size_t unaligned_size)125*4882a593Smuzhiyun struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
126*4882a593Smuzhiyun 			     size_t unaligned_size)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct drm_gem_shmem_object *shmem_obj;
129*4882a593Smuzhiyun 	struct v3d_bo *bo;
130*4882a593Smuzhiyun 	int ret;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	shmem_obj = drm_gem_shmem_create(dev, unaligned_size);
133*4882a593Smuzhiyun 	if (IS_ERR(shmem_obj))
134*4882a593Smuzhiyun 		return ERR_CAST(shmem_obj);
135*4882a593Smuzhiyun 	bo = to_v3d_bo(&shmem_obj->base);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	ret = v3d_bo_create_finish(&shmem_obj->base);
138*4882a593Smuzhiyun 	if (ret)
139*4882a593Smuzhiyun 		goto free_obj;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return bo;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun free_obj:
144*4882a593Smuzhiyun 	drm_gem_shmem_free_object(&shmem_obj->base);
145*4882a593Smuzhiyun 	return ERR_PTR(ret);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun struct drm_gem_object *
v3d_prime_import_sg_table(struct drm_device * dev,struct dma_buf_attachment * attach,struct sg_table * sgt)149*4882a593Smuzhiyun v3d_prime_import_sg_table(struct drm_device *dev,
150*4882a593Smuzhiyun 			  struct dma_buf_attachment *attach,
151*4882a593Smuzhiyun 			  struct sg_table *sgt)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct drm_gem_object *obj;
154*4882a593Smuzhiyun 	int ret;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);
157*4882a593Smuzhiyun 	if (IS_ERR(obj))
158*4882a593Smuzhiyun 		return obj;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	ret = v3d_bo_create_finish(obj);
161*4882a593Smuzhiyun 	if (ret) {
162*4882a593Smuzhiyun 		drm_gem_shmem_free_object(obj);
163*4882a593Smuzhiyun 		return ERR_PTR(ret);
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return obj;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
v3d_create_bo_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)169*4882a593Smuzhiyun int v3d_create_bo_ioctl(struct drm_device *dev, void *data,
170*4882a593Smuzhiyun 			struct drm_file *file_priv)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct drm_v3d_create_bo *args = data;
173*4882a593Smuzhiyun 	struct v3d_bo *bo = NULL;
174*4882a593Smuzhiyun 	int ret;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (args->flags != 0) {
177*4882a593Smuzhiyun 		DRM_INFO("unknown create_bo flags: %d\n", args->flags);
178*4882a593Smuzhiyun 		return -EINVAL;
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	bo = v3d_bo_create(dev, file_priv, PAGE_ALIGN(args->size));
182*4882a593Smuzhiyun 	if (IS_ERR(bo))
183*4882a593Smuzhiyun 		return PTR_ERR(bo);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	args->offset = bo->node.start << PAGE_SHIFT;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
188*4882a593Smuzhiyun 	drm_gem_object_put(&bo->base.base);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	return ret;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
v3d_mmap_bo_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)193*4882a593Smuzhiyun int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data,
194*4882a593Smuzhiyun 		      struct drm_file *file_priv)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	struct drm_v3d_mmap_bo *args = data;
197*4882a593Smuzhiyun 	struct drm_gem_object *gem_obj;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (args->flags != 0) {
200*4882a593Smuzhiyun 		DRM_INFO("unknown mmap_bo flags: %d\n", args->flags);
201*4882a593Smuzhiyun 		return -EINVAL;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
205*4882a593Smuzhiyun 	if (!gem_obj) {
206*4882a593Smuzhiyun 		DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
207*4882a593Smuzhiyun 		return -ENOENT;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
211*4882a593Smuzhiyun 	drm_gem_object_put(gem_obj);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
v3d_get_bo_offset_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)216*4882a593Smuzhiyun int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data,
217*4882a593Smuzhiyun 			    struct drm_file *file_priv)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct drm_v3d_get_bo_offset *args = data;
220*4882a593Smuzhiyun 	struct drm_gem_object *gem_obj;
221*4882a593Smuzhiyun 	struct v3d_bo *bo;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
224*4882a593Smuzhiyun 	if (!gem_obj) {
225*4882a593Smuzhiyun 		DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
226*4882a593Smuzhiyun 		return -ENOENT;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	bo = to_v3d_bo(gem_obj);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	args->offset = bo->node.start << PAGE_SHIFT;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	drm_gem_object_put(gem_obj);
233*4882a593Smuzhiyun 	return 0;
234*4882a593Smuzhiyun }
235