amdgpu_device.c revision d8807b2f
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 const struct amdgpu_asic_id *id; 134d8807b2fSmrg amdgpu_vamgr_deinit(&dev->vamgr_32); 135d8807b2fSmrg amdgpu_vamgr_deinit(&dev->vamgr); 1363f012e29Smrg util_hash_table_destroy(dev->bo_flink_names); 1373f012e29Smrg util_hash_table_destroy(dev->bo_handles); 1383f012e29Smrg pthread_mutex_destroy(&dev->bo_table_mutex); 1393f012e29Smrg util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd)); 1403f012e29Smrg close(dev->fd); 1413f012e29Smrg if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd)) 1423f012e29Smrg close(dev->flink_fd); 143d8807b2fSmrg if (dev->asic_ids) { 144d8807b2fSmrg for (id = dev->asic_ids; id->did; id++) 145d8807b2fSmrg free(id->marketing_name); 146d8807b2fSmrg 147d8807b2fSmrg free(dev->asic_ids); 148d8807b2fSmrg } 1493f012e29Smrg free(dev); 1503f012e29Smrg} 1513f012e29Smrg 1523f012e29Smrg/** 1533f012e29Smrg * Assignment between two amdgpu_device pointers with reference counting. 1543f012e29Smrg * 1553f012e29Smrg * Usage: 1563f012e29Smrg * struct amdgpu_device *dst = ... , *src = ...; 1573f012e29Smrg * 1583f012e29Smrg * dst = src; 1593f012e29Smrg * // No reference counting. Only use this when you need to move 1603f012e29Smrg * // a reference from one pointer to another. 1613f012e29Smrg * 1623f012e29Smrg * amdgpu_device_reference(&dst, src); 1633f012e29Smrg * // Reference counters are updated. dst is decremented and src is 1643f012e29Smrg * // incremented. dst is freed if its reference counter is 0. 1653f012e29Smrg */ 1663f012e29Smrgstatic void amdgpu_device_reference(struct amdgpu_device **dst, 1673f012e29Smrg struct amdgpu_device *src) 1683f012e29Smrg{ 1693f012e29Smrg if (update_references(&(*dst)->refcount, &src->refcount)) 1703f012e29Smrg amdgpu_device_free_internal(*dst); 1713f012e29Smrg *dst = src; 1723f012e29Smrg} 1733f012e29Smrg 1743f012e29Smrgint amdgpu_device_initialize(int fd, 1753f012e29Smrg uint32_t *major_version, 1763f012e29Smrg uint32_t *minor_version, 1773f012e29Smrg amdgpu_device_handle *device_handle) 1783f012e29Smrg{ 1793f012e29Smrg struct amdgpu_device *dev; 1803f012e29Smrg drmVersionPtr version; 1813f012e29Smrg int r; 1823f012e29Smrg int flag_auth = 0; 1833f012e29Smrg int flag_authexist=0; 1843f012e29Smrg uint32_t accel_working = 0; 1853f012e29Smrg uint64_t start, max; 1863f012e29Smrg 1873f012e29Smrg *device_handle = NULL; 1883f012e29Smrg 1893f012e29Smrg pthread_mutex_lock(&fd_mutex); 1903f012e29Smrg if (!fd_tab) 1913f012e29Smrg fd_tab = util_hash_table_create(fd_hash, fd_compare); 1923f012e29Smrg r = amdgpu_get_auth(fd, &flag_auth); 1933f012e29Smrg if (r) { 1943f012e29Smrg pthread_mutex_unlock(&fd_mutex); 1953f012e29Smrg return r; 1963f012e29Smrg } 1973f012e29Smrg dev = util_hash_table_get(fd_tab, UINT_TO_PTR(fd)); 1983f012e29Smrg if (dev) { 1993f012e29Smrg r = amdgpu_get_auth(dev->fd, &flag_authexist); 2003f012e29Smrg if (r) { 2013f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2023f012e29Smrg return r; 2033f012e29Smrg } 2043f012e29Smrg if ((flag_auth) && (!flag_authexist)) { 2053f012e29Smrg dev->flink_fd = dup(fd); 2063f012e29Smrg } 2073f012e29Smrg *major_version = dev->major_version; 2083f012e29Smrg *minor_version = dev->minor_version; 2093f012e29Smrg amdgpu_device_reference(device_handle, dev); 2103f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2113f012e29Smrg return 0; 2123f012e29Smrg } 2133f012e29Smrg 2143f012e29Smrg dev = calloc(1, sizeof(struct amdgpu_device)); 2153f012e29Smrg if (!dev) { 2163f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2173f012e29Smrg return -ENOMEM; 2183f012e29Smrg } 2193f012e29Smrg 2203f012e29Smrg dev->fd = -1; 2213f012e29Smrg dev->flink_fd = -1; 2223f012e29Smrg 2233f012e29Smrg atomic_set(&dev->refcount, 1); 2243f012e29Smrg 2253f012e29Smrg version = drmGetVersion(fd); 2263f012e29Smrg if (version->version_major != 3) { 2273f012e29Smrg fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " 2283f012e29Smrg "only compatible with 3.x.x.\n", 2293f012e29Smrg __func__, 2303f012e29Smrg version->version_major, 2313f012e29Smrg version->version_minor, 2323f012e29Smrg version->version_patchlevel); 2333f012e29Smrg drmFreeVersion(version); 2343f012e29Smrg r = -EBADF; 2353f012e29Smrg goto cleanup; 2363f012e29Smrg } 2373f012e29Smrg 2383f012e29Smrg dev->fd = dup(fd); 2393f012e29Smrg dev->flink_fd = dev->fd; 2403f012e29Smrg dev->major_version = version->version_major; 2413f012e29Smrg dev->minor_version = version->version_minor; 2423f012e29Smrg drmFreeVersion(version); 2433f012e29Smrg 2443f012e29Smrg dev->bo_flink_names = util_hash_table_create(handle_hash, 2453f012e29Smrg handle_compare); 2463f012e29Smrg dev->bo_handles = util_hash_table_create(handle_hash, handle_compare); 2473f012e29Smrg pthread_mutex_init(&dev->bo_table_mutex, NULL); 2483f012e29Smrg 2493f012e29Smrg /* Check if acceleration is working. */ 2503f012e29Smrg r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working); 2513f012e29Smrg if (r) 2523f012e29Smrg goto cleanup; 2533f012e29Smrg if (!accel_working) { 2543f012e29Smrg r = -EBADF; 2553f012e29Smrg goto cleanup; 2563f012e29Smrg } 2573f012e29Smrg 2583f012e29Smrg r = amdgpu_query_gpu_info_init(dev); 2593f012e29Smrg if (r) 2603f012e29Smrg goto cleanup; 2613f012e29Smrg 262d8807b2fSmrg 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); 267d8807b2fSmrg 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 273d8807b2fSmrg amdgpu_vamgr_init(&dev->vamgr_32, start, max, 2743f012e29Smrg dev->dev_info.virtual_address_alignment); 2753f012e29Smrg 276d8807b2fSmrg r = amdgpu_parse_asic_ids(&dev->asic_ids); 277d8807b2fSmrg if (r) { 278d8807b2fSmrg fprintf(stderr, "%s: Cannot parse ASIC IDs, 0x%x.", 279d8807b2fSmrg __func__, r); 280d8807b2fSmrg } 281d8807b2fSmrg 2823f012e29Smrg *major_version = dev->major_version; 2833f012e29Smrg *minor_version = dev->minor_version; 2843f012e29Smrg *device_handle = dev; 2853f012e29Smrg util_hash_table_set(fd_tab, UINT_TO_PTR(dev->fd), dev); 2863f012e29Smrg pthread_mutex_unlock(&fd_mutex); 2873f012e29Smrg 2883f012e29Smrg return 0; 2893f012e29Smrg 2903f012e29Smrgfree_va: 2913f012e29Smrg r = -ENOMEM; 292d8807b2fSmrg amdgpu_vamgr_free_va(&dev->vamgr, start, 2933f012e29Smrg max - dev->dev_info.virtual_address_offset); 294d8807b2fSmrg amdgpu_vamgr_deinit(&dev->vamgr); 2953f012e29Smrg 2963f012e29Smrgcleanup: 2973f012e29Smrg if (dev->fd >= 0) 2983f012e29Smrg close(dev->fd); 2993f012e29Smrg free(dev); 3003f012e29Smrg pthread_mutex_unlock(&fd_mutex); 3013f012e29Smrg return r; 3023f012e29Smrg} 3033f012e29Smrg 3043f012e29Smrgint amdgpu_device_deinitialize(amdgpu_device_handle dev) 3053f012e29Smrg{ 3063f012e29Smrg amdgpu_device_reference(&dev, NULL); 3073f012e29Smrg return 0; 3083f012e29Smrg} 309037b3c26Smrg 310037b3c26Smrgconst char *amdgpu_get_marketing_name(amdgpu_device_handle dev) 311037b3c26Smrg{ 312d8807b2fSmrg const struct amdgpu_asic_id *id; 313d8807b2fSmrg 314d8807b2fSmrg if (!dev->asic_ids) 315d8807b2fSmrg return NULL; 316037b3c26Smrg 317d8807b2fSmrg for (id = dev->asic_ids; id->did; id++) { 318d8807b2fSmrg if ((id->did == dev->info.asic_id) && 319d8807b2fSmrg (id->rid == dev->info.pci_rev_id)) 320d8807b2fSmrg return id->marketing_name; 321037b3c26Smrg } 322037b3c26Smrg 323037b3c26Smrg return NULL; 324037b3c26Smrg} 325