Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / lima / lima_object.c
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */
3
4 #include <drm/drm_prime.h>
5 #include <linux/pagemap.h>
6 #include <linux/dma-mapping.h>
7
8 #include "lima_object.h"
9
10 void lima_bo_destroy(struct lima_bo *bo)
11 {
12         if (bo->sgt) {
13                 kfree(bo->pages);
14                 drm_prime_gem_destroy(&bo->gem, bo->sgt);
15         } else {
16                 if (bo->pages_dma_addr) {
17                         int i, npages = bo->gem.size >> PAGE_SHIFT;
18
19                         for (i = 0; i < npages; i++) {
20                                 if (bo->pages_dma_addr[i])
21                                         dma_unmap_page(bo->gem.dev->dev,
22                                                        bo->pages_dma_addr[i],
23                                                        PAGE_SIZE, DMA_BIDIRECTIONAL);
24                         }
25                 }
26
27                 if (bo->pages)
28                         drm_gem_put_pages(&bo->gem, bo->pages, true, true);
29         }
30
31         kfree(bo->pages_dma_addr);
32         drm_gem_object_release(&bo->gem);
33         kfree(bo);
34 }
35
36 static struct lima_bo *lima_bo_create_struct(struct lima_device *dev, u32 size, u32 flags,
37                                              struct reservation_object *resv)
38 {
39         struct lima_bo *bo;
40         int err;
41
42         size = PAGE_ALIGN(size);
43
44         bo = kzalloc(sizeof(*bo), GFP_KERNEL);
45         if (!bo)
46                 return ERR_PTR(-ENOMEM);
47
48         mutex_init(&bo->lock);
49         INIT_LIST_HEAD(&bo->va);
50         bo->gem.resv = resv;
51
52         err = drm_gem_object_init(dev->ddev, &bo->gem, size);
53         if (err) {
54                 kfree(bo);
55                 return ERR_PTR(err);
56         }
57
58         return bo;
59 }
60
61 struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size,
62                                u32 flags, struct sg_table *sgt,
63                                struct reservation_object *resv)
64 {
65         int i, err;
66         size_t npages;
67         struct lima_bo *bo, *ret;
68
69         bo = lima_bo_create_struct(dev, size, flags, resv);
70         if (IS_ERR(bo))
71                 return bo;
72
73         npages = bo->gem.size >> PAGE_SHIFT;
74
75         bo->pages_dma_addr = kcalloc(npages, sizeof(dma_addr_t), GFP_KERNEL);
76         if (!bo->pages_dma_addr) {
77                 ret = ERR_PTR(-ENOMEM);
78                 goto err_out;
79         }
80
81         if (sgt) {
82                 bo->sgt = sgt;
83
84                 bo->pages = kcalloc(npages, sizeof(*bo->pages), GFP_KERNEL);
85                 if (!bo->pages) {
86                         ret = ERR_PTR(-ENOMEM);
87                         goto err_out;
88                 }
89
90                 err = drm_prime_sg_to_page_addr_arrays(
91                         sgt, bo->pages, bo->pages_dma_addr, npages);
92                 if (err) {
93                         ret = ERR_PTR(err);
94                         goto err_out;
95                 }
96         } else {
97                 mapping_set_gfp_mask(bo->gem.filp->f_mapping, GFP_DMA32);
98                 bo->pages = drm_gem_get_pages(&bo->gem);
99                 if (IS_ERR(bo->pages)) {
100                         ret = ERR_CAST(bo->pages);
101                         bo->pages = NULL;
102                         goto err_out;
103                 }
104
105                 for (i = 0; i < npages; i++) {
106                         dma_addr_t addr = dma_map_page(dev->dev, bo->pages[i], 0,
107                                                        PAGE_SIZE, DMA_BIDIRECTIONAL);
108                         if (dma_mapping_error(dev->dev, addr)) {
109                                 ret = ERR_PTR(-EFAULT);
110                                 goto err_out;
111                         }
112                         bo->pages_dma_addr[i] = addr;
113                 }
114
115         }
116
117         return bo;
118
119 err_out:
120         lima_bo_destroy(bo);
121         return ret;
122 }