drm/ttm: Fix ttm_bo_move_memcpy() for subclassed struct ttm_resource
[linux-2.6-microblaze.git] / drivers / gpu / drm / mediatek / mtk_drm_gem.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015 MediaTek Inc.
4  */
5
6 #include <linux/dma-buf.h>
7
8 #include <drm/drm.h>
9 #include <drm/drm_device.h>
10 #include <drm/drm_gem.h>
11 #include <drm/drm_gem_cma_helper.h>
12 #include <drm/drm_prime.h>
13
14 #include "mtk_drm_drv.h"
15 #include "mtk_drm_gem.h"
16
17 static const struct drm_gem_object_funcs mtk_drm_gem_object_funcs = {
18         .free = mtk_drm_gem_free_object,
19         .get_sg_table = mtk_gem_prime_get_sg_table,
20         .vmap = mtk_drm_gem_prime_vmap,
21         .vunmap = mtk_drm_gem_prime_vunmap,
22         .vm_ops = &drm_gem_cma_vm_ops,
23 };
24
25 static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
26                                                 unsigned long size)
27 {
28         struct mtk_drm_gem_obj *mtk_gem_obj;
29         int ret;
30
31         size = round_up(size, PAGE_SIZE);
32
33         mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL);
34         if (!mtk_gem_obj)
35                 return ERR_PTR(-ENOMEM);
36
37         mtk_gem_obj->base.funcs = &mtk_drm_gem_object_funcs;
38
39         ret = drm_gem_object_init(dev, &mtk_gem_obj->base, size);
40         if (ret < 0) {
41                 DRM_ERROR("failed to initialize gem object\n");
42                 kfree(mtk_gem_obj);
43                 return ERR_PTR(ret);
44         }
45
46         return mtk_gem_obj;
47 }
48
49 struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
50                                            size_t size, bool alloc_kmap)
51 {
52         struct mtk_drm_private *priv = dev->dev_private;
53         struct mtk_drm_gem_obj *mtk_gem;
54         struct drm_gem_object *obj;
55         int ret;
56
57         mtk_gem = mtk_drm_gem_init(dev, size);
58         if (IS_ERR(mtk_gem))
59                 return ERR_CAST(mtk_gem);
60
61         obj = &mtk_gem->base;
62
63         mtk_gem->dma_attrs = DMA_ATTR_WRITE_COMBINE;
64
65         if (!alloc_kmap)
66                 mtk_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
67
68         mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size,
69                                           &mtk_gem->dma_addr, GFP_KERNEL,
70                                           mtk_gem->dma_attrs);
71         if (!mtk_gem->cookie) {
72                 DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size);
73                 ret = -ENOMEM;
74                 goto err_gem_free;
75         }
76
77         if (alloc_kmap)
78                 mtk_gem->kvaddr = mtk_gem->cookie;
79
80         DRM_DEBUG_DRIVER("cookie = %p dma_addr = %pad size = %zu\n",
81                          mtk_gem->cookie, &mtk_gem->dma_addr,
82                          size);
83
84         return mtk_gem;
85
86 err_gem_free:
87         drm_gem_object_release(obj);
88         kfree(mtk_gem);
89         return ERR_PTR(ret);
90 }
91
92 void mtk_drm_gem_free_object(struct drm_gem_object *obj)
93 {
94         struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
95         struct mtk_drm_private *priv = obj->dev->dev_private;
96
97         if (mtk_gem->sg)
98                 drm_prime_gem_destroy(obj, mtk_gem->sg);
99         else
100                 dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie,
101                                mtk_gem->dma_addr, mtk_gem->dma_attrs);
102
103         /* release file pointer to gem object. */
104         drm_gem_object_release(obj);
105
106         kfree(mtk_gem);
107 }
108
109 int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
110                             struct drm_mode_create_dumb *args)
111 {
112         struct mtk_drm_gem_obj *mtk_gem;
113         int ret;
114
115         args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
116         args->size = args->pitch * args->height;
117
118         mtk_gem = mtk_drm_gem_create(dev, args->size, false);
119         if (IS_ERR(mtk_gem))
120                 return PTR_ERR(mtk_gem);
121
122         /*
123          * allocate a id of idr table where the obj is registered
124          * and handle has the id what user can see.
125          */
126         ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle);
127         if (ret)
128                 goto err_handle_create;
129
130         /* drop reference from allocate - handle holds it now. */
131         drm_gem_object_put(&mtk_gem->base);
132
133         return 0;
134
135 err_handle_create:
136         mtk_drm_gem_free_object(&mtk_gem->base);
137         return ret;
138 }
139
140 static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj,
141                                    struct vm_area_struct *vma)
142
143 {
144         int ret;
145         struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
146         struct mtk_drm_private *priv = obj->dev->dev_private;
147
148         /*
149          * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear
150          * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
151          */
152         vma->vm_flags &= ~VM_PFNMAP;
153
154         ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie,
155                              mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs);
156         if (ret)
157                 drm_gem_vm_close(vma);
158
159         return ret;
160 }
161
162 int mtk_drm_gem_mmap_buf(struct drm_gem_object *obj, struct vm_area_struct *vma)
163 {
164         int ret;
165
166         ret = drm_gem_mmap_obj(obj, obj->size, vma);
167         if (ret)
168                 return ret;
169
170         return mtk_drm_gem_object_mmap(obj, vma);
171 }
172
173 int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
174 {
175         struct drm_gem_object *obj;
176         int ret;
177
178         ret = drm_gem_mmap(filp, vma);
179         if (ret)
180                 return ret;
181
182         obj = vma->vm_private_data;
183
184         /*
185          * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the
186          * whole buffer from the start.
187          */
188         vma->vm_pgoff = 0;
189
190         return mtk_drm_gem_object_mmap(obj, vma);
191 }
192
193 /*
194  * Allocate a sg_table for this GEM object.
195  * Note: Both the table's contents, and the sg_table itself must be freed by
196  *       the caller.
197  * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error.
198  */
199 struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj)
200 {
201         struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
202         struct mtk_drm_private *priv = obj->dev->dev_private;
203         struct sg_table *sgt;
204         int ret;
205
206         sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
207         if (!sgt)
208                 return ERR_PTR(-ENOMEM);
209
210         ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie,
211                                     mtk_gem->dma_addr, obj->size,
212                                     mtk_gem->dma_attrs);
213         if (ret) {
214                 DRM_ERROR("failed to allocate sgt, %d\n", ret);
215                 kfree(sgt);
216                 return ERR_PTR(ret);
217         }
218
219         return sgt;
220 }
221
222 struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev,
223                         struct dma_buf_attachment *attach, struct sg_table *sg)
224 {
225         struct mtk_drm_gem_obj *mtk_gem;
226
227         /* check if the entries in the sg_table are contiguous */
228         if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
229                 DRM_ERROR("sg_table is not contiguous");
230                 return ERR_PTR(-EINVAL);
231         }
232
233         mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);
234         if (IS_ERR(mtk_gem))
235                 return ERR_CAST(mtk_gem);
236
237         mtk_gem->dma_addr = sg_dma_address(sg->sgl);
238         mtk_gem->sg = sg;
239
240         return &mtk_gem->base;
241 }
242
243 int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map)
244 {
245         struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
246         struct sg_table *sgt = NULL;
247         unsigned int npages;
248
249         if (mtk_gem->kvaddr)
250                 goto out;
251
252         sgt = mtk_gem_prime_get_sg_table(obj);
253         if (IS_ERR(sgt))
254                 return PTR_ERR(sgt);
255
256         npages = obj->size >> PAGE_SHIFT;
257         mtk_gem->pages = kcalloc(npages, sizeof(*mtk_gem->pages), GFP_KERNEL);
258         if (!mtk_gem->pages) {
259                 kfree(sgt);
260                 return -ENOMEM;
261         }
262
263         drm_prime_sg_to_page_array(sgt, mtk_gem->pages, npages);
264
265         mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,
266                                pgprot_writecombine(PAGE_KERNEL));
267
268 out:
269         kfree(sgt);
270         dma_buf_map_set_vaddr(map, mtk_gem->kvaddr);
271
272         return 0;
273 }
274
275 void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map)
276 {
277         struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
278         void *vaddr = map->vaddr;
279
280         if (!mtk_gem->pages)
281                 return;
282
283         vunmap(vaddr);
284         mtk_gem->kvaddr = 0;
285         kfree(mtk_gem->pages);
286 }