amdgpu_device.c revision 00a23bda
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#ifdef HAVE_CONFIG_H 323f012e29Smrg#include "config.h" 333f012e29Smrg#endif 343f012e29Smrg 353f012e29Smrg#include <sys/stat.h> 363f012e29Smrg#include <errno.h> 373f012e29Smrg#include <string.h> 383f012e29Smrg#include <stdio.h> 393f012e29Smrg#include <stdlib.h> 403f012e29Smrg#include <unistd.h> 413f012e29Smrg 423f012e29Smrg#include "xf86drm.h" 433f012e29Smrg#include "amdgpu_drm.h" 443f012e29Smrg#include "amdgpu_internal.h" 453f012e29Smrg#include "util_hash_table.h" 463f012e29Smrg#include "util_math.h" 473f012e29Smrg 483f012e29Smrg#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x))) 493f012e29Smrg#define UINT_TO_PTR(x) ((void *)((intptr_t)(x))) 503f012e29Smrg 513f012e29Smrgstatic pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER; 523f012e29Smrgstatic struct util_hash_table *fd_tab; 533f012e29Smrg 543f012e29Smrgstatic unsigned handle_hash(void *key) 553f012e29Smrg{ 563f012e29Smrg return PTR_TO_UINT(key); 573f012e29Smrg} 583f012e29Smrg 593f012e29Smrgstatic int handle_compare(void *key1, void *key2) 603f012e29Smrg{ 613f012e29Smrg return PTR_TO_UINT(key1) != PTR_TO_UINT(key2); 623f012e29Smrg} 633f012e29Smrg 643f012e29Smrgstatic unsigned fd_hash(void *key) 653f012e29Smrg{ 663f012e29Smrg int fd = PTR_TO_UINT(key); 673f012e29Smrg char *name = drmGetPrimaryDeviceNameFromFd(fd); 683f012e29Smrg unsigned result = 0; 693f012e29Smrg char *c; 703f012e29Smrg 713f012e29Smrg if (name == NULL) 723f012e29Smrg return 0; 733f012e29Smrg 743f012e29Smrg for (c = name; *c; ++c) 753f012e29Smrg result += *c; 763f012e29Smrg 773f012e29Smrg free(name); 783f012e29Smrg 793f012e29Smrg return result; 803f012e29Smrg} 813f012e29Smrg 823f012e29Smrgstatic int fd_compare(void *key1, void *key2) 833f012e29Smrg{ 843f012e29Smrg int fd1 = PTR_TO_UINT(key1); 853f012e29Smrg int fd2 = PTR_TO_UINT(key2); 863f012e29Smrg char *name1 = drmGetPrimaryDeviceNameFromFd(fd1); 873f012e29Smrg char *name2 = drmGetPrimaryDeviceNameFromFd(fd2); 883f012e29Smrg int result; 893f012e29Smrg 903f012e29Smrg if (name1 == NULL || name2 == NULL) { 913f012e29Smrg free(name1); 923f012e29Smrg free(name2); 933f012e29Smrg return 0; 943f012e29Smrg } 953f012e29Smrg 963f012e29Smrg result = strcmp(name1, name2); 973f012e29Smrg free(name1); 983f012e29Smrg free(name2); 993f012e29Smrg 1003f012e29Smrg return result; 1013f012e29Smrg} 1023f012e29Smrg 1033f012e29Smrg/** 1043f012e29Smrg* Get the authenticated form fd, 1053f012e29Smrg* 1063f012e29Smrg* \param fd - \c [in] File descriptor for AMD GPU device 1073f012e29Smrg* \param auth - \c [out] Pointer to output the fd is authenticated or not 1083f012e29Smrg* A render node fd, output auth = 0 1093f012e29Smrg* A legacy fd, get the authenticated for compatibility root 1103f012e29Smrg* 1113f012e29Smrg* \return 0 on success\n 1123f012e29Smrg* >0 - AMD specific error code\n 1133f012e29Smrg* <0 - Negative POSIX Error code 1143f012e29Smrg*/ 1153f012e29Smrgstatic int amdgpu_get_auth(int fd, int *auth) 1163f012e29Smrg{ 1173f012e29Smrg int r = 0; 1183f012e29Smrg drm_client_t client = {}; 1193f012e29Smrg 1203f012e29Smrg if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER) 1213f012e29Smrg *auth = 0; 1223f012e29Smrg else { 1233f012e29Smrg client.idx = 0; 1243f012e29Smrg r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client); 1253f012e29Smrg if (!r) 1263f012e29Smrg *auth = client.auth; 1273f012e29Smrg } 1283f012e29Smrg return r; 1293f012e29Smrg} 1303f012e29Smrg 1313f012e29Smrgstatic void amdgpu_device_free_internal(amdgpu_device_handle dev) 1323f012e29Smrg{ 133d8807b2fSmrg amdgpu_vamgr_deinit(&dev->vamgr_32); 134d8807b2fSmrg amdgpu_vamgr_deinit(&dev->vamgr); 1353f012e29Smrg util_hash_table_destroy(dev->bo_flink_names); 1363f012e29Smrg util_hash_table_destroy(dev->bo_handles); 1373f012e29Smrg pthread_mutex_destroy(&dev->bo_table_mutex); 1383f012e29Smrg util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd)); 1393f012e29Smrg close(dev->fd); 1403f012e29Smrg if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd)) 1413f012e29Smrg close(dev->flink_fd); 14200a23bdaSmrg free(dev->marketing_name); 1433f012e29Smrg free(dev); 1443f012e29Smrg} 1453f012e29Smrg 1463f012e29Smrg/** 1473f012e29Smrg * Assignment between two amdgpu_device pointers with reference counting. 1483f012e29Smrg * 1493f012e29Smrg * Usage: 1503f012e29Smrg * struct amdgpu_device *dst = ... , *src = ...; 1513f012e29Smrg * 1523f012e29Smrg * dst = src; 1533f012e29Smrg * // No reference counting. Only use this when you need to move 1543f012e29Smrg * // a reference from one pointer to another. 1553f012e29Smrg * 1563f012e29Smrg * amdgpu_device_reference(&dst, src); 1573f012e29Smrg * // Reference counters are updated. dst is decremented and src is 1583f012e29Smrg * // incremented. dst is freed if its reference counter is 0. 1593f012e29Smrg */ 1603f012e29Smrgstatic void amdgpu_device_reference(struct amdgpu_device **dst, 1613f012e29Smrg struct amdgpu_device *src) 1623f012e29Smrg{ 1633f012e29Smrg if (update_references(&(*dst)->refcount, &src->refcount)) 1643f012e29Smrg amdgpu_device_free_internal(*dst); 1653f012e29Smrg *dst = src; 1663f012e29Smrg} 1673f012e29Smrg 1683f012e29Smrgint amdgpu_device_initialize(int fd, 1693f012e29Smrg uint32_t *major_version, 1703f012e29Smrg uint32_t *minor_version, 1713f012e29Smrg amdgpu_device_handle *device_handle) 1723f012e29Smrg{ 1733f012e29Smrg struct amdgpu_device *dev; 1743f012e29Smrg drmVersionPtr version; 1753f012e29Smrg int r; 1763f012e29Smrg int flag_auth = 0; 1773f012e29Smrg int flag_authexist=0; 1783f012e29Smrg uint32_t accel_working = 0; 1793f012e29Smrg uint64_t start, max; 1803f012e29Smrg 1813f012e29Smrg *device_handle = NULL; 1823f012e29Smrg 1833f012e29Smrg pthread_mutex_lock(&fd_mutex); 1843f012e29Smrg if (!fd_tab) 1853f012e29Smrg fd_tab = util_hash_table_create(fd_hash, fd_compare); 1863f012e29Smrg r = amdgpu_get_auth(fd, &flag_auth); 1873f012e29Smrg if (r) { 18800a23bdaSmrg fprintf(stderr, "%s: amdgpu_get_auth (1) failed (%i)\n", 18900a23bdaSmrg __func__, r); 1903f012e29Smrg pthread_mutex_unlock(&fd_mutex); 1913f012e29Smrg return r; 1923f012e29Smrg } 1933f012e29Smrg dev = util_hash_table_get(fd_tab, UINT_TO_PTR(fd)); 1943f012e29Smrg if (dev) { 1953f012e29Smrg r = amdgpu_get_auth(dev->fd, &flag_authexist); 1963f012e29Smrg if (r) { 19700a23bdaSmrg fprintf(stderr, "%s: amdgpu_get_auth (2) failed (%i)\n", 19800a23bdaSmrg __func__, r); 1993f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2003f012e29Smrg return r; 2013f012e29Smrg } 2023f012e29Smrg if ((flag_auth) && (!flag_authexist)) { 2033f012e29Smrg dev->flink_fd = dup(fd); 2043f012e29Smrg } 2053f012e29Smrg *major_version = dev->major_version; 2063f012e29Smrg *minor_version = dev->minor_version; 2073f012e29Smrg amdgpu_device_reference(device_handle, dev); 2083f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2093f012e29Smrg return 0; 2103f012e29Smrg } 2113f012e29Smrg 2123f012e29Smrg dev = calloc(1, sizeof(struct amdgpu_device)); 2133f012e29Smrg if (!dev) { 21400a23bdaSmrg fprintf(stderr, "%s: calloc failed\n", __func__); 2153f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2163f012e29Smrg return -ENOMEM; 2173f012e29Smrg } 2183f012e29Smrg 2193f012e29Smrg dev->fd = -1; 2203f012e29Smrg dev->flink_fd = -1; 2213f012e29Smrg 2223f012e29Smrg atomic_set(&dev->refcount, 1); 2233f012e29Smrg 2243f012e29Smrg version = drmGetVersion(fd); 2253f012e29Smrg if (version->version_major != 3) { 2263f012e29Smrg fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " 2273f012e29Smrg "only compatible with 3.x.x.\n", 2283f012e29Smrg __func__, 2293f012e29Smrg version->version_major, 2303f012e29Smrg version->version_minor, 2313f012e29Smrg version->version_patchlevel); 2323f012e29Smrg drmFreeVersion(version); 2333f012e29Smrg r = -EBADF; 2343f012e29Smrg goto cleanup; 2353f012e29Smrg } 2363f012e29Smrg 2373f012e29Smrg dev->fd = dup(fd); 2383f012e29Smrg dev->flink_fd = dev->fd; 2393f012e29Smrg dev->major_version = version->version_major; 2403f012e29Smrg dev->minor_version = version->version_minor; 2413f012e29Smrg drmFreeVersion(version); 2423f012e29Smrg 2433f012e29Smrg dev->bo_flink_names = util_hash_table_create(handle_hash, 2443f012e29Smrg handle_compare); 2453f012e29Smrg dev->bo_handles = util_hash_table_create(handle_hash, handle_compare); 2463f012e29Smrg pthread_mutex_init(&dev->bo_table_mutex, NULL); 2473f012e29Smrg 2483f012e29Smrg /* Check if acceleration is working. */ 2493f012e29Smrg r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working); 25000a23bdaSmrg if (r) { 25100a23bdaSmrg fprintf(stderr, "%s: amdgpu_query_info(ACCEL_WORKING) failed (%i)\n", 25200a23bdaSmrg __func__, r); 2533f012e29Smrg goto cleanup; 25400a23bdaSmrg } 2553f012e29Smrg if (!accel_working) { 25600a23bdaSmrg fprintf(stderr, "%s: AMDGPU_INFO_ACCEL_WORKING = 0\n", __func__); 2573f012e29Smrg r = -EBADF; 2583f012e29Smrg goto cleanup; 2593f012e29Smrg } 2603f012e29Smrg 2613f012e29Smrg r = amdgpu_query_gpu_info_init(dev); 26200a23bdaSmrg if (r) { 26300a23bdaSmrg fprintf(stderr, "%s: amdgpu_query_gpu_info_init failed\n", __func__); 2643f012e29Smrg goto cleanup; 26500a23bdaSmrg } 2663f012e29Smrg 26700a23bdaSmrg start = dev->dev_info.virtual_address_offset; 26800a23bdaSmrg max = MIN2(dev->dev_info.virtual_address_max, 0x100000000ULL); 26900a23bdaSmrg amdgpu_vamgr_init(&dev->vamgr_32, start, max, 2703f012e29Smrg dev->dev_info.virtual_address_alignment); 2713f012e29Smrg 27200a23bdaSmrg start = max; 27300a23bdaSmrg max = MAX2(dev->dev_info.virtual_address_max, 0x100000000ULL); 27400a23bdaSmrg amdgpu_vamgr_init(&dev->vamgr, start, max, 27500a23bdaSmrg dev->dev_info.virtual_address_alignment); 2763f012e29Smrg 27700a23bdaSmrg start = dev->dev_info.high_va_offset; 27800a23bdaSmrg max = MIN2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) + 27900a23bdaSmrg 0x100000000ULL); 28000a23bdaSmrg amdgpu_vamgr_init(&dev->vamgr_high_32, start, max, 2813f012e29Smrg dev->dev_info.virtual_address_alignment); 2823f012e29Smrg 28300a23bdaSmrg start = max; 28400a23bdaSmrg max = MAX2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) + 28500a23bdaSmrg 0x100000000ULL); 28600a23bdaSmrg amdgpu_vamgr_init(&dev->vamgr_high, start, max, 28700a23bdaSmrg dev->dev_info.virtual_address_alignment); 28800a23bdaSmrg 28900a23bdaSmrg amdgpu_parse_asic_ids(dev); 290d8807b2fSmrg 2913f012e29Smrg *major_version = dev->major_version; 2923f012e29Smrg *minor_version = dev->minor_version; 2933f012e29Smrg *device_handle = dev; 2943f012e29Smrg util_hash_table_set(fd_tab, UINT_TO_PTR(dev->fd), dev); 2953f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2963f012e29Smrg 2973f012e29Smrg return 0; 2983f012e29Smrg 2993f012e29Smrgcleanup: 3003f012e29Smrg if (dev->fd >= 0) 3013f012e29Smrg close(dev->fd); 3023f012e29Smrg free(dev); 3033f012e29Smrg pthread_mutex_unlock(&fd_mutex); 3043f012e29Smrg return r; 3053f012e29Smrg} 3063f012e29Smrg 3073f012e29Smrgint amdgpu_device_deinitialize(amdgpu_device_handle dev) 3083f012e29Smrg{ 3093f012e29Smrg amdgpu_device_reference(&dev, NULL); 3103f012e29Smrg return 0; 3113f012e29Smrg} 312037b3c26Smrg 313037b3c26Smrgconst char *amdgpu_get_marketing_name(amdgpu_device_handle dev) 314037b3c26Smrg{ 31500a23bdaSmrg return dev->marketing_name; 31600a23bdaSmrg} 317037b3c26Smrg 31800a23bdaSmrgint amdgpu_query_sw_info(amdgpu_device_handle dev, enum amdgpu_sw_info info, 31900a23bdaSmrg void *value) 32000a23bdaSmrg{ 32100a23bdaSmrg uint32_t *val32 = (uint32_t*)value; 32200a23bdaSmrg 32300a23bdaSmrg switch (info) { 32400a23bdaSmrg case amdgpu_sw_info_address32_hi: 32500a23bdaSmrg if (dev->vamgr_high_32.va_max) 32600a23bdaSmrg *val32 = (dev->vamgr_high_32.va_max - 1) >> 32; 32700a23bdaSmrg else 32800a23bdaSmrg *val32 = (dev->vamgr_32.va_max - 1) >> 32; 32900a23bdaSmrg return 0; 330037b3c26Smrg } 33100a23bdaSmrg return -EINVAL; 332037b3c26Smrg} 333