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