1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /************************************************************************** 3 * 4 * Copyright 2016 VMware, Inc., Palo Alto, CA., USA 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 * USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 #include "vmwgfx_drv.h" 29 #include "vmwgfx_resource_priv.h" 30 31 /** 32 * struct vmw_user_simple_resource - User-space simple resource struct 33 * 34 * @base: The TTM base object implementing user-space visibility. 35 * @account_size: How much memory was accounted for this object. 36 * @simple: The embedded struct vmw_simple_resource. 37 */ 38 struct vmw_user_simple_resource { 39 struct ttm_base_object base; 40 size_t account_size; 41 struct vmw_simple_resource simple; 42 /* 43 * Nothing to be placed after @simple, since size of @simple is 44 * unknown. 45 */ 46 }; 47 48 49 /** 50 * vmw_simple_resource_init - Initialize a simple resource object. 51 * 52 * @dev_priv: Pointer to a struct device private. 53 * @simple: The struct vmw_simple_resource to initialize. 54 * @data: Data passed to the information initialization function. 55 * @res_free: Function pointer to destroy the simple resource. 56 * 57 * Returns: 58 * 0 if succeeded. 59 * Negative error value if error, in which case the resource will have been 60 * freed. 61 */ 62 static int vmw_simple_resource_init(struct vmw_private *dev_priv, 63 struct vmw_simple_resource *simple, 64 void *data, 65 void (*res_free)(struct vmw_resource *res)) 66 { 67 struct vmw_resource *res = &simple->res; 68 int ret; 69 70 ret = vmw_resource_init(dev_priv, res, false, res_free, 71 &simple->func->res_func); 72 73 if (ret) { 74 res_free(res); 75 return ret; 76 } 77 78 ret = simple->func->init(res, data); 79 if (ret) { 80 vmw_resource_unreference(&res); 81 return ret; 82 } 83 84 simple->res.hw_destroy = simple->func->hw_destroy; 85 86 return 0; 87 } 88 89 /** 90 * vmw_simple_resource_free - Free a simple resource object. 91 * 92 * @res: The struct vmw_resource member of the simple resource object. 93 * 94 * Frees memory and memory accounting for the object. 95 */ 96 static void vmw_simple_resource_free(struct vmw_resource *res) 97 { 98 struct vmw_user_simple_resource *usimple = 99 container_of(res, struct vmw_user_simple_resource, 100 simple.res); 101 struct vmw_private *dev_priv = res->dev_priv; 102 size_t size = usimple->account_size; 103 104 ttm_base_object_kfree(usimple, base); 105 ttm_mem_global_free(vmw_mem_glob(dev_priv), size); 106 } 107 108 /** 109 * vmw_simple_resource_base_release - TTM object release callback 110 * 111 * @p_base: The struct ttm_base_object member of the simple resource object. 112 * 113 * Called when the last reference to the embedded struct ttm_base_object is 114 * gone. Typically results in an object free, unless there are other 115 * references to the embedded struct vmw_resource. 116 */ 117 static void vmw_simple_resource_base_release(struct ttm_base_object **p_base) 118 { 119 struct ttm_base_object *base = *p_base; 120 struct vmw_user_simple_resource *usimple = 121 container_of(base, struct vmw_user_simple_resource, base); 122 struct vmw_resource *res = &usimple->simple.res; 123 124 *p_base = NULL; 125 vmw_resource_unreference(&res); 126 } 127 128 /** 129 * vmw_simple_resource_create_ioctl - Helper to set up an ioctl function to 130 * create a struct vmw_simple_resource. 131 * 132 * @dev: Pointer to a struct drm device. 133 * @data: Ioctl argument. 134 * @file_priv: Pointer to a struct drm_file identifying the caller. 135 * @func: Pointer to a struct vmw_simple_resource_func identifying the 136 * simple resource type. 137 * 138 * Returns: 139 * 0 if success, 140 * Negative error value on error. 141 */ 142 int 143 vmw_simple_resource_create_ioctl(struct drm_device *dev, void *data, 144 struct drm_file *file_priv, 145 const struct vmw_simple_resource_func *func) 146 { 147 struct vmw_private *dev_priv = vmw_priv(dev); 148 struct vmw_user_simple_resource *usimple; 149 struct vmw_resource *res; 150 struct vmw_resource *tmp; 151 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 152 struct ttm_operation_ctx ctx = { 153 .interruptible = true, 154 .no_wait_gpu = false 155 }; 156 size_t alloc_size; 157 size_t account_size; 158 int ret; 159 160 alloc_size = offsetof(struct vmw_user_simple_resource, simple) + 161 func->size; 162 account_size = ttm_round_pot(alloc_size) + VMW_IDA_ACC_SIZE + 163 TTM_OBJ_EXTRA_SIZE; 164 165 ret = ttm_read_lock(&dev_priv->reservation_sem, true); 166 if (ret) 167 return ret; 168 169 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), account_size, 170 &ctx); 171 ttm_read_unlock(&dev_priv->reservation_sem); 172 if (ret) { 173 if (ret != -ERESTARTSYS) 174 DRM_ERROR("Out of graphics memory for %s" 175 " creation.\n", func->res_func.type_name); 176 177 goto out_ret; 178 } 179 180 usimple = kzalloc(alloc_size, GFP_KERNEL); 181 if (!usimple) { 182 ttm_mem_global_free(vmw_mem_glob(dev_priv), 183 account_size); 184 ret = -ENOMEM; 185 goto out_ret; 186 } 187 188 usimple->simple.func = func; 189 usimple->account_size = account_size; 190 res = &usimple->simple.res; 191 usimple->base.shareable = false; 192 usimple->base.tfile = NULL; 193 194 /* 195 * From here on, the destructor takes over resource freeing. 196 */ 197 ret = vmw_simple_resource_init(dev_priv, &usimple->simple, 198 data, vmw_simple_resource_free); 199 if (ret) 200 goto out_ret; 201 202 tmp = vmw_resource_reference(res); 203 ret = ttm_base_object_init(tfile, &usimple->base, false, 204 func->ttm_res_type, 205 &vmw_simple_resource_base_release, NULL); 206 207 if (ret) { 208 vmw_resource_unreference(&tmp); 209 goto out_err; 210 } 211 212 func->set_arg_handle(data, usimple->base.handle); 213 out_err: 214 vmw_resource_unreference(&res); 215 out_ret: 216 return ret; 217 } 218 219 /** 220 * vmw_simple_resource_lookup - Look up a simple resource from its user-space 221 * handle. 222 * 223 * @tfile: struct ttm_object_file identifying the caller. 224 * @handle: The user-space handle. 225 * @func: The struct vmw_simple_resource_func identifying the simple resource 226 * type. 227 * 228 * Returns: Refcounted pointer to the embedded struct vmw_resource if 229 * successfule. Error pointer otherwise. 230 */ 231 struct vmw_resource * 232 vmw_simple_resource_lookup(struct ttm_object_file *tfile, 233 uint32_t handle, 234 const struct vmw_simple_resource_func *func) 235 { 236 struct vmw_user_simple_resource *usimple; 237 struct ttm_base_object *base; 238 struct vmw_resource *res; 239 240 base = ttm_base_object_lookup(tfile, handle); 241 if (!base) { 242 VMW_DEBUG_USER("Invalid %s handle 0x%08lx.\n", 243 func->res_func.type_name, 244 (unsigned long) handle); 245 return ERR_PTR(-ESRCH); 246 } 247 248 if (ttm_base_object_type(base) != func->ttm_res_type) { 249 ttm_base_object_unref(&base); 250 VMW_DEBUG_USER("Invalid type of %s handle 0x%08lx.\n", 251 func->res_func.type_name, 252 (unsigned long) handle); 253 return ERR_PTR(-EINVAL); 254 } 255 256 usimple = container_of(base, typeof(*usimple), base); 257 res = vmw_resource_reference(&usimple->simple.res); 258 ttm_base_object_unref(&base); 259 260 return res; 261 } 262