18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2016 VMware, Inc., Palo Alto, CA., USA 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 128c2ecf20Sopenharmony_ci * the following conditions: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 168c2ecf20Sopenharmony_ci * of the Software. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci **************************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h" 298c2ecf20Sopenharmony_ci#include "vmwgfx_resource_priv.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * struct vmw_user_simple_resource - User-space simple resource struct 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * @base: The TTM base object implementing user-space visibility. 358c2ecf20Sopenharmony_ci * @account_size: How much memory was accounted for this object. 368c2ecf20Sopenharmony_ci * @simple: The embedded struct vmw_simple_resource. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistruct vmw_user_simple_resource { 398c2ecf20Sopenharmony_ci struct ttm_base_object base; 408c2ecf20Sopenharmony_ci size_t account_size; 418c2ecf20Sopenharmony_ci struct vmw_simple_resource simple; 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Nothing to be placed after @simple, since size of @simple is 448c2ecf20Sopenharmony_ci * unknown. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/** 508c2ecf20Sopenharmony_ci * vmw_simple_resource_init - Initialize a simple resource object. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * @dev_priv: Pointer to a struct device private. 538c2ecf20Sopenharmony_ci * @simple: The struct vmw_simple_resource to initialize. 548c2ecf20Sopenharmony_ci * @data: Data passed to the information initialization function. 558c2ecf20Sopenharmony_ci * @res_free: Function pointer to destroy the simple resource. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Returns: 588c2ecf20Sopenharmony_ci * 0 if succeeded. 598c2ecf20Sopenharmony_ci * Negative error value if error, in which case the resource will have been 608c2ecf20Sopenharmony_ci * freed. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistatic int vmw_simple_resource_init(struct vmw_private *dev_priv, 638c2ecf20Sopenharmony_ci struct vmw_simple_resource *simple, 648c2ecf20Sopenharmony_ci void *data, 658c2ecf20Sopenharmony_ci void (*res_free)(struct vmw_resource *res)) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct vmw_resource *res = &simple->res; 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci ret = vmw_resource_init(dev_priv, res, false, res_free, 718c2ecf20Sopenharmony_ci &simple->func->res_func); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (ret) { 748c2ecf20Sopenharmony_ci res_free(res); 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = simple->func->init(res, data); 798c2ecf20Sopenharmony_ci if (ret) { 808c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 818c2ecf20Sopenharmony_ci return ret; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci simple->res.hw_destroy = simple->func->hw_destroy; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/** 908c2ecf20Sopenharmony_ci * vmw_simple_resource_free - Free a simple resource object. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * @res: The struct vmw_resource member of the simple resource object. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * Frees memory and memory accounting for the object. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_cistatic void vmw_simple_resource_free(struct vmw_resource *res) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct vmw_user_simple_resource *usimple = 998c2ecf20Sopenharmony_ci container_of(res, struct vmw_user_simple_resource, 1008c2ecf20Sopenharmony_ci simple.res); 1018c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = res->dev_priv; 1028c2ecf20Sopenharmony_ci size_t size = usimple->account_size; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ttm_base_object_kfree(usimple, base); 1058c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(dev_priv), size); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/** 1098c2ecf20Sopenharmony_ci * vmw_simple_resource_base_release - TTM object release callback 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * @p_base: The struct ttm_base_object member of the simple resource object. 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * Called when the last reference to the embedded struct ttm_base_object is 1148c2ecf20Sopenharmony_ci * gone. Typically results in an object free, unless there are other 1158c2ecf20Sopenharmony_ci * references to the embedded struct vmw_resource. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_cistatic void vmw_simple_resource_base_release(struct ttm_base_object **p_base) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct ttm_base_object *base = *p_base; 1208c2ecf20Sopenharmony_ci struct vmw_user_simple_resource *usimple = 1218c2ecf20Sopenharmony_ci container_of(base, struct vmw_user_simple_resource, base); 1228c2ecf20Sopenharmony_ci struct vmw_resource *res = &usimple->simple.res; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci *p_base = NULL; 1258c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/** 1298c2ecf20Sopenharmony_ci * vmw_simple_resource_create_ioctl - Helper to set up an ioctl function to 1308c2ecf20Sopenharmony_ci * create a struct vmw_simple_resource. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * @dev: Pointer to a struct drm device. 1338c2ecf20Sopenharmony_ci * @data: Ioctl argument. 1348c2ecf20Sopenharmony_ci * @file_priv: Pointer to a struct drm_file identifying the caller. 1358c2ecf20Sopenharmony_ci * @func: Pointer to a struct vmw_simple_resource_func identifying the 1368c2ecf20Sopenharmony_ci * simple resource type. 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Returns: 1398c2ecf20Sopenharmony_ci * 0 if success, 1408c2ecf20Sopenharmony_ci * Negative error value on error. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ciint 1438c2ecf20Sopenharmony_civmw_simple_resource_create_ioctl(struct drm_device *dev, void *data, 1448c2ecf20Sopenharmony_ci struct drm_file *file_priv, 1458c2ecf20Sopenharmony_ci const struct vmw_simple_resource_func *func) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 1488c2ecf20Sopenharmony_ci struct vmw_user_simple_resource *usimple; 1498c2ecf20Sopenharmony_ci struct vmw_resource *res; 1508c2ecf20Sopenharmony_ci struct vmw_resource *tmp; 1518c2ecf20Sopenharmony_ci struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 1528c2ecf20Sopenharmony_ci struct ttm_operation_ctx ctx = { 1538c2ecf20Sopenharmony_ci .interruptible = true, 1548c2ecf20Sopenharmony_ci .no_wait_gpu = false 1558c2ecf20Sopenharmony_ci }; 1568c2ecf20Sopenharmony_ci size_t alloc_size; 1578c2ecf20Sopenharmony_ci size_t account_size; 1588c2ecf20Sopenharmony_ci int ret; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci alloc_size = offsetof(struct vmw_user_simple_resource, simple) + 1618c2ecf20Sopenharmony_ci func->size; 1628c2ecf20Sopenharmony_ci account_size = ttm_round_pot(alloc_size) + VMW_IDA_ACC_SIZE + 1638c2ecf20Sopenharmony_ci TTM_OBJ_EXTRA_SIZE; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = ttm_read_lock(&dev_priv->reservation_sem, true); 1668c2ecf20Sopenharmony_ci if (ret) 1678c2ecf20Sopenharmony_ci return ret; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), account_size, 1708c2ecf20Sopenharmony_ci &ctx); 1718c2ecf20Sopenharmony_ci ttm_read_unlock(&dev_priv->reservation_sem); 1728c2ecf20Sopenharmony_ci if (ret) { 1738c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 1748c2ecf20Sopenharmony_ci DRM_ERROR("Out of graphics memory for %s" 1758c2ecf20Sopenharmony_ci " creation.\n", func->res_func.type_name); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci goto out_ret; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci usimple = kzalloc(alloc_size, GFP_KERNEL); 1818c2ecf20Sopenharmony_ci if (!usimple) { 1828c2ecf20Sopenharmony_ci ttm_mem_global_free(vmw_mem_glob(dev_priv), 1838c2ecf20Sopenharmony_ci account_size); 1848c2ecf20Sopenharmony_ci ret = -ENOMEM; 1858c2ecf20Sopenharmony_ci goto out_ret; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci usimple->simple.func = func; 1898c2ecf20Sopenharmony_ci usimple->account_size = account_size; 1908c2ecf20Sopenharmony_ci res = &usimple->simple.res; 1918c2ecf20Sopenharmony_ci usimple->base.shareable = false; 1928c2ecf20Sopenharmony_ci usimple->base.tfile = NULL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* 1958c2ecf20Sopenharmony_ci * From here on, the destructor takes over resource freeing. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci ret = vmw_simple_resource_init(dev_priv, &usimple->simple, 1988c2ecf20Sopenharmony_ci data, vmw_simple_resource_free); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci goto out_ret; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci tmp = vmw_resource_reference(res); 2038c2ecf20Sopenharmony_ci ret = ttm_base_object_init(tfile, &usimple->base, false, 2048c2ecf20Sopenharmony_ci func->ttm_res_type, 2058c2ecf20Sopenharmony_ci &vmw_simple_resource_base_release, NULL); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (ret) { 2088c2ecf20Sopenharmony_ci vmw_resource_unreference(&tmp); 2098c2ecf20Sopenharmony_ci goto out_err; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci func->set_arg_handle(data, usimple->base.handle); 2138c2ecf20Sopenharmony_ciout_err: 2148c2ecf20Sopenharmony_ci vmw_resource_unreference(&res); 2158c2ecf20Sopenharmony_ciout_ret: 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/** 2208c2ecf20Sopenharmony_ci * vmw_simple_resource_lookup - Look up a simple resource from its user-space 2218c2ecf20Sopenharmony_ci * handle. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * @tfile: struct ttm_object_file identifying the caller. 2248c2ecf20Sopenharmony_ci * @handle: The user-space handle. 2258c2ecf20Sopenharmony_ci * @func: The struct vmw_simple_resource_func identifying the simple resource 2268c2ecf20Sopenharmony_ci * type. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Returns: Refcounted pointer to the embedded struct vmw_resource if 2298c2ecf20Sopenharmony_ci * successfule. Error pointer otherwise. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_cistruct vmw_resource * 2328c2ecf20Sopenharmony_civmw_simple_resource_lookup(struct ttm_object_file *tfile, 2338c2ecf20Sopenharmony_ci uint32_t handle, 2348c2ecf20Sopenharmony_ci const struct vmw_simple_resource_func *func) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct vmw_user_simple_resource *usimple; 2378c2ecf20Sopenharmony_ci struct ttm_base_object *base; 2388c2ecf20Sopenharmony_ci struct vmw_resource *res; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci base = ttm_base_object_lookup(tfile, handle); 2418c2ecf20Sopenharmony_ci if (!base) { 2428c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid %s handle 0x%08lx.\n", 2438c2ecf20Sopenharmony_ci func->res_func.type_name, 2448c2ecf20Sopenharmony_ci (unsigned long) handle); 2458c2ecf20Sopenharmony_ci return ERR_PTR(-ESRCH); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (ttm_base_object_type(base) != func->ttm_res_type) { 2498c2ecf20Sopenharmony_ci ttm_base_object_unref(&base); 2508c2ecf20Sopenharmony_ci VMW_DEBUG_USER("Invalid type of %s handle 0x%08lx.\n", 2518c2ecf20Sopenharmony_ci func->res_func.type_name, 2528c2ecf20Sopenharmony_ci (unsigned long) handle); 2538c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci usimple = container_of(base, typeof(*usimple), base); 2578c2ecf20Sopenharmony_ci res = vmw_resource_reference(&usimple->simple.res); 2588c2ecf20Sopenharmony_ci ttm_base_object_unref(&base); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return res; 2618c2ecf20Sopenharmony_ci} 262