1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <drm/drmP.h>
26#include "amdgpu.h"
27
28struct amdgpu_gtt_mgr {
29 struct drm_mm mm;
30 spinlock_t lock;
31 uint64_t available;
32};
33
34
35
36
37
38
39
40
41
42static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
43 unsigned long p_size)
44{
45 struct amdgpu_gtt_mgr *mgr;
46
47 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
48 if (!mgr)
49 return -ENOMEM;
50
51 drm_mm_init(&mgr->mm, 0, p_size);
52 spin_lock_init(&mgr->lock);
53 mgr->available = p_size;
54 man->priv = mgr;
55 return 0;
56}
57
58
59
60
61
62
63
64
65
66static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
67{
68 struct amdgpu_gtt_mgr *mgr = man->priv;
69
70 spin_lock(&mgr->lock);
71 if (!drm_mm_clean(&mgr->mm)) {
72 spin_unlock(&mgr->lock);
73 return -EBUSY;
74 }
75
76 drm_mm_takedown(&mgr->mm);
77 spin_unlock(&mgr->lock);
78 kfree(mgr);
79 man->priv = NULL;
80 return 0;
81}
82
83
84
85
86
87
88
89
90
91
92
93int amdgpu_gtt_mgr_alloc(struct ttm_mem_type_manager *man,
94 struct ttm_buffer_object *tbo,
95 const struct ttm_place *place,
96 struct ttm_mem_reg *mem)
97{
98 struct amdgpu_gtt_mgr *mgr = man->priv;
99 struct drm_mm_node *node = mem->mm_node;
100 enum drm_mm_insert_mode mode;
101 unsigned long fpfn, lpfn;
102 int r;
103
104 if (node->start != AMDGPU_BO_INVALID_OFFSET)
105 return 0;
106
107 if (place)
108 fpfn = place->fpfn;
109 else
110 fpfn = 0;
111
112 if (place && place->lpfn)
113 lpfn = place->lpfn;
114 else
115 lpfn = man->size;
116
117 mode = DRM_MM_INSERT_BEST;
118 if (place && place->flags & TTM_PL_FLAG_TOPDOWN)
119 mode = DRM_MM_INSERT_HIGH;
120
121 spin_lock(&mgr->lock);
122 r = drm_mm_insert_node_in_range(&mgr->mm, node,
123 mem->num_pages, mem->page_alignment, 0,
124 fpfn, lpfn, mode);
125 spin_unlock(&mgr->lock);
126
127 if (!r) {
128 mem->start = node->start;
129 if (&tbo->mem == mem)
130 tbo->offset = (tbo->mem.start << PAGE_SHIFT) +
131 tbo->bdev->man[tbo->mem.mem_type].gpu_offset;
132 }
133
134 return r;
135}
136
137void amdgpu_gtt_mgr_print(struct seq_file *m, struct ttm_mem_type_manager *man)
138{
139 struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
140 struct amdgpu_gtt_mgr *mgr = man->priv;
141
142 seq_printf(m, "man size:%llu pages, gtt available:%llu pages, usage:%lluMB\n",
143 man->size, mgr->available, (u64)atomic64_read(&adev->gtt_usage) >> 20);
144
145}
146
147
148
149
150
151
152
153
154
155
156static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
157 struct ttm_buffer_object *tbo,
158 const struct ttm_place *place,
159 struct ttm_mem_reg *mem)
160{
161 struct amdgpu_gtt_mgr *mgr = man->priv;
162 struct drm_mm_node *node;
163 int r;
164
165 spin_lock(&mgr->lock);
166 if (mgr->available < mem->num_pages) {
167 spin_unlock(&mgr->lock);
168 return 0;
169 }
170 mgr->available -= mem->num_pages;
171 spin_unlock(&mgr->lock);
172
173 node = kzalloc(sizeof(*node), GFP_KERNEL);
174 if (!node) {
175 r = -ENOMEM;
176 goto err_out;
177 }
178
179 node->start = AMDGPU_BO_INVALID_OFFSET;
180 node->size = mem->num_pages;
181 mem->mm_node = node;
182
183 if (place->fpfn || place->lpfn || place->flags & TTM_PL_FLAG_TOPDOWN) {
184 r = amdgpu_gtt_mgr_alloc(man, tbo, place, mem);
185 if (unlikely(r)) {
186 kfree(node);
187 mem->mm_node = NULL;
188 r = 0;
189 goto err_out;
190 }
191 } else {
192 mem->start = node->start;
193 }
194
195 return 0;
196err_out:
197 spin_lock(&mgr->lock);
198 mgr->available += mem->num_pages;
199 spin_unlock(&mgr->lock);
200
201 return r;
202}
203
204
205
206
207
208
209
210
211
212
213
214static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
215 struct ttm_mem_reg *mem)
216{
217 struct amdgpu_gtt_mgr *mgr = man->priv;
218 struct drm_mm_node *node = mem->mm_node;
219
220 if (!node)
221 return;
222
223 spin_lock(&mgr->lock);
224 if (node->start != AMDGPU_BO_INVALID_OFFSET)
225 drm_mm_remove_node(node);
226 mgr->available += mem->num_pages;
227 spin_unlock(&mgr->lock);
228
229 kfree(node);
230 mem->mm_node = NULL;
231}
232
233
234
235
236
237
238
239
240
241static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
242 const char *prefix)
243{
244 struct amdgpu_gtt_mgr *mgr = man->priv;
245 struct drm_printer p = drm_debug_printer(prefix);
246
247 spin_lock(&mgr->lock);
248 drm_mm_print(&mgr->mm, &p);
249 spin_unlock(&mgr->lock);
250}
251
252const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = {
253 .init = amdgpu_gtt_mgr_init,
254 .takedown = amdgpu_gtt_mgr_fini,
255 .get_node = amdgpu_gtt_mgr_new,
256 .put_node = amdgpu_gtt_mgr_del,
257 .debug = amdgpu_gtt_mgr_debug
258};
259