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