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