blob: 2328e5d71db5de7576605dbb363f1dff8ec0884d [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 *
22*/
23
24#include <stdlib.h>
25#include <string.h>
26#include "amdgpu.h"
27#include "amdgpu_drm.h"
28#include "amdgpu_internal.h"
29#include "util_math.h"
30
Ken Wang322d02d2015-05-21 17:21:21 +080031static struct amdgpu_bo_va_mgr vamgr = {{0}};
32
33static void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, struct amdgpu_device *dev)
Alex Deucher09361392015-04-20 12:04:22 -040034{
Ken Wang322d02d2015-05-21 17:21:21 +080035 mgr->va_offset = dev->dev_info.virtual_address_offset;
36 mgr->va_max = dev->dev_info.virtual_address_max;
37 mgr->va_alignment = dev->dev_info.virtual_address_alignment;
Alex Deucher09361392015-04-20 12:04:22 -040038
Ken Wang322d02d2015-05-21 17:21:21 +080039 list_inithead(&mgr->va_holes);
40 pthread_mutex_init(&mgr->bo_va_mutex, NULL);
41}
Alex Deucher09361392015-04-20 12:04:22 -040042
Ken Wang322d02d2015-05-21 17:21:21 +080043static void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr)
44{
45 struct amdgpu_bo_va_hole *hole;
46 LIST_FOR_EACH_ENTRY(hole, &mgr->va_holes, list) {
47 list_del(&hole->list);
48 free(hole);
49 }
50 pthread_mutex_destroy(&mgr->bo_va_mutex);
51}
52
53struct amdgpu_bo_va_mgr * amdgpu_vamgr_get_global(struct amdgpu_device *dev)
54{
55 int ref;
56 ref = atomic_inc_return(&vamgr.refcount);
57
58 if (ref == 1)
59 amdgpu_vamgr_init(&vamgr, dev);
60 return &vamgr;
61}
62
63void amdgpu_vamgr_reference(struct amdgpu_bo_va_mgr **dst,
64 struct amdgpu_bo_va_mgr *src)
65{
66 if (update_references(&(*dst)->refcount, NULL))
67 amdgpu_vamgr_deinit(*dst);
68 *dst = src;
Alex Deucher09361392015-04-20 12:04:22 -040069}
70
Ken Wang5b019082015-07-09 13:48:25 +080071uint64_t amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size,
72 uint64_t alignment, uint64_t base_required)
Alex Deucher09361392015-04-20 12:04:22 -040073{
monk.liu9066acf2015-05-13 13:58:43 +080074 struct amdgpu_bo_va_hole *hole, *n;
75 uint64_t offset = 0, waste = 0;
Alex Deucher09361392015-04-20 12:04:22 -040076
monk.liu9066acf2015-05-13 13:58:43 +080077 alignment = MAX2(alignment, mgr->va_alignment);
78 size = ALIGN(size, mgr->va_alignment);
Alex Deucher09361392015-04-20 12:04:22 -040079
Ken Wang5b019082015-07-09 13:48:25 +080080 if (base_required % alignment)
81 return AMDGPU_INVALID_VA_ADDRESS;
82
monk.liu9066acf2015-05-13 13:58:43 +080083 pthread_mutex_lock(&mgr->bo_va_mutex);
84 /* TODO: using more appropriate way to track the holes */
85 /* first look for a hole */
Ken Wang5b019082015-07-09 13:48:25 +080086 LIST_FOR_EACH_ENTRY_SAFE(hole, n, &vamgr.va_holes, list) {
87 if (base_required) {
88 if(hole->offset > base_required ||
89 (hole->offset + hole->size) < (base_required + size))
90 continue;
91 waste = base_required - hole->offset;
92 offset = base_required;
93 } else {
94 offset = hole->offset;
95 waste = offset % alignment;
96 waste = waste ? alignment - waste : 0;
97 offset += waste;
98 if (offset >= (hole->offset + hole->size)) {
99 continue;
100 }
monk.liu9066acf2015-05-13 13:58:43 +0800101 }
102 if (!waste && hole->size == size) {
103 offset = hole->offset;
104 list_del(&hole->list);
105 free(hole);
106 pthread_mutex_unlock(&mgr->bo_va_mutex);
107 return offset;
108 }
109 if ((hole->size - waste) > size) {
110 if (waste) {
Ken Wang5b019082015-07-09 13:48:25 +0800111 n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
monk.liu9066acf2015-05-13 13:58:43 +0800112 n->size = waste;
113 n->offset = hole->offset;
114 list_add(&n->list, &hole->list);
115 }
116 hole->size -= (size + waste);
117 hole->offset += size + waste;
118 pthread_mutex_unlock(&mgr->bo_va_mutex);
119 return offset;
120 }
121 if ((hole->size - waste) == size) {
122 hole->size = waste;
123 pthread_mutex_unlock(&mgr->bo_va_mutex);
124 return offset;
125 }
126 }
Alex Deucher09361392015-04-20 12:04:22 -0400127
Ken Wang5b019082015-07-09 13:48:25 +0800128 if (base_required) {
129 if (base_required < mgr->va_offset)
130 return AMDGPU_INVALID_VA_ADDRESS;
131 offset = mgr->va_offset;
132 waste = base_required - mgr->va_offset;
133 } else {
134 offset = mgr->va_offset;
135 waste = offset % alignment;
136 waste = waste ? alignment - waste : 0;
137 }
Jammy Zhou241cf6d2015-05-13 01:14:11 +0800138
139 if (offset + waste + size > mgr->va_max) {
140 pthread_mutex_unlock(&mgr->bo_va_mutex);
141 return AMDGPU_INVALID_VA_ADDRESS;
142 }
143
monk.liu9066acf2015-05-13 13:58:43 +0800144 if (waste) {
145 n = calloc(1, sizeof(struct amdgpu_bo_va_hole));
146 n->size = waste;
147 n->offset = offset;
148 list_add(&n->list, &mgr->va_holes);
149 }
Ken Wang5b019082015-07-09 13:48:25 +0800150
monk.liu9066acf2015-05-13 13:58:43 +0800151 offset += waste;
152 mgr->va_offset += size + waste;
153 pthread_mutex_unlock(&mgr->bo_va_mutex);
154 return offset;
Alex Deucher09361392015-04-20 12:04:22 -0400155}
156
Ken Wang322d02d2015-05-21 17:21:21 +0800157void amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr,
158 uint64_t va, uint64_t size)
Alex Deucher09361392015-04-20 12:04:22 -0400159{
monk.liu9066acf2015-05-13 13:58:43 +0800160 struct amdgpu_bo_va_hole *hole;
Alex Deucher09361392015-04-20 12:04:22 -0400161
monk.liud3e71952015-05-13 14:01:53 +0800162 if (va == AMDGPU_INVALID_VA_ADDRESS)
163 return;
164
monk.liu9066acf2015-05-13 13:58:43 +0800165 size = ALIGN(size, mgr->va_alignment);
Alex Deucher09361392015-04-20 12:04:22 -0400166
monk.liu9066acf2015-05-13 13:58:43 +0800167 pthread_mutex_lock(&mgr->bo_va_mutex);
168 if ((va + size) == mgr->va_offset) {
169 mgr->va_offset = va;
170 /* Delete uppermost hole if it reaches the new top */
171 if (!LIST_IS_EMPTY(&mgr->va_holes)) {
172 hole = container_of(mgr->va_holes.next, hole, list);
173 if ((hole->offset + hole->size) == va) {
174 mgr->va_offset = hole->offset;
175 list_del(&hole->list);
176 free(hole);
177 }
178 }
179 } else {
180 struct amdgpu_bo_va_hole *next;
Alex Deucher09361392015-04-20 12:04:22 -0400181
monk.liu9066acf2015-05-13 13:58:43 +0800182 hole = container_of(&mgr->va_holes, hole, list);
183 LIST_FOR_EACH_ENTRY(next, &mgr->va_holes, list) {
184 if (next->offset < va)
185 break;
186 hole = next;
187 }
Alex Deucher09361392015-04-20 12:04:22 -0400188
monk.liu9066acf2015-05-13 13:58:43 +0800189 if (&hole->list != &mgr->va_holes) {
190 /* Grow upper hole if it's adjacent */
191 if (hole->offset == (va + size)) {
192 hole->offset = va;
193 hole->size += size;
194 /* Merge lower hole if it's adjacent */
195 if (next != hole
196 && &next->list != &mgr->va_holes
197 && (next->offset + next->size) == va) {
198 next->size += hole->size;
199 list_del(&hole->list);
200 free(hole);
201 }
202 goto out;
203 }
204 }
Alex Deucher09361392015-04-20 12:04:22 -0400205
monk.liu9066acf2015-05-13 13:58:43 +0800206 /* Grow lower hole if it's adjacent */
207 if (next != hole && &next->list != &mgr->va_holes &&
208 (next->offset + next->size) == va) {
209 next->size += size;
210 goto out;
211 }
Alex Deucher09361392015-04-20 12:04:22 -0400212
monk.liu9066acf2015-05-13 13:58:43 +0800213 /* FIXME on allocation failure we just lose virtual address space
214 * maybe print a warning
215 */
216 next = calloc(1, sizeof(struct amdgpu_bo_va_hole));
217 if (next) {
218 next->size = size;
219 next->offset = va;
220 list_add(&next->list, &hole->list);
221 }
222 }
Alex Deucher09361392015-04-20 12:04:22 -0400223out:
monk.liu9066acf2015-05-13 13:58:43 +0800224 pthread_mutex_unlock(&mgr->bo_va_mutex);
Alex Deucher09361392015-04-20 12:04:22 -0400225}