13f012e29Smrg/* 23f012e29Smrg * Copyright 2014 Advanced Micro Devices, Inc. 33f012e29Smrg * 43f012e29Smrg * Permission is hereby granted, free of charge, to any person obtaining a 53f012e29Smrg * copy of this software and associated documentation files (the "Software"), 63f012e29Smrg * to deal in the Software without restriction, including without limitation 73f012e29Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 83f012e29Smrg * and/or sell copies of the Software, and to permit persons to whom the 93f012e29Smrg * Software is furnished to do so, subject to the following conditions: 103f012e29Smrg * 113f012e29Smrg * The above copyright notice and this permission notice shall be included in 123f012e29Smrg * all copies or substantial portions of the Software. 133f012e29Smrg * 143f012e29Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 153f012e29Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 163f012e29Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 173f012e29Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 183f012e29Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 193f012e29Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 203f012e29Smrg * OTHER DEALINGS IN THE SOFTWARE. 213f012e29Smrg * 223f012e29Smrg */ 233f012e29Smrg 243f012e29Smrg/** 253f012e29Smrg * \file amdgpu_device.c 263f012e29Smrg * 273f012e29Smrg * Implementation of functions for AMD GPU device 283f012e29Smrg * 293f012e29Smrg */ 303f012e29Smrg 313f012e29Smrg#include <sys/stat.h> 323f012e29Smrg#include <errno.h> 333f012e29Smrg#include <string.h> 343f012e29Smrg#include <stdio.h> 353f012e29Smrg#include <stdlib.h> 363f012e29Smrg#include <unistd.h> 377cdc0497Smrg#include <fcntl.h> 383f012e29Smrg 393f012e29Smrg#include "xf86drm.h" 403f012e29Smrg#include "amdgpu_drm.h" 413f012e29Smrg#include "amdgpu_internal.h" 423f012e29Smrg#include "util_math.h" 433f012e29Smrg 443f012e29Smrg#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x))) 453f012e29Smrg 465324fb0dSmrgstatic pthread_mutex_t dev_mutex = PTHREAD_MUTEX_INITIALIZER; 475324fb0dSmrgstatic amdgpu_device_handle dev_list; 483f012e29Smrg 497cdc0497Smrgstatic int fd_compare(int fd1, int fd2) 503f012e29Smrg{ 513f012e29Smrg char *name1 = drmGetPrimaryDeviceNameFromFd(fd1); 523f012e29Smrg char *name2 = drmGetPrimaryDeviceNameFromFd(fd2); 533f012e29Smrg int result; 543f012e29Smrg 553f012e29Smrg if (name1 == NULL || name2 == NULL) { 563f012e29Smrg free(name1); 573f012e29Smrg free(name2); 583f012e29Smrg return 0; 593f012e29Smrg } 603f012e29Smrg 613f012e29Smrg result = strcmp(name1, name2); 623f012e29Smrg free(name1); 633f012e29Smrg free(name2); 643f012e29Smrg 653f012e29Smrg return result; 663f012e29Smrg} 673f012e29Smrg 683f012e29Smrg/** 693f012e29Smrg* Get the authenticated form fd, 703f012e29Smrg* 713f012e29Smrg* \param fd - \c [in] File descriptor for AMD GPU device 723f012e29Smrg* \param auth - \c [out] Pointer to output the fd is authenticated or not 733f012e29Smrg* A render node fd, output auth = 0 743f012e29Smrg* A legacy fd, get the authenticated for compatibility root 753f012e29Smrg* 763f012e29Smrg* \return 0 on success\n 773f012e29Smrg* >0 - AMD specific error code\n 783f012e29Smrg* <0 - Negative POSIX Error code 793f012e29Smrg*/ 803f012e29Smrgstatic int amdgpu_get_auth(int fd, int *auth) 813f012e29Smrg{ 823f012e29Smrg int r = 0; 833f012e29Smrg drm_client_t client = {}; 843f012e29Smrg 853f012e29Smrg if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER) 863f012e29Smrg *auth = 0; 873f012e29Smrg else { 883f012e29Smrg client.idx = 0; 893f012e29Smrg r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client); 903f012e29Smrg if (!r) 913f012e29Smrg *auth = client.auth; 923f012e29Smrg } 933f012e29Smrg return r; 943f012e29Smrg} 953f012e29Smrg 963f012e29Smrgstatic void amdgpu_device_free_internal(amdgpu_device_handle dev) 973f012e29Smrg{ 98bbff01ceSmrg /* Remove dev from dev_list, if it was added there. */ 99bbff01ceSmrg if (dev == dev_list) { 100bbff01ceSmrg dev_list = dev->next; 101bbff01ceSmrg } else { 102bbff01ceSmrg for (amdgpu_device_handle node = dev_list; node; node = node->next) { 103bbff01ceSmrg if (node->next == dev) { 104bbff01ceSmrg node->next = dev->next; 105bbff01ceSmrg break; 106bbff01ceSmrg } 107bbff01ceSmrg } 108bbff01ceSmrg } 1097cdc0497Smrg 1103f012e29Smrg close(dev->fd); 1113f012e29Smrg if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd)) 1123f012e29Smrg close(dev->flink_fd); 1137cdc0497Smrg 114bbff01ceSmrg amdgpu_vamgr_deinit(&dev->va_mgr.vamgr_32); 115bbff01ceSmrg amdgpu_vamgr_deinit(&dev->va_mgr.vamgr_low); 116bbff01ceSmrg amdgpu_vamgr_deinit(&dev->va_mgr.vamgr_high_32); 117bbff01ceSmrg amdgpu_vamgr_deinit(&dev->va_mgr.vamgr_high); 1187cdc0497Smrg handle_table_fini(&dev->bo_handles); 1197cdc0497Smrg handle_table_fini(&dev->bo_flink_names); 1207cdc0497Smrg pthread_mutex_destroy(&dev->bo_table_mutex); 12100a23bdaSmrg free(dev->marketing_name); 1223f012e29Smrg free(dev); 1233f012e29Smrg} 1243f012e29Smrg 1253f012e29Smrg/** 1263f012e29Smrg * Assignment between two amdgpu_device pointers with reference counting. 1273f012e29Smrg * 1283f012e29Smrg * Usage: 1293f012e29Smrg * struct amdgpu_device *dst = ... , *src = ...; 1303f012e29Smrg * 1313f012e29Smrg * dst = src; 1323f012e29Smrg * // No reference counting. Only use this when you need to move 1333f012e29Smrg * // a reference from one pointer to another. 1343f012e29Smrg * 1353f012e29Smrg * amdgpu_device_reference(&dst, src); 1363f012e29Smrg * // Reference counters are updated. dst is decremented and src is 1373f012e29Smrg * // incremented. dst is freed if its reference counter is 0. 1383f012e29Smrg */ 1393f012e29Smrgstatic void amdgpu_device_reference(struct amdgpu_device **dst, 1407cdc0497Smrg struct amdgpu_device *src) 1413f012e29Smrg{ 1423f012e29Smrg if (update_references(&(*dst)->refcount, &src->refcount)) 1433f012e29Smrg amdgpu_device_free_internal(*dst); 1443f012e29Smrg *dst = src; 1453f012e29Smrg} 1463f012e29Smrg 147bbff01ceSmrgstatic int _amdgpu_device_initialize(int fd, 148bbff01ceSmrg uint32_t *major_version, 149bbff01ceSmrg uint32_t *minor_version, 150bbff01ceSmrg amdgpu_device_handle *device_handle, 151bbff01ceSmrg bool deduplicate_device) 1523f012e29Smrg{ 153bbff01ceSmrg struct amdgpu_device *dev = NULL; 1543f012e29Smrg drmVersionPtr version; 1553f012e29Smrg int r; 1563f012e29Smrg int flag_auth = 0; 1573f012e29Smrg int flag_authexist=0; 1583f012e29Smrg uint32_t accel_working = 0; 1593f012e29Smrg 1603f012e29Smrg *device_handle = NULL; 1613f012e29Smrg 1625324fb0dSmrg pthread_mutex_lock(&dev_mutex); 163bbff01ceSmrg 1643f012e29Smrg r = amdgpu_get_auth(fd, &flag_auth); 1653f012e29Smrg if (r) { 16600a23bdaSmrg fprintf(stderr, "%s: amdgpu_get_auth (1) failed (%i)\n", 16700a23bdaSmrg __func__, r); 1685324fb0dSmrg pthread_mutex_unlock(&dev_mutex); 1693f012e29Smrg return r; 1703f012e29Smrg } 1717cdc0497Smrg 172bbff01ceSmrg if (deduplicate_device) 173bbff01ceSmrg for (dev = dev_list; dev; dev = dev->next) 174bbff01ceSmrg if (fd_compare(dev->fd, fd) == 0) 175bbff01ceSmrg break; 1767cdc0497Smrg 1773f012e29Smrg if (dev) { 1783f012e29Smrg r = amdgpu_get_auth(dev->fd, &flag_authexist); 1793f012e29Smrg if (r) { 18000a23bdaSmrg fprintf(stderr, "%s: amdgpu_get_auth (2) failed (%i)\n", 18100a23bdaSmrg __func__, r); 1825324fb0dSmrg pthread_mutex_unlock(&dev_mutex); 1833f012e29Smrg return r; 1843f012e29Smrg } 1853f012e29Smrg if ((flag_auth) && (!flag_authexist)) { 1867cdc0497Smrg dev->flink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); 1873f012e29Smrg } 1883f012e29Smrg *major_version = dev->major_version; 1893f012e29Smrg *minor_version = dev->minor_version; 1903f012e29Smrg amdgpu_device_reference(device_handle, dev); 1915324fb0dSmrg pthread_mutex_unlock(&dev_mutex); 1923f012e29Smrg return 0; 1933f012e29Smrg } 1943f012e29Smrg 1953f012e29Smrg dev = calloc(1, sizeof(struct amdgpu_device)); 1963f012e29Smrg if (!dev) { 19700a23bdaSmrg fprintf(stderr, "%s: calloc failed\n", __func__); 1985324fb0dSmrg pthread_mutex_unlock(&dev_mutex); 1993f012e29Smrg return -ENOMEM; 2003f012e29Smrg } 2013f012e29Smrg 2023f012e29Smrg dev->fd = -1; 2033f012e29Smrg dev->flink_fd = -1; 2043f012e29Smrg 2053f012e29Smrg atomic_set(&dev->refcount, 1); 2063f012e29Smrg 2073f012e29Smrg version = drmGetVersion(fd); 2083f012e29Smrg if (version->version_major != 3) { 2093f012e29Smrg fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " 2103f012e29Smrg "only compatible with 3.x.x.\n", 2113f012e29Smrg __func__, 2123f012e29Smrg version->version_major, 2133f012e29Smrg version->version_minor, 2143f012e29Smrg version->version_patchlevel); 2153f012e29Smrg drmFreeVersion(version); 2163f012e29Smrg r = -EBADF; 2173f012e29Smrg goto cleanup; 2183f012e29Smrg } 2193f012e29Smrg 2207cdc0497Smrg dev->fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); 2213f012e29Smrg dev->flink_fd = dev->fd; 2223f012e29Smrg dev->major_version = version->version_major; 2233f012e29Smrg dev->minor_version = version->version_minor; 2243f012e29Smrg drmFreeVersion(version); 2253f012e29Smrg 2263f012e29Smrg pthread_mutex_init(&dev->bo_table_mutex, NULL); 2273f012e29Smrg 2283f012e29Smrg /* Check if acceleration is working. */ 2293f012e29Smrg r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working); 23000a23bdaSmrg if (r) { 23100a23bdaSmrg fprintf(stderr, "%s: amdgpu_query_info(ACCEL_WORKING) failed (%i)\n", 23200a23bdaSmrg __func__, r); 2333f012e29Smrg goto cleanup; 23400a23bdaSmrg } 2353f012e29Smrg if (!accel_working) { 23600a23bdaSmrg fprintf(stderr, "%s: AMDGPU_INFO_ACCEL_WORKING = 0\n", __func__); 2373f012e29Smrg r = -EBADF; 2383f012e29Smrg goto cleanup; 2393f012e29Smrg } 2403f012e29Smrg 2413f012e29Smrg r = amdgpu_query_gpu_info_init(dev); 24200a23bdaSmrg if (r) { 24300a23bdaSmrg fprintf(stderr, "%s: amdgpu_query_gpu_info_init failed\n", __func__); 2443f012e29Smrg goto cleanup; 24500a23bdaSmrg } 2463f012e29Smrg 247bbff01ceSmrg amdgpu_va_manager_init(&dev->va_mgr, 248bbff01ceSmrg dev->dev_info.virtual_address_offset, 249bbff01ceSmrg dev->dev_info.virtual_address_max, 250bbff01ceSmrg dev->dev_info.high_va_offset, 251bbff01ceSmrg dev->dev_info.high_va_max, 252bbff01ceSmrg dev->dev_info.virtual_address_alignment); 25300a23bdaSmrg 25400a23bdaSmrg amdgpu_parse_asic_ids(dev); 255d8807b2fSmrg 2563f012e29Smrg *major_version = dev->major_version; 2573f012e29Smrg *minor_version = dev->minor_version; 2583f012e29Smrg *device_handle = dev; 259bbff01ceSmrg if (deduplicate_device) { 260bbff01ceSmrg dev->next = dev_list; 261bbff01ceSmrg dev_list = dev; 262bbff01ceSmrg } 2635324fb0dSmrg pthread_mutex_unlock(&dev_mutex); 2643f012e29Smrg 2653f012e29Smrg return 0; 2663f012e29Smrg 2673f012e29Smrgcleanup: 2683f012e29Smrg if (dev->fd >= 0) 2693f012e29Smrg close(dev->fd); 2703f012e29Smrg free(dev); 2715324fb0dSmrg pthread_mutex_unlock(&dev_mutex); 2723f012e29Smrg return r; 2733f012e29Smrg} 2743f012e29Smrg 275bbff01ceSmrgdrm_public int amdgpu_device_initialize(int fd, 276bbff01ceSmrg uint32_t *major_version, 277bbff01ceSmrg uint32_t *minor_version, 278bbff01ceSmrg amdgpu_device_handle *device_handle) 279bbff01ceSmrg{ 280bbff01ceSmrg return _amdgpu_device_initialize(fd, major_version, minor_version, device_handle, true); 281bbff01ceSmrg} 282bbff01ceSmrg 283bbff01ceSmrgdrm_public int amdgpu_device_initialize2(int fd, bool deduplicate_device, 284bbff01ceSmrg uint32_t *major_version, 285bbff01ceSmrg uint32_t *minor_version, 286bbff01ceSmrg amdgpu_device_handle *device_handle) 287bbff01ceSmrg{ 288bbff01ceSmrg return _amdgpu_device_initialize(fd, major_version, minor_version, device_handle, deduplicate_device); 289bbff01ceSmrg} 290bbff01ceSmrg 2917cdc0497Smrgdrm_public int amdgpu_device_deinitialize(amdgpu_device_handle dev) 2923f012e29Smrg{ 293bbff01ceSmrg pthread_mutex_lock(&dev_mutex); 2943f012e29Smrg amdgpu_device_reference(&dev, NULL); 295bbff01ceSmrg pthread_mutex_unlock(&dev_mutex); 2963f012e29Smrg return 0; 2973f012e29Smrg} 298037b3c26Smrg 29949ef06a4Smrgdrm_public int amdgpu_device_get_fd(amdgpu_device_handle device_handle) 30049ef06a4Smrg{ 30149ef06a4Smrg return device_handle->fd; 30249ef06a4Smrg} 30349ef06a4Smrg 3047cdc0497Smrgdrm_public const char *amdgpu_get_marketing_name(amdgpu_device_handle dev) 305037b3c26Smrg{ 306b0ab5608Smrg if (dev->marketing_name) 307b0ab5608Smrg return dev->marketing_name; 308b0ab5608Smrg else 309b0ab5608Smrg return "AMD Radeon Graphics"; 31000a23bdaSmrg} 311037b3c26Smrg 3127cdc0497Smrgdrm_public int amdgpu_query_sw_info(amdgpu_device_handle dev, 3137cdc0497Smrg enum amdgpu_sw_info info, 3147cdc0497Smrg void *value) 31500a23bdaSmrg{ 31600a23bdaSmrg uint32_t *val32 = (uint32_t*)value; 31700a23bdaSmrg 31800a23bdaSmrg switch (info) { 31900a23bdaSmrg case amdgpu_sw_info_address32_hi: 320bbff01ceSmrg if (dev->va_mgr.vamgr_high_32.va_max) 321bbff01ceSmrg *val32 = (dev->va_mgr.vamgr_high_32.va_max - 1) >> 32; 32200a23bdaSmrg else 323bbff01ceSmrg *val32 = (dev->va_mgr.vamgr_32.va_max - 1) >> 32; 32400a23bdaSmrg return 0; 325037b3c26Smrg } 32600a23bdaSmrg return -EINVAL; 327037b3c26Smrg} 328