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_mem_global_alloc(vmw_mem_glob(dev_priv), account_size, 166 &ctx); 167 if (ret) { 168 if (ret != -ERESTARTSYS) 169 DRM_ERROR("Out of graphics memory for %s" 170 " creation.\n", func->res_func.type_name); 171 172 goto out_ret; 173 } 174 175 usimple = kzalloc(alloc_size, GFP_KERNEL); 176 if (!usimple) { 177 ttm_mem_global_free(vmw_mem_glob(dev_priv), 178 account_size); 179 ret = -ENOMEM; 180 goto out_ret; 181 } 182 183 usimple->simple.func = func; 184 usimple->account_size = account_size; 185 res = &usimple->simple.res; 186 usimple->base.shareable = false; 187 usimple->base.tfile = NULL; 188 189 /* 190 * From here on, the destructor takes over resource freeing. 191 */ 192 ret = vmw_simple_resource_init(dev_priv, &usimple->simple, 193 data, vmw_simple_resource_free); 194 if (ret) 195 goto out_ret; 196 197 tmp = vmw_resource_reference(res); 198 ret = ttm_base_object_init(tfile, &usimple->base, false, 199 func->ttm_res_type, 200 &vmw_simple_resource_base_release, NULL); 201 202 if (ret) { 203 vmw_resource_unreference(&tmp); 204 goto out_err; 205 } 206 207 func->set_arg_handle(data, usimple->base.handle); 208 out_err: 209 vmw_resource_unreference(&res); 210 out_ret: 211 return ret; 212 } 213 214 /** 215 * vmw_simple_resource_lookup - Look up a simple resource from its user-space 216 * handle. 217 * 218 * @tfile: struct ttm_object_file identifying the caller. 219 * @handle: The user-space handle. 220 * @func: The struct vmw_simple_resource_func identifying the simple resource 221 * type. 222 * 223 * Returns: Refcounted pointer to the embedded struct vmw_resource if 224 * successfule. Error pointer otherwise. 225 */ 226 struct vmw_resource * 227 vmw_simple_resource_lookup(struct ttm_object_file *tfile, 228 uint32_t handle, 229 const struct vmw_simple_resource_func *func) 230 { 231 struct vmw_user_simple_resource *usimple; 232 struct ttm_base_object *base; 233 struct vmw_resource *res; 234 235 base = ttm_base_object_lookup(tfile, handle); 236 if (!base) { 237 VMW_DEBUG_USER("Invalid %s handle 0x%08lx.\n", 238 func->res_func.type_name, 239 (unsigned long) handle); 240 return ERR_PTR(-ESRCH); 241 } 242 243 if (ttm_base_object_type(base) != func->ttm_res_type) { 244 ttm_base_object_unref(&base); 245 VMW_DEBUG_USER("Invalid type of %s handle 0x%08lx.\n", 246 func->res_func.type_name, 247 (unsigned long) handle); 248 return ERR_PTR(-EINVAL); 249 } 250 251 usimple = container_of(base, typeof(*usimple), base); 252 res = vmw_resource_reference(&usimple->simple.res); 253 ttm_base_object_unref(&base); 254 255 return res; 256 } 257