OSDN Git Service

amdgpu: add sync_file import and export functions
[android-x86/external-libdrm.git] / amdgpu / amdgpu_bo.c
1 /*
2  * Copyright © 2014 Advanced Micro Devices, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <sys/ioctl.h>
37 #include <sys/mman.h>
38 #include <sys/time.h>
39
40 #include "libdrm_macros.h"
41 #include "xf86drm.h"
42 #include "amdgpu_drm.h"
43 #include "amdgpu_internal.h"
44 #include "util_hash_table.h"
45 #include "util_math.h"
46
47 static void amdgpu_close_kms_handle(amdgpu_device_handle dev,
48                                      uint32_t handle)
49 {
50         struct drm_gem_close args = {};
51
52         args.handle = handle;
53         drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &args);
54 }
55
56 int amdgpu_bo_alloc(amdgpu_device_handle dev,
57                     struct amdgpu_bo_alloc_request *alloc_buffer,
58                     amdgpu_bo_handle *buf_handle)
59 {
60         struct amdgpu_bo *bo;
61         union drm_amdgpu_gem_create args;
62         unsigned heap = alloc_buffer->preferred_heap;
63         int r = 0;
64
65         /* It's an error if the heap is not specified */
66         if (!(heap & (AMDGPU_GEM_DOMAIN_GTT | AMDGPU_GEM_DOMAIN_VRAM)))
67                 return -EINVAL;
68
69         bo = calloc(1, sizeof(struct amdgpu_bo));
70         if (!bo)
71                 return -ENOMEM;
72
73         atomic_set(&bo->refcount, 1);
74         bo->dev = dev;
75         bo->alloc_size = alloc_buffer->alloc_size;
76
77         memset(&args, 0, sizeof(args));
78         args.in.bo_size = alloc_buffer->alloc_size;
79         args.in.alignment = alloc_buffer->phys_alignment;
80
81         /* Set the placement. */
82         args.in.domains = heap;
83         args.in.domain_flags = alloc_buffer->flags;
84
85         /* Allocate the buffer with the preferred heap. */
86         r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_CREATE,
87                                 &args, sizeof(args));
88         if (r) {
89                 free(bo);
90                 return r;
91         }
92
93         bo->handle = args.out.handle;
94
95         pthread_mutex_init(&bo->cpu_access_mutex, NULL);
96
97         *buf_handle = bo;
98         return 0;
99 }
100
101 int amdgpu_bo_set_metadata(amdgpu_bo_handle bo,
102                            struct amdgpu_bo_metadata *info)
103 {
104         struct drm_amdgpu_gem_metadata args = {};
105
106         args.handle = bo->handle;
107         args.op = AMDGPU_GEM_METADATA_OP_SET_METADATA;
108         args.data.flags = info->flags;
109         args.data.tiling_info = info->tiling_info;
110
111         if (info->size_metadata > sizeof(args.data.data))
112                 return -EINVAL;
113
114         if (info->size_metadata) {
115                 args.data.data_size_bytes = info->size_metadata;
116                 memcpy(args.data.data, info->umd_metadata, info->size_metadata);
117         }
118
119         return drmCommandWriteRead(bo->dev->fd,
120                                    DRM_AMDGPU_GEM_METADATA,
121                                    &args, sizeof(args));
122 }
123
124 int amdgpu_bo_query_info(amdgpu_bo_handle bo,
125                          struct amdgpu_bo_info *info)
126 {
127         struct drm_amdgpu_gem_metadata metadata = {};
128         struct drm_amdgpu_gem_create_in bo_info = {};
129         struct drm_amdgpu_gem_op gem_op = {};
130         int r;
131
132         /* Validate the BO passed in */
133         if (!bo->handle)
134                 return -EINVAL;
135
136         /* Query metadata. */
137         metadata.handle = bo->handle;
138         metadata.op = AMDGPU_GEM_METADATA_OP_GET_METADATA;
139
140         r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_METADATA,
141                                 &metadata, sizeof(metadata));
142         if (r)
143                 return r;
144
145         if (metadata.data.data_size_bytes >
146             sizeof(info->metadata.umd_metadata))
147                 return -EINVAL;
148
149         /* Query buffer info. */
150         gem_op.handle = bo->handle;
151         gem_op.op = AMDGPU_GEM_OP_GET_GEM_CREATE_INFO;
152         gem_op.value = (uintptr_t)&bo_info;
153
154         r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_OP,
155                                 &gem_op, sizeof(gem_op));
156         if (r)
157                 return r;
158
159         memset(info, 0, sizeof(*info));
160         info->alloc_size = bo_info.bo_size;
161         info->phys_alignment = bo_info.alignment;
162         info->preferred_heap = bo_info.domains;
163         info->alloc_flags = bo_info.domain_flags;
164         info->metadata.flags = metadata.data.flags;
165         info->metadata.tiling_info = metadata.data.tiling_info;
166
167         info->metadata.size_metadata = metadata.data.data_size_bytes;
168         if (metadata.data.data_size_bytes > 0)
169                 memcpy(info->metadata.umd_metadata, metadata.data.data,
170                        metadata.data.data_size_bytes);
171
172         return 0;
173 }
174
175 static void amdgpu_add_handle_to_table(amdgpu_bo_handle bo)
176 {
177         pthread_mutex_lock(&bo->dev->bo_table_mutex);
178         util_hash_table_set(bo->dev->bo_handles,
179                             (void*)(uintptr_t)bo->handle, bo);
180         pthread_mutex_unlock(&bo->dev->bo_table_mutex);
181 }
182
183 static int amdgpu_bo_export_flink(amdgpu_bo_handle bo)
184 {
185         struct drm_gem_flink flink;
186         int fd, dma_fd;
187         uint32_t handle;
188         int r;
189
190         fd = bo->dev->fd;
191         handle = bo->handle;
192         if (bo->flink_name)
193                 return 0;
194
195
196         if (bo->dev->flink_fd != bo->dev->fd) {
197                 r = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
198                                        &dma_fd);
199                 if (!r) {
200                         r = drmPrimeFDToHandle(bo->dev->flink_fd, dma_fd, &handle);
201                         close(dma_fd);
202                 }
203                 if (r)
204                         return r;
205                 fd = bo->dev->flink_fd;
206         }
207         memset(&flink, 0, sizeof(flink));
208         flink.handle = handle;
209
210         r = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
211         if (r)
212                 return r;
213
214         bo->flink_name = flink.name;
215
216         if (bo->dev->flink_fd != bo->dev->fd) {
217                 struct drm_gem_close args = {};
218                 args.handle = handle;
219                 drmIoctl(bo->dev->flink_fd, DRM_IOCTL_GEM_CLOSE, &args);
220         }
221
222         pthread_mutex_lock(&bo->dev->bo_table_mutex);
223         util_hash_table_set(bo->dev->bo_flink_names,
224                             (void*)(uintptr_t)bo->flink_name,
225                             bo);
226         pthread_mutex_unlock(&bo->dev->bo_table_mutex);
227
228         return 0;
229 }
230
231 int amdgpu_bo_export(amdgpu_bo_handle bo,
232                      enum amdgpu_bo_handle_type type,
233                      uint32_t *shared_handle)
234 {
235         int r;
236
237         switch (type) {
238         case amdgpu_bo_handle_type_gem_flink_name:
239                 r = amdgpu_bo_export_flink(bo);
240                 if (r)
241                         return r;
242
243                 *shared_handle = bo->flink_name;
244                 return 0;
245
246         case amdgpu_bo_handle_type_kms:
247                 amdgpu_add_handle_to_table(bo);
248                 *shared_handle = bo->handle;
249                 return 0;
250
251         case amdgpu_bo_handle_type_dma_buf_fd:
252                 amdgpu_add_handle_to_table(bo);
253                 return drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
254                                        (int*)shared_handle);
255         }
256         return -EINVAL;
257 }
258
259 int amdgpu_bo_import(amdgpu_device_handle dev,
260                      enum amdgpu_bo_handle_type type,
261                      uint32_t shared_handle,
262                      struct amdgpu_bo_import_result *output)
263 {
264         struct drm_gem_open open_arg = {};
265         struct amdgpu_bo *bo = NULL;
266         int r;
267         int dma_fd;
268         uint64_t dma_buf_size = 0;
269
270         /* We must maintain a list of pairs <handle, bo>, so that we always
271          * return the same amdgpu_bo instance for the same handle. */
272         pthread_mutex_lock(&dev->bo_table_mutex);
273
274         /* Convert a DMA buf handle to a KMS handle now. */
275         if (type == amdgpu_bo_handle_type_dma_buf_fd) {
276                 uint32_t handle;
277                 off_t size;
278
279                 /* Get a KMS handle. */
280                 r = drmPrimeFDToHandle(dev->fd, shared_handle, &handle);
281                 if (r) {
282                         pthread_mutex_unlock(&dev->bo_table_mutex);
283                         return r;
284                 }
285
286                 /* Query the buffer size. */
287                 size = lseek(shared_handle, 0, SEEK_END);
288                 if (size == (off_t)-1) {
289                         pthread_mutex_unlock(&dev->bo_table_mutex);
290                         amdgpu_close_kms_handle(dev, handle);
291                         return -errno;
292                 }
293                 lseek(shared_handle, 0, SEEK_SET);
294
295                 dma_buf_size = size;
296                 shared_handle = handle;
297         }
298
299         /* If we have already created a buffer with this handle, find it. */
300         switch (type) {
301         case amdgpu_bo_handle_type_gem_flink_name:
302                 bo = util_hash_table_get(dev->bo_flink_names,
303                                          (void*)(uintptr_t)shared_handle);
304                 break;
305
306         case amdgpu_bo_handle_type_dma_buf_fd:
307                 bo = util_hash_table_get(dev->bo_handles,
308                                          (void*)(uintptr_t)shared_handle);
309                 break;
310
311         case amdgpu_bo_handle_type_kms:
312                 /* Importing a KMS handle in not allowed. */
313                 pthread_mutex_unlock(&dev->bo_table_mutex);
314                 return -EPERM;
315
316         default:
317                 pthread_mutex_unlock(&dev->bo_table_mutex);
318                 return -EINVAL;
319         }
320
321         if (bo) {
322                 /* The buffer already exists, just bump the refcount. */
323                 atomic_inc(&bo->refcount);
324                 pthread_mutex_unlock(&dev->bo_table_mutex);
325
326                 output->buf_handle = bo;
327                 output->alloc_size = bo->alloc_size;
328                 return 0;
329         }
330
331         bo = calloc(1, sizeof(struct amdgpu_bo));
332         if (!bo) {
333                 pthread_mutex_unlock(&dev->bo_table_mutex);
334                 if (type == amdgpu_bo_handle_type_dma_buf_fd) {
335                         amdgpu_close_kms_handle(dev, shared_handle);
336                 }
337                 return -ENOMEM;
338         }
339
340         /* Open the handle. */
341         switch (type) {
342         case amdgpu_bo_handle_type_gem_flink_name:
343                 open_arg.name = shared_handle;
344                 r = drmIoctl(dev->flink_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
345                 if (r) {
346                         free(bo);
347                         pthread_mutex_unlock(&dev->bo_table_mutex);
348                         return r;
349                 }
350
351                 bo->handle = open_arg.handle;
352                 if (dev->flink_fd != dev->fd) {
353                         r = drmPrimeHandleToFD(dev->flink_fd, bo->handle, DRM_CLOEXEC, &dma_fd);
354                         if (r) {
355                                 free(bo);
356                                 pthread_mutex_unlock(&dev->bo_table_mutex);
357                                 return r;
358                         }
359                         r = drmPrimeFDToHandle(dev->fd, dma_fd, &bo->handle );
360
361                         close(dma_fd);
362
363                         if (r) {
364                                 free(bo);
365                                 pthread_mutex_unlock(&dev->bo_table_mutex);
366                                 return r;
367                         }
368                 }
369                 bo->flink_name = shared_handle;
370                 bo->alloc_size = open_arg.size;
371                 util_hash_table_set(dev->bo_flink_names,
372                                     (void*)(uintptr_t)bo->flink_name, bo);
373                 break;
374
375         case amdgpu_bo_handle_type_dma_buf_fd:
376                 bo->handle = shared_handle;
377                 bo->alloc_size = dma_buf_size;
378                 break;
379
380         case amdgpu_bo_handle_type_kms:
381                 assert(0); /* unreachable */
382         }
383
384         /* Initialize it. */
385         atomic_set(&bo->refcount, 1);
386         bo->dev = dev;
387         pthread_mutex_init(&bo->cpu_access_mutex, NULL);
388
389         util_hash_table_set(dev->bo_handles, (void*)(uintptr_t)bo->handle, bo);
390         pthread_mutex_unlock(&dev->bo_table_mutex);
391
392         output->buf_handle = bo;
393         output->alloc_size = bo->alloc_size;
394         return 0;
395 }
396
397 int amdgpu_bo_free(amdgpu_bo_handle buf_handle)
398 {
399         struct amdgpu_device *dev;
400         struct amdgpu_bo *bo = buf_handle;
401
402         assert(bo != NULL);
403         dev = bo->dev;
404         pthread_mutex_lock(&dev->bo_table_mutex);
405
406         if (update_references(&bo->refcount, NULL)) {
407                 /* Remove the buffer from the hash tables. */
408                 util_hash_table_remove(dev->bo_handles,
409                                         (void*)(uintptr_t)bo->handle);
410
411                 if (bo->flink_name) {
412                         util_hash_table_remove(dev->bo_flink_names,
413                                                 (void*)(uintptr_t)bo->flink_name);
414                 }
415
416                 /* Release CPU access. */
417                 if (bo->cpu_map_count > 0) {
418                         bo->cpu_map_count = 1;
419                         amdgpu_bo_cpu_unmap(bo);
420                 }
421
422                 amdgpu_close_kms_handle(dev, bo->handle);
423                 pthread_mutex_destroy(&bo->cpu_access_mutex);
424                 free(bo);
425         }
426
427         pthread_mutex_unlock(&dev->bo_table_mutex);
428         return 0;
429 }
430
431 int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu)
432 {
433         union drm_amdgpu_gem_mmap args;
434         void *ptr;
435         int r;
436
437         pthread_mutex_lock(&bo->cpu_access_mutex);
438
439         if (bo->cpu_ptr) {
440                 /* already mapped */
441                 assert(bo->cpu_map_count > 0);
442                 bo->cpu_map_count++;
443                 *cpu = bo->cpu_ptr;
444                 pthread_mutex_unlock(&bo->cpu_access_mutex);
445                 return 0;
446         }
447
448         assert(bo->cpu_map_count == 0);
449
450         memset(&args, 0, sizeof(args));
451
452         /* Query the buffer address (args.addr_ptr).
453          * The kernel driver ignores the offset and size parameters. */
454         args.in.handle = bo->handle;
455
456         r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_MMAP, &args,
457                                 sizeof(args));
458         if (r) {
459                 pthread_mutex_unlock(&bo->cpu_access_mutex);
460                 return r;
461         }
462
463         /* Map the buffer. */
464         ptr = drm_mmap(NULL, bo->alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED,
465                        bo->dev->fd, args.out.addr_ptr);
466         if (ptr == MAP_FAILED) {
467                 pthread_mutex_unlock(&bo->cpu_access_mutex);
468                 return -errno;
469         }
470
471         bo->cpu_ptr = ptr;
472         bo->cpu_map_count = 1;
473         pthread_mutex_unlock(&bo->cpu_access_mutex);
474
475         *cpu = ptr;
476         return 0;
477 }
478
479 int amdgpu_bo_cpu_unmap(amdgpu_bo_handle bo)
480 {
481         int r;
482
483         pthread_mutex_lock(&bo->cpu_access_mutex);
484         assert(bo->cpu_map_count >= 0);
485
486         if (bo->cpu_map_count == 0) {
487                 /* not mapped */
488                 pthread_mutex_unlock(&bo->cpu_access_mutex);
489                 return -EINVAL;
490         }
491
492         bo->cpu_map_count--;
493         if (bo->cpu_map_count > 0) {
494                 /* mapped multiple times */
495                 pthread_mutex_unlock(&bo->cpu_access_mutex);
496                 return 0;
497         }
498
499         r = drm_munmap(bo->cpu_ptr, bo->alloc_size) == 0 ? 0 : -errno;
500         bo->cpu_ptr = NULL;
501         pthread_mutex_unlock(&bo->cpu_access_mutex);
502         return r;
503 }
504
505 int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev,
506                                 struct amdgpu_buffer_size_alignments *info)
507 {
508         info->size_local = dev->dev_info.pte_fragment_size;
509         info->size_remote = dev->dev_info.gart_page_size;
510         return 0;
511 }
512
513 int amdgpu_bo_wait_for_idle(amdgpu_bo_handle bo,
514                             uint64_t timeout_ns,
515                             bool *busy)
516 {
517         union drm_amdgpu_gem_wait_idle args;
518         int r;
519
520         memset(&args, 0, sizeof(args));
521         args.in.handle = bo->handle;
522         args.in.timeout = amdgpu_cs_calculate_timeout(timeout_ns);
523
524         r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_WAIT_IDLE,
525                                 &args, sizeof(args));
526
527         if (r == 0) {
528                 *busy = args.out.status;
529                 return 0;
530         } else {
531                 fprintf(stderr, "amdgpu: GEM_WAIT_IDLE failed with %i\n", r);
532                 return r;
533         }
534 }
535
536 int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev,
537                                     void *cpu,
538                                     uint64_t size,
539                                     amdgpu_bo_handle *buf_handle)
540 {
541         int r;
542         struct amdgpu_bo *bo;
543         struct drm_amdgpu_gem_userptr args;
544
545         args.addr = (uintptr_t)cpu;
546         args.flags = AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_REGISTER |
547                 AMDGPU_GEM_USERPTR_VALIDATE;
548         args.size = size;
549         r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_USERPTR,
550                                 &args, sizeof(args));
551         if (r)
552                 return r;
553
554         bo = calloc(1, sizeof(struct amdgpu_bo));
555         if (!bo)
556                 return -ENOMEM;
557
558         atomic_set(&bo->refcount, 1);
559         bo->dev = dev;
560         bo->alloc_size = size;
561         bo->handle = args.handle;
562
563         *buf_handle = bo;
564
565         return r;
566 }
567
568 int amdgpu_bo_list_create(amdgpu_device_handle dev,
569                           uint32_t number_of_resources,
570                           amdgpu_bo_handle *resources,
571                           uint8_t *resource_prios,
572                           amdgpu_bo_list_handle *result)
573 {
574         struct drm_amdgpu_bo_list_entry *list;
575         union drm_amdgpu_bo_list args;
576         unsigned i;
577         int r;
578
579         if (!number_of_resources)
580                 return -EINVAL;
581
582         /* overflow check for multiplication */
583         if (number_of_resources > UINT32_MAX / sizeof(struct drm_amdgpu_bo_list_entry))
584                 return -EINVAL;
585
586         list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry));
587         if (!list)
588                 return -ENOMEM;
589
590         *result = malloc(sizeof(struct amdgpu_bo_list));
591         if (!*result) {
592                 free(list);
593                 return -ENOMEM;
594         }
595
596         memset(&args, 0, sizeof(args));
597         args.in.operation = AMDGPU_BO_LIST_OP_CREATE;
598         args.in.bo_number = number_of_resources;
599         args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry);
600         args.in.bo_info_ptr = (uint64_t)(uintptr_t)list;
601
602         for (i = 0; i < number_of_resources; i++) {
603                 list[i].bo_handle = resources[i]->handle;
604                 if (resource_prios)
605                         list[i].bo_priority = resource_prios[i];
606                 else
607                         list[i].bo_priority = 0;
608         }
609
610         r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST,
611                                 &args, sizeof(args));
612         free(list);
613         if (r) {
614                 free(*result);
615                 return r;
616         }
617
618         (*result)->dev = dev;
619         (*result)->handle = args.out.list_handle;
620         return 0;
621 }
622
623 int amdgpu_bo_list_destroy(amdgpu_bo_list_handle list)
624 {
625         union drm_amdgpu_bo_list args;
626         int r;
627
628         memset(&args, 0, sizeof(args));
629         args.in.operation = AMDGPU_BO_LIST_OP_DESTROY;
630         args.in.list_handle = list->handle;
631
632         r = drmCommandWriteRead(list->dev->fd, DRM_AMDGPU_BO_LIST,
633                                 &args, sizeof(args));
634
635         if (!r)
636                 free(list);
637
638         return r;
639 }
640
641 int amdgpu_bo_list_update(amdgpu_bo_list_handle handle,
642                           uint32_t number_of_resources,
643                           amdgpu_bo_handle *resources,
644                           uint8_t *resource_prios)
645 {
646         struct drm_amdgpu_bo_list_entry *list;
647         union drm_amdgpu_bo_list args;
648         unsigned i;
649         int r;
650
651         if (!number_of_resources)
652                 return -EINVAL;
653
654         /* overflow check for multiplication */
655         if (number_of_resources > UINT32_MAX / sizeof(struct drm_amdgpu_bo_list_entry))
656                 return -EINVAL;
657
658         list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry));
659         if (!list)
660                 return -ENOMEM;
661
662         args.in.operation = AMDGPU_BO_LIST_OP_UPDATE;
663         args.in.list_handle = handle->handle;
664         args.in.bo_number = number_of_resources;
665         args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry);
666         args.in.bo_info_ptr = (uintptr_t)list;
667
668         for (i = 0; i < number_of_resources; i++) {
669                 list[i].bo_handle = resources[i]->handle;
670                 if (resource_prios)
671                         list[i].bo_priority = resource_prios[i];
672                 else
673                         list[i].bo_priority = 0;
674         }
675
676         r = drmCommandWriteRead(handle->dev->fd, DRM_AMDGPU_BO_LIST,
677                                 &args, sizeof(args));
678         free(list);
679         return r;
680 }
681
682 int amdgpu_bo_va_op(amdgpu_bo_handle bo,
683                      uint64_t offset,
684                      uint64_t size,
685                      uint64_t addr,
686                      uint64_t flags,
687                      uint32_t ops)
688 {
689         amdgpu_device_handle dev = bo->dev;
690
691         size = ALIGN(size, getpagesize());
692
693         return amdgpu_bo_va_op_raw(dev, bo, offset, size, addr,
694                                    AMDGPU_VM_PAGE_READABLE |
695                                    AMDGPU_VM_PAGE_WRITEABLE |
696                                    AMDGPU_VM_PAGE_EXECUTABLE, ops);
697 }
698
699 int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
700                         amdgpu_bo_handle bo,
701                         uint64_t offset,
702                         uint64_t size,
703                         uint64_t addr,
704                         uint64_t flags,
705                         uint32_t ops)
706 {
707         struct drm_amdgpu_gem_va va;
708         int r;
709
710         if (ops != AMDGPU_VA_OP_MAP && ops != AMDGPU_VA_OP_UNMAP &&
711             ops != AMDGPU_VA_OP_REPLACE && ops != AMDGPU_VA_OP_CLEAR)
712                 return -EINVAL;
713
714         memset(&va, 0, sizeof(va));
715         va.handle = bo ? bo->handle : 0;
716         va.operation = ops;
717         va.flags = flags;
718         va.va_address = addr;
719         va.offset_in_bo = offset;
720         va.map_size = size;
721
722         r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va));
723
724         return r;
725 }