1bf215546Sopenharmony_ci/********************************************************** 2bf215546Sopenharmony_ci * Copyright 2009-2015 VMware, Inc. All rights reserved. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person 5bf215546Sopenharmony_ci * obtaining a copy of this software and associated documentation 6bf215546Sopenharmony_ci * files (the "Software"), to deal in the Software without 7bf215546Sopenharmony_ci * restriction, including without limitation the rights to use, copy, 8bf215546Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies 9bf215546Sopenharmony_ci * of the Software, and to permit persons to whom the Software is 10bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be 13bf215546Sopenharmony_ci * included in all copies or substantial portions of the Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19bf215546Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20bf215546Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21bf215546Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22bf215546Sopenharmony_ci * SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci **********************************************************/ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "vmw_screen.h" 28bf215546Sopenharmony_ci#include "vmw_fence.h" 29bf215546Sopenharmony_ci#include "vmw_context.h" 30bf215546Sopenharmony_ci#include "vmwgfx_drm.h" 31bf215546Sopenharmony_ci#include "xf86drm.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include "util/os_file.h" 34bf215546Sopenharmony_ci#include "util/u_memory.h" 35bf215546Sopenharmony_ci#include "pipe/p_compiler.h" 36bf215546Sopenharmony_ci#include "util/u_hash_table.h" 37bf215546Sopenharmony_ci#ifdef MAJOR_IN_MKDEV 38bf215546Sopenharmony_ci#include <sys/mkdev.h> 39bf215546Sopenharmony_ci#endif 40bf215546Sopenharmony_ci#ifdef MAJOR_IN_SYSMACROS 41bf215546Sopenharmony_ci#include <sys/sysmacros.h> 42bf215546Sopenharmony_ci#endif 43bf215546Sopenharmony_ci#include <sys/stat.h> 44bf215546Sopenharmony_ci#include <unistd.h> 45bf215546Sopenharmony_ci#include <fcntl.h> 46bf215546Sopenharmony_ci#include <sys/ioctl.h> 47bf215546Sopenharmony_ci#include <sys/mman.h> 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_cistatic struct hash_table *dev_hash = NULL; 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_cistatic bool vmw_dev_compare(const void *key1, const void *key2) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci return (major(*(dev_t *)key1) == major(*(dev_t *)key2) && 54bf215546Sopenharmony_ci minor(*(dev_t *)key1) == minor(*(dev_t *)key2)); 55bf215546Sopenharmony_ci} 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_cistatic uint32_t vmw_dev_hash(const void *key) 58bf215546Sopenharmony_ci{ 59bf215546Sopenharmony_ci return (major(*(dev_t *) key) << 16) | minor(*(dev_t *) key); 60bf215546Sopenharmony_ci} 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci#ifdef VMX86_STATS 63bf215546Sopenharmony_ci/** 64bf215546Sopenharmony_ci * Initializes mksstat TLS store. 65bf215546Sopenharmony_ci */ 66bf215546Sopenharmony_cistatic void 67bf215546Sopenharmony_civmw_winsys_screen_init_mksstat(struct vmw_winsys_screen *vws) 68bf215546Sopenharmony_ci{ 69bf215546Sopenharmony_ci size_t i; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vws->mksstat_tls); ++i) { 72bf215546Sopenharmony_ci vws->mksstat_tls[i].stat_pages = NULL; 73bf215546Sopenharmony_ci vws->mksstat_tls[i].stat_id = -1UL; 74bf215546Sopenharmony_ci vws->mksstat_tls[i].pid = 0; 75bf215546Sopenharmony_ci } 76bf215546Sopenharmony_ci} 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci/** 79bf215546Sopenharmony_ci * Deinits mksstat TLS store. 80bf215546Sopenharmony_ci */ 81bf215546Sopenharmony_cistatic void 82bf215546Sopenharmony_civmw_winsys_screen_deinit_mksstat(struct vmw_winsys_screen *vws) 83bf215546Sopenharmony_ci{ 84bf215546Sopenharmony_ci size_t i; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vws->mksstat_tls); ++i) { 87bf215546Sopenharmony_ci uint32_t expected = __atomic_load_n(&vws->mksstat_tls[i].pid, __ATOMIC_ACQUIRE); 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci if (expected == -1U) { 90bf215546Sopenharmony_ci fprintf(stderr, "%s encountered locked mksstat TLS entry at index %lu.\n", __FUNCTION__, i); 91bf215546Sopenharmony_ci continue; 92bf215546Sopenharmony_ci } 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci if (expected == 0) 95bf215546Sopenharmony_ci continue; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci if (__atomic_compare_exchange_n(&vws->mksstat_tls[i].pid, &expected, 0, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) { 98bf215546Sopenharmony_ci struct drm_vmw_mksstat_remove_arg arg = { 99bf215546Sopenharmony_ci .id = vws->mksstat_tls[i].stat_id 100bf215546Sopenharmony_ci }; 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci assert(vws->mksstat_tls[i].stat_pages); 103bf215546Sopenharmony_ci assert(vws->mksstat_tls[i].stat_id != -1UL); 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci if (drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_MKSSTAT_REMOVE, &arg, sizeof(arg))) { 106bf215546Sopenharmony_ci fprintf(stderr, "%s could not ioctl: %s\n", __FUNCTION__, strerror(errno)); 107bf215546Sopenharmony_ci } else if (munmap(vws->mksstat_tls[i].stat_pages, vmw_svga_winsys_stats_len())) { 108bf215546Sopenharmony_ci fprintf(stderr, "%s could not munmap: %s\n", __FUNCTION__, strerror(errno)); 109bf215546Sopenharmony_ci } 110bf215546Sopenharmony_ci } else { 111bf215546Sopenharmony_ci fprintf(stderr, "%s encountered volatile mksstat TLS entry at index %lu.\n", __FUNCTION__, i); 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci } 114bf215546Sopenharmony_ci} 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci#endif 117bf215546Sopenharmony_ci/* Called from vmw_drm_create_screen(), creates and initializes the 118bf215546Sopenharmony_ci * vmw_winsys_screen structure, which is the main entity in this 119bf215546Sopenharmony_ci * module. 120bf215546Sopenharmony_ci * First, check whether a vmw_winsys_screen object already exists for 121bf215546Sopenharmony_ci * this device, and in that case return that one, making sure that we 122bf215546Sopenharmony_ci * have our own file descriptor open to DRM. 123bf215546Sopenharmony_ci */ 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_cistruct vmw_winsys_screen * 126bf215546Sopenharmony_civmw_winsys_create( int fd ) 127bf215546Sopenharmony_ci{ 128bf215546Sopenharmony_ci struct vmw_winsys_screen *vws; 129bf215546Sopenharmony_ci struct stat stat_buf; 130bf215546Sopenharmony_ci const char *getenv_val; 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci if (dev_hash == NULL) { 133bf215546Sopenharmony_ci dev_hash = _mesa_hash_table_create(NULL, vmw_dev_hash, vmw_dev_compare); 134bf215546Sopenharmony_ci if (dev_hash == NULL) 135bf215546Sopenharmony_ci return NULL; 136bf215546Sopenharmony_ci } 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci if (fstat(fd, &stat_buf)) 139bf215546Sopenharmony_ci return NULL; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci vws = util_hash_table_get(dev_hash, &stat_buf.st_rdev); 142bf215546Sopenharmony_ci if (vws) { 143bf215546Sopenharmony_ci vws->open_count++; 144bf215546Sopenharmony_ci return vws; 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci vws = CALLOC_STRUCT(vmw_winsys_screen); 148bf215546Sopenharmony_ci if (!vws) 149bf215546Sopenharmony_ci goto out_no_vws; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci vws->device = stat_buf.st_rdev; 152bf215546Sopenharmony_ci vws->open_count = 1; 153bf215546Sopenharmony_ci vws->ioctl.drm_fd = os_dupfd_cloexec(fd); 154bf215546Sopenharmony_ci vws->force_coherent = FALSE; 155bf215546Sopenharmony_ci if (!vmw_ioctl_init(vws)) 156bf215546Sopenharmony_ci goto out_no_ioctl; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci vws->base.have_gb_dma = !vws->force_coherent; 159bf215546Sopenharmony_ci vws->base.need_to_rebind_resources = FALSE; 160bf215546Sopenharmony_ci vws->base.have_transfer_from_buffer_cmd = vws->base.have_vgpu10; 161bf215546Sopenharmony_ci vws->base.have_constant_buffer_offset_cmd = 162bf215546Sopenharmony_ci vws->ioctl.have_drm_2_20 && vws->base.have_sm5; 163bf215546Sopenharmony_ci vws->base.have_index_vertex_buffer_offset_cmd = FALSE; 164bf215546Sopenharmony_ci vws->base.have_rasterizer_state_v2_cmd = 165bf215546Sopenharmony_ci vws->ioctl.have_drm_2_20 && vws->base.have_sm5; 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci getenv_val = getenv("SVGA_FORCE_KERNEL_UNMAPS"); 168bf215546Sopenharmony_ci vws->cache_maps = !getenv_val || strcmp(getenv_val, "0") == 0; 169bf215546Sopenharmony_ci vws->fence_ops = vmw_fence_ops_create(vws); 170bf215546Sopenharmony_ci if (!vws->fence_ops) 171bf215546Sopenharmony_ci goto out_no_fence_ops; 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci if(!vmw_pools_init(vws)) 174bf215546Sopenharmony_ci goto out_no_pools; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci if (!vmw_winsys_screen_init_svga(vws)) 177bf215546Sopenharmony_ci goto out_no_svga; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci#ifdef VMX86_STATS 180bf215546Sopenharmony_ci vmw_winsys_screen_init_mksstat(vws); 181bf215546Sopenharmony_ci#endif 182bf215546Sopenharmony_ci _mesa_hash_table_insert(dev_hash, &vws->device, vws); 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci cnd_init(&vws->cs_cond); 185bf215546Sopenharmony_ci mtx_init(&vws->cs_mutex, mtx_plain); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci return vws; 188bf215546Sopenharmony_ciout_no_svga: 189bf215546Sopenharmony_ci vmw_pools_cleanup(vws); 190bf215546Sopenharmony_ciout_no_pools: 191bf215546Sopenharmony_ci vws->fence_ops->destroy(vws->fence_ops); 192bf215546Sopenharmony_ciout_no_fence_ops: 193bf215546Sopenharmony_ci vmw_ioctl_cleanup(vws); 194bf215546Sopenharmony_ciout_no_ioctl: 195bf215546Sopenharmony_ci close(vws->ioctl.drm_fd); 196bf215546Sopenharmony_ci FREE(vws); 197bf215546Sopenharmony_ciout_no_vws: 198bf215546Sopenharmony_ci return NULL; 199bf215546Sopenharmony_ci} 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_civoid 202bf215546Sopenharmony_civmw_winsys_destroy(struct vmw_winsys_screen *vws) 203bf215546Sopenharmony_ci{ 204bf215546Sopenharmony_ci if (--vws->open_count == 0) { 205bf215546Sopenharmony_ci _mesa_hash_table_remove_key(dev_hash, &vws->device); 206bf215546Sopenharmony_ci vmw_pools_cleanup(vws); 207bf215546Sopenharmony_ci vws->fence_ops->destroy(vws->fence_ops); 208bf215546Sopenharmony_ci vmw_ioctl_cleanup(vws); 209bf215546Sopenharmony_ci#ifdef VMX86_STATS 210bf215546Sopenharmony_ci vmw_winsys_screen_deinit_mksstat(vws); 211bf215546Sopenharmony_ci#endif 212bf215546Sopenharmony_ci close(vws->ioctl.drm_fd); 213bf215546Sopenharmony_ci mtx_destroy(&vws->cs_mutex); 214bf215546Sopenharmony_ci cnd_destroy(&vws->cs_cond); 215bf215546Sopenharmony_ci FREE(vws); 216bf215546Sopenharmony_ci } 217bf215546Sopenharmony_ci} 218