]>
Commit | Line | Data |
---|---|---|
bb990bb0 CK |
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 | uint64_t available; | |
32 | }; | |
33 | ||
34 | /** | |
35 | * amdgpu_gtt_mgr_init - init GTT manager and DRM MM | |
36 | * | |
37 | * @man: TTM memory type manager | |
38 | * @p_size: maximum size of GTT | |
39 | * | |
40 | * Allocate and initialize the GTT manager. | |
41 | */ | |
42 | static 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 | * amdgpu_gtt_mgr_fini - free and destroy GTT manager | |
60 | * | |
61 | * @man: TTM memory type manager | |
62 | * | |
63 | * Destroy and free the GTT manager, returns -EBUSY if ranges are still | |
64 | * allocated inside it. | |
65 | */ | |
66 | static 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 | * amdgpu_gtt_mgr_alloc - allocate new ranges | |
85 | * | |
86 | * @man: TTM memory type manager | |
87 | * @tbo: TTM BO we need this range for | |
88 | * @place: placement flags and restrictions | |
89 | * @mem: the resulting mem object | |
90 | * | |
91 | * Allocate the address space for a node. | |
92 | */ | |
93 | int 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_search_flags sflags = DRM_MM_SEARCH_BEST; | |
101 | enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; | |
102 | unsigned long fpfn, lpfn; | |
103 | int r; | |
104 | ||
105 | if (node->start != AMDGPU_BO_INVALID_OFFSET) | |
106 | return 0; | |
107 | ||
108 | if (place) | |
109 | fpfn = place->fpfn; | |
110 | else | |
111 | fpfn = 0; | |
112 | ||
113 | if (place && place->lpfn) | |
114 | lpfn = place->lpfn; | |
115 | else | |
116 | lpfn = man->size; | |
117 | ||
118 | if (place && place->flags & TTM_PL_FLAG_TOPDOWN) { | |
119 | sflags = DRM_MM_SEARCH_BELOW; | |
120 | aflags = DRM_MM_CREATE_TOP; | |
121 | } | |
122 | ||
123 | spin_lock(&mgr->lock); | |
124 | r = drm_mm_insert_node_in_range_generic(&mgr->mm, node, mem->num_pages, | |
125 | mem->page_alignment, 0, | |
126 | fpfn, lpfn, sflags, aflags); | |
127 | spin_unlock(&mgr->lock); | |
128 | ||
129 | if (!r) { | |
130 | mem->start = node->start; | |
81597303 FC |
131 | if (&tbo->mem == mem) |
132 | tbo->offset = (tbo->mem.start << PAGE_SHIFT) + | |
133 | tbo->bdev->man[tbo->mem.mem_type].gpu_offset; | |
bb990bb0 CK |
134 | } |
135 | ||
136 | return r; | |
137 | } | |
138 | ||
139 | /** | |
140 | * amdgpu_gtt_mgr_new - allocate a new node | |
141 | * | |
142 | * @man: TTM memory type manager | |
143 | * @tbo: TTM BO we need this range for | |
144 | * @place: placement flags and restrictions | |
145 | * @mem: the resulting mem object | |
146 | * | |
147 | * Dummy, allocate the node but no space for it yet. | |
148 | */ | |
149 | static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man, | |
150 | struct ttm_buffer_object *tbo, | |
151 | const struct ttm_place *place, | |
152 | struct ttm_mem_reg *mem) | |
153 | { | |
154 | struct amdgpu_gtt_mgr *mgr = man->priv; | |
155 | struct drm_mm_node *node; | |
156 | int r; | |
157 | ||
158 | spin_lock(&mgr->lock); | |
159 | if (mgr->available < mem->num_pages) { | |
160 | spin_unlock(&mgr->lock); | |
161 | return 0; | |
162 | } | |
163 | mgr->available -= mem->num_pages; | |
164 | spin_unlock(&mgr->lock); | |
165 | ||
166 | node = kzalloc(sizeof(*node), GFP_KERNEL); | |
47e50d5c FC |
167 | if (!node) { |
168 | r = -ENOMEM; | |
169 | goto err_out; | |
170 | } | |
bb990bb0 CK |
171 | |
172 | node->start = AMDGPU_BO_INVALID_OFFSET; | |
d2e93870 | 173 | node->size = mem->num_pages; |
bb990bb0 CK |
174 | mem->mm_node = node; |
175 | ||
176 | if (place->fpfn || place->lpfn || place->flags & TTM_PL_FLAG_TOPDOWN) { | |
177 | r = amdgpu_gtt_mgr_alloc(man, tbo, place, mem); | |
178 | if (unlikely(r)) { | |
179 | kfree(node); | |
180 | mem->mm_node = NULL; | |
47e50d5c FC |
181 | r = 0; |
182 | goto err_out; | |
bb990bb0 CK |
183 | } |
184 | } else { | |
185 | mem->start = node->start; | |
186 | } | |
187 | ||
188 | return 0; | |
47e50d5c FC |
189 | err_out: |
190 | spin_lock(&mgr->lock); | |
191 | mgr->available += mem->num_pages; | |
192 | spin_unlock(&mgr->lock); | |
193 | ||
194 | return r; | |
bb990bb0 CK |
195 | } |
196 | ||
197 | /** | |
198 | * amdgpu_gtt_mgr_del - free ranges | |
199 | * | |
200 | * @man: TTM memory type manager | |
201 | * @tbo: TTM BO we need this range for | |
202 | * @place: placement flags and restrictions | |
203 | * @mem: TTM memory object | |
204 | * | |
205 | * Free the allocated GTT again. | |
206 | */ | |
207 | static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, | |
208 | struct ttm_mem_reg *mem) | |
209 | { | |
210 | struct amdgpu_gtt_mgr *mgr = man->priv; | |
211 | struct drm_mm_node *node = mem->mm_node; | |
212 | ||
213 | if (!node) | |
214 | return; | |
215 | ||
216 | spin_lock(&mgr->lock); | |
217 | if (node->start != AMDGPU_BO_INVALID_OFFSET) | |
218 | drm_mm_remove_node(node); | |
219 | mgr->available += mem->num_pages; | |
220 | spin_unlock(&mgr->lock); | |
221 | ||
222 | kfree(node); | |
223 | mem->mm_node = NULL; | |
224 | } | |
225 | ||
226 | /** | |
227 | * amdgpu_gtt_mgr_debug - dump VRAM table | |
228 | * | |
229 | * @man: TTM memory type manager | |
230 | * @prefix: text prefix | |
231 | * | |
232 | * Dump the table content using printk. | |
233 | */ | |
234 | static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, | |
235 | const char *prefix) | |
236 | { | |
237 | struct amdgpu_gtt_mgr *mgr = man->priv; | |
b5c3714f | 238 | struct drm_printer p = drm_debug_printer(prefix); |
bb990bb0 CK |
239 | |
240 | spin_lock(&mgr->lock); | |
b5c3714f | 241 | drm_mm_print(&mgr->mm, &p); |
bb990bb0 CK |
242 | spin_unlock(&mgr->lock); |
243 | } | |
244 | ||
245 | const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = { | |
246 | amdgpu_gtt_mgr_init, | |
247 | amdgpu_gtt_mgr_fini, | |
248 | amdgpu_gtt_mgr_new, | |
249 | amdgpu_gtt_mgr_del, | |
250 | amdgpu_gtt_mgr_debug | |
251 | }; |