blob: 8516b594a48e5888907bd6853c4a8c70b2720151 [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
Sabre Shao12802da2015-07-09 13:53:24 +080036int amdgpu_va_range_query(amdgpu_device_handle dev,
Christian König4b4ccaa2017-11-02 18:47:34 +010037 enum amdgpu_gpu_va_range type,
38 uint64_t *start, uint64_t *end)
Sabre Shao12802da2015-07-09 13:53:24 +080039{
Christian König4b4ccaa2017-11-02 18:47:34 +010040 if (type != amdgpu_gpu_va_range_general)
41 return -EINVAL;
42
43 *start = dev->dev_info.virtual_address_offset;
44 *end = dev->dev_info.virtual_address_max;
45 return 0;
Sabre Shao12802da2015-07-09 13:53:24 +080046}
47
Jammy Zhouffa305d2015-08-17 11:09:08 +080048drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start,
Christian König4b4ccaa2017-11-02 18:47:34 +010049 uint64_t max, uint64_t alignment)
Alex Deucher09361392015-04-20 12:04:22 -040050{
Jammy Zhou102ab6f2015-08-17 11:09:07 +080051 mgr->va_offset = start;
52 mgr->va_max = max;
53 mgr->va_alignment = alignment;
Alex Deucher09361392015-04-20 12:04:22 -040054
Ken Wang322d02d2015-05-21 17:21:21 +080055 list_inithead(&mgr->va_holes);
56 pthread_mutex_init(&mgr->bo_va_mutex, NULL);
57}
Alex Deucher09361392015-04-20 12:04:22 -040058
Jammy Zhouffa305d2015-08-17 11:09:08 +080059drm_private void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr)
Ken Wang322d02d2015-05-21 17:21:21 +080060{
Tom St Denis1a6a8f32015-10-09 12:07:26 -040061 struct amdgpu_bo_va_hole *hole, *tmp;
62 LIST_FOR_EACH_ENTRY_SAFE(hole, tmp, &mgr->va_holes, list) {
Ken Wang322d02d2015-05-21 17:21:21 +080063 list_del(&hole->list);
64 free(hole);
65 }
66 pthread_mutex_destroy(&mgr->bo_va_mutex);
67}
68
Emil Velikovb4718182015-08-07 16:54:29 +010069drm_private uint64_t
70amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size,
71 uint64_t alignment, uint64_t base_required)
Alex Deucher09361392015-04-20 12:04:22 -040072{
monk.liu9066acf2015-05-13 13:58:43 +080073 struct amdgpu_bo_va_hole *hole, *n;
74 uint64_t offset = 0, waste = 0;
Alex Deucher09361392015-04-20 12:04:22 -040075
monk.liu9066acf2015-05-13 13:58:43 +080076 alignment = MAX2(alignment, mgr->va_alignment);
77 size = ALIGN(size, mgr->va_alignment);
Alex Deucher09361392015-04-20 12:04:22 -040078
Ken Wang5b019082015-07-09 13:48:25 +080079 if (base_required % alignment)
80 return AMDGPU_INVALID_VA_ADDRESS;
81
monk.liu9066acf2015-05-13 13:58:43 +080082 pthread_mutex_lock(&mgr->bo_va_mutex);
83 /* TODO: using more appropriate way to track the holes */
84 /* first look for a hole */
Jammy Zhou56d8dd62015-08-17 11:09:09 +080085 LIST_FOR_EACH_ENTRY_SAFE(hole, n, &mgr->va_holes, list) {
Ken Wang5b019082015-07-09 13:48:25 +080086 if (base_required) {
Christian König4b4ccaa2017-11-02 18:47:34 +010087 if (hole->offset > base_required ||
88 (hole->offset + hole->size) < (base_required + size))
Ken Wang5b019082015-07-09 13:48:25 +080089 continue;
90 waste = base_required - hole->offset;
91 offset = base_required;
92 } else {
93 offset = hole->offset;
94 waste = offset % alignment;
95 waste = waste ? alignment - waste : 0;
96 offset += waste;
97 if (offset >= (hole->offset + hole->size)) {
98 continue;
99 }
monk.liu9066acf2015-05-13 13:58:43 +0800100 }
101 if (!waste && hole->size == size) {
102 offset = hole->offset;
103 list_del(&hole->list);
104 free(hole);
105 pthread_mutex_unlock(&mgr->bo_va_mutex);
106 return offset;
107 }
108 if ((hole->size - waste) > size) {
109 if (waste) {
Ken Wang5b019082015-07-09 13:48:25 +0800110 n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
monk.liu9066acf2015-05-13 13:58:43 +0800111 n->size = waste;
112 n->offset = hole->offset;
113 list_add(&n->list, &hole->list);
114 }
115 hole->size -= (size + waste);
116 hole->offset += size + waste;
117 pthread_mutex_unlock(&mgr->bo_va_mutex);
118 return offset;
119 }
120 if ((hole->size - waste) == size) {
121 hole->size = waste;
122 pthread_mutex_unlock(&mgr->bo_va_mutex);
123 return offset;
124 }
125 }
Alex Deucher09361392015-04-20 12:04:22 -0400126
Ken Wang5b019082015-07-09 13:48:25 +0800127 if (base_required) {
Tom St Denis988f31e2015-10-09 10:36:04 -0400128 if (base_required < mgr->va_offset) {
129 pthread_mutex_unlock(&mgr->bo_va_mutex);
Ken Wang5b019082015-07-09 13:48:25 +0800130 return AMDGPU_INVALID_VA_ADDRESS;
Tom St Denis988f31e2015-10-09 10:36:04 -0400131 }
Ken Wang5b019082015-07-09 13:48:25 +0800132 offset = mgr->va_offset;
133 waste = base_required - mgr->va_offset;
134 } else {
135 offset = mgr->va_offset;
136 waste = offset % alignment;
137 waste = waste ? alignment - waste : 0;
138 }
Jammy Zhou241cf6d2015-05-13 01:14:11 +0800139
140 if (offset + waste + size > mgr->va_max) {
141 pthread_mutex_unlock(&mgr->bo_va_mutex);
142 return AMDGPU_INVALID_VA_ADDRESS;
143 }
144
monk.liu9066acf2015-05-13 13:58:43 +0800145 if (waste) {
146 n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
147 n->size = waste;
148 n->offset = offset;
149 list_add(&n->list, &mgr->va_holes);
150 }
Ken Wang5b019082015-07-09 13:48:25 +0800151
monk.liu9066acf2015-05-13 13:58:43 +0800152 offset += waste;
153 mgr->va_offset += size + waste;
154 pthread_mutex_unlock(&mgr->bo_va_mutex);
155 return offset;
Alex Deucher09361392015-04-20 12:04:22 -0400156}
157
Emil Velikovb4718182015-08-07 16:54:29 +0100158drm_private void
159amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va, uint64_t size)
Alex Deucher09361392015-04-20 12:04:22 -0400160{
monk.liu9066acf2015-05-13 13:58:43 +0800161 struct amdgpu_bo_va_hole *hole;
Alex Deucher09361392015-04-20 12:04:22 -0400162
monk.liud3e71952015-05-13 14:01:53 +0800163 if (va == AMDGPU_INVALID_VA_ADDRESS)
164 return;
165
monk.liu9066acf2015-05-13 13:58:43 +0800166 size = ALIGN(size, mgr->va_alignment);
Alex Deucher09361392015-04-20 12:04:22 -0400167
monk.liu9066acf2015-05-13 13:58:43 +0800168 pthread_mutex_lock(&mgr->bo_va_mutex);
169 if ((va + size) == mgr->va_offset) {
170 mgr->va_offset = va;
171 /* Delete uppermost hole if it reaches the new top */
172 if (!LIST_IS_EMPTY(&mgr->va_holes)) {
173 hole = container_of(mgr->va_holes.next, hole, list);
174 if ((hole->offset + hole->size) == va) {
175 mgr->va_offset = hole->offset;
176 list_del(&hole->list);
177 free(hole);
178 }
179 }
180 } else {
181 struct amdgpu_bo_va_hole *next;
Alex Deucher09361392015-04-20 12:04:22 -0400182
monk.liu9066acf2015-05-13 13:58:43 +0800183 hole = container_of(&mgr->va_holes, hole, list);
184 LIST_FOR_EACH_ENTRY(next, &mgr->va_holes, list) {
185 if (next->offset < va)
186 break;
187 hole = next;
188 }
Alex Deucher09361392015-04-20 12:04:22 -0400189
monk.liu9066acf2015-05-13 13:58:43 +0800190 if (&hole->list != &mgr->va_holes) {
191 /* Grow upper hole if it's adjacent */
192 if (hole->offset == (va + size)) {
193 hole->offset = va;
194 hole->size += size;
195 /* Merge lower hole if it's adjacent */
Christian König4b4ccaa2017-11-02 18:47:34 +0100196 if (next != hole &&
197 &next->list != &mgr->va_holes &&
198 (next->offset + next->size) == va) {
monk.liu9066acf2015-05-13 13:58:43 +0800199 next->size += hole->size;
200 list_del(&hole->list);
201 free(hole);
202 }
203 goto out;
204 }
205 }
Alex Deucher09361392015-04-20 12:04:22 -0400206
monk.liu9066acf2015-05-13 13:58:43 +0800207 /* Grow lower hole if it's adjacent */
208 if (next != hole && &next->list != &mgr->va_holes &&
209 (next->offset + next->size) == va) {
210 next->size += size;
211 goto out;
212 }
Alex Deucher09361392015-04-20 12:04:22 -0400213
monk.liu9066acf2015-05-13 13:58:43 +0800214 /* FIXME on allocation failure we just lose virtual address space
215 * maybe print a warning
216 */
217 next = calloc(1, sizeof(struct amdgpu_bo_va_hole));
218 if (next) {
219 next->size = size;
220 next->offset = va;
221 list_add(&next->list, &hole->list);
222 }
223 }
Alex Deucher09361392015-04-20 12:04:22 -0400224out:
monk.liu9066acf2015-05-13 13:58:43 +0800225 pthread_mutex_unlock(&mgr->bo_va_mutex);
Alex Deucher09361392015-04-20 12:04:22 -0400226}
Sabre Shao23fab592015-07-09 13:50:36 +0800227
228int amdgpu_va_range_alloc(amdgpu_device_handle dev,
229 enum amdgpu_gpu_va_range va_range_type,
230 uint64_t size,
231 uint64_t va_base_alignment,
232 uint64_t va_base_required,
233 uint64_t *va_base_allocated,
Jammy Zhou95d0f352015-07-16 10:29:58 +0800234 amdgpu_va_handle *va_range_handle,
235 uint64_t flags)
Sabre Shao23fab592015-07-09 13:50:36 +0800236{
Jammy Zhouffa305d2015-08-17 11:09:08 +0800237 struct amdgpu_bo_va_mgr *vamgr;
Sabre Shao23fab592015-07-09 13:50:36 +0800238
Jammy Zhouffa305d2015-08-17 11:09:08 +0800239 if (flags & AMDGPU_VA_RANGE_32_BIT)
Alex Xie067e9a12017-01-28 21:50:36 +0200240 vamgr = &dev->vamgr_32;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800241 else
Alex Xiefe7cb342017-01-28 21:50:44 +0200242 vamgr = &dev->vamgr;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800243
244 va_base_alignment = MAX2(va_base_alignment, vamgr->va_alignment);
245 size = ALIGN(size, vamgr->va_alignment);
246
247 *va_base_allocated = amdgpu_vamgr_find_va(vamgr, size,
Sabre Shao23fab592015-07-09 13:50:36 +0800248 va_base_alignment, va_base_required);
249
Jammy Zhouffa305d2015-08-17 11:09:08 +0800250 if (!(flags & AMDGPU_VA_RANGE_32_BIT) &&
251 (*va_base_allocated == AMDGPU_INVALID_VA_ADDRESS)) {
252 /* fallback to 32bit address */
Alex Xie067e9a12017-01-28 21:50:36 +0200253 vamgr = &dev->vamgr_32;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800254 *va_base_allocated = amdgpu_vamgr_find_va(vamgr, size,
255 va_base_alignment, va_base_required);
256 }
257
Sabre Shao23fab592015-07-09 13:50:36 +0800258 if (*va_base_allocated != AMDGPU_INVALID_VA_ADDRESS) {
259 struct amdgpu_va* va;
260 va = calloc(1, sizeof(struct amdgpu_va));
261 if(!va){
Jammy Zhouffa305d2015-08-17 11:09:08 +0800262 amdgpu_vamgr_free_va(vamgr, *va_base_allocated, size);
Sabre Shao23fab592015-07-09 13:50:36 +0800263 return -ENOMEM;
264 }
265 va->dev = dev;
266 va->address = *va_base_allocated;
267 va->size = size;
268 va->range = va_range_type;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800269 va->vamgr = vamgr;
Sabre Shao23fab592015-07-09 13:50:36 +0800270 *va_range_handle = va;
271 } else {
272 return -EINVAL;
273 }
274
275 return 0;
276}
277
278int amdgpu_va_range_free(amdgpu_va_handle va_range_handle)
279{
280 if(!va_range_handle || !va_range_handle->address)
281 return 0;
Jammy Zhouffa305d2015-08-17 11:09:08 +0800282
283 amdgpu_vamgr_free_va(va_range_handle->vamgr,
284 va_range_handle->address,
Sabre Shao23fab592015-07-09 13:50:36 +0800285 va_range_handle->size);
286 free(va_range_handle);
287 return 0;
288}