blob: 507a73a2a0a6e4e527e82aa4927f982848f6e59b [file] [log] [blame]
Alex Deucher09361392015-04-20 12:04:22 -04001/*
2 * Copyright 2014 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 *
Emil Velikova30da8e2015-08-07 17:20:51 +010022 */
Alex Deucher09361392015-04-20 12:04:22 -040023
Emil Velikovf4c2bfd2015-08-07 17:17:43 +010024#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
Alex Deucher09361392015-04-20 12:04:22 -040028#include <stdlib.h>
29#include <string.h>
Sabre Shao23fab592015-07-09 13:50:36 +080030#include <errno.h>
Alex Deucher09361392015-04-20 12:04:22 -040031#include "amdgpu.h"
32#include "amdgpu_drm.h"
33#include "amdgpu_internal.h"
34#include "util_math.h"
35
Ken Wang322d02d2015-05-21 17:21:21 +080036static struct amdgpu_bo_va_mgr vamgr = {{0}};
37
Sabre Shao12802da2015-07-09 13:53:24 +080038int amdgpu_va_range_query(amdgpu_device_handle dev,
39 enum amdgpu_gpu_va_range type, uint64_t *start, uint64_t *end)
40{
41 if (type == amdgpu_gpu_va_range_general) {
42 *start = dev->dev_info.virtual_address_offset;
43 *end = dev->dev_info.virtual_address_max;
44 return 0;
45 }
46 return -EINVAL;
47}
48
Jammy Zhouffa305d2015-08-17 11:09:08 +080049drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start,
Jammy Zhou102ab6f2015-08-17 11:09:07 +080050 uint64_t max, uint64_t alignment)
Alex Deucher09361392015-04-20 12:04:22 -040051{
Jammy Zhou102ab6f2015-08-17 11:09:07 +080052 mgr->va_offset = start;
53 mgr->va_max = max;
54 mgr->va_alignment = alignment;
Alex Deucher09361392015-04-20 12:04:22 -040055
Ken Wang322d02d2015-05-21 17:21:21 +080056 list_inithead(&mgr->va_holes);
57 pthread_mutex_init(&mgr->bo_va_mutex, NULL);
58}
Alex Deucher09361392015-04-20 12:04:22 -040059
Jammy Zhouffa305d2015-08-17 11:09:08 +080060drm_private void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr)
Ken Wang322d02d2015-05-21 17:21:21 +080061{
62 struct amdgpu_bo_va_hole *hole;
63 LIST_FOR_EACH_ENTRY(hole, &mgr->va_holes, list) {
64 list_del(&hole->list);
65 free(hole);
66 }
67 pthread_mutex_destroy(&mgr->bo_va_mutex);
68}
69
Emil Velikovb4718182015-08-07 16:54:29 +010070drm_private struct amdgpu_bo_va_mgr *
71amdgpu_vamgr_get_global(struct amdgpu_device *dev)
Ken Wang322d02d2015-05-21 17:21:21 +080072{
73 int ref;
74 ref = atomic_inc_return(&vamgr.refcount);
75
76 if (ref == 1)
Jammy Zhou102ab6f2015-08-17 11:09:07 +080077 amdgpu_vamgr_init(&vamgr, dev->dev_info.virtual_address_offset,
78 dev->dev_info.virtual_address_max,
79 dev->dev_info.virtual_address_alignment);
Ken Wang322d02d2015-05-21 17:21:21 +080080 return &vamgr;
81}
82
Emil Velikovb4718182015-08-07 16:54:29 +010083drm_private void
84amdgpu_vamgr_reference(struct amdgpu_bo_va_mgr **dst,
85 struct amdgpu_bo_va_mgr *src)
Ken Wang322d02d2015-05-21 17:21:21 +080086{
87 if (update_references(&(*dst)->refcount, NULL))
88 amdgpu_vamgr_deinit(*dst);
89 *dst = src;
Alex Deucher09361392015-04-20 12:04:22 -040090}
91
Emil Velikovb4718182015-08-07 16:54:29 +010092drm_private uint64_t
93amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size,
94 uint64_t alignment, uint64_t base_required)
Alex Deucher09361392015-04-20 12:04:22 -040095{
monk.liu9066acf2015-05-13 13:58:43 +080096 struct amdgpu_bo_va_hole *hole, *n;
97 uint64_t offset = 0, waste = 0;
Alex Deucher09361392015-04-20 12:04:22 -040098
monk.liu9066acf2015-05-13 13:58:43 +080099 alignment = MAX2(alignment, mgr->va_alignment);
100 size = ALIGN(size, mgr->va_alignment);
Alex Deucher09361392015-04-20 12:04:22 -0400101
Ken Wang5b019082015-07-09 13:48:25 +0800102 if (base_required % alignment)
103 return AMDGPU_INVALID_VA_ADDRESS;
104
monk.liu9066acf2015-05-13 13:58:43 +0800105 pthread_mutex_lock(&mgr->bo_va_mutex);
106 /* TODO: using more appropriate way to track the holes */
107 /* first look for a hole */
Ken Wang5b019082015-07-09 13:48:25 +0800108 LIST_FOR_EACH_ENTRY_SAFE(hole, n, &vamgr.va_holes, list) {
109 if (base_required) {
110 if(hole->offset > base_required ||
111 (hole->offset + hole->size) < (base_required + size))
112 continue;
113 waste = base_required - hole->offset;
114 offset = base_required;
115 } else {
116 offset = hole->offset;
117 waste = offset % alignment;
118 waste = waste ? alignment - waste : 0;
119 offset += waste;
120 if (offset >= (hole->offset + hole->size)) {
121 continue;
122 }
monk.liu9066acf2015-05-13 13:58:43 +0800123 }
124 if (!waste && hole->size == size) {
125 offset = hole->offset;
126 list_del(&hole->list);
127 free(hole);
128 pthread_mutex_unlock(&mgr->bo_va_mutex);
129 return offset;
130 }
131 if ((hole->size - waste) > size) {
132 if (waste) {
Ken Wang5b019082015-07-09 13:48:25 +0800133 n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
monk.liu9066acf2015-05-13 13:58:43 +0800134 n->size = waste;
135 n->offset = hole->offset;
136 list_add(&n->list, &hole->list);
137 }
138 hole->size -= (size + waste);
139 hole->offset += size + waste;
140 pthread_mutex_unlock(&mgr->bo_va_mutex);
141 return offset;
142 }
143 if ((hole->size - waste) == size) {
144 hole->size = waste;
145 pthread_mutex_unlock(&mgr->bo_va_mutex);
146 return offset;
147 }
148 }
Alex Deucher09361392015-04-20 12:04:22 -0400149
Ken Wang5b019082015-07-09 13:48:25 +0800150 if (base_required) {
151 if (base_required < mgr->va_offset)
152 return AMDGPU_INVALID_VA_ADDRESS;
153 offset = mgr->va_offset;
154 waste = base_required - mgr->va_offset;
155 } else {
156 offset = mgr->va_offset;
157 waste = offset % alignment;
158 waste = waste ? alignment - waste : 0;
159 }
Jammy Zhou241cf6d2015-05-13 01:14:11 +0800160
161 if (offset + waste + size > mgr->va_max) {
162 pthread_mutex_unlock(&mgr->bo_va_mutex);
163 return AMDGPU_INVALID_VA_ADDRESS;
164 }
165
monk.liu9066acf2015-05-13 13:58:43 +0800166 if (waste) {
167 n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
168 n->size = waste;
169 n->offset = offset;
170 list_add(&n->list, &mgr->va_holes);
171 }
Ken Wang5b019082015-07-09 13:48:25 +0800172
monk.liu9066acf2015-05-13 13:58:43 +0800173 offset += waste;
174 mgr->va_offset += size + waste;
175 pthread_mutex_unlock(&mgr->bo_va_mutex);
176 return offset;
Alex Deucher09361392015-04-20 12:04:22 -0400177}
178
Emil Velikovb4718182015-08-07 16:54:29 +0100179drm_private void
180amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va, uint64_t size)
Alex Deucher09361392015-04-20 12:04:22 -0400181{
monk.liu9066acf2015-05-13 13:58:43 +0800182 struct amdgpu_bo_va_hole *hole;
Alex Deucher09361392015-04-20 12:04:22 -0400183
monk.liud3e71952015-05-13 14:01:53 +0800184 if (va == AMDGPU_INVALID_VA_ADDRESS)
185 return;
186
monk.liu9066acf2015-05-13 13:58:43 +0800187 size = ALIGN(size, mgr->va_alignment);
Alex Deucher09361392015-04-20 12:04:22 -0400188
monk.liu9066acf2015-05-13 13:58:43 +0800189 pthread_mutex_lock(&mgr->bo_va_mutex);
190 if ((va + size) == mgr->va_offset) {
191 mgr->va_offset = va;
192 /* Delete uppermost hole if it reaches the new top */
193 if (!LIST_IS_EMPTY(&mgr->va_holes)) {
194 hole = container_of(mgr->va_holes.next, hole, list);
195 if ((hole->offset + hole->size) == va) {
196 mgr->va_offset = hole->offset;
197 list_del(&hole->list);
198 free(hole);
199 }
200 }
201 } else {
202 struct amdgpu_bo_va_hole *next;
Alex Deucher09361392015-04-20 12:04:22 -0400203
monk.liu9066acf2015-05-13 13:58:43 +0800204 hole = container_of(&mgr->va_holes, hole, list);
205 LIST_FOR_EACH_ENTRY(next, &mgr->va_holes, list) {
206 if (next->offset < va)
207 break;
208 hole = next;
209 }
Alex Deucher09361392015-04-20 12:04:22 -0400210
monk.liu9066acf2015-05-13 13:58:43 +0800211 if (&hole->list != &mgr->va_holes) {
212 /* Grow upper hole if it's adjacent */
213 if (hole->offset == (va + size)) {
214 hole->offset = va;
215 hole->size += size;
216 /* Merge lower hole if it's adjacent */
217 if (next != hole
218 && &next->list != &mgr->va_holes
219 && (next->offset + next->size) == va) {
220 next->size += hole->size;
221 list_del(&hole->list);
222 free(hole);
223 }
224 goto out;
225 }
226 }
Alex Deucher09361392015-04-20 12:04:22 -0400227
monk.liu9066acf2015-05-13 13:58:43 +0800228 /* Grow lower hole if it's adjacent */
229 if (next != hole && &next->list != &mgr->va_holes &&
230 (next->offset + next->size) == va) {
231 next->size += size;
232 goto out;
233 }
Alex Deucher09361392015-04-20 12:04:22 -0400234
monk.liu9066acf2015-05-13 13:58:43 +0800235 /* FIXME on allocation failure we just lose virtual address space
236 * maybe print a warning
237 */
238 next = calloc(1, sizeof(struct amdgpu_bo_va_hole));
239 if (next) {
240 next->size = size;
241 next->offset = va;
242 list_add(&next->list, &hole->list);
243 }
244 }
Alex Deucher09361392015-04-20 12:04:22 -0400245out:
monk.liu9066acf2015-05-13 13:58:43 +0800246 pthread_mutex_unlock(&mgr->bo_va_mutex);
Alex Deucher09361392015-04-20 12:04:22 -0400247}
Sabre Shao23fab592015-07-09 13:50:36 +0800248
249int amdgpu_va_range_alloc(amdgpu_device_handle dev,
250 enum amdgpu_gpu_va_range va_range_type,
251 uint64_t size,
252 uint64_t va_base_alignment,
253 uint64_t va_base_required,
254 uint64_t *va_base_allocated,
Jammy Zhou95d0f352015-07-16 10:29:58 +0800255 amdgpu_va_handle *va_range_handle,
256 uint64_t flags)
Sabre Shao23fab592015-07-09 13:50:36 +0800257{
Jammy Zhouffa305d2015-08-17 11:09:08 +0800258 struct amdgpu_bo_va_mgr *vamgr;
Sabre Shao23fab592015-07-09 13:50:36 +0800259
Jammy Zhouffa305d2015-08-17 11:09:08 +0800260 if (flags & AMDGPU_VA_RANGE_32_BIT)
261 vamgr = dev->vamgr_32;
262 else
263 vamgr = dev->vamgr;
264
265 va_base_alignment = MAX2(va_base_alignment, vamgr->va_alignment);
266 size = ALIGN(size, vamgr->va_alignment);
267
268 *va_base_allocated = amdgpu_vamgr_find_va(vamgr, size,
Sabre Shao23fab592015-07-09 13:50:36 +0800269 va_base_alignment, va_base_required);
270
Jammy Zhouffa305d2015-08-17 11:09:08 +0800271 if (!(flags & AMDGPU_VA_RANGE_32_BIT) &&
272 (*va_base_allocated == AMDGPU_INVALID_VA_ADDRESS)) {
273 /* fallback to 32bit address */
274 vamgr = dev->vamgr_32;
275 *va_base_allocated = amdgpu_vamgr_find_va(vamgr, size,
276 va_base_alignment, va_base_required);
277 }
278
Sabre Shao23fab592015-07-09 13:50:36 +0800279 if (*va_base_allocated != AMDGPU_INVALID_VA_ADDRESS) {
280 struct amdgpu_va* va;
281 va = calloc(1, sizeof(struct amdgpu_va));
282 if(!va){
Jammy Zhouffa305d2015-08-17 11:09:08 +0800283 amdgpu_vamgr_free_va(vamgr, *va_base_allocated, size);
Sabre Shao23fab592015-07-09 13:50:36 +0800284 return -ENOMEM;
285 }
286 va->dev = dev;
287 va->address = *va_base_allocated;
288 va->size = size;
289 va->range = va_range_type;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800290 va->vamgr = vamgr;
Sabre Shao23fab592015-07-09 13:50:36 +0800291 *va_range_handle = va;
292 } else {
293 return -EINVAL;
294 }
295
296 return 0;
297}
298
299int amdgpu_va_range_free(amdgpu_va_handle va_range_handle)
300{
301 if(!va_range_handle || !va_range_handle->address)
302 return 0;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800303
304 amdgpu_vamgr_free_va(va_range_handle->vamgr,
305 va_range_handle->address,
Sabre Shao23fab592015-07-09 13:50:36 +0800306 va_range_handle->size);
307 free(va_range_handle);
308 return 0;
309}