diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c new file mode 100644 index 000000000000..262e872bea0e --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | |||
@@ -0,0 +1,238 @@ | |||
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; | ||
131 | tbo->offset = (tbo->mem.start << PAGE_SHIFT) + | ||
132 | tbo->bdev->man[tbo->mem.mem_type].gpu_offset; | ||
133 | } | ||
134 | |||
135 | return r; | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * amdgpu_gtt_mgr_new - allocate a new node | ||
140 | * | ||
141 | * @man: TTM memory type manager | ||
142 | * @tbo: TTM BO we need this range for | ||
143 | * @place: placement flags and restrictions | ||
144 | * @mem: the resulting mem object | ||
145 | * | ||
146 | * Dummy, allocate the node but no space for it yet. | ||
147 | */ | ||
148 | static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man, | ||
149 | struct ttm_buffer_object *tbo, | ||
150 | const struct ttm_place *place, | ||
151 | struct ttm_mem_reg *mem) | ||
152 | { | ||
153 | struct amdgpu_gtt_mgr *mgr = man->priv; | ||
154 | struct drm_mm_node *node; | ||
155 | int r; | ||
156 | |||
157 | spin_lock(&mgr->lock); | ||
158 | if (mgr->available < mem->num_pages) { | ||
159 | spin_unlock(&mgr->lock); | ||
160 | return 0; | ||
161 | } | ||
162 | mgr->available -= mem->num_pages; | ||
163 | spin_unlock(&mgr->lock); | ||
164 | |||
165 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
166 | if (!node) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | node->start = AMDGPU_BO_INVALID_OFFSET; | ||
170 | mem->mm_node = node; | ||
171 | |||
172 | if (place->fpfn || place->lpfn || place->flags & TTM_PL_FLAG_TOPDOWN) { | ||
173 | r = amdgpu_gtt_mgr_alloc(man, tbo, place, mem); | ||
174 | if (unlikely(r)) { | ||
175 | kfree(node); | ||
176 | mem->mm_node = NULL; | ||
177 | } | ||
178 | } else { | ||
179 | mem->start = node->start; | ||
180 | } | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * amdgpu_gtt_mgr_del - free ranges | ||
187 | * | ||
188 | * @man: TTM memory type manager | ||
189 | * @tbo: TTM BO we need this range for | ||
190 | * @place: placement flags and restrictions | ||
191 | * @mem: TTM memory object | ||
192 | * | ||
193 | * Free the allocated GTT again. | ||
194 | */ | ||
195 | static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, | ||
196 | struct ttm_mem_reg *mem) | ||
197 | { | ||
198 | struct amdgpu_gtt_mgr *mgr = man->priv; | ||
199 | struct drm_mm_node *node = mem->mm_node; | ||
200 | |||
201 | if (!node) | ||
202 | return; | ||
203 | |||
204 | spin_lock(&mgr->lock); | ||
205 | if (node->start != AMDGPU_BO_INVALID_OFFSET) | ||
206 | drm_mm_remove_node(node); | ||
207 | mgr->available += mem->num_pages; | ||
208 | spin_unlock(&mgr->lock); | ||
209 | |||
210 | kfree(node); | ||
211 | mem->mm_node = NULL; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * amdgpu_gtt_mgr_debug - dump VRAM table | ||
216 | * | ||
217 | * @man: TTM memory type manager | ||
218 | * @prefix: text prefix | ||
219 | * | ||
220 | * Dump the table content using printk. | ||
221 | */ | ||
222 | static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, | ||
223 | const char *prefix) | ||
224 | { | ||
225 | struct amdgpu_gtt_mgr *mgr = man->priv; | ||
226 | |||
227 | spin_lock(&mgr->lock); | ||
228 | drm_mm_debug_table(&mgr->mm, prefix); | ||
229 | spin_unlock(&mgr->lock); | ||
230 | } | ||
231 | |||
232 | const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = { | ||
233 | amdgpu_gtt_mgr_init, | ||
234 | amdgpu_gtt_mgr_fini, | ||
235 | amdgpu_gtt_mgr_new, | ||
236 | amdgpu_gtt_mgr_del, | ||
237 | amdgpu_gtt_mgr_debug | ||
238 | }; | ||