2 * Copyright © 2016-2018 Intel Corporation
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:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 #include <sys/types.h>
31 #ifndef HAVE_MEMFD_CREATE
32 #include <sys/syscall.h>
35 memfd_create(const char *name
, unsigned int flags
)
37 return syscall(SYS_memfd_create
, name
, flags
);
42 struct list_head link
;
43 struct gen_batch_decode_bo bo
;
61 add_gtt_bo_map(struct aub_mem
*mem
, struct gen_batch_decode_bo bo
, bool unmap_after_use
)
63 struct bo_map
*m
= calloc(1, sizeof(*m
));
66 m
->unmap_after_use
= unmap_after_use
;
67 list_add(&m
->link
, &mem
->maps
);
71 aub_mem_clear_bo_maps(struct aub_mem
*mem
)
73 list_for_each_entry_safe(struct bo_map
, i
, &mem
->maps
, link
) {
74 if (i
->unmap_after_use
)
75 munmap((void *)i
->bo
.map
, i
->bo
.size
);
81 static inline struct ggtt_entry
*
82 ggtt_entry_next(struct ggtt_entry
*entry
)
86 struct rb_node
*node
= rb_node_next(&entry
->node
);
89 return rb_node_data(struct ggtt_entry
, node
, node
);
93 cmp_uint64(uint64_t a
, uint64_t b
)
103 cmp_ggtt_entry(const struct rb_node
*node
, const void *addr
)
105 struct ggtt_entry
*entry
= rb_node_data(struct ggtt_entry
, node
, node
);
106 return cmp_uint64(entry
->virt_addr
, *(const uint64_t *)addr
);
109 static struct ggtt_entry
*
110 ensure_ggtt_entry(struct aub_mem
*mem
, uint64_t virt_addr
)
112 struct rb_node
*node
= rb_tree_search_sloppy(&mem
->ggtt
, &virt_addr
,
115 if (!node
|| (cmp
= cmp_ggtt_entry(node
, &virt_addr
))) {
116 struct ggtt_entry
*new_entry
= calloc(1, sizeof(*new_entry
));
117 new_entry
->virt_addr
= virt_addr
;
118 rb_tree_insert_at(&mem
->ggtt
, node
, &new_entry
->node
, cmp
> 0);
119 node
= &new_entry
->node
;
122 return rb_node_data(struct ggtt_entry
, node
, node
);
125 static struct ggtt_entry
*
126 search_ggtt_entry(struct aub_mem
*mem
, uint64_t virt_addr
)
130 struct rb_node
*node
= rb_tree_search(&mem
->ggtt
, &virt_addr
, cmp_ggtt_entry
);
135 return rb_node_data(struct ggtt_entry
, node
, node
);
139 cmp_phys_mem(const struct rb_node
*node
, const void *addr
)
141 struct phys_mem
*mem
= rb_node_data(struct phys_mem
, node
, node
);
142 return cmp_uint64(mem
->phys_addr
, *(uint64_t *)addr
);
145 static struct phys_mem
*
146 ensure_phys_mem(struct aub_mem
*mem
, uint64_t phys_addr
)
148 struct rb_node
*node
= rb_tree_search_sloppy(&mem
->mem
, &phys_addr
, cmp_phys_mem
);
150 if (!node
|| (cmp
= cmp_phys_mem(node
, &phys_addr
))) {
151 struct phys_mem
*new_mem
= calloc(1, sizeof(*new_mem
));
152 new_mem
->phys_addr
= phys_addr
;
153 new_mem
->fd_offset
= mem
->mem_fd_len
;
155 MAYBE_UNUSED
int ftruncate_res
= ftruncate(mem
->mem_fd
, mem
->mem_fd_len
+= 4096);
156 assert(ftruncate_res
== 0);
158 new_mem
->data
= mmap(NULL
, 4096, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
159 mem
->mem_fd
, new_mem
->fd_offset
);
160 assert(new_mem
->data
!= MAP_FAILED
);
162 rb_tree_insert_at(&mem
->mem
, node
, &new_mem
->node
, cmp
> 0);
163 node
= &new_mem
->node
;
166 return rb_node_data(struct phys_mem
, node
, node
);
169 static struct phys_mem
*
170 search_phys_mem(struct aub_mem
*mem
, uint64_t phys_addr
)
174 struct rb_node
*node
= rb_tree_search(&mem
->mem
, &phys_addr
, cmp_phys_mem
);
179 return rb_node_data(struct phys_mem
, node
, node
);
183 aub_mem_local_write(void *_mem
, uint64_t address
,
184 const void *data
, uint32_t size
)
186 struct aub_mem
*mem
= _mem
;
187 struct gen_batch_decode_bo bo
= {
192 add_gtt_bo_map(mem
, bo
, false);
196 aub_mem_ggtt_entry_write(void *_mem
, uint64_t address
,
197 const void *_data
, uint32_t _size
)
199 struct aub_mem
*mem
= _mem
;
200 uint64_t virt_addr
= (address
/ sizeof(uint64_t)) << 12;
201 const uint64_t *data
= _data
;
202 size_t size
= _size
/ sizeof(*data
);
203 for (const uint64_t *entry
= data
;
205 entry
++, virt_addr
+= 4096) {
206 struct ggtt_entry
*pt
= ensure_ggtt_entry(mem
, virt_addr
);
207 pt
->phys_addr
= *entry
;
212 aub_mem_phys_write(void *_mem
, uint64_t phys_address
,
213 const void *data
, uint32_t size
)
215 struct aub_mem
*mem
= _mem
;
216 uint32_t to_write
= size
;
217 for (uint64_t page
= phys_address
& ~0xfff; page
< phys_address
+ size
; page
+= 4096) {
218 struct phys_mem
*pmem
= ensure_phys_mem(mem
, page
);
219 uint64_t offset
= MAX2(page
, phys_address
) - page
;
220 uint32_t size_this_page
= MIN2(to_write
, 4096 - offset
);
221 to_write
-= size_this_page
;
222 memcpy(pmem
->data
+ offset
, data
, size_this_page
);
223 data
= (const uint8_t *)data
+ size_this_page
;
228 aub_mem_ggtt_write(void *_mem
, uint64_t virt_address
,
229 const void *data
, uint32_t size
)
231 struct aub_mem
*mem
= _mem
;
232 uint32_t to_write
= size
;
233 for (uint64_t page
= virt_address
& ~0xfff; page
< virt_address
+ size
; page
+= 4096) {
234 struct ggtt_entry
*entry
= search_ggtt_entry(mem
, page
);
235 assert(entry
&& entry
->phys_addr
& 0x1);
237 uint64_t offset
= MAX2(page
, virt_address
) - page
;
238 uint32_t size_this_page
= MIN2(to_write
, 4096 - offset
);
239 to_write
-= size_this_page
;
241 uint64_t phys_page
= entry
->phys_addr
& ~0xfff; /* Clear the validity bits. */
242 aub_mem_phys_write(mem
, phys_page
+ offset
, data
, size_this_page
);
243 data
= (const uint8_t *)data
+ size_this_page
;
247 struct gen_batch_decode_bo
248 aub_mem_get_ggtt_bo(void *_mem
, uint64_t address
)
250 struct aub_mem
*mem
= _mem
;
251 struct gen_batch_decode_bo bo
= {0};
253 list_for_each_entry(struct bo_map
, i
, &mem
->maps
, link
)
254 if (i
->bo
.addr
<= address
&& i
->bo
.addr
+ i
->bo
.size
> address
)
259 struct ggtt_entry
*start
=
260 (struct ggtt_entry
*)rb_tree_search_sloppy(&mem
->ggtt
, &address
,
262 if (start
&& start
->virt_addr
< address
)
263 start
= ggtt_entry_next(start
);
267 struct ggtt_entry
*last
= start
;
268 for (struct ggtt_entry
*i
= ggtt_entry_next(last
);
269 i
&& last
->virt_addr
+ 4096 == i
->virt_addr
;
270 last
= i
, i
= ggtt_entry_next(last
))
273 bo
.addr
= MIN2(address
, start
->virt_addr
);
274 bo
.size
= last
->virt_addr
- bo
.addr
+ 4096;
275 bo
.map
= mmap(NULL
, bo
.size
, PROT_READ
, MAP_SHARED
| MAP_ANONYMOUS
, -1, 0);
276 assert(bo
.map
!= MAP_FAILED
);
278 for (struct ggtt_entry
*i
= start
;
280 i
= i
== last
? NULL
: ggtt_entry_next(i
)) {
281 uint64_t phys_addr
= i
->phys_addr
& ~0xfff;
282 struct phys_mem
*phys_mem
= search_phys_mem(mem
, phys_addr
);
287 uint32_t map_offset
= i
->virt_addr
- address
;
288 void *res
= mmap((uint8_t *)bo
.map
+ map_offset
, 4096, PROT_READ
,
289 MAP_SHARED
| MAP_FIXED
, mem
->mem_fd
, phys_mem
->fd_offset
);
290 assert(res
!= MAP_FAILED
);
293 add_gtt_bo_map(mem
, bo
, true);
298 static struct phys_mem
*
299 ppgtt_walk(struct aub_mem
*mem
, uint64_t pml4
, uint64_t address
)
302 uint64_t addr
= pml4
;
303 for (int level
= 4; level
> 0; level
--) {
304 struct phys_mem
*table
= search_phys_mem(mem
, addr
);
307 int index
= (address
>> shift
) & 0x1ff;
308 uint64_t entry
= ((uint64_t *)table
->data
)[index
];
311 addr
= entry
& ~0xfff;
314 return search_phys_mem(mem
, addr
);
318 ppgtt_mapped(struct aub_mem
*mem
, uint64_t pml4
, uint64_t address
)
320 return ppgtt_walk(mem
, pml4
, address
) != NULL
;
323 struct gen_batch_decode_bo
324 aub_mem_get_ppgtt_bo(void *_mem
, uint64_t address
)
326 struct aub_mem
*mem
= _mem
;
327 struct gen_batch_decode_bo bo
= {0};
331 if (!ppgtt_mapped(mem
, mem
->pml4
, address
))
334 /* Map everything until the first gap since we don't know how much the
335 * decoder actually needs.
337 uint64_t end
= address
;
338 while (ppgtt_mapped(mem
, mem
->pml4
, end
))
342 bo
.size
= end
- address
;
343 bo
.map
= mmap(NULL
, bo
.size
, PROT_READ
, MAP_SHARED
| MAP_ANONYMOUS
, -1, 0);
344 assert(bo
.map
!= MAP_FAILED
);
346 for (uint64_t page
= address
; page
< end
; page
+= 4096) {
347 struct phys_mem
*phys_mem
= ppgtt_walk(mem
, mem
->pml4
, page
);
349 void *res
= mmap((uint8_t *)bo
.map
+ (page
- bo
.addr
), 4096, PROT_READ
,
350 MAP_SHARED
| MAP_FIXED
, mem
->mem_fd
, phys_mem
->fd_offset
);
351 assert(res
!= MAP_FAILED
);
354 add_gtt_bo_map(mem
, bo
, true);
360 aub_mem_init(struct aub_mem
*mem
)
362 memset(mem
, 0, sizeof(*mem
));
364 list_inithead(&mem
->maps
);
366 mem
->mem_fd
= memfd_create("phys memory", 0);
368 return mem
->mem_fd
!= -1;
372 aub_mem_fini(struct aub_mem
*mem
)
374 if (mem
->mem_fd
== -1)
377 aub_mem_clear_bo_maps(mem
);
380 rb_tree_foreach_safe(struct ggtt_entry
, entry
, &mem
->ggtt
, node
) {
381 rb_tree_remove(&mem
->ggtt
, &entry
->node
);
384 rb_tree_foreach_safe(struct phys_mem
, entry
, &mem
->mem
, node
) {
385 rb_tree_remove(&mem
->mem
, &entry
->node
);