diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c new file mode 100644 index 000000000000..180eed7c8bca --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | |||
@@ -0,0 +1,222 @@ | |||
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_vram_mgr { | ||
29 | struct drm_mm mm; | ||
30 | spinlock_t lock; | ||
31 | }; | ||
32 | |||
33 | /** | ||
34 | * amdgpu_vram_mgr_init - init VRAM manager and DRM MM | ||
35 | * | ||
36 | * @man: TTM memory type manager | ||
37 | * @p_size: maximum size of VRAM | ||
38 | * | ||
39 | * Allocate and initialize the VRAM manager. | ||
40 | */ | ||
41 | static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, | ||
42 | unsigned long p_size) | ||
43 | { | ||
44 | struct amdgpu_vram_mgr *mgr; | ||
45 | |||
46 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | ||
47 | if (!mgr) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | drm_mm_init(&mgr->mm, 0, p_size); | ||
51 | spin_lock_init(&mgr->lock); | ||
52 | man->priv = mgr; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * amdgpu_vram_mgr_fini - free and destroy VRAM manager | ||
58 | * | ||
59 | * @man: TTM memory type manager | ||
60 | * | ||
61 | * Destroy and free the VRAM manager, returns -EBUSY if ranges are still | ||
62 | * allocated inside it. | ||
63 | */ | ||
64 | static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man) | ||
65 | { | ||
66 | struct amdgpu_vram_mgr *mgr = man->priv; | ||
67 | |||
68 | spin_lock(&mgr->lock); | ||
69 | if (!drm_mm_clean(&mgr->mm)) { | ||
70 | spin_unlock(&mgr->lock); | ||
71 | return -EBUSY; | ||
72 | } | ||
73 | |||
74 | drm_mm_takedown(&mgr->mm); | ||
75 | spin_unlock(&mgr->lock); | ||
76 | kfree(mgr); | ||
77 | man->priv = NULL; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * amdgpu_vram_mgr_new - allocate new ranges | ||
83 | * | ||
84 | * @man: TTM memory type manager | ||
85 | * @tbo: TTM BO we need this range for | ||
86 | * @place: placement flags and restrictions | ||
87 | * @mem: the resulting mem object | ||
88 | * | ||
89 | * Allocate VRAM for the given BO. | ||
90 | */ | ||
91 | static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man, | ||
92 | struct ttm_buffer_object *tbo, | ||
93 | const struct ttm_place *place, | ||
94 | struct ttm_mem_reg *mem) | ||
95 | { | ||
96 | struct amdgpu_bo *bo = container_of(tbo, struct amdgpu_bo, tbo); | ||
97 | struct amdgpu_vram_mgr *mgr = man->priv; | ||
98 | struct drm_mm *mm = &mgr->mm; | ||
99 | struct drm_mm_node *nodes; | ||
100 | enum drm_mm_search_flags sflags = DRM_MM_SEARCH_DEFAULT; | ||
101 | enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; | ||
102 | unsigned long lpfn, num_nodes, pages_per_node, pages_left; | ||
103 | unsigned i; | ||
104 | int r; | ||
105 | |||
106 | lpfn = place->lpfn; | ||
107 | if (!lpfn) | ||
108 | lpfn = man->size; | ||
109 | |||
110 | if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS || | ||
111 | amdgpu_vram_page_split == -1) { | ||
112 | pages_per_node = ~0ul; | ||
113 | num_nodes = 1; | ||
114 | } else { | ||
115 | pages_per_node = max((uint32_t)amdgpu_vram_page_split, | ||
116 | mem->page_alignment); | ||
117 | num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node); | ||
118 | } | ||
119 | |||
120 | nodes = kcalloc(num_nodes, sizeof(*nodes), GFP_KERNEL); | ||
121 | if (!nodes) | ||
122 | return -ENOMEM; | ||
123 | |||
124 | if (place->flags & TTM_PL_FLAG_TOPDOWN) { | ||
125 | sflags = DRM_MM_SEARCH_BELOW; | ||
126 | aflags = DRM_MM_CREATE_TOP; | ||
127 | } | ||
128 | |||
129 | pages_left = mem->num_pages; | ||
130 | |||
131 | spin_lock(&mgr->lock); | ||
132 | for (i = 0; i < num_nodes; ++i) { | ||
133 | unsigned long pages = min(pages_left, pages_per_node); | ||
134 | uint32_t alignment = mem->page_alignment; | ||
135 | |||
136 | if (pages == pages_per_node) | ||
137 | alignment = pages_per_node; | ||
138 | else | ||
139 | sflags |= DRM_MM_SEARCH_BEST; | ||
140 | |||
141 | r = drm_mm_insert_node_in_range_generic(mm, &nodes[i], pages, | ||
142 | alignment, 0, | ||
143 | place->fpfn, lpfn, | ||
144 | sflags, aflags); | ||
145 | if (unlikely(r)) | ||
146 | goto error; | ||
147 | |||
148 | pages_left -= pages; | ||
149 | } | ||
150 | spin_unlock(&mgr->lock); | ||
151 | |||
152 | mem->start = num_nodes == 1 ? nodes[0].start : AMDGPU_BO_INVALID_OFFSET; | ||
153 | mem->mm_node = nodes; | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | error: | ||
158 | while (i--) | ||
159 | drm_mm_remove_node(&nodes[i]); | ||
160 | spin_unlock(&mgr->lock); | ||
161 | |||
162 | kfree(nodes); | ||
163 | return r == -ENOSPC ? 0 : r; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * amdgpu_vram_mgr_del - free ranges | ||
168 | * | ||
169 | * @man: TTM memory type manager | ||
170 | * @tbo: TTM BO we need this range for | ||
171 | * @place: placement flags and restrictions | ||
172 | * @mem: TTM memory object | ||
173 | * | ||
174 | * Free the allocated VRAM again. | ||
175 | */ | ||
176 | static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, | ||
177 | struct ttm_mem_reg *mem) | ||
178 | { | ||
179 | struct amdgpu_vram_mgr *mgr = man->priv; | ||
180 | struct drm_mm_node *nodes = mem->mm_node; | ||
181 | unsigned pages = mem->num_pages; | ||
182 | |||
183 | if (!mem->mm_node) | ||
184 | return; | ||
185 | |||
186 | spin_lock(&mgr->lock); | ||
187 | while (pages) { | ||
188 | pages -= nodes->size; | ||
189 | drm_mm_remove_node(nodes); | ||
190 | ++nodes; | ||
191 | } | ||
192 | spin_unlock(&mgr->lock); | ||
193 | |||
194 | kfree(mem->mm_node); | ||
195 | mem->mm_node = NULL; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * amdgpu_vram_mgr_debug - dump VRAM table | ||
200 | * | ||
201 | * @man: TTM memory type manager | ||
202 | * @prefix: text prefix | ||
203 | * | ||
204 | * Dump the table content using printk. | ||
205 | */ | ||
206 | static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, | ||
207 | const char *prefix) | ||
208 | { | ||
209 | struct amdgpu_vram_mgr *mgr = man->priv; | ||
210 | |||
211 | spin_lock(&mgr->lock); | ||
212 | drm_mm_debug_table(&mgr->mm, prefix); | ||
213 | spin_unlock(&mgr->lock); | ||
214 | } | ||
215 | |||
216 | const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { | ||
217 | amdgpu_vram_mgr_init, | ||
218 | amdgpu_vram_mgr_fini, | ||
219 | amdgpu_vram_mgr_new, | ||
220 | amdgpu_vram_mgr_del, | ||
221 | amdgpu_vram_mgr_debug | ||
222 | }; | ||