amdgpu_bo.c revision bf6cc7dc
13f012e29Smrg/* 23f012e29Smrg * Copyright © 2014 Advanced Micro Devices, Inc. 33f012e29Smrg * All Rights Reserved. 43f012e29Smrg * 53f012e29Smrg * Permission is hereby granted, free of charge, to any person obtaining a 63f012e29Smrg * copy of this software and associated documentation files (the "Software"), 73f012e29Smrg * to deal in the Software without restriction, including without limitation 83f012e29Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 93f012e29Smrg * and/or sell copies of the Software, and to permit persons to whom the 103f012e29Smrg * Software is furnished to do so, subject to the following conditions: 113f012e29Smrg * 123f012e29Smrg * The above copyright notice and this permission notice shall be included in 133f012e29Smrg * all copies or substantial portions of the Software. 143f012e29Smrg * 153f012e29Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 163f012e29Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 173f012e29Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 183f012e29Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 193f012e29Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 203f012e29Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 213f012e29Smrg * OTHER DEALINGS IN THE SOFTWARE. 223f012e29Smrg * 233f012e29Smrg */ 243f012e29Smrg 253f012e29Smrg#include <stdlib.h> 263f012e29Smrg#include <stdio.h> 273f012e29Smrg#include <stdint.h> 283f012e29Smrg#include <string.h> 293f012e29Smrg#include <errno.h> 303f012e29Smrg#include <fcntl.h> 313f012e29Smrg#include <unistd.h> 323f012e29Smrg#include <sys/ioctl.h> 333f012e29Smrg#include <sys/mman.h> 343f012e29Smrg#include <sys/time.h> 353f012e29Smrg 363f012e29Smrg#include "libdrm_macros.h" 373f012e29Smrg#include "xf86drm.h" 383f012e29Smrg#include "amdgpu_drm.h" 393f012e29Smrg#include "amdgpu_internal.h" 403f012e29Smrg#include "util_math.h" 413f012e29Smrg 42bf6cc7dcSmrgstatic int amdgpu_close_kms_handle(int fd, uint32_t handle) 433f012e29Smrg{ 443f012e29Smrg struct drm_gem_close args = {}; 453f012e29Smrg 463f012e29Smrg args.handle = handle; 47bf6cc7dcSmrg return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args); 483f012e29Smrg} 493f012e29Smrg 507cdc0497Smrgstatic int amdgpu_bo_create(amdgpu_device_handle dev, 517cdc0497Smrg uint64_t size, 527cdc0497Smrg uint32_t handle, 537cdc0497Smrg amdgpu_bo_handle *buf_handle) 543f012e29Smrg{ 553f012e29Smrg struct amdgpu_bo *bo; 56bf6cc7dcSmrg int r; 573f012e29Smrg 583f012e29Smrg bo = calloc(1, sizeof(struct amdgpu_bo)); 593f012e29Smrg if (!bo) 603f012e29Smrg return -ENOMEM; 613f012e29Smrg 62bf6cc7dcSmrg r = handle_table_insert(&dev->bo_handles, handle, bo); 63bf6cc7dcSmrg if (r) { 64bf6cc7dcSmrg free(bo); 65bf6cc7dcSmrg return r; 66bf6cc7dcSmrg } 67bf6cc7dcSmrg 683f012e29Smrg atomic_set(&bo->refcount, 1); 693f012e29Smrg bo->dev = dev; 707cdc0497Smrg bo->alloc_size = size; 717cdc0497Smrg bo->handle = handle; 727cdc0497Smrg pthread_mutex_init(&bo->cpu_access_mutex, NULL); 737cdc0497Smrg 747cdc0497Smrg *buf_handle = bo; 757cdc0497Smrg return 0; 767cdc0497Smrg} 777cdc0497Smrg 787cdc0497Smrgdrm_public int amdgpu_bo_alloc(amdgpu_device_handle dev, 797cdc0497Smrg struct amdgpu_bo_alloc_request *alloc_buffer, 807cdc0497Smrg amdgpu_bo_handle *buf_handle) 817cdc0497Smrg{ 827cdc0497Smrg union drm_amdgpu_gem_create args; 837cdc0497Smrg int r; 843f012e29Smrg 853f012e29Smrg memset(&args, 0, sizeof(args)); 863f012e29Smrg args.in.bo_size = alloc_buffer->alloc_size; 873f012e29Smrg args.in.alignment = alloc_buffer->phys_alignment; 883f012e29Smrg 893f012e29Smrg /* Set the placement. */ 907cdc0497Smrg args.in.domains = alloc_buffer->preferred_heap; 913f012e29Smrg args.in.domain_flags = alloc_buffer->flags; 923f012e29Smrg 933f012e29Smrg /* Allocate the buffer with the preferred heap. */ 943f012e29Smrg r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_CREATE, 953f012e29Smrg &args, sizeof(args)); 967cdc0497Smrg if (r) 977cdc0497Smrg goto out; 987cdc0497Smrg 99bf6cc7dcSmrg pthread_mutex_lock(&dev->bo_table_mutex); 1007cdc0497Smrg r = amdgpu_bo_create(dev, alloc_buffer->alloc_size, args.out.handle, 1017cdc0497Smrg buf_handle); 102bf6cc7dcSmrg pthread_mutex_unlock(&dev->bo_table_mutex); 1033f012e29Smrg if (r) { 104bf6cc7dcSmrg amdgpu_close_kms_handle(dev->fd, args.out.handle); 1053f012e29Smrg } 1063f012e29Smrg 1077cdc0497Smrgout: 1087cdc0497Smrg return r; 1093f012e29Smrg} 1103f012e29Smrg 1117cdc0497Smrgdrm_public int amdgpu_bo_set_metadata(amdgpu_bo_handle bo, 1127cdc0497Smrg struct amdgpu_bo_metadata *info) 1133f012e29Smrg{ 1143f012e29Smrg struct drm_amdgpu_gem_metadata args = {}; 1153f012e29Smrg 1163f012e29Smrg args.handle = bo->handle; 1173f012e29Smrg args.op = AMDGPU_GEM_METADATA_OP_SET_METADATA; 1183f012e29Smrg args.data.flags = info->flags; 1193f012e29Smrg args.data.tiling_info = info->tiling_info; 1203f012e29Smrg 1213f012e29Smrg if (info->size_metadata > sizeof(args.data.data)) 1223f012e29Smrg return -EINVAL; 1233f012e29Smrg 1243f012e29Smrg if (info->size_metadata) { 1253f012e29Smrg args.data.data_size_bytes = info->size_metadata; 1263f012e29Smrg memcpy(args.data.data, info->umd_metadata, info->size_metadata); 1273f012e29Smrg } 1283f012e29Smrg 1293f012e29Smrg return drmCommandWriteRead(bo->dev->fd, 1303f012e29Smrg DRM_AMDGPU_GEM_METADATA, 1313f012e29Smrg &args, sizeof(args)); 1323f012e29Smrg} 1333f012e29Smrg 1347cdc0497Smrgdrm_public int amdgpu_bo_query_info(amdgpu_bo_handle bo, 1357cdc0497Smrg struct amdgpu_bo_info *info) 1363f012e29Smrg{ 1373f012e29Smrg struct drm_amdgpu_gem_metadata metadata = {}; 1383f012e29Smrg struct drm_amdgpu_gem_create_in bo_info = {}; 1393f012e29Smrg struct drm_amdgpu_gem_op gem_op = {}; 1403f012e29Smrg int r; 1413f012e29Smrg 1423f012e29Smrg /* Validate the BO passed in */ 1433f012e29Smrg if (!bo->handle) 1443f012e29Smrg return -EINVAL; 1453f012e29Smrg 1463f012e29Smrg /* Query metadata. */ 1473f012e29Smrg metadata.handle = bo->handle; 1483f012e29Smrg metadata.op = AMDGPU_GEM_METADATA_OP_GET_METADATA; 1493f012e29Smrg 1503f012e29Smrg r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_METADATA, 1513f012e29Smrg &metadata, sizeof(metadata)); 1523f012e29Smrg if (r) 1533f012e29Smrg return r; 1543f012e29Smrg 1553f012e29Smrg if (metadata.data.data_size_bytes > 1563f012e29Smrg sizeof(info->metadata.umd_metadata)) 1573f012e29Smrg return -EINVAL; 1583f012e29Smrg 1593f012e29Smrg /* Query buffer info. */ 1603f012e29Smrg gem_op.handle = bo->handle; 1613f012e29Smrg gem_op.op = AMDGPU_GEM_OP_GET_GEM_CREATE_INFO; 1623f012e29Smrg gem_op.value = (uintptr_t)&bo_info; 1633f012e29Smrg 1643f012e29Smrg r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_OP, 1653f012e29Smrg &gem_op, sizeof(gem_op)); 1663f012e29Smrg if (r) 1673f012e29Smrg return r; 1683f012e29Smrg 1693f012e29Smrg memset(info, 0, sizeof(*info)); 1703f012e29Smrg info->alloc_size = bo_info.bo_size; 1713f012e29Smrg info->phys_alignment = bo_info.alignment; 1723f012e29Smrg info->preferred_heap = bo_info.domains; 1733f012e29Smrg info->alloc_flags = bo_info.domain_flags; 1743f012e29Smrg info->metadata.flags = metadata.data.flags; 1753f012e29Smrg info->metadata.tiling_info = metadata.data.tiling_info; 1763f012e29Smrg 1773f012e29Smrg info->metadata.size_metadata = metadata.data.data_size_bytes; 1783f012e29Smrg if (metadata.data.data_size_bytes > 0) 1793f012e29Smrg memcpy(info->metadata.umd_metadata, metadata.data.data, 1803f012e29Smrg metadata.data.data_size_bytes); 1813f012e29Smrg 1823f012e29Smrg return 0; 1833f012e29Smrg} 1843f012e29Smrg 1853f012e29Smrgstatic int amdgpu_bo_export_flink(amdgpu_bo_handle bo) 1863f012e29Smrg{ 1873f012e29Smrg struct drm_gem_flink flink; 1883f012e29Smrg int fd, dma_fd; 1893f012e29Smrg uint32_t handle; 1903f012e29Smrg int r; 1913f012e29Smrg 1923f012e29Smrg fd = bo->dev->fd; 1933f012e29Smrg handle = bo->handle; 1943f012e29Smrg if (bo->flink_name) 1953f012e29Smrg return 0; 1963f012e29Smrg 1973f012e29Smrg 1983f012e29Smrg if (bo->dev->flink_fd != bo->dev->fd) { 1993f012e29Smrg r = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, 2003f012e29Smrg &dma_fd); 2013f012e29Smrg if (!r) { 2023f012e29Smrg r = drmPrimeFDToHandle(bo->dev->flink_fd, dma_fd, &handle); 2033f012e29Smrg close(dma_fd); 2043f012e29Smrg } 2053f012e29Smrg if (r) 2063f012e29Smrg return r; 2073f012e29Smrg fd = bo->dev->flink_fd; 2083f012e29Smrg } 2093f012e29Smrg memset(&flink, 0, sizeof(flink)); 2103f012e29Smrg flink.handle = handle; 2113f012e29Smrg 2123f012e29Smrg r = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink); 2133f012e29Smrg if (r) 2143f012e29Smrg return r; 2153f012e29Smrg 2163f012e29Smrg bo->flink_name = flink.name; 2173f012e29Smrg 218bf6cc7dcSmrg if (bo->dev->flink_fd != bo->dev->fd) 219bf6cc7dcSmrg amdgpu_close_kms_handle(bo->dev->flink_fd, handle); 2203f012e29Smrg 2213f012e29Smrg pthread_mutex_lock(&bo->dev->bo_table_mutex); 2227cdc0497Smrg r = handle_table_insert(&bo->dev->bo_flink_names, bo->flink_name, bo); 2233f012e29Smrg pthread_mutex_unlock(&bo->dev->bo_table_mutex); 2243f012e29Smrg 2257cdc0497Smrg return r; 2263f012e29Smrg} 2273f012e29Smrg 2287cdc0497Smrgdrm_public int amdgpu_bo_export(amdgpu_bo_handle bo, 2297cdc0497Smrg enum amdgpu_bo_handle_type type, 2307cdc0497Smrg uint32_t *shared_handle) 2313f012e29Smrg{ 2323f012e29Smrg int r; 2333f012e29Smrg 2343f012e29Smrg switch (type) { 2353f012e29Smrg case amdgpu_bo_handle_type_gem_flink_name: 2363f012e29Smrg r = amdgpu_bo_export_flink(bo); 2373f012e29Smrg if (r) 2383f012e29Smrg return r; 2393f012e29Smrg 2403f012e29Smrg *shared_handle = bo->flink_name; 2413f012e29Smrg return 0; 2423f012e29Smrg 2433f012e29Smrg case amdgpu_bo_handle_type_kms: 2447cdc0497Smrg case amdgpu_bo_handle_type_kms_noimport: 2453f012e29Smrg *shared_handle = bo->handle; 2463f012e29Smrg return 0; 2473f012e29Smrg 2483f012e29Smrg case amdgpu_bo_handle_type_dma_buf_fd: 2497cdc0497Smrg return drmPrimeHandleToFD(bo->dev->fd, bo->handle, 2507cdc0497Smrg DRM_CLOEXEC | DRM_RDWR, 2517cdc0497Smrg (int*)shared_handle); 2523f012e29Smrg } 2533f012e29Smrg return -EINVAL; 2543f012e29Smrg} 2553f012e29Smrg 2567cdc0497Smrgdrm_public int amdgpu_bo_import(amdgpu_device_handle dev, 2577cdc0497Smrg enum amdgpu_bo_handle_type type, 2587cdc0497Smrg uint32_t shared_handle, 2593f012e29Smrg struct amdgpu_bo_import_result *output) 2603f012e29Smrg{ 2613f012e29Smrg struct drm_gem_open open_arg = {}; 2623f012e29Smrg struct amdgpu_bo *bo = NULL; 2637cdc0497Smrg uint32_t handle = 0, flink_name = 0; 2647cdc0497Smrg uint64_t alloc_size = 0; 2657cdc0497Smrg int r = 0; 2663f012e29Smrg int dma_fd; 2673f012e29Smrg uint64_t dma_buf_size = 0; 2683f012e29Smrg 2693f012e29Smrg /* We must maintain a list of pairs <handle, bo>, so that we always 2703f012e29Smrg * return the same amdgpu_bo instance for the same handle. */ 2713f012e29Smrg pthread_mutex_lock(&dev->bo_table_mutex); 2723f012e29Smrg 2733f012e29Smrg /* Convert a DMA buf handle to a KMS handle now. */ 2743f012e29Smrg if (type == amdgpu_bo_handle_type_dma_buf_fd) { 2753f012e29Smrg off_t size; 2763f012e29Smrg 2773f012e29Smrg /* Get a KMS handle. */ 2783f012e29Smrg r = drmPrimeFDToHandle(dev->fd, shared_handle, &handle); 2797cdc0497Smrg if (r) 2807cdc0497Smrg goto unlock; 2813f012e29Smrg 2823f012e29Smrg /* Query the buffer size. */ 2833f012e29Smrg size = lseek(shared_handle, 0, SEEK_END); 2843f012e29Smrg if (size == (off_t)-1) { 2857cdc0497Smrg r = -errno; 2867cdc0497Smrg goto free_bo_handle; 2873f012e29Smrg } 2883f012e29Smrg lseek(shared_handle, 0, SEEK_SET); 2893f012e29Smrg 2903f012e29Smrg dma_buf_size = size; 2913f012e29Smrg shared_handle = handle; 2923f012e29Smrg } 2933f012e29Smrg 2943f012e29Smrg /* If we have already created a buffer with this handle, find it. */ 2953f012e29Smrg switch (type) { 2963f012e29Smrg case amdgpu_bo_handle_type_gem_flink_name: 2977cdc0497Smrg bo = handle_table_lookup(&dev->bo_flink_names, shared_handle); 2983f012e29Smrg break; 2993f012e29Smrg 3003f012e29Smrg case amdgpu_bo_handle_type_dma_buf_fd: 3017cdc0497Smrg bo = handle_table_lookup(&dev->bo_handles, shared_handle); 3023f012e29Smrg break; 3033f012e29Smrg 3043f012e29Smrg case amdgpu_bo_handle_type_kms: 3057cdc0497Smrg case amdgpu_bo_handle_type_kms_noimport: 3063f012e29Smrg /* Importing a KMS handle in not allowed. */ 3077cdc0497Smrg r = -EPERM; 3087cdc0497Smrg goto unlock; 3093f012e29Smrg 3103f012e29Smrg default: 3117cdc0497Smrg r = -EINVAL; 3127cdc0497Smrg goto unlock; 3133f012e29Smrg } 3143f012e29Smrg 3153f012e29Smrg if (bo) { 3163f012e29Smrg /* The buffer already exists, just bump the refcount. */ 3173f012e29Smrg atomic_inc(&bo->refcount); 318d8807b2fSmrg pthread_mutex_unlock(&dev->bo_table_mutex); 3193f012e29Smrg 3203f012e29Smrg output->buf_handle = bo; 3213f012e29Smrg output->alloc_size = bo->alloc_size; 3223f012e29Smrg return 0; 3233f012e29Smrg } 3243f012e29Smrg 3253f012e29Smrg /* Open the handle. */ 3263f012e29Smrg switch (type) { 3273f012e29Smrg case amdgpu_bo_handle_type_gem_flink_name: 3283f012e29Smrg open_arg.name = shared_handle; 3293f012e29Smrg r = drmIoctl(dev->flink_fd, DRM_IOCTL_GEM_OPEN, &open_arg); 3307cdc0497Smrg if (r) 3317cdc0497Smrg goto unlock; 3323f012e29Smrg 3337cdc0497Smrg flink_name = shared_handle; 3347cdc0497Smrg handle = open_arg.handle; 3357cdc0497Smrg alloc_size = open_arg.size; 3363f012e29Smrg if (dev->flink_fd != dev->fd) { 3377cdc0497Smrg r = drmPrimeHandleToFD(dev->flink_fd, handle, 3387cdc0497Smrg DRM_CLOEXEC, &dma_fd); 3397cdc0497Smrg if (r) 3407cdc0497Smrg goto free_bo_handle; 3417cdc0497Smrg r = drmPrimeFDToHandle(dev->fd, dma_fd, &handle); 3423f012e29Smrg close(dma_fd); 3437cdc0497Smrg if (r) 3447cdc0497Smrg goto free_bo_handle; 345bf6cc7dcSmrg r = amdgpu_close_kms_handle(dev->flink_fd, 346bf6cc7dcSmrg open_arg.handle); 3477cdc0497Smrg if (r) 3487cdc0497Smrg goto free_bo_handle; 3493f012e29Smrg } 350bf6cc7dcSmrg open_arg.handle = 0; 3513f012e29Smrg break; 3523f012e29Smrg 3533f012e29Smrg case amdgpu_bo_handle_type_dma_buf_fd: 3547cdc0497Smrg handle = shared_handle; 3557cdc0497Smrg alloc_size = dma_buf_size; 3563f012e29Smrg break; 3573f012e29Smrg 3583f012e29Smrg case amdgpu_bo_handle_type_kms: 3597cdc0497Smrg case amdgpu_bo_handle_type_kms_noimport: 3603f012e29Smrg assert(0); /* unreachable */ 3613f012e29Smrg } 3623f012e29Smrg 3633f012e29Smrg /* Initialize it. */ 3647cdc0497Smrg r = amdgpu_bo_create(dev, alloc_size, handle, &bo); 3657cdc0497Smrg if (r) 3667cdc0497Smrg goto free_bo_handle; 3673f012e29Smrg 3687cdc0497Smrg if (flink_name) { 3697cdc0497Smrg bo->flink_name = flink_name; 3707cdc0497Smrg r = handle_table_insert(&dev->bo_flink_names, flink_name, 3717cdc0497Smrg bo); 3727cdc0497Smrg if (r) 373bf6cc7dcSmrg goto free_bo_handle; 3747cdc0497Smrg 3757cdc0497Smrg } 3763f012e29Smrg 3773f012e29Smrg output->buf_handle = bo; 3783f012e29Smrg output->alloc_size = bo->alloc_size; 3797cdc0497Smrg pthread_mutex_unlock(&dev->bo_table_mutex); 3803f012e29Smrg return 0; 3817cdc0497Smrg 3827cdc0497Smrgfree_bo_handle: 383bf6cc7dcSmrg if (flink_name && open_arg.handle) 384bf6cc7dcSmrg amdgpu_close_kms_handle(dev->flink_fd, open_arg.handle); 385bf6cc7dcSmrg 3867cdc0497Smrg if (bo) 3877cdc0497Smrg amdgpu_bo_free(bo); 3887cdc0497Smrg else 389bf6cc7dcSmrg amdgpu_close_kms_handle(dev->fd, handle); 3907cdc0497Smrgunlock: 3917cdc0497Smrg pthread_mutex_unlock(&dev->bo_table_mutex); 3927cdc0497Smrg return r; 3933f012e29Smrg} 3943f012e29Smrg 3957cdc0497Smrgdrm_public int amdgpu_bo_free(amdgpu_bo_handle buf_handle) 3963f012e29Smrg{ 397d8807b2fSmrg struct amdgpu_device *dev; 398d8807b2fSmrg struct amdgpu_bo *bo = buf_handle; 399d8807b2fSmrg 400d8807b2fSmrg assert(bo != NULL); 401d8807b2fSmrg dev = bo->dev; 402d8807b2fSmrg pthread_mutex_lock(&dev->bo_table_mutex); 403d8807b2fSmrg 404d8807b2fSmrg if (update_references(&bo->refcount, NULL)) { 405d8807b2fSmrg /* Remove the buffer from the hash tables. */ 4067cdc0497Smrg handle_table_remove(&dev->bo_handles, bo->handle); 407d8807b2fSmrg 4087cdc0497Smrg if (bo->flink_name) 4097cdc0497Smrg handle_table_remove(&dev->bo_flink_names, 4107cdc0497Smrg bo->flink_name); 411d8807b2fSmrg 412d8807b2fSmrg /* Release CPU access. */ 413d8807b2fSmrg if (bo->cpu_map_count > 0) { 414d8807b2fSmrg bo->cpu_map_count = 1; 415d8807b2fSmrg amdgpu_bo_cpu_unmap(bo); 416d8807b2fSmrg } 417d8807b2fSmrg 418bf6cc7dcSmrg amdgpu_close_kms_handle(dev->fd, bo->handle); 419d8807b2fSmrg pthread_mutex_destroy(&bo->cpu_access_mutex); 420d8807b2fSmrg free(bo); 421d8807b2fSmrg } 422d8807b2fSmrg 423d8807b2fSmrg pthread_mutex_unlock(&dev->bo_table_mutex); 424bf6cc7dcSmrg 4253f012e29Smrg return 0; 4263f012e29Smrg} 4273f012e29Smrg 4287cdc0497Smrgdrm_public void amdgpu_bo_inc_ref(amdgpu_bo_handle bo) 4297cdc0497Smrg{ 4307cdc0497Smrg atomic_inc(&bo->refcount); 4317cdc0497Smrg} 4327cdc0497Smrg 4337cdc0497Smrgdrm_public int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu) 4343f012e29Smrg{ 4353f012e29Smrg union drm_amdgpu_gem_mmap args; 4363f012e29Smrg void *ptr; 4373f012e29Smrg int r; 4383f012e29Smrg 4393f012e29Smrg pthread_mutex_lock(&bo->cpu_access_mutex); 4403f012e29Smrg 4413f012e29Smrg if (bo->cpu_ptr) { 4423f012e29Smrg /* already mapped */ 4433f012e29Smrg assert(bo->cpu_map_count > 0); 4443f012e29Smrg bo->cpu_map_count++; 4453f012e29Smrg *cpu = bo->cpu_ptr; 4463f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 4473f012e29Smrg return 0; 4483f012e29Smrg } 4493f012e29Smrg 4503f012e29Smrg assert(bo->cpu_map_count == 0); 4513f012e29Smrg 4523f012e29Smrg memset(&args, 0, sizeof(args)); 4533f012e29Smrg 4543f012e29Smrg /* Query the buffer address (args.addr_ptr). 4553f012e29Smrg * The kernel driver ignores the offset and size parameters. */ 4563f012e29Smrg args.in.handle = bo->handle; 4573f012e29Smrg 4583f012e29Smrg r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_MMAP, &args, 4593f012e29Smrg sizeof(args)); 4603f012e29Smrg if (r) { 4613f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 4623f012e29Smrg return r; 4633f012e29Smrg } 4643f012e29Smrg 4653f012e29Smrg /* Map the buffer. */ 4663f012e29Smrg ptr = drm_mmap(NULL, bo->alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED, 4673f012e29Smrg bo->dev->fd, args.out.addr_ptr); 4683f012e29Smrg if (ptr == MAP_FAILED) { 4693f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 4703f012e29Smrg return -errno; 4713f012e29Smrg } 4723f012e29Smrg 4733f012e29Smrg bo->cpu_ptr = ptr; 4743f012e29Smrg bo->cpu_map_count = 1; 4753f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 4763f012e29Smrg 4773f012e29Smrg *cpu = ptr; 4783f012e29Smrg return 0; 4793f012e29Smrg} 4803f012e29Smrg 4817cdc0497Smrgdrm_public int amdgpu_bo_cpu_unmap(amdgpu_bo_handle bo) 4823f012e29Smrg{ 4833f012e29Smrg int r; 4843f012e29Smrg 4853f012e29Smrg pthread_mutex_lock(&bo->cpu_access_mutex); 4863f012e29Smrg assert(bo->cpu_map_count >= 0); 4873f012e29Smrg 4883f012e29Smrg if (bo->cpu_map_count == 0) { 4893f012e29Smrg /* not mapped */ 4903f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 4913f012e29Smrg return -EINVAL; 4923f012e29Smrg } 4933f012e29Smrg 4943f012e29Smrg bo->cpu_map_count--; 4953f012e29Smrg if (bo->cpu_map_count > 0) { 4963f012e29Smrg /* mapped multiple times */ 4973f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 4983f012e29Smrg return 0; 4993f012e29Smrg } 5003f012e29Smrg 5013f012e29Smrg r = drm_munmap(bo->cpu_ptr, bo->alloc_size) == 0 ? 0 : -errno; 5023f012e29Smrg bo->cpu_ptr = NULL; 5033f012e29Smrg pthread_mutex_unlock(&bo->cpu_access_mutex); 5043f012e29Smrg return r; 5053f012e29Smrg} 5063f012e29Smrg 5077cdc0497Smrgdrm_public int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev, 5083f012e29Smrg struct amdgpu_buffer_size_alignments *info) 5093f012e29Smrg{ 5103f012e29Smrg info->size_local = dev->dev_info.pte_fragment_size; 5113f012e29Smrg info->size_remote = dev->dev_info.gart_page_size; 5123f012e29Smrg return 0; 5133f012e29Smrg} 5143f012e29Smrg 5157cdc0497Smrgdrm_public int amdgpu_bo_wait_for_idle(amdgpu_bo_handle bo, 5167cdc0497Smrg uint64_t timeout_ns, 5173f012e29Smrg bool *busy) 5183f012e29Smrg{ 5193f012e29Smrg union drm_amdgpu_gem_wait_idle args; 5203f012e29Smrg int r; 5213f012e29Smrg 5223f012e29Smrg memset(&args, 0, sizeof(args)); 5233f012e29Smrg args.in.handle = bo->handle; 5243f012e29Smrg args.in.timeout = amdgpu_cs_calculate_timeout(timeout_ns); 5253f012e29Smrg 5263f012e29Smrg r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_WAIT_IDLE, 5273f012e29Smrg &args, sizeof(args)); 5283f012e29Smrg 5293f012e29Smrg if (r == 0) { 5303f012e29Smrg *busy = args.out.status; 5313f012e29Smrg return 0; 5323f012e29Smrg } else { 5333f012e29Smrg fprintf(stderr, "amdgpu: GEM_WAIT_IDLE failed with %i\n", r); 5343f012e29Smrg return r; 5353f012e29Smrg } 5363f012e29Smrg} 5373f012e29Smrg 5387cdc0497Smrgdrm_public int amdgpu_find_bo_by_cpu_mapping(amdgpu_device_handle dev, 5397cdc0497Smrg void *cpu, 5407cdc0497Smrg uint64_t size, 5417cdc0497Smrg amdgpu_bo_handle *buf_handle, 5427cdc0497Smrg uint64_t *offset_in_bo) 5433f012e29Smrg{ 5443f012e29Smrg struct amdgpu_bo *bo; 5457cdc0497Smrg uint32_t i; 5467cdc0497Smrg int r = 0; 5477cdc0497Smrg 5487cdc0497Smrg if (cpu == NULL || size == 0) 5497cdc0497Smrg return -EINVAL; 5507cdc0497Smrg 5517cdc0497Smrg /* 5527cdc0497Smrg * Workaround for a buggy application which tries to import previously 5537cdc0497Smrg * exposed CPU pointers. If we find a real world use case we should 5547cdc0497Smrg * improve that by asking the kernel for the right handle. 5557cdc0497Smrg */ 5567cdc0497Smrg pthread_mutex_lock(&dev->bo_table_mutex); 5577cdc0497Smrg for (i = 0; i < dev->bo_handles.max_key; i++) { 5587cdc0497Smrg bo = handle_table_lookup(&dev->bo_handles, i); 5597cdc0497Smrg if (!bo || !bo->cpu_ptr || size > bo->alloc_size) 5607cdc0497Smrg continue; 5617cdc0497Smrg if (cpu >= bo->cpu_ptr && 5627e21dcc5Schristos cpu < (void*)((char *)bo->cpu_ptr + bo->alloc_size)) 5637cdc0497Smrg break; 5647cdc0497Smrg } 5657cdc0497Smrg 5667cdc0497Smrg if (i < dev->bo_handles.max_key) { 5677cdc0497Smrg atomic_inc(&bo->refcount); 5687cdc0497Smrg *buf_handle = bo; 5697cdc0497Smrg *offset_in_bo = (uintptr_t)cpu - (uintptr_t)bo->cpu_ptr; 5707cdc0497Smrg } else { 5717cdc0497Smrg *buf_handle = NULL; 5727cdc0497Smrg *offset_in_bo = 0; 5737cdc0497Smrg r = -ENXIO; 5747cdc0497Smrg } 5757cdc0497Smrg pthread_mutex_unlock(&dev->bo_table_mutex); 5767cdc0497Smrg 5777cdc0497Smrg return r; 5787cdc0497Smrg} 5797cdc0497Smrg 5807cdc0497Smrgdrm_public int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev, 5817cdc0497Smrg void *cpu, 5827cdc0497Smrg uint64_t size, 5837cdc0497Smrg amdgpu_bo_handle *buf_handle) 5847cdc0497Smrg{ 5857cdc0497Smrg int r; 5863f012e29Smrg struct drm_amdgpu_gem_userptr args; 5873f012e29Smrg 5883f012e29Smrg args.addr = (uintptr_t)cpu; 5893f012e29Smrg args.flags = AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_REGISTER | 5903f012e29Smrg AMDGPU_GEM_USERPTR_VALIDATE; 5913f012e29Smrg args.size = size; 5923f012e29Smrg r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_USERPTR, 5933f012e29Smrg &args, sizeof(args)); 5943f012e29Smrg if (r) 5957cdc0497Smrg goto out; 5963f012e29Smrg 597bf6cc7dcSmrg pthread_mutex_lock(&dev->bo_table_mutex); 5987cdc0497Smrg r = amdgpu_bo_create(dev, size, args.handle, buf_handle); 599bf6cc7dcSmrg pthread_mutex_unlock(&dev->bo_table_mutex); 6007cdc0497Smrg if (r) { 601bf6cc7dcSmrg amdgpu_close_kms_handle(dev->fd, args.handle); 6027cdc0497Smrg } 6033f012e29Smrg 6047cdc0497Smrgout: 6053f012e29Smrg return r; 6063f012e29Smrg} 6073f012e29Smrg 6084545e80cSmrgdrm_public int amdgpu_bo_list_create_raw(amdgpu_device_handle dev, 6094545e80cSmrg uint32_t number_of_buffers, 6104545e80cSmrg struct drm_amdgpu_bo_list_entry *buffers, 6114545e80cSmrg uint32_t *result) 6124545e80cSmrg{ 6134545e80cSmrg union drm_amdgpu_bo_list args; 6144545e80cSmrg int r; 6154545e80cSmrg 6164545e80cSmrg memset(&args, 0, sizeof(args)); 6174545e80cSmrg args.in.operation = AMDGPU_BO_LIST_OP_CREATE; 6184545e80cSmrg args.in.bo_number = number_of_buffers; 6194545e80cSmrg args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry); 6204545e80cSmrg args.in.bo_info_ptr = (uint64_t)(uintptr_t)buffers; 6214545e80cSmrg 6224545e80cSmrg r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST, 6234545e80cSmrg &args, sizeof(args)); 6244545e80cSmrg if (!r) 6254545e80cSmrg *result = args.out.list_handle; 6264545e80cSmrg return r; 6274545e80cSmrg} 6284545e80cSmrg 6294545e80cSmrgdrm_public int amdgpu_bo_list_destroy_raw(amdgpu_device_handle dev, 6304545e80cSmrg uint32_t bo_list) 6314545e80cSmrg{ 6324545e80cSmrg union drm_amdgpu_bo_list args; 6334545e80cSmrg 6344545e80cSmrg memset(&args, 0, sizeof(args)); 6354545e80cSmrg args.in.operation = AMDGPU_BO_LIST_OP_DESTROY; 6364545e80cSmrg args.in.list_handle = bo_list; 6374545e80cSmrg 6384545e80cSmrg return drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST, 6394545e80cSmrg &args, sizeof(args)); 6404545e80cSmrg} 6414545e80cSmrg 6427cdc0497Smrgdrm_public int amdgpu_bo_list_create(amdgpu_device_handle dev, 6437cdc0497Smrg uint32_t number_of_resources, 6447cdc0497Smrg amdgpu_bo_handle *resources, 6457cdc0497Smrg uint8_t *resource_prios, 6467cdc0497Smrg amdgpu_bo_list_handle *result) 6473f012e29Smrg{ 6483f012e29Smrg struct drm_amdgpu_bo_list_entry *list; 6493f012e29Smrg union drm_amdgpu_bo_list args; 6503f012e29Smrg unsigned i; 6513f012e29Smrg int r; 6523f012e29Smrg 6533f012e29Smrg if (!number_of_resources) 6543f012e29Smrg return -EINVAL; 6553f012e29Smrg 6563f012e29Smrg /* overflow check for multiplication */ 6573f012e29Smrg if (number_of_resources > UINT32_MAX / sizeof(struct drm_amdgpu_bo_list_entry)) 6583f012e29Smrg return -EINVAL; 6593f012e29Smrg 6603f012e29Smrg list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry)); 6613f012e29Smrg if (!list) 6623f012e29Smrg return -ENOMEM; 6633f012e29Smrg 6643f012e29Smrg *result = malloc(sizeof(struct amdgpu_bo_list)); 6653f012e29Smrg if (!*result) { 6663f012e29Smrg free(list); 6673f012e29Smrg return -ENOMEM; 6683f012e29Smrg } 6693f012e29Smrg 6703f012e29Smrg memset(&args, 0, sizeof(args)); 6713f012e29Smrg args.in.operation = AMDGPU_BO_LIST_OP_CREATE; 6723f012e29Smrg args.in.bo_number = number_of_resources; 6733f012e29Smrg args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry); 6743f012e29Smrg args.in.bo_info_ptr = (uint64_t)(uintptr_t)list; 6753f012e29Smrg 6763f012e29Smrg for (i = 0; i < number_of_resources; i++) { 6773f012e29Smrg list[i].bo_handle = resources[i]->handle; 6783f012e29Smrg if (resource_prios) 6793f012e29Smrg list[i].bo_priority = resource_prios[i]; 6803f012e29Smrg else 6813f012e29Smrg list[i].bo_priority = 0; 6823f012e29Smrg } 6833f012e29Smrg 6843f012e29Smrg r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST, 6853f012e29Smrg &args, sizeof(args)); 6863f012e29Smrg free(list); 6873f012e29Smrg if (r) { 6883f012e29Smrg free(*result); 6893f012e29Smrg return r; 6903f012e29Smrg } 6913f012e29Smrg 6923f012e29Smrg (*result)->dev = dev; 6933f012e29Smrg (*result)->handle = args.out.list_handle; 6943f012e29Smrg return 0; 6953f012e29Smrg} 6963f012e29Smrg 6977cdc0497Smrgdrm_public int amdgpu_bo_list_destroy(amdgpu_bo_list_handle list) 6983f012e29Smrg{ 6993f012e29Smrg union drm_amdgpu_bo_list args; 7003f012e29Smrg int r; 7013f012e29Smrg 7023f012e29Smrg memset(&args, 0, sizeof(args)); 7033f012e29Smrg args.in.operation = AMDGPU_BO_LIST_OP_DESTROY; 7043f012e29Smrg args.in.list_handle = list->handle; 7053f012e29Smrg 7063f012e29Smrg r = drmCommandWriteRead(list->dev->fd, DRM_AMDGPU_BO_LIST, 7073f012e29Smrg &args, sizeof(args)); 7083f012e29Smrg 7093f012e29Smrg if (!r) 7103f012e29Smrg free(list); 7113f012e29Smrg 7123f012e29Smrg return r; 7133f012e29Smrg} 7143f012e29Smrg 7157cdc0497Smrgdrm_public int amdgpu_bo_list_update(amdgpu_bo_list_handle handle, 7167cdc0497Smrg uint32_t number_of_resources, 7177cdc0497Smrg amdgpu_bo_handle *resources, 7187cdc0497Smrg uint8_t *resource_prios) 7193f012e29Smrg{ 7203f012e29Smrg struct drm_amdgpu_bo_list_entry *list; 7213f012e29Smrg union drm_amdgpu_bo_list args; 7223f012e29Smrg unsigned i; 7233f012e29Smrg int r; 7243f012e29Smrg 7253f012e29Smrg if (!number_of_resources) 7263f012e29Smrg return -EINVAL; 7273f012e29Smrg 7283f012e29Smrg /* overflow check for multiplication */ 7293f012e29Smrg if (number_of_resources > UINT32_MAX / sizeof(struct drm_amdgpu_bo_list_entry)) 7303f012e29Smrg return -EINVAL; 7313f012e29Smrg 7323f012e29Smrg list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry)); 733d8807b2fSmrg if (!list) 7343f012e29Smrg return -ENOMEM; 7353f012e29Smrg 7363f012e29Smrg args.in.operation = AMDGPU_BO_LIST_OP_UPDATE; 7373f012e29Smrg args.in.list_handle = handle->handle; 7383f012e29Smrg args.in.bo_number = number_of_resources; 7393f012e29Smrg args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry); 7403f012e29Smrg args.in.bo_info_ptr = (uintptr_t)list; 7413f012e29Smrg 7423f012e29Smrg for (i = 0; i < number_of_resources; i++) { 7433f012e29Smrg list[i].bo_handle = resources[i]->handle; 7443f012e29Smrg if (resource_prios) 7453f012e29Smrg list[i].bo_priority = resource_prios[i]; 7463f012e29Smrg else 7473f012e29Smrg list[i].bo_priority = 0; 7483f012e29Smrg } 7493f012e29Smrg 7503f012e29Smrg r = drmCommandWriteRead(handle->dev->fd, DRM_AMDGPU_BO_LIST, 7513f012e29Smrg &args, sizeof(args)); 7523f012e29Smrg free(list); 7533f012e29Smrg return r; 7543f012e29Smrg} 7553f012e29Smrg 7567cdc0497Smrgdrm_public int amdgpu_bo_va_op(amdgpu_bo_handle bo, 7577cdc0497Smrg uint64_t offset, 7587cdc0497Smrg uint64_t size, 7597cdc0497Smrg uint64_t addr, 7607cdc0497Smrg uint64_t flags, 7617cdc0497Smrg uint32_t ops) 7623f012e29Smrg{ 7633f012e29Smrg amdgpu_device_handle dev = bo->dev; 764d8807b2fSmrg 765d8807b2fSmrg size = ALIGN(size, getpagesize()); 766d8807b2fSmrg 767d8807b2fSmrg return amdgpu_bo_va_op_raw(dev, bo, offset, size, addr, 768d8807b2fSmrg AMDGPU_VM_PAGE_READABLE | 769d8807b2fSmrg AMDGPU_VM_PAGE_WRITEABLE | 770d8807b2fSmrg AMDGPU_VM_PAGE_EXECUTABLE, ops); 771d8807b2fSmrg} 772d8807b2fSmrg 7737cdc0497Smrgdrm_public int amdgpu_bo_va_op_raw(amdgpu_device_handle dev, 7747cdc0497Smrg amdgpu_bo_handle bo, 7757cdc0497Smrg uint64_t offset, 7767cdc0497Smrg uint64_t size, 7777cdc0497Smrg uint64_t addr, 7787cdc0497Smrg uint64_t flags, 7797cdc0497Smrg uint32_t ops) 780d8807b2fSmrg{ 7813f012e29Smrg struct drm_amdgpu_gem_va va; 7823f012e29Smrg int r; 7833f012e29Smrg 784d8807b2fSmrg if (ops != AMDGPU_VA_OP_MAP && ops != AMDGPU_VA_OP_UNMAP && 785d8807b2fSmrg ops != AMDGPU_VA_OP_REPLACE && ops != AMDGPU_VA_OP_CLEAR) 7863f012e29Smrg return -EINVAL; 7873f012e29Smrg 7883f012e29Smrg memset(&va, 0, sizeof(va)); 789d8807b2fSmrg va.handle = bo ? bo->handle : 0; 7903f012e29Smrg va.operation = ops; 791d8807b2fSmrg va.flags = flags; 7923f012e29Smrg va.va_address = addr; 7933f012e29Smrg va.offset_in_bo = offset; 794d8807b2fSmrg va.map_size = size; 7953f012e29Smrg 7963f012e29Smrg r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va)); 7973f012e29Smrg 7983f012e29Smrg return r; 7993f012e29Smrg} 800