1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) Rockchip Electronics Co., Ltd.
4 * Author:Mark Yao <mark.yao@rock-chips.com>
5 */
6
7 #include <linux/dma-buf.h>
8 #include <linux/iommu.h>
9 #include <linux/vmalloc.h>
10
11 #include <drm/drm.h>
12 #include <drm/drm_dumb_buffers.h>
13 #include <drm/drm_fb_helper.h>
14 #include <drm/drm_gem.h>
15 #include <drm/drm_gem_dma_helper.h>
16 #include <drm/drm_prime.h>
17 #include <drm/drm_print.h>
18 #include <drm/drm_vma_manager.h>
19
20 #include "rockchip_drm_drv.h"
21 #include "rockchip_drm_gem.h"
22
rockchip_gem_iommu_map(struct rockchip_gem_object * rk_obj)23 static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj)
24 {
25 struct drm_device *drm = rk_obj->base.dev;
26 struct rockchip_drm_private *private = drm->dev_private;
27 int prot = IOMMU_READ | IOMMU_WRITE;
28 ssize_t ret;
29
30 mutex_lock(&private->mm_lock);
31 ret = drm_mm_insert_node_generic(&private->mm, &rk_obj->mm,
32 rk_obj->base.size, PAGE_SIZE,
33 0, 0);
34 mutex_unlock(&private->mm_lock);
35
36 if (ret < 0) {
37 DRM_ERROR("out of I/O virtual memory: %zd\n", ret);
38 return ret;
39 }
40
41 rk_obj->dma_addr = rk_obj->mm.start;
42
43 ret = iommu_map_sgtable(private->domain, rk_obj->dma_addr, rk_obj->sgt,
44 prot);
45 if (ret < (ssize_t)rk_obj->base.size) {
46 DRM_ERROR("failed to map buffer: size=%zd request_size=%zd\n",
47 ret, rk_obj->base.size);
48 ret = -ENOMEM;
49 goto err_remove_node;
50 }
51
52 rk_obj->size = ret;
53
54 return 0;
55
56 err_remove_node:
57 mutex_lock(&private->mm_lock);
58 drm_mm_remove_node(&rk_obj->mm);
59 mutex_unlock(&private->mm_lock);
60
61 return ret;
62 }
63
rockchip_gem_iommu_unmap(struct rockchip_gem_object * rk_obj)64 static int rockchip_gem_iommu_unmap(struct rockchip_gem_object *rk_obj)
65 {
66 struct drm_device *drm = rk_obj->base.dev;
67 struct rockchip_drm_private *private = drm->dev_private;
68
69 iommu_unmap(private->domain, rk_obj->dma_addr, rk_obj->size);
70
71 mutex_lock(&private->mm_lock);
72
73 drm_mm_remove_node(&rk_obj->mm);
74
75 mutex_unlock(&private->mm_lock);
76
77 return 0;
78 }
79
rockchip_gem_get_pages(struct rockchip_gem_object * rk_obj)80 static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
81 {
82 struct drm_device *drm = rk_obj->base.dev;
83 int ret, i;
84 struct scatterlist *s;
85
86 rk_obj->pages = drm_gem_get_pages(&rk_obj->base);
87 if (IS_ERR(rk_obj->pages))
88 return PTR_ERR(rk_obj->pages);
89
90 rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
91
92 rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->base.dev,
93 rk_obj->pages, rk_obj->num_pages);
94 if (IS_ERR(rk_obj->sgt)) {
95 ret = PTR_ERR(rk_obj->sgt);
96 goto err_put_pages;
97 }
98
99 /*
100 * Fake up the SG table so that dma_sync_sg_for_device() can be used
101 * to flush the pages associated with it.
102 *
103 * TODO: Replace this by drm_clflush_sg() once it can be implemented
104 * without relying on symbols that are not exported.
105 */
106 for_each_sgtable_sg(rk_obj->sgt, s, i)
107 sg_dma_address(s) = sg_phys(s);
108
109 dma_sync_sgtable_for_device(drm->dev, rk_obj->sgt, DMA_TO_DEVICE);
110
111 return 0;
112
113 err_put_pages:
114 drm_gem_put_pages(&rk_obj->base, rk_obj->pages, false, false);
115 return ret;
116 }
117
rockchip_gem_put_pages(struct rockchip_gem_object * rk_obj)118 static void rockchip_gem_put_pages(struct rockchip_gem_object *rk_obj)
119 {
120 sg_free_table(rk_obj->sgt);
121 kfree(rk_obj->sgt);
122 drm_gem_put_pages(&rk_obj->base, rk_obj->pages, true, true);
123 }
124
rockchip_gem_alloc_iommu(struct rockchip_gem_object * rk_obj,bool alloc_kmap)125 static int rockchip_gem_alloc_iommu(struct rockchip_gem_object *rk_obj,
126 bool alloc_kmap)
127 {
128 int ret;
129
130 ret = rockchip_gem_get_pages(rk_obj);
131 if (ret < 0)
132 return ret;
133
134 ret = rockchip_gem_iommu_map(rk_obj);
135 if (ret < 0)
136 goto err_free;
137
138 if (alloc_kmap) {
139 rk_obj->kvaddr = vmap(rk_obj->pages, rk_obj->num_pages, VM_MAP,
140 pgprot_writecombine(PAGE_KERNEL));
141 if (!rk_obj->kvaddr) {
142 DRM_ERROR("failed to vmap() buffer\n");
143 ret = -ENOMEM;
144 goto err_unmap;
145 }
146 }
147
148 return 0;
149
150 err_unmap:
151 rockchip_gem_iommu_unmap(rk_obj);
152 err_free:
153 rockchip_gem_put_pages(rk_obj);
154
155 return ret;
156 }
157
rockchip_gem_alloc_dma(struct rockchip_gem_object * rk_obj,bool alloc_kmap)158 static int rockchip_gem_alloc_dma(struct rockchip_gem_object *rk_obj,
159 bool alloc_kmap)
160 {
161 struct drm_gem_object *obj = &rk_obj->base;
162 struct drm_device *drm = obj->dev;
163
164 rk_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE;
165
166 if (!alloc_kmap)
167 rk_obj->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
168
169 rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
170 &rk_obj->dma_addr, GFP_KERNEL,
171 rk_obj->dma_attrs);
172 if (!rk_obj->kvaddr) {
173 DRM_ERROR("failed to allocate %zu byte dma buffer", obj->size);
174 return -ENOMEM;
175 }
176
177 return 0;
178 }
179
rockchip_gem_alloc_buf(struct rockchip_gem_object * rk_obj,bool alloc_kmap)180 static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
181 bool alloc_kmap)
182 {
183 struct drm_gem_object *obj = &rk_obj->base;
184 struct drm_device *drm = obj->dev;
185 struct rockchip_drm_private *private = drm->dev_private;
186
187 if (private->domain)
188 return rockchip_gem_alloc_iommu(rk_obj, alloc_kmap);
189 else
190 return rockchip_gem_alloc_dma(rk_obj, alloc_kmap);
191 }
192
rockchip_gem_free_iommu(struct rockchip_gem_object * rk_obj)193 static void rockchip_gem_free_iommu(struct rockchip_gem_object *rk_obj)
194 {
195 vunmap(rk_obj->kvaddr);
196 rockchip_gem_iommu_unmap(rk_obj);
197 rockchip_gem_put_pages(rk_obj);
198 }
199
rockchip_gem_free_dma(struct rockchip_gem_object * rk_obj)200 static void rockchip_gem_free_dma(struct rockchip_gem_object *rk_obj)
201 {
202 struct drm_gem_object *obj = &rk_obj->base;
203 struct drm_device *drm = obj->dev;
204
205 dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr, rk_obj->dma_addr,
206 rk_obj->dma_attrs);
207 }
208
rockchip_gem_free_buf(struct rockchip_gem_object * rk_obj)209 static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
210 {
211 if (rk_obj->pages)
212 rockchip_gem_free_iommu(rk_obj);
213 else
214 rockchip_gem_free_dma(rk_obj);
215 }
216
rockchip_drm_gem_object_mmap_iommu(struct drm_gem_object * obj,struct vm_area_struct * vma)217 static int rockchip_drm_gem_object_mmap_iommu(struct drm_gem_object *obj,
218 struct vm_area_struct *vma)
219 {
220 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
221 unsigned int count = obj->size >> PAGE_SHIFT;
222 unsigned long user_count = vma_pages(vma);
223
224 if (user_count == 0)
225 return -ENXIO;
226
227 return vm_map_pages(vma, rk_obj->pages, count);
228 }
229
rockchip_drm_gem_object_mmap_dma(struct drm_gem_object * obj,struct vm_area_struct * vma)230 static int rockchip_drm_gem_object_mmap_dma(struct drm_gem_object *obj,
231 struct vm_area_struct *vma)
232 {
233 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
234 struct drm_device *drm = obj->dev;
235
236 return dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
237 obj->size, rk_obj->dma_attrs);
238 }
239
rockchip_drm_gem_object_mmap(struct drm_gem_object * obj,struct vm_area_struct * vma)240 static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
241 struct vm_area_struct *vma)
242 {
243 int ret;
244 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
245
246 /*
247 * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the
248 * whole buffer from the start.
249 */
250 vma->vm_pgoff = 0;
251
252 /*
253 * We allocated a struct page table for rk_obj, so clear
254 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
255 */
256 vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP);
257
258 vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
259 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
260
261 if (rk_obj->pages)
262 ret = rockchip_drm_gem_object_mmap_iommu(obj, vma);
263 else
264 ret = rockchip_drm_gem_object_mmap_dma(obj, vma);
265
266 return ret;
267 }
268
rockchip_gem_release_object(struct rockchip_gem_object * rk_obj)269 static void rockchip_gem_release_object(struct rockchip_gem_object *rk_obj)
270 {
271 drm_gem_object_release(&rk_obj->base);
272 kfree(rk_obj);
273 }
274
275 static const struct drm_gem_object_funcs rockchip_gem_object_funcs = {
276 .free = rockchip_gem_free_object,
277 .get_sg_table = rockchip_gem_prime_get_sg_table,
278 .vmap = rockchip_gem_prime_vmap,
279 .vunmap = rockchip_gem_prime_vunmap,
280 .mmap = rockchip_drm_gem_object_mmap,
281 .vm_ops = &drm_gem_dma_vm_ops,
282 };
283
284 static struct rockchip_gem_object *
rockchip_gem_alloc_object(struct drm_device * drm,unsigned int size)285 rockchip_gem_alloc_object(struct drm_device *drm, unsigned int size)
286 {
287 struct rockchip_gem_object *rk_obj;
288 struct drm_gem_object *obj;
289
290 size = round_up(size, PAGE_SIZE);
291
292 rk_obj = kzalloc_obj(*rk_obj);
293 if (!rk_obj)
294 return ERR_PTR(-ENOMEM);
295
296 obj = &rk_obj->base;
297
298 obj->funcs = &rockchip_gem_object_funcs;
299
300 drm_gem_object_init(drm, obj, size);
301
302 return rk_obj;
303 }
304
305 struct rockchip_gem_object *
rockchip_gem_create_object(struct drm_device * drm,unsigned int size,bool alloc_kmap)306 rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
307 bool alloc_kmap)
308 {
309 struct rockchip_gem_object *rk_obj;
310 int ret;
311
312 rk_obj = rockchip_gem_alloc_object(drm, size);
313 if (IS_ERR(rk_obj))
314 return rk_obj;
315
316 ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
317 if (ret)
318 goto err_free_rk_obj;
319
320 return rk_obj;
321
322 err_free_rk_obj:
323 rockchip_gem_release_object(rk_obj);
324 return ERR_PTR(ret);
325 }
326
327 /*
328 * rockchip_gem_free_object - (struct drm_gem_object_funcs)->free
329 * callback function
330 */
rockchip_gem_free_object(struct drm_gem_object * obj)331 void rockchip_gem_free_object(struct drm_gem_object *obj)
332 {
333 struct drm_device *drm = obj->dev;
334 struct rockchip_drm_private *private = drm->dev_private;
335 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
336
337 if (obj->import_attach) {
338 if (private->domain) {
339 rockchip_gem_iommu_unmap(rk_obj);
340 } else {
341 dma_unmap_sgtable(drm->dev, rk_obj->sgt,
342 DMA_BIDIRECTIONAL, 0);
343 }
344 drm_prime_gem_destroy(obj, rk_obj->sgt);
345 } else {
346 rockchip_gem_free_buf(rk_obj);
347 }
348
349 rockchip_gem_release_object(rk_obj);
350 }
351
352 /*
353 * rockchip_gem_create_with_handle - allocate an object with the given
354 * size and create a gem handle on it
355 *
356 * returns a struct rockchip_gem_object* on success or ERR_PTR values
357 * on failure.
358 */
359 static struct rockchip_gem_object *
rockchip_gem_create_with_handle(struct drm_file * file_priv,struct drm_device * drm,unsigned int size,unsigned int * handle)360 rockchip_gem_create_with_handle(struct drm_file *file_priv,
361 struct drm_device *drm, unsigned int size,
362 unsigned int *handle)
363 {
364 struct rockchip_gem_object *rk_obj;
365 struct drm_gem_object *obj;
366 bool is_framebuffer;
367 int ret;
368
369 is_framebuffer = drm->fb_helper && file_priv == drm->fb_helper->client.file;
370
371 rk_obj = rockchip_gem_create_object(drm, size, is_framebuffer);
372 if (IS_ERR(rk_obj))
373 return ERR_CAST(rk_obj);
374
375 obj = &rk_obj->base;
376
377 /*
378 * allocate a id of idr table where the obj is registered
379 * and handle has the id what user can see.
380 */
381 ret = drm_gem_handle_create(file_priv, obj, handle);
382 if (ret)
383 goto err_handle_create;
384
385 /* drop reference from allocate - handle holds it now. */
386 drm_gem_object_put(obj);
387
388 return rk_obj;
389
390 err_handle_create:
391 rockchip_gem_free_object(obj);
392
393 return ERR_PTR(ret);
394 }
395
396 /*
397 * rockchip_gem_dumb_create - (struct drm_driver)->dumb_create callback
398 * function
399 *
400 * This aligns the pitch and size arguments to the minimum required. wrap
401 * this into your own function if you need bigger alignment.
402 */
rockchip_gem_dumb_create(struct drm_file * file_priv,struct drm_device * dev,struct drm_mode_create_dumb * args)403 int rockchip_gem_dumb_create(struct drm_file *file_priv,
404 struct drm_device *dev,
405 struct drm_mode_create_dumb *args)
406 {
407 struct rockchip_gem_object *rk_obj;
408 int ret;
409
410 /* 64-byte alignment required by Mali */
411 ret = drm_mode_size_dumb(dev, args, SZ_64, 0);
412 if (ret)
413 return ret;
414
415 rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args->size,
416 &args->handle);
417
418 return PTR_ERR_OR_ZERO(rk_obj);
419 }
420
421 /*
422 * Allocate a sg_table for this GEM object.
423 * Note: Both the table's contents, and the sg_table itself must be freed by
424 * the caller.
425 * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error.
426 */
rockchip_gem_prime_get_sg_table(struct drm_gem_object * obj)427 struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
428 {
429 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
430 struct drm_device *drm = obj->dev;
431 struct sg_table *sgt;
432 int ret;
433
434 if (rk_obj->pages)
435 return drm_prime_pages_to_sg(obj->dev, rk_obj->pages, rk_obj->num_pages);
436
437 sgt = kzalloc_obj(*sgt);
438 if (!sgt)
439 return ERR_PTR(-ENOMEM);
440
441 ret = dma_get_sgtable_attrs(drm->dev, sgt, rk_obj->kvaddr,
442 rk_obj->dma_addr, obj->size,
443 rk_obj->dma_attrs);
444 if (ret) {
445 DRM_ERROR("failed to allocate sgt, %d\n", ret);
446 kfree(sgt);
447 return ERR_PTR(ret);
448 }
449
450 return sgt;
451 }
452
453 static int
rockchip_gem_iommu_map_sg(struct drm_device * drm,struct dma_buf_attachment * attach,struct sg_table * sg,struct rockchip_gem_object * rk_obj)454 rockchip_gem_iommu_map_sg(struct drm_device *drm,
455 struct dma_buf_attachment *attach,
456 struct sg_table *sg,
457 struct rockchip_gem_object *rk_obj)
458 {
459 rk_obj->sgt = sg;
460 return rockchip_gem_iommu_map(rk_obj);
461 }
462
463 static int
rockchip_gem_dma_map_sg(struct drm_device * drm,struct dma_buf_attachment * attach,struct sg_table * sg,struct rockchip_gem_object * rk_obj)464 rockchip_gem_dma_map_sg(struct drm_device *drm,
465 struct dma_buf_attachment *attach,
466 struct sg_table *sg,
467 struct rockchip_gem_object *rk_obj)
468 {
469 int err = dma_map_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
470 if (err)
471 return err;
472
473 if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) {
474 DRM_ERROR("failed to map sg_table to contiguous linear address.\n");
475 dma_unmap_sgtable(drm->dev, sg, DMA_BIDIRECTIONAL, 0);
476 return -EINVAL;
477 }
478
479 rk_obj->dma_addr = sg_dma_address(sg->sgl);
480 rk_obj->sgt = sg;
481 return 0;
482 }
483
484 struct drm_gem_object *
rockchip_gem_prime_import_sg_table(struct drm_device * drm,struct dma_buf_attachment * attach,struct sg_table * sg)485 rockchip_gem_prime_import_sg_table(struct drm_device *drm,
486 struct dma_buf_attachment *attach,
487 struct sg_table *sg)
488 {
489 struct rockchip_drm_private *private = drm->dev_private;
490 struct rockchip_gem_object *rk_obj;
491 int ret;
492
493 rk_obj = rockchip_gem_alloc_object(drm, attach->dmabuf->size);
494 if (IS_ERR(rk_obj))
495 return ERR_CAST(rk_obj);
496
497 if (private->domain)
498 ret = rockchip_gem_iommu_map_sg(drm, attach, sg, rk_obj);
499 else
500 ret = rockchip_gem_dma_map_sg(drm, attach, sg, rk_obj);
501
502 if (ret < 0) {
503 DRM_ERROR("failed to import sg table: %d\n", ret);
504 goto err_free_rk_obj;
505 }
506
507 return &rk_obj->base;
508
509 err_free_rk_obj:
510 rockchip_gem_release_object(rk_obj);
511 return ERR_PTR(ret);
512 }
513
rockchip_gem_prime_vmap(struct drm_gem_object * obj,struct iosys_map * map)514 int rockchip_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
515 {
516 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
517
518 if (rk_obj->pages) {
519 void *vaddr;
520
521 if (rk_obj->kvaddr)
522 vaddr = rk_obj->kvaddr;
523 else
524 vaddr = vmap(rk_obj->pages, rk_obj->num_pages, VM_MAP,
525 pgprot_writecombine(PAGE_KERNEL));
526
527 if (!vaddr)
528 return -ENOMEM;
529 iosys_map_set_vaddr(map, vaddr);
530 return 0;
531 }
532
533 if (rk_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING)
534 return -ENOMEM;
535 iosys_map_set_vaddr(map, rk_obj->kvaddr);
536
537 return 0;
538 }
539
rockchip_gem_prime_vunmap(struct drm_gem_object * obj,struct iosys_map * map)540 void rockchip_gem_prime_vunmap(struct drm_gem_object *obj,
541 struct iosys_map *map)
542 {
543 struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
544
545 if (rk_obj->pages) {
546 if (map->vaddr != rk_obj->kvaddr)
547 vunmap(map->vaddr);
548 return;
549 }
550
551 /* Nothing to do if allocated by DMA mapping API. */
552 }
553