1/* 2 * Copyright © 2016 Red Hat. 3 * Copyright © 2016 Bas Nieuwenhuizen 4 * based on amdgpu winsys. 5 * Copyright © 2011 Marek Olšák <maraeo@gmail.com> 6 * Copyright © 2015 Advanced Micro Devices, Inc. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 25 * IN THE SOFTWARE. 26 */ 27#include "radv_amdgpu_winsys.h" 28#include <assert.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include "drm-uapi/amdgpu_drm.h" 33#include "ac_surface.h" 34#include "radv_amdgpu_bo.h" 35#include "radv_amdgpu_cs.h" 36#include "radv_amdgpu_surface.h" 37#include "radv_amdgpu_winsys_public.h" 38#include "radv_debug.h" 39#include "xf86drm.h" 40 41static bool 42do_winsys_init(struct radv_amdgpu_winsys *ws, int fd) 43{ 44 if (!ac_query_gpu_info(fd, ws->dev, &ws->info, &ws->amdinfo)) 45 return false; 46 47 if (ws->info.drm_minor < 23) { 48 fprintf(stderr, "radv: DRM 3.23+ is required (Linux kernel 4.15+)\n"); 49 return false; 50 } 51 52 ws->addrlib = ac_addrlib_create(&ws->info, &ws->info.max_alignment); 53 if (!ws->addrlib) { 54 fprintf(stderr, "amdgpu: Cannot create addrlib.\n"); 55 return false; 56 } 57 58 ws->info.num_rings[RING_DMA] = MIN2(ws->info.num_rings[RING_DMA], MAX_RINGS_PER_TYPE); 59 ws->info.num_rings[RING_COMPUTE] = MIN2(ws->info.num_rings[RING_COMPUTE], MAX_RINGS_PER_TYPE); 60 61 ws->use_ib_bos = ws->info.chip_class >= GFX7; 62 return true; 63} 64 65static void 66radv_amdgpu_winsys_query_info(struct radeon_winsys *rws, struct radeon_info *info) 67{ 68 *info = ((struct radv_amdgpu_winsys *)rws)->info; 69} 70 71static uint64_t 72radv_amdgpu_winsys_query_value(struct radeon_winsys *rws, enum radeon_value_id value) 73{ 74 struct radv_amdgpu_winsys *ws = (struct radv_amdgpu_winsys *)rws; 75 struct amdgpu_heap_info heap; 76 uint64_t retval = 0; 77 78 switch (value) { 79 case RADEON_ALLOCATED_VRAM: 80 return ws->allocated_vram; 81 case RADEON_ALLOCATED_VRAM_VIS: 82 return ws->allocated_vram_vis; 83 case RADEON_ALLOCATED_GTT: 84 return ws->allocated_gtt; 85 case RADEON_TIMESTAMP: 86 amdgpu_query_info(ws->dev, AMDGPU_INFO_TIMESTAMP, 8, &retval); 87 return retval; 88 case RADEON_NUM_BYTES_MOVED: 89 amdgpu_query_info(ws->dev, AMDGPU_INFO_NUM_BYTES_MOVED, 8, &retval); 90 return retval; 91 case RADEON_NUM_EVICTIONS: 92 amdgpu_query_info(ws->dev, AMDGPU_INFO_NUM_EVICTIONS, 8, &retval); 93 return retval; 94 case RADEON_NUM_VRAM_CPU_PAGE_FAULTS: 95 amdgpu_query_info(ws->dev, AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS, 8, &retval); 96 return retval; 97 case RADEON_VRAM_USAGE: 98 amdgpu_query_heap_info(ws->dev, AMDGPU_GEM_DOMAIN_VRAM, 0, &heap); 99 return heap.heap_usage; 100 case RADEON_VRAM_VIS_USAGE: 101 amdgpu_query_heap_info(ws->dev, AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, 102 &heap); 103 return heap.heap_usage; 104 case RADEON_GTT_USAGE: 105 amdgpu_query_heap_info(ws->dev, AMDGPU_GEM_DOMAIN_GTT, 0, &heap); 106 return heap.heap_usage; 107 case RADEON_GPU_TEMPERATURE: 108 amdgpu_query_sensor_info(ws->dev, AMDGPU_INFO_SENSOR_GPU_TEMP, 4, &retval); 109 return retval; 110 case RADEON_CURRENT_SCLK: 111 amdgpu_query_sensor_info(ws->dev, AMDGPU_INFO_SENSOR_GFX_SCLK, 4, &retval); 112 return retval; 113 case RADEON_CURRENT_MCLK: 114 amdgpu_query_sensor_info(ws->dev, AMDGPU_INFO_SENSOR_GFX_MCLK, 4, &retval); 115 return retval; 116 default: 117 unreachable("invalid query value"); 118 } 119 120 return 0; 121} 122 123static bool 124radv_amdgpu_winsys_read_registers(struct radeon_winsys *rws, unsigned reg_offset, 125 unsigned num_registers, uint32_t *out) 126{ 127 struct radv_amdgpu_winsys *ws = (struct radv_amdgpu_winsys *)rws; 128 129 return amdgpu_read_mm_registers(ws->dev, reg_offset / 4, num_registers, 0xffffffff, 0, out) == 0; 130} 131 132static const char * 133radv_amdgpu_winsys_get_chip_name(struct radeon_winsys *rws) 134{ 135 amdgpu_device_handle dev = ((struct radv_amdgpu_winsys *)rws)->dev; 136 137 return amdgpu_get_marketing_name(dev); 138} 139 140static simple_mtx_t winsys_creation_mutex = _SIMPLE_MTX_INITIALIZER_NP; 141static struct hash_table *winsyses = NULL; 142 143static void 144radv_amdgpu_winsys_destroy(struct radeon_winsys *rws) 145{ 146 struct radv_amdgpu_winsys *ws = (struct radv_amdgpu_winsys *)rws; 147 bool destroy = false; 148 149 simple_mtx_lock(&winsys_creation_mutex); 150 if (!--ws->refcount) { 151 _mesa_hash_table_remove_key(winsyses, ws->dev); 152 153 /* Clean the hashtable up if empty, though there is no 154 * empty function. */ 155 if (_mesa_hash_table_num_entries(winsyses) == 0) { 156 _mesa_hash_table_destroy(winsyses, NULL); 157 winsyses = NULL; 158 } 159 160 destroy = true; 161 } 162 simple_mtx_unlock(&winsys_creation_mutex); 163 if (!destroy) 164 return; 165 166 for (unsigned i = 0; i < ws->syncobj_count; ++i) 167 amdgpu_cs_destroy_syncobj(ws->dev, ws->syncobj[i]); 168 free(ws->syncobj); 169 170 u_rwlock_destroy(&ws->global_bo_list.lock); 171 free(ws->global_bo_list.bos); 172 173 if (ws->reserve_vmid) 174 amdgpu_vm_unreserve_vmid(ws->dev, 0); 175 176 pthread_mutex_destroy(&ws->syncobj_lock); 177 u_rwlock_destroy(&ws->log_bo_list_lock); 178 ac_addrlib_destroy(ws->addrlib); 179 amdgpu_device_deinitialize(ws->dev); 180 FREE(rws); 181} 182 183struct radeon_winsys * 184radv_amdgpu_winsys_create(int fd, uint64_t debug_flags, uint64_t perftest_flags, bool reserve_vmid) 185{ 186 uint32_t drm_major, drm_minor, r; 187 amdgpu_device_handle dev; 188 struct radv_amdgpu_winsys *ws = NULL; 189 190 r = amdgpu_device_initialize(fd, &drm_major, &drm_minor, &dev); 191 if (r) 192 return NULL; 193 194 /* We have to keep this lock till insertion. */ 195 simple_mtx_lock(&winsys_creation_mutex); 196 if (!winsyses) 197 winsyses = _mesa_pointer_hash_table_create(NULL); 198 if (!winsyses) 199 goto fail; 200 201 struct hash_entry *entry = _mesa_hash_table_search(winsyses, dev); 202 if (entry) { 203 ws = (struct radv_amdgpu_winsys *)entry->data; 204 ++ws->refcount; 205 } 206 207 if (ws) { 208 simple_mtx_unlock(&winsys_creation_mutex); 209 amdgpu_device_deinitialize(dev); 210 211 /* Check that options don't differ from the existing winsys. */ 212 if (((debug_flags & RADV_DEBUG_ALL_BOS) && !ws->debug_all_bos) || 213 ((debug_flags & RADV_DEBUG_HANG) && !ws->debug_log_bos) || 214 ((debug_flags & RADV_DEBUG_NO_IBS) && ws->use_ib_bos) || 215 (perftest_flags != ws->perftest)) { 216 fprintf(stderr, "amdgpu: Found options that differ from the existing winsys.\n"); 217 return NULL; 218 } 219 220 /* RADV_DEBUG_ZERO_VRAM is the only option that is allowed to be set again. */ 221 if (debug_flags & RADV_DEBUG_ZERO_VRAM) 222 ws->zero_all_vram_allocs = true; 223 224 return &ws->base; 225 } 226 227 ws = calloc(1, sizeof(struct radv_amdgpu_winsys)); 228 if (!ws) 229 goto fail; 230 231 ws->refcount = 1; 232 ws->dev = dev; 233 ws->info.drm_major = drm_major; 234 ws->info.drm_minor = drm_minor; 235 if (!do_winsys_init(ws, fd)) 236 goto winsys_fail; 237 238 ws->debug_all_bos = !!(debug_flags & RADV_DEBUG_ALL_BOS); 239 ws->debug_log_bos = debug_flags & RADV_DEBUG_HANG; 240 if (debug_flags & RADV_DEBUG_NO_IBS) 241 ws->use_ib_bos = false; 242 243 ws->reserve_vmid = reserve_vmid; 244 if (ws->reserve_vmid) { 245 r = amdgpu_vm_reserve_vmid(dev, 0); 246 if (r) 247 goto vmid_fail; 248 } 249 250 ws->perftest = perftest_flags; 251 ws->zero_all_vram_allocs = debug_flags & RADV_DEBUG_ZERO_VRAM; 252 u_rwlock_init(&ws->global_bo_list.lock); 253 list_inithead(&ws->log_bo_list); 254 u_rwlock_init(&ws->log_bo_list_lock); 255 pthread_mutex_init(&ws->syncobj_lock, NULL); 256 ws->base.query_info = radv_amdgpu_winsys_query_info; 257 ws->base.query_value = radv_amdgpu_winsys_query_value; 258 ws->base.read_registers = radv_amdgpu_winsys_read_registers; 259 ws->base.get_chip_name = radv_amdgpu_winsys_get_chip_name; 260 ws->base.destroy = radv_amdgpu_winsys_destroy; 261 radv_amdgpu_bo_init_functions(ws); 262 radv_amdgpu_cs_init_functions(ws); 263 radv_amdgpu_surface_init_functions(ws); 264 265 _mesa_hash_table_insert(winsyses, dev, ws); 266 simple_mtx_unlock(&winsys_creation_mutex); 267 268 return &ws->base; 269 270vmid_fail: 271 ac_addrlib_destroy(ws->addrlib); 272winsys_fail: 273 free(ws); 274fail: 275 if (winsyses && _mesa_hash_table_num_entries(winsyses) == 0) { 276 _mesa_hash_table_destroy(winsyses, NULL); 277 winsyses = NULL; 278 } 279 simple_mtx_unlock(&winsys_creation_mutex); 280 amdgpu_device_deinitialize(dev); 281 return NULL; 282} 283