1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include <mali_kbase.h>
23 #include <mali_kbase_mem_linux.h>
24 #include <mali_kbase_defs.h>
25 #include <mali_kbase_trace_gpu_mem.h>
26
27 /**
28 * struct kbase_dma_buf - Object instantiated when a dma-buf imported allocation
29 * is mapped to GPU for the first time within a process.
30 * Another instantiation is done for the case when that
31 * allocation is mapped for the first time to GPU.
32 *
33 * @dma_buf: Reference to dma_buf been imported.
34 * @dma_buf_node: Link node to maintain a rb_tree of kbase_dma_buf.
35 * @import_count: The number of times the dma_buf was imported.
36 */
37 struct kbase_dma_buf {
38 struct dma_buf *dma_buf;
39 struct rb_node dma_buf_node;
40 u32 import_count;
41 };
42
43 /**
44 * kbase_delete_dma_buf_mapping - Delete a dma buffer mapping.
45 *
46 * @kctx: Pointer to kbase context.
47 * @dma_buf: Pointer to a dma buffer mapping.
48 * @tree: Pointer to root of rb_tree containing the dma_buf's mapped.
49 *
50 * when we un-map any dma mapping we need to remove them from rb_tree,
51 * rb_tree is maintained at kbase_device level and kbase_process level
52 * by passing the root of kbase_device or kbase_process we can remove
53 * the node from the tree.
54 *
55 * Return: true on success.
56 */
kbase_delete_dma_buf_mapping(struct kbase_context * kctx,struct dma_buf * dma_buf,struct rb_root * tree)57 static bool kbase_delete_dma_buf_mapping(struct kbase_context *kctx,
58 struct dma_buf *dma_buf,
59 struct rb_root *tree)
60 {
61 struct kbase_dma_buf *buf_node = NULL;
62 struct rb_node *node = tree->rb_node;
63 bool mapping_removed = false;
64
65 lockdep_assert_held(&kctx->kbdev->dma_buf_lock);
66
67 while (node) {
68 buf_node = rb_entry(node, struct kbase_dma_buf, dma_buf_node);
69
70 if (dma_buf == buf_node->dma_buf) {
71 WARN_ON(!buf_node->import_count);
72
73 buf_node->import_count--;
74
75 if (!buf_node->import_count) {
76 rb_erase(&buf_node->dma_buf_node, tree);
77 kfree(buf_node);
78 mapping_removed = true;
79 }
80
81 break;
82 }
83
84 if (dma_buf < buf_node->dma_buf)
85 node = node->rb_left;
86 else
87 node = node->rb_right;
88 }
89
90 WARN_ON(!buf_node);
91 return mapping_removed;
92 }
93
94 /**
95 * kbase_capture_dma_buf_mapping - capture a dma buffer mapping.
96 *
97 * @kctx: Pointer to kbase context.
98 * @dma_buf: Pointer to a dma buffer mapping.
99 * @root: Pointer to root of rb_tree containing the dma_buf's.
100 *
101 * We maintain a kbase_device level and kbase_process level rb_tree
102 * of all unique dma_buf's mapped to gpu memory. So when attach any
103 * dma_buf add it the rb_tree's. To add the unique mapping we need
104 * check if the mapping is not a duplicate and then add them.
105 *
106 * Return: true on success
107 */
kbase_capture_dma_buf_mapping(struct kbase_context * kctx,struct dma_buf * dma_buf,struct rb_root * root)108 static bool kbase_capture_dma_buf_mapping(struct kbase_context *kctx,
109 struct dma_buf *dma_buf,
110 struct rb_root *root)
111 {
112 struct kbase_dma_buf *buf_node = NULL;
113 struct rb_node *node = root->rb_node;
114 bool unique_buf_imported = true;
115
116 lockdep_assert_held(&kctx->kbdev->dma_buf_lock);
117
118 while (node) {
119 buf_node = rb_entry(node, struct kbase_dma_buf, dma_buf_node);
120
121 if (dma_buf == buf_node->dma_buf) {
122 unique_buf_imported = false;
123 break;
124 }
125
126 if (dma_buf < buf_node->dma_buf)
127 node = node->rb_left;
128 else
129 node = node->rb_right;
130 }
131
132 if (unique_buf_imported) {
133 struct kbase_dma_buf *new_buf_node =
134 kzalloc(sizeof(*new_buf_node), GFP_KERNEL);
135
136 if (new_buf_node == NULL) {
137 dev_err(kctx->kbdev->dev, "Error allocating memory for kbase_dma_buf\n");
138 /* Dont account for it if we fail to allocate memory */
139 unique_buf_imported = false;
140 } else {
141 struct rb_node **new = &(root->rb_node), *parent = NULL;
142
143 new_buf_node->dma_buf = dma_buf;
144 new_buf_node->import_count = 1;
145 while (*new) {
146 struct kbase_dma_buf *new_node;
147
148 parent = *new;
149 new_node = rb_entry(parent, struct kbase_dma_buf,
150 dma_buf_node);
151 if (dma_buf < new_node->dma_buf)
152 new = &(*new)->rb_left;
153 else
154 new = &(*new)->rb_right;
155 }
156 rb_link_node(&new_buf_node->dma_buf_node, parent, new);
157 rb_insert_color(&new_buf_node->dma_buf_node, root);
158 }
159 } else if (!WARN_ON(!buf_node)) {
160 buf_node->import_count++;
161 }
162
163 return unique_buf_imported;
164 }
165
kbase_remove_dma_buf_usage(struct kbase_context * kctx,struct kbase_mem_phy_alloc * alloc)166 void kbase_remove_dma_buf_usage(struct kbase_context *kctx,
167 struct kbase_mem_phy_alloc *alloc)
168 {
169 struct kbase_device *kbdev = kctx->kbdev;
170 bool dev_mapping_removed, prcs_mapping_removed;
171
172 mutex_lock(&kbdev->dma_buf_lock);
173
174 dev_mapping_removed = kbase_delete_dma_buf_mapping(
175 kctx, alloc->imported.umm.dma_buf, &kbdev->dma_buf_root);
176
177 prcs_mapping_removed = kbase_delete_dma_buf_mapping(
178 kctx, alloc->imported.umm.dma_buf, &kctx->kprcs->dma_buf_root);
179
180 WARN_ON(dev_mapping_removed && !prcs_mapping_removed);
181
182 spin_lock(&kbdev->gpu_mem_usage_lock);
183 if (dev_mapping_removed)
184 kbdev->total_gpu_pages -= alloc->nents;
185
186 if (prcs_mapping_removed)
187 kctx->kprcs->total_gpu_pages -= alloc->nents;
188
189 if (dev_mapping_removed || prcs_mapping_removed)
190 kbase_trace_gpu_mem_usage(kbdev, kctx);
191 spin_unlock(&kbdev->gpu_mem_usage_lock);
192
193 mutex_unlock(&kbdev->dma_buf_lock);
194 }
195
kbase_add_dma_buf_usage(struct kbase_context * kctx,struct kbase_mem_phy_alloc * alloc)196 void kbase_add_dma_buf_usage(struct kbase_context *kctx,
197 struct kbase_mem_phy_alloc *alloc)
198 {
199 struct kbase_device *kbdev = kctx->kbdev;
200 bool unique_dev_dmabuf, unique_prcs_dmabuf;
201
202 mutex_lock(&kbdev->dma_buf_lock);
203
204 /* add dma_buf to device and process. */
205 unique_dev_dmabuf = kbase_capture_dma_buf_mapping(
206 kctx, alloc->imported.umm.dma_buf, &kbdev->dma_buf_root);
207
208 unique_prcs_dmabuf = kbase_capture_dma_buf_mapping(
209 kctx, alloc->imported.umm.dma_buf, &kctx->kprcs->dma_buf_root);
210
211 WARN_ON(unique_dev_dmabuf && !unique_prcs_dmabuf);
212
213 spin_lock(&kbdev->gpu_mem_usage_lock);
214 if (unique_dev_dmabuf)
215 kbdev->total_gpu_pages += alloc->nents;
216
217 if (unique_prcs_dmabuf)
218 kctx->kprcs->total_gpu_pages += alloc->nents;
219
220 if (unique_prcs_dmabuf || unique_dev_dmabuf)
221 kbase_trace_gpu_mem_usage(kbdev, kctx);
222 spin_unlock(&kbdev->gpu_mem_usage_lock);
223
224 mutex_unlock(&kbdev->dma_buf_lock);
225 }
226