amdgpu_device.c revision 037b3c26
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" 47037b3c26Smrg#include "amdgpu_asic_id.h" 483f012e29Smrg 493f012e29Smrg#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x))) 503f012e29Smrg#define UINT_TO_PTR(x) ((void *)((intptr_t)(x))) 513f012e29Smrg 523f012e29Smrgstatic pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER; 533f012e29Smrgstatic struct util_hash_table *fd_tab; 543f012e29Smrg 553f012e29Smrgstatic unsigned handle_hash(void *key) 563f012e29Smrg{ 573f012e29Smrg return PTR_TO_UINT(key); 583f012e29Smrg} 593f012e29Smrg 603f012e29Smrgstatic int handle_compare(void *key1, void *key2) 613f012e29Smrg{ 623f012e29Smrg return PTR_TO_UINT(key1) != PTR_TO_UINT(key2); 633f012e29Smrg} 643f012e29Smrg 653f012e29Smrgstatic unsigned fd_hash(void *key) 663f012e29Smrg{ 673f012e29Smrg int fd = PTR_TO_UINT(key); 683f012e29Smrg char *name = drmGetPrimaryDeviceNameFromFd(fd); 693f012e29Smrg unsigned result = 0; 703f012e29Smrg char *c; 713f012e29Smrg 723f012e29Smrg if (name == NULL) 733f012e29Smrg return 0; 743f012e29Smrg 753f012e29Smrg for (c = name; *c; ++c) 763f012e29Smrg result += *c; 773f012e29Smrg 783f012e29Smrg free(name); 793f012e29Smrg 803f012e29Smrg return result; 813f012e29Smrg} 823f012e29Smrg 833f012e29Smrgstatic int fd_compare(void *key1, void *key2) 843f012e29Smrg{ 853f012e29Smrg int fd1 = PTR_TO_UINT(key1); 863f012e29Smrg int fd2 = PTR_TO_UINT(key2); 873f012e29Smrg char *name1 = drmGetPrimaryDeviceNameFromFd(fd1); 883f012e29Smrg char *name2 = drmGetPrimaryDeviceNameFromFd(fd2); 893f012e29Smrg int result; 903f012e29Smrg 913f012e29Smrg if (name1 == NULL || name2 == NULL) { 923f012e29Smrg free(name1); 933f012e29Smrg free(name2); 943f012e29Smrg return 0; 953f012e29Smrg } 963f012e29Smrg 973f012e29Smrg result = strcmp(name1, name2); 983f012e29Smrg free(name1); 993f012e29Smrg free(name2); 1003f012e29Smrg 1013f012e29Smrg return result; 1023f012e29Smrg} 1033f012e29Smrg 1043f012e29Smrg/** 1053f012e29Smrg* Get the authenticated form fd, 1063f012e29Smrg* 1073f012e29Smrg* \param fd - \c [in] File descriptor for AMD GPU device 1083f012e29Smrg* \param auth - \c [out] Pointer to output the fd is authenticated or not 1093f012e29Smrg* A render node fd, output auth = 0 1103f012e29Smrg* A legacy fd, get the authenticated for compatibility root 1113f012e29Smrg* 1123f012e29Smrg* \return 0 on success\n 1133f012e29Smrg* >0 - AMD specific error code\n 1143f012e29Smrg* <0 - Negative POSIX Error code 1153f012e29Smrg*/ 1163f012e29Smrgstatic int amdgpu_get_auth(int fd, int *auth) 1173f012e29Smrg{ 1183f012e29Smrg int r = 0; 1193f012e29Smrg drm_client_t client = {}; 1203f012e29Smrg 1213f012e29Smrg if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER) 1223f012e29Smrg *auth = 0; 1233f012e29Smrg else { 1243f012e29Smrg client.idx = 0; 1253f012e29Smrg r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client); 1263f012e29Smrg if (!r) 1273f012e29Smrg *auth = client.auth; 1283f012e29Smrg } 1293f012e29Smrg return r; 1303f012e29Smrg} 1313f012e29Smrg 1323f012e29Smrgstatic void amdgpu_device_free_internal(amdgpu_device_handle dev) 1333f012e29Smrg{ 1343f012e29Smrg amdgpu_vamgr_deinit(dev->vamgr); 1353f012e29Smrg free(dev->vamgr); 1363f012e29Smrg amdgpu_vamgr_deinit(dev->vamgr_32); 1373f012e29Smrg free(dev->vamgr_32); 1383f012e29Smrg util_hash_table_destroy(dev->bo_flink_names); 1393f012e29Smrg util_hash_table_destroy(dev->bo_handles); 1403f012e29Smrg pthread_mutex_destroy(&dev->bo_table_mutex); 1413f012e29Smrg util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd)); 1423f012e29Smrg close(dev->fd); 1433f012e29Smrg if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd)) 1443f012e29Smrg close(dev->flink_fd); 1453f012e29Smrg free(dev); 1463f012e29Smrg} 1473f012e29Smrg 1483f012e29Smrg/** 1493f012e29Smrg * Assignment between two amdgpu_device pointers with reference counting. 1503f012e29Smrg * 1513f012e29Smrg * Usage: 1523f012e29Smrg * struct amdgpu_device *dst = ... , *src = ...; 1533f012e29Smrg * 1543f012e29Smrg * dst = src; 1553f012e29Smrg * // No reference counting. Only use this when you need to move 1563f012e29Smrg * // a reference from one pointer to another. 1573f012e29Smrg * 1583f012e29Smrg * amdgpu_device_reference(&dst, src); 1593f012e29Smrg * // Reference counters are updated. dst is decremented and src is 1603f012e29Smrg * // incremented. dst is freed if its reference counter is 0. 1613f012e29Smrg */ 1623f012e29Smrgstatic void amdgpu_device_reference(struct amdgpu_device **dst, 1633f012e29Smrg struct amdgpu_device *src) 1643f012e29Smrg{ 1653f012e29Smrg if (update_references(&(*dst)->refcount, &src->refcount)) 1663f012e29Smrg amdgpu_device_free_internal(*dst); 1673f012e29Smrg *dst = src; 1683f012e29Smrg} 1693f012e29Smrg 1703f012e29Smrgint amdgpu_device_initialize(int fd, 1713f012e29Smrg uint32_t *major_version, 1723f012e29Smrg uint32_t *minor_version, 1733f012e29Smrg amdgpu_device_handle *device_handle) 1743f012e29Smrg{ 1753f012e29Smrg struct amdgpu_device *dev; 1763f012e29Smrg drmVersionPtr version; 1773f012e29Smrg int r; 1783f012e29Smrg int flag_auth = 0; 1793f012e29Smrg int flag_authexist=0; 1803f012e29Smrg uint32_t accel_working = 0; 1813f012e29Smrg uint64_t start, max; 1823f012e29Smrg 1833f012e29Smrg *device_handle = NULL; 1843f012e29Smrg 1853f012e29Smrg pthread_mutex_lock(&fd_mutex); 1863f012e29Smrg if (!fd_tab) 1873f012e29Smrg fd_tab = util_hash_table_create(fd_hash, fd_compare); 1883f012e29Smrg r = amdgpu_get_auth(fd, &flag_auth); 1893f012e29Smrg if (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) { 1973f012e29Smrg pthread_mutex_unlock(&fd_mutex); 1983f012e29Smrg return r; 1993f012e29Smrg } 2003f012e29Smrg if ((flag_auth) && (!flag_authexist)) { 2013f012e29Smrg dev->flink_fd = dup(fd); 2023f012e29Smrg } 2033f012e29Smrg *major_version = dev->major_version; 2043f012e29Smrg *minor_version = dev->minor_version; 2053f012e29Smrg amdgpu_device_reference(device_handle, dev); 2063f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2073f012e29Smrg return 0; 2083f012e29Smrg } 2093f012e29Smrg 2103f012e29Smrg dev = calloc(1, sizeof(struct amdgpu_device)); 2113f012e29Smrg if (!dev) { 2123f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2133f012e29Smrg return -ENOMEM; 2143f012e29Smrg } 2153f012e29Smrg 2163f012e29Smrg dev->fd = -1; 2173f012e29Smrg dev->flink_fd = -1; 2183f012e29Smrg 2193f012e29Smrg atomic_set(&dev->refcount, 1); 2203f012e29Smrg 2213f012e29Smrg version = drmGetVersion(fd); 2223f012e29Smrg if (version->version_major != 3) { 2233f012e29Smrg fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " 2243f012e29Smrg "only compatible with 3.x.x.\n", 2253f012e29Smrg __func__, 2263f012e29Smrg version->version_major, 2273f012e29Smrg version->version_minor, 2283f012e29Smrg version->version_patchlevel); 2293f012e29Smrg drmFreeVersion(version); 2303f012e29Smrg r = -EBADF; 2313f012e29Smrg goto cleanup; 2323f012e29Smrg } 2333f012e29Smrg 2343f012e29Smrg dev->fd = dup(fd); 2353f012e29Smrg dev->flink_fd = dev->fd; 2363f012e29Smrg dev->major_version = version->version_major; 2373f012e29Smrg dev->minor_version = version->version_minor; 2383f012e29Smrg drmFreeVersion(version); 2393f012e29Smrg 2403f012e29Smrg dev->bo_flink_names = util_hash_table_create(handle_hash, 2413f012e29Smrg handle_compare); 2423f012e29Smrg dev->bo_handles = util_hash_table_create(handle_hash, handle_compare); 2433f012e29Smrg pthread_mutex_init(&dev->bo_table_mutex, NULL); 2443f012e29Smrg 2453f012e29Smrg /* Check if acceleration is working. */ 2463f012e29Smrg r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working); 2473f012e29Smrg if (r) 2483f012e29Smrg goto cleanup; 2493f012e29Smrg if (!accel_working) { 2503f012e29Smrg r = -EBADF; 2513f012e29Smrg goto cleanup; 2523f012e29Smrg } 2533f012e29Smrg 2543f012e29Smrg r = amdgpu_query_gpu_info_init(dev); 2553f012e29Smrg if (r) 2563f012e29Smrg goto cleanup; 2573f012e29Smrg 2583f012e29Smrg dev->vamgr = calloc(1, sizeof(struct amdgpu_bo_va_mgr)); 2593f012e29Smrg if (dev->vamgr == NULL) 2603f012e29Smrg goto cleanup; 2613f012e29Smrg 2623f012e29Smrg amdgpu_vamgr_init(dev->vamgr, dev->dev_info.virtual_address_offset, 2633f012e29Smrg dev->dev_info.virtual_address_max, 2643f012e29Smrg dev->dev_info.virtual_address_alignment); 2653f012e29Smrg 2663f012e29Smrg max = MIN2(dev->dev_info.virtual_address_max, 0xffffffff); 2673f012e29Smrg start = amdgpu_vamgr_find_va(dev->vamgr, 2683f012e29Smrg max - dev->dev_info.virtual_address_offset, 2693f012e29Smrg dev->dev_info.virtual_address_alignment, 0); 2703f012e29Smrg if (start > 0xffffffff) 2713f012e29Smrg goto free_va; /* shouldn't get here */ 2723f012e29Smrg 2733f012e29Smrg dev->vamgr_32 = calloc(1, sizeof(struct amdgpu_bo_va_mgr)); 2743f012e29Smrg if (dev->vamgr_32 == NULL) 2753f012e29Smrg goto free_va; 2763f012e29Smrg amdgpu_vamgr_init(dev->vamgr_32, start, max, 2773f012e29Smrg dev->dev_info.virtual_address_alignment); 2783f012e29Smrg 2793f012e29Smrg *major_version = dev->major_version; 2803f012e29Smrg *minor_version = dev->minor_version; 2813f012e29Smrg *device_handle = dev; 2823f012e29Smrg util_hash_table_set(fd_tab, UINT_TO_PTR(dev->fd), dev); 2833f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2843f012e29Smrg 2853f012e29Smrg return 0; 2863f012e29Smrg 2873f012e29Smrgfree_va: 2883f012e29Smrg r = -ENOMEM; 2893f012e29Smrg amdgpu_vamgr_free_va(dev->vamgr, start, 2903f012e29Smrg max - dev->dev_info.virtual_address_offset); 2913f012e29Smrg amdgpu_vamgr_deinit(dev->vamgr); 2923f012e29Smrg free(dev->vamgr); 2933f012e29Smrg 2943f012e29Smrgcleanup: 2953f012e29Smrg if (dev->fd >= 0) 2963f012e29Smrg close(dev->fd); 2973f012e29Smrg free(dev); 2983f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2993f012e29Smrg return r; 3003f012e29Smrg} 3013f012e29Smrg 3023f012e29Smrgint amdgpu_device_deinitialize(amdgpu_device_handle dev) 3033f012e29Smrg{ 3043f012e29Smrg amdgpu_device_reference(&dev, NULL); 3053f012e29Smrg return 0; 3063f012e29Smrg} 307037b3c26Smrg 308037b3c26Smrgconst char *amdgpu_get_marketing_name(amdgpu_device_handle dev) 309037b3c26Smrg{ 310037b3c26Smrg const struct amdgpu_asic_id_table_t *t = amdgpu_asic_id_table; 311037b3c26Smrg 312037b3c26Smrg while (t->did) { 313037b3c26Smrg if ((t->did == dev->info.asic_id) && 314037b3c26Smrg (t->rid == dev->info.pci_rev_id)) 315037b3c26Smrg return t->marketing_name; 316037b3c26Smrg t++; 317037b3c26Smrg } 318037b3c26Smrg 319037b3c26Smrg return NULL; 320037b3c26Smrg} 321