xref: /dragonfly/sys/dev/drm/amd/amdgpu/amdgpu_gtt_mgr.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
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           struct spinlock 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  */
amdgpu_gtt_mgr_init(struct ttm_mem_type_manager * man,unsigned long p_size)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->gmc.gart_size >> PAGE_SHIFT) - start;
60           drm_mm_init(&mgr->mm, start, size);
61           spin_init(&mgr->lock, "aggmml");
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  */
amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager * man)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  */
amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg * mem)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  */
amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager * man,struct ttm_buffer_object * tbo,const struct ttm_place * place,struct ttm_mem_reg * mem)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  */
amdgpu_gtt_mgr_new(struct ttm_mem_type_manager * man,struct ttm_buffer_object * tbo,const struct ttm_place * place,struct ttm_mem_reg * mem)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  */
amdgpu_gtt_mgr_del(struct ttm_mem_type_manager * man,struct ttm_mem_reg * mem)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  */
amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager * man)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 
amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager * man)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  */
amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager * man,struct drm_printer * printer)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:%lu pages, gtt available:%lld pages, usage:%luMB\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 };
301