1d722e3fbSopenharmony_ci/* 2d722e3fbSopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc. 3d722e3fbSopenharmony_ci * 4d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 7d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10d722e3fbSopenharmony_ci * 11d722e3fbSopenharmony_ci * The above copyright notice and this permission notice shall be included in 12d722e3fbSopenharmony_ci * all copies or substantial portions of the Software. 13d722e3fbSopenharmony_ci * 14d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17d722e3fbSopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18d722e3fbSopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19d722e3fbSopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20d722e3fbSopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 21d722e3fbSopenharmony_ci * 22d722e3fbSopenharmony_ci */ 23d722e3fbSopenharmony_ci 24d722e3fbSopenharmony_ci/** 25d722e3fbSopenharmony_ci * \file amdgpu_device.c 26d722e3fbSopenharmony_ci * 27d722e3fbSopenharmony_ci * Implementation of functions for AMD GPU device 28d722e3fbSopenharmony_ci * 29d722e3fbSopenharmony_ci */ 30d722e3fbSopenharmony_ci 31d722e3fbSopenharmony_ci#include <sys/stat.h> 32d722e3fbSopenharmony_ci#include <errno.h> 33d722e3fbSopenharmony_ci#include <string.h> 34d722e3fbSopenharmony_ci#include <stdio.h> 35d722e3fbSopenharmony_ci#include <stdlib.h> 36d722e3fbSopenharmony_ci#include <unistd.h> 37d722e3fbSopenharmony_ci#include <fcntl.h> 38d722e3fbSopenharmony_ci 39d722e3fbSopenharmony_ci#include "xf86drm.h" 40d722e3fbSopenharmony_ci#include "amdgpu_drm.h" 41d722e3fbSopenharmony_ci#include "amdgpu_internal.h" 42d722e3fbSopenharmony_ci#include "util_math.h" 43d722e3fbSopenharmony_ci 44d722e3fbSopenharmony_ci#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x))) 45d722e3fbSopenharmony_ci 46d722e3fbSopenharmony_cistatic pthread_mutex_t dev_mutex = PTHREAD_MUTEX_INITIALIZER; 47d722e3fbSopenharmony_cistatic amdgpu_device_handle dev_list; 48d722e3fbSopenharmony_ci 49d722e3fbSopenharmony_cistatic int fd_compare(int fd1, int fd2) 50d722e3fbSopenharmony_ci{ 51d722e3fbSopenharmony_ci char *name1 = drmGetPrimaryDeviceNameFromFd(fd1); 52d722e3fbSopenharmony_ci char *name2 = drmGetPrimaryDeviceNameFromFd(fd2); 53d722e3fbSopenharmony_ci int result; 54d722e3fbSopenharmony_ci 55d722e3fbSopenharmony_ci if (name1 == NULL || name2 == NULL) { 56d722e3fbSopenharmony_ci free(name1); 57d722e3fbSopenharmony_ci free(name2); 58d722e3fbSopenharmony_ci return 0; 59d722e3fbSopenharmony_ci } 60d722e3fbSopenharmony_ci 61d722e3fbSopenharmony_ci result = strcmp(name1, name2); 62d722e3fbSopenharmony_ci free(name1); 63d722e3fbSopenharmony_ci free(name2); 64d722e3fbSopenharmony_ci 65d722e3fbSopenharmony_ci return result; 66d722e3fbSopenharmony_ci} 67d722e3fbSopenharmony_ci 68d722e3fbSopenharmony_ci/** 69d722e3fbSopenharmony_ci* Get the authenticated form fd, 70d722e3fbSopenharmony_ci* 71d722e3fbSopenharmony_ci* \param fd - \c [in] File descriptor for AMD GPU device 72d722e3fbSopenharmony_ci* \param auth - \c [out] Pointer to output the fd is authenticated or not 73d722e3fbSopenharmony_ci* A render node fd, output auth = 0 74d722e3fbSopenharmony_ci* A legacy fd, get the authenticated for compatibility root 75d722e3fbSopenharmony_ci* 76d722e3fbSopenharmony_ci* \return 0 on success\n 77d722e3fbSopenharmony_ci* >0 - AMD specific error code\n 78d722e3fbSopenharmony_ci* <0 - Negative POSIX Error code 79d722e3fbSopenharmony_ci*/ 80d722e3fbSopenharmony_cistatic int amdgpu_get_auth(int fd, int *auth) 81d722e3fbSopenharmony_ci{ 82d722e3fbSopenharmony_ci int r = 0; 83d722e3fbSopenharmony_ci drm_client_t client = {}; 84d722e3fbSopenharmony_ci 85d722e3fbSopenharmony_ci if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER) 86d722e3fbSopenharmony_ci *auth = 0; 87d722e3fbSopenharmony_ci else { 88d722e3fbSopenharmony_ci client.idx = 0; 89d722e3fbSopenharmony_ci r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client); 90d722e3fbSopenharmony_ci if (!r) 91d722e3fbSopenharmony_ci *auth = client.auth; 92d722e3fbSopenharmony_ci } 93d722e3fbSopenharmony_ci return r; 94d722e3fbSopenharmony_ci} 95d722e3fbSopenharmony_ci 96d722e3fbSopenharmony_cistatic void amdgpu_device_free_internal(amdgpu_device_handle dev) 97d722e3fbSopenharmony_ci{ 98d722e3fbSopenharmony_ci amdgpu_device_handle *node = &dev_list; 99d722e3fbSopenharmony_ci 100d722e3fbSopenharmony_ci pthread_mutex_lock(&dev_mutex); 101d722e3fbSopenharmony_ci while (*node != dev && (*node)->next) 102d722e3fbSopenharmony_ci node = &(*node)->next; 103d722e3fbSopenharmony_ci *node = (*node)->next; 104d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 105d722e3fbSopenharmony_ci 106d722e3fbSopenharmony_ci close(dev->fd); 107d722e3fbSopenharmony_ci if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd)) 108d722e3fbSopenharmony_ci close(dev->flink_fd); 109d722e3fbSopenharmony_ci 110d722e3fbSopenharmony_ci amdgpu_vamgr_deinit(&dev->vamgr_32); 111d722e3fbSopenharmony_ci amdgpu_vamgr_deinit(&dev->vamgr); 112d722e3fbSopenharmony_ci amdgpu_vamgr_deinit(&dev->vamgr_high_32); 113d722e3fbSopenharmony_ci amdgpu_vamgr_deinit(&dev->vamgr_high); 114d722e3fbSopenharmony_ci handle_table_fini(&dev->bo_handles); 115d722e3fbSopenharmony_ci handle_table_fini(&dev->bo_flink_names); 116d722e3fbSopenharmony_ci pthread_mutex_destroy(&dev->bo_table_mutex); 117d722e3fbSopenharmony_ci free(dev->marketing_name); 118d722e3fbSopenharmony_ci free(dev); 119d722e3fbSopenharmony_ci} 120d722e3fbSopenharmony_ci 121d722e3fbSopenharmony_ci/** 122d722e3fbSopenharmony_ci * Assignment between two amdgpu_device pointers with reference counting. 123d722e3fbSopenharmony_ci * 124d722e3fbSopenharmony_ci * Usage: 125d722e3fbSopenharmony_ci * struct amdgpu_device *dst = ... , *src = ...; 126d722e3fbSopenharmony_ci * 127d722e3fbSopenharmony_ci * dst = src; 128d722e3fbSopenharmony_ci * // No reference counting. Only use this when you need to move 129d722e3fbSopenharmony_ci * // a reference from one pointer to another. 130d722e3fbSopenharmony_ci * 131d722e3fbSopenharmony_ci * amdgpu_device_reference(&dst, src); 132d722e3fbSopenharmony_ci * // Reference counters are updated. dst is decremented and src is 133d722e3fbSopenharmony_ci * // incremented. dst is freed if its reference counter is 0. 134d722e3fbSopenharmony_ci */ 135d722e3fbSopenharmony_cistatic void amdgpu_device_reference(struct amdgpu_device **dst, 136d722e3fbSopenharmony_ci struct amdgpu_device *src) 137d722e3fbSopenharmony_ci{ 138d722e3fbSopenharmony_ci if (update_references(&(*dst)->refcount, &src->refcount)) 139d722e3fbSopenharmony_ci amdgpu_device_free_internal(*dst); 140d722e3fbSopenharmony_ci *dst = src; 141d722e3fbSopenharmony_ci} 142d722e3fbSopenharmony_ci 143d722e3fbSopenharmony_cidrm_public int amdgpu_device_initialize(int fd, 144d722e3fbSopenharmony_ci uint32_t *major_version, 145d722e3fbSopenharmony_ci uint32_t *minor_version, 146d722e3fbSopenharmony_ci amdgpu_device_handle *device_handle) 147d722e3fbSopenharmony_ci{ 148d722e3fbSopenharmony_ci struct amdgpu_device *dev; 149d722e3fbSopenharmony_ci drmVersionPtr version; 150d722e3fbSopenharmony_ci int r; 151d722e3fbSopenharmony_ci int flag_auth = 0; 152d722e3fbSopenharmony_ci int flag_authexist=0; 153d722e3fbSopenharmony_ci uint32_t accel_working = 0; 154d722e3fbSopenharmony_ci uint64_t start, max; 155d722e3fbSopenharmony_ci 156d722e3fbSopenharmony_ci *device_handle = NULL; 157d722e3fbSopenharmony_ci 158d722e3fbSopenharmony_ci pthread_mutex_lock(&dev_mutex); 159d722e3fbSopenharmony_ci r = amdgpu_get_auth(fd, &flag_auth); 160d722e3fbSopenharmony_ci if (r) { 161d722e3fbSopenharmony_ci fprintf(stderr, "%s: amdgpu_get_auth (1) failed (%i)\n", 162d722e3fbSopenharmony_ci __func__, r); 163d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 164d722e3fbSopenharmony_ci return r; 165d722e3fbSopenharmony_ci } 166d722e3fbSopenharmony_ci 167d722e3fbSopenharmony_ci for (dev = dev_list; dev; dev = dev->next) 168d722e3fbSopenharmony_ci if (fd_compare(dev->fd, fd) == 0) 169d722e3fbSopenharmony_ci break; 170d722e3fbSopenharmony_ci 171d722e3fbSopenharmony_ci if (dev) { 172d722e3fbSopenharmony_ci r = amdgpu_get_auth(dev->fd, &flag_authexist); 173d722e3fbSopenharmony_ci if (r) { 174d722e3fbSopenharmony_ci fprintf(stderr, "%s: amdgpu_get_auth (2) failed (%i)\n", 175d722e3fbSopenharmony_ci __func__, r); 176d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 177d722e3fbSopenharmony_ci return r; 178d722e3fbSopenharmony_ci } 179d722e3fbSopenharmony_ci if ((flag_auth) && (!flag_authexist)) { 180d722e3fbSopenharmony_ci dev->flink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); 181d722e3fbSopenharmony_ci } 182d722e3fbSopenharmony_ci *major_version = dev->major_version; 183d722e3fbSopenharmony_ci *minor_version = dev->minor_version; 184d722e3fbSopenharmony_ci amdgpu_device_reference(device_handle, dev); 185d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 186d722e3fbSopenharmony_ci return 0; 187d722e3fbSopenharmony_ci } 188d722e3fbSopenharmony_ci 189d722e3fbSopenharmony_ci dev = calloc(1, sizeof(struct amdgpu_device)); 190d722e3fbSopenharmony_ci if (!dev) { 191d722e3fbSopenharmony_ci fprintf(stderr, "%s: calloc failed\n", __func__); 192d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 193d722e3fbSopenharmony_ci return -ENOMEM; 194d722e3fbSopenharmony_ci } 195d722e3fbSopenharmony_ci 196d722e3fbSopenharmony_ci dev->fd = -1; 197d722e3fbSopenharmony_ci dev->flink_fd = -1; 198d722e3fbSopenharmony_ci 199d722e3fbSopenharmony_ci atomic_set(&dev->refcount, 1); 200d722e3fbSopenharmony_ci 201d722e3fbSopenharmony_ci version = drmGetVersion(fd); 202d722e3fbSopenharmony_ci if (version->version_major != 3) { 203d722e3fbSopenharmony_ci fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " 204d722e3fbSopenharmony_ci "only compatible with 3.x.x.\n", 205d722e3fbSopenharmony_ci __func__, 206d722e3fbSopenharmony_ci version->version_major, 207d722e3fbSopenharmony_ci version->version_minor, 208d722e3fbSopenharmony_ci version->version_patchlevel); 209d722e3fbSopenharmony_ci drmFreeVersion(version); 210d722e3fbSopenharmony_ci r = -EBADF; 211d722e3fbSopenharmony_ci goto cleanup; 212d722e3fbSopenharmony_ci } 213d722e3fbSopenharmony_ci 214d722e3fbSopenharmony_ci dev->fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); 215d722e3fbSopenharmony_ci dev->flink_fd = dev->fd; 216d722e3fbSopenharmony_ci dev->major_version = version->version_major; 217d722e3fbSopenharmony_ci dev->minor_version = version->version_minor; 218d722e3fbSopenharmony_ci drmFreeVersion(version); 219d722e3fbSopenharmony_ci 220d722e3fbSopenharmony_ci pthread_mutex_init(&dev->bo_table_mutex, NULL); 221d722e3fbSopenharmony_ci 222d722e3fbSopenharmony_ci /* Check if acceleration is working. */ 223d722e3fbSopenharmony_ci r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working); 224d722e3fbSopenharmony_ci if (r) { 225d722e3fbSopenharmony_ci fprintf(stderr, "%s: amdgpu_query_info(ACCEL_WORKING) failed (%i)\n", 226d722e3fbSopenharmony_ci __func__, r); 227d722e3fbSopenharmony_ci goto cleanup; 228d722e3fbSopenharmony_ci } 229d722e3fbSopenharmony_ci if (!accel_working) { 230d722e3fbSopenharmony_ci fprintf(stderr, "%s: AMDGPU_INFO_ACCEL_WORKING = 0\n", __func__); 231d722e3fbSopenharmony_ci r = -EBADF; 232d722e3fbSopenharmony_ci goto cleanup; 233d722e3fbSopenharmony_ci } 234d722e3fbSopenharmony_ci 235d722e3fbSopenharmony_ci r = amdgpu_query_gpu_info_init(dev); 236d722e3fbSopenharmony_ci if (r) { 237d722e3fbSopenharmony_ci fprintf(stderr, "%s: amdgpu_query_gpu_info_init failed\n", __func__); 238d722e3fbSopenharmony_ci goto cleanup; 239d722e3fbSopenharmony_ci } 240d722e3fbSopenharmony_ci 241d722e3fbSopenharmony_ci start = dev->dev_info.virtual_address_offset; 242d722e3fbSopenharmony_ci max = MIN2(dev->dev_info.virtual_address_max, 0x100000000ULL); 243d722e3fbSopenharmony_ci amdgpu_vamgr_init(&dev->vamgr_32, start, max, 244d722e3fbSopenharmony_ci dev->dev_info.virtual_address_alignment); 245d722e3fbSopenharmony_ci 246d722e3fbSopenharmony_ci start = max; 247d722e3fbSopenharmony_ci max = MAX2(dev->dev_info.virtual_address_max, 0x100000000ULL); 248d722e3fbSopenharmony_ci amdgpu_vamgr_init(&dev->vamgr, start, max, 249d722e3fbSopenharmony_ci dev->dev_info.virtual_address_alignment); 250d722e3fbSopenharmony_ci 251d722e3fbSopenharmony_ci start = dev->dev_info.high_va_offset; 252d722e3fbSopenharmony_ci max = MIN2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) + 253d722e3fbSopenharmony_ci 0x100000000ULL); 254d722e3fbSopenharmony_ci amdgpu_vamgr_init(&dev->vamgr_high_32, start, max, 255d722e3fbSopenharmony_ci dev->dev_info.virtual_address_alignment); 256d722e3fbSopenharmony_ci 257d722e3fbSopenharmony_ci start = max; 258d722e3fbSopenharmony_ci max = MAX2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) + 259d722e3fbSopenharmony_ci 0x100000000ULL); 260d722e3fbSopenharmony_ci amdgpu_vamgr_init(&dev->vamgr_high, start, max, 261d722e3fbSopenharmony_ci dev->dev_info.virtual_address_alignment); 262d722e3fbSopenharmony_ci 263d722e3fbSopenharmony_ci amdgpu_parse_asic_ids(dev); 264d722e3fbSopenharmony_ci 265d722e3fbSopenharmony_ci *major_version = dev->major_version; 266d722e3fbSopenharmony_ci *minor_version = dev->minor_version; 267d722e3fbSopenharmony_ci *device_handle = dev; 268d722e3fbSopenharmony_ci dev->next = dev_list; 269d722e3fbSopenharmony_ci dev_list = dev; 270d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 271d722e3fbSopenharmony_ci 272d722e3fbSopenharmony_ci return 0; 273d722e3fbSopenharmony_ci 274d722e3fbSopenharmony_cicleanup: 275d722e3fbSopenharmony_ci if (dev->fd >= 0) 276d722e3fbSopenharmony_ci close(dev->fd); 277d722e3fbSopenharmony_ci free(dev); 278d722e3fbSopenharmony_ci pthread_mutex_unlock(&dev_mutex); 279d722e3fbSopenharmony_ci return r; 280d722e3fbSopenharmony_ci} 281d722e3fbSopenharmony_ci 282d722e3fbSopenharmony_cidrm_public int amdgpu_device_deinitialize(amdgpu_device_handle dev) 283d722e3fbSopenharmony_ci{ 284d722e3fbSopenharmony_ci amdgpu_device_reference(&dev, NULL); 285d722e3fbSopenharmony_ci return 0; 286d722e3fbSopenharmony_ci} 287d722e3fbSopenharmony_ci 288d722e3fbSopenharmony_cidrm_public int amdgpu_device_get_fd(amdgpu_device_handle device_handle) 289d722e3fbSopenharmony_ci{ 290d722e3fbSopenharmony_ci return device_handle->fd; 291d722e3fbSopenharmony_ci} 292d722e3fbSopenharmony_ci 293d722e3fbSopenharmony_cidrm_public const char *amdgpu_get_marketing_name(amdgpu_device_handle dev) 294d722e3fbSopenharmony_ci{ 295d722e3fbSopenharmony_ci return dev->marketing_name; 296d722e3fbSopenharmony_ci} 297d722e3fbSopenharmony_ci 298d722e3fbSopenharmony_cidrm_public int amdgpu_query_sw_info(amdgpu_device_handle dev, 299d722e3fbSopenharmony_ci enum amdgpu_sw_info info, 300d722e3fbSopenharmony_ci void *value) 301d722e3fbSopenharmony_ci{ 302d722e3fbSopenharmony_ci uint32_t *val32 = (uint32_t*)value; 303d722e3fbSopenharmony_ci 304d722e3fbSopenharmony_ci switch (info) { 305d722e3fbSopenharmony_ci case amdgpu_sw_info_address32_hi: 306d722e3fbSopenharmony_ci if (dev->vamgr_high_32.va_max) 307d722e3fbSopenharmony_ci *val32 = (dev->vamgr_high_32.va_max - 1) >> 32; 308d722e3fbSopenharmony_ci else 309d722e3fbSopenharmony_ci *val32 = (dev->vamgr_32.va_max - 1) >> 32; 310d722e3fbSopenharmony_ci return 0; 311d722e3fbSopenharmony_ci } 312d722e3fbSopenharmony_ci return -EINVAL; 313d722e3fbSopenharmony_ci} 314