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