Merge tag 'media/v4.16-4' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_gtt_mgr.c
1 /*
2  * Copyright 2016 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Christian König
23  */
24
25 #include <drm/drmP.h>
26 #include "amdgpu.h"
27
28 struct amdgpu_gtt_mgr {
29         struct drm_mm mm;
30         spinlock_t lock;
31         atomic64_t available;
32 };
33
34 struct amdgpu_gtt_node {
35         struct drm_mm_node node;
36         struct ttm_buffer_object *tbo;
37 };
38
39 /**
40  * amdgpu_gtt_mgr_init - init GTT manager and DRM MM
41  *
42  * @man: TTM memory type manager
43  * @p_size: maximum size of GTT
44  *
45  * Allocate and initialize the GTT manager.
46  */
47 static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
48                                unsigned long p_size)
49 {
50         struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
51         struct amdgpu_gtt_mgr *mgr;
52         uint64_t start, size;
53
54         mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
55         if (!mgr)
56                 return -ENOMEM;
57
58         start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
59         size = (adev->mc.gart_size >> PAGE_SHIFT) - start;
60         drm_mm_init(&mgr->mm, start, size);
61         spin_lock_init(&mgr->lock);
62         atomic64_set(&mgr->available, p_size);
63         man->priv = mgr;
64         return 0;
65 }
66
67 /**
68  * amdgpu_gtt_mgr_fini - free and destroy GTT manager
69  *
70  * @man: TTM memory type manager
71  *
72  * Destroy and free the GTT manager, returns -EBUSY if ranges are still
73  * allocated inside it.
74  */
75 static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
76 {
77         struct amdgpu_gtt_mgr *mgr = man->priv;
78         spin_lock(&mgr->lock);
79         drm_mm_takedown(&mgr->mm);
80         spin_unlock(&mgr->lock);
81         kfree(mgr);
82         man->priv = NULL;
83         return 0;
84 }
85
86 /**
87  * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space
88  *
89  * @mem: the mem object to check
90  *
91  * Check if a mem object has already address space allocated.
92  */
93 bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem)
94 {
95         struct amdgpu_gtt_node *node = mem->mm_node;
96
97         return (node->node.start != AMDGPU_BO_INVALID_OFFSET);
98 }
99
100 /**
101  * amdgpu_gtt_mgr_alloc - allocate new ranges
102  *
103  * @man: TTM memory type manager
104  * @tbo: TTM BO we need this range for
105  * @place: placement flags and restrictions
106  * @mem: the resulting mem object
107  *
108  * Allocate the address space for a node.
109  */
110 static int amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager *man,
111                                 struct ttm_buffer_object *tbo,
112                                 const struct ttm_place *place,
113                                 struct ttm_mem_reg *mem)
114 {
115         struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
116         struct amdgpu_gtt_mgr *mgr = man->priv;
117         struct amdgpu_gtt_node *node = mem->mm_node;
118         enum drm_mm_insert_mode mode;
119         unsigned long fpfn, lpfn;
120         int r;
121
122         if (amdgpu_gtt_mgr_has_gart_addr(mem))
123                 return 0;
124
125         if (place)
126                 fpfn = place->fpfn;
127         else
128                 fpfn = 0;
129
130         if (place && place->lpfn)
131                 lpfn = place->lpfn;
132         else
133                 lpfn = adev->gart.num_cpu_pages;
134
135         mode = DRM_MM_INSERT_BEST;
136         if (place && place->flags & TTM_PL_FLAG_TOPDOWN)
137                 mode = DRM_MM_INSERT_HIGH;
138
139         spin_lock(&mgr->lock);
140         r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages,
141                                         mem->page_alignment, 0, fpfn, lpfn,
142                                         mode);
143         spin_unlock(&mgr->lock);
144
145         if (!r)
146                 mem->start = node->node.start;
147
148         return r;
149 }
150
151 /**
152  * amdgpu_gtt_mgr_new - allocate a new node
153  *
154  * @man: TTM memory type manager
155  * @tbo: TTM BO we need this range for
156  * @place: placement flags and restrictions
157  * @mem: the resulting mem object
158  *
159  * Dummy, allocate the node but no space for it yet.
160  */
161 static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
162                               struct ttm_buffer_object *tbo,
163                               const struct ttm_place *place,
164                               struct ttm_mem_reg *mem)
165 {
166         struct amdgpu_gtt_mgr *mgr = man->priv;
167         struct amdgpu_gtt_node *node;
168         int r;
169
170         spin_lock(&mgr->lock);
171         if ((&tbo->mem == mem || tbo->mem.mem_type != TTM_PL_TT) &&
172             atomic64_read(&mgr->available) < mem->num_pages) {
173                 spin_unlock(&mgr->lock);
174                 return 0;
175         }
176         atomic64_sub(mem->num_pages, &mgr->available);
177         spin_unlock(&mgr->lock);
178
179         node = kzalloc(sizeof(*node), GFP_KERNEL);
180         if (!node) {
181                 r = -ENOMEM;
182                 goto err_out;
183         }
184
185         node->node.start = AMDGPU_BO_INVALID_OFFSET;
186         node->node.size = mem->num_pages;
187         node->tbo = tbo;
188         mem->mm_node = node;
189
190         if (place->fpfn || place->lpfn || place->flags & TTM_PL_FLAG_TOPDOWN) {
191                 r = amdgpu_gtt_mgr_alloc(man, tbo, place, mem);
192                 if (unlikely(r)) {
193                         kfree(node);
194                         mem->mm_node = NULL;
195                         r = 0;
196                         goto err_out;
197                 }
198         } else {
199                 mem->start = node->node.start;
200         }
201
202         return 0;
203 err_out:
204         atomic64_add(mem->num_pages, &mgr->available);
205
206         return r;
207 }
208
209 /**
210  * amdgpu_gtt_mgr_del - free ranges
211  *
212  * @man: TTM memory type manager
213  * @tbo: TTM BO we need this range for
214  * @place: placement flags and restrictions
215  * @mem: TTM memory object
216  *
217  * Free the allocated GTT again.
218  */
219 static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
220                                struct ttm_mem_reg *mem)
221 {
222         struct amdgpu_gtt_mgr *mgr = man->priv;
223         struct amdgpu_gtt_node *node = mem->mm_node;
224
225         if (!node)
226                 return;
227
228         spin_lock(&mgr->lock);
229         if (node->node.start != AMDGPU_BO_INVALID_OFFSET)
230                 drm_mm_remove_node(&node->node);
231         spin_unlock(&mgr->lock);
232         atomic64_add(mem->num_pages, &mgr->available);
233
234         kfree(node);
235         mem->mm_node = NULL;
236 }
237
238 /**
239  * amdgpu_gtt_mgr_usage - return usage of GTT domain
240  *
241  * @man: TTM memory type manager
242  *
243  * Return how many bytes are used in the GTT domain
244  */
245 uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man)
246 {
247         struct amdgpu_gtt_mgr *mgr = man->priv;
248         s64 result = man->size - atomic64_read(&mgr->available);
249
250         return (result > 0 ? result : 0) * PAGE_SIZE;
251 }
252
253 int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man)
254 {
255         struct amdgpu_gtt_mgr *mgr = man->priv;
256         struct amdgpu_gtt_node *node;
257         struct drm_mm_node *mm_node;
258         int r = 0;
259
260         spin_lock(&mgr->lock);
261         drm_mm_for_each_node(mm_node, &mgr->mm) {
262                 node = container_of(mm_node, struct amdgpu_gtt_node, node);
263                 r = amdgpu_ttm_recover_gart(node->tbo);
264                 if (r)
265                         break;
266         }
267         spin_unlock(&mgr->lock);
268
269         return r;
270 }
271
272 /**
273  * amdgpu_gtt_mgr_debug - dump VRAM table
274  *
275  * @man: TTM memory type manager
276  * @printer: DRM printer to use
277  *
278  * Dump the table content using printk.
279  */
280 static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
281                                  struct drm_printer *printer)
282 {
283         struct amdgpu_gtt_mgr *mgr = man->priv;
284
285         spin_lock(&mgr->lock);
286         drm_mm_print(&mgr->mm, printer);
287         spin_unlock(&mgr->lock);
288
289         drm_printf(printer, "man size:%llu pages, gtt available:%lld pages, usage:%lluMB\n",
290                    man->size, (u64)atomic64_read(&mgr->available),
291                    amdgpu_gtt_mgr_usage(man) >> 20);
292 }
293
294 const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = {
295         .init = amdgpu_gtt_mgr_init,
296         .takedown = amdgpu_gtt_mgr_fini,
297         .get_node = amdgpu_gtt_mgr_new,
298         .put_node = amdgpu_gtt_mgr_del,
299         .debug = amdgpu_gtt_mgr_debug
300 };