162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2016 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the
862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1262306a36Sopenharmony_ci * the following conditions:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1662306a36Sopenharmony_ci * of the Software.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci **************************************************************************/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "vmwgfx_drv.h"
2962306a36Sopenharmony_ci#include "vmwgfx_resource_priv.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/**
3262306a36Sopenharmony_ci * struct vmw_user_simple_resource - User-space simple resource struct
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * @base: The TTM base object implementing user-space visibility.
3562306a36Sopenharmony_ci * @simple: The embedded struct vmw_simple_resource.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistruct vmw_user_simple_resource {
3862306a36Sopenharmony_ci	struct ttm_base_object base;
3962306a36Sopenharmony_ci	struct vmw_simple_resource simple;
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * Nothing to be placed after @simple, since size of @simple is
4262306a36Sopenharmony_ci * unknown.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * vmw_simple_resource_init - Initialize a simple resource object.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * @dev_priv: Pointer to a struct device private.
5162306a36Sopenharmony_ci * @simple: The struct vmw_simple_resource to initialize.
5262306a36Sopenharmony_ci * @data: Data passed to the information initialization function.
5362306a36Sopenharmony_ci * @res_free: Function pointer to destroy the simple resource.
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * Returns:
5662306a36Sopenharmony_ci *   0 if succeeded.
5762306a36Sopenharmony_ci *   Negative error value if error, in which case the resource will have been
5862306a36Sopenharmony_ci * freed.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_cistatic int vmw_simple_resource_init(struct vmw_private *dev_priv,
6162306a36Sopenharmony_ci				    struct vmw_simple_resource *simple,
6262306a36Sopenharmony_ci				    void *data,
6362306a36Sopenharmony_ci				    void (*res_free)(struct vmw_resource *res))
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct vmw_resource *res = &simple->res;
6662306a36Sopenharmony_ci	int ret;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, false, res_free,
6962306a36Sopenharmony_ci				&simple->func->res_func);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (ret) {
7262306a36Sopenharmony_ci		res_free(res);
7362306a36Sopenharmony_ci		return ret;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	ret = simple->func->init(res, data);
7762306a36Sopenharmony_ci	if (ret) {
7862306a36Sopenharmony_ci		vmw_resource_unreference(&res);
7962306a36Sopenharmony_ci		return ret;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	simple->res.hw_destroy = simple->func->hw_destroy;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/**
8862306a36Sopenharmony_ci * vmw_simple_resource_free - Free a simple resource object.
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * @res: The struct vmw_resource member of the simple resource object.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * Frees memory for the object.
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic void vmw_simple_resource_free(struct vmw_resource *res)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct vmw_user_simple_resource *usimple =
9762306a36Sopenharmony_ci		container_of(res, struct vmw_user_simple_resource,
9862306a36Sopenharmony_ci			     simple.res);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	ttm_base_object_kfree(usimple, base);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci * vmw_simple_resource_base_release - TTM object release callback
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci * @p_base: The struct ttm_base_object member of the simple resource object.
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * Called when the last reference to the embedded struct ttm_base_object is
10962306a36Sopenharmony_ci * gone. Typically results in an object free, unless there are other
11062306a36Sopenharmony_ci * references to the embedded struct vmw_resource.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cistatic void vmw_simple_resource_base_release(struct ttm_base_object **p_base)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct ttm_base_object *base = *p_base;
11562306a36Sopenharmony_ci	struct vmw_user_simple_resource *usimple =
11662306a36Sopenharmony_ci		container_of(base, struct vmw_user_simple_resource, base);
11762306a36Sopenharmony_ci	struct vmw_resource *res = &usimple->simple.res;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	*p_base = NULL;
12062306a36Sopenharmony_ci	vmw_resource_unreference(&res);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/**
12462306a36Sopenharmony_ci * vmw_simple_resource_create_ioctl - Helper to set up an ioctl function to
12562306a36Sopenharmony_ci * create a struct vmw_simple_resource.
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * @dev: Pointer to a struct drm device.
12862306a36Sopenharmony_ci * @data: Ioctl argument.
12962306a36Sopenharmony_ci * @file_priv: Pointer to a struct drm_file identifying the caller.
13062306a36Sopenharmony_ci * @func: Pointer to a struct vmw_simple_resource_func identifying the
13162306a36Sopenharmony_ci * simple resource type.
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * Returns:
13462306a36Sopenharmony_ci *   0 if success,
13562306a36Sopenharmony_ci *   Negative error value on error.
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_ciint
13862306a36Sopenharmony_civmw_simple_resource_create_ioctl(struct drm_device *dev, void *data,
13962306a36Sopenharmony_ci				 struct drm_file *file_priv,
14062306a36Sopenharmony_ci				 const struct vmw_simple_resource_func *func)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
14362306a36Sopenharmony_ci	struct vmw_user_simple_resource *usimple;
14462306a36Sopenharmony_ci	struct vmw_resource *res;
14562306a36Sopenharmony_ci	struct vmw_resource *tmp;
14662306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
14762306a36Sopenharmony_ci	size_t alloc_size;
14862306a36Sopenharmony_ci	int ret;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	alloc_size = offsetof(struct vmw_user_simple_resource, simple) +
15162306a36Sopenharmony_ci	  func->size;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	usimple = kzalloc(alloc_size, GFP_KERNEL);
15462306a36Sopenharmony_ci	if (!usimple) {
15562306a36Sopenharmony_ci		ret = -ENOMEM;
15662306a36Sopenharmony_ci		goto out_ret;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	usimple->simple.func = func;
16062306a36Sopenharmony_ci	res = &usimple->simple.res;
16162306a36Sopenharmony_ci	usimple->base.shareable = false;
16262306a36Sopenharmony_ci	usimple->base.tfile = NULL;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/*
16562306a36Sopenharmony_ci	 * From here on, the destructor takes over resource freeing.
16662306a36Sopenharmony_ci	 */
16762306a36Sopenharmony_ci	ret = vmw_simple_resource_init(dev_priv, &usimple->simple,
16862306a36Sopenharmony_ci				       data, vmw_simple_resource_free);
16962306a36Sopenharmony_ci	if (ret)
17062306a36Sopenharmony_ci		goto out_ret;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	tmp = vmw_resource_reference(res);
17362306a36Sopenharmony_ci	ret = ttm_base_object_init(tfile, &usimple->base, false,
17462306a36Sopenharmony_ci				   func->ttm_res_type,
17562306a36Sopenharmony_ci				   &vmw_simple_resource_base_release);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (ret) {
17862306a36Sopenharmony_ci		vmw_resource_unreference(&tmp);
17962306a36Sopenharmony_ci		goto out_err;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	func->set_arg_handle(data, usimple->base.handle);
18362306a36Sopenharmony_ciout_err:
18462306a36Sopenharmony_ci	vmw_resource_unreference(&res);
18562306a36Sopenharmony_ciout_ret:
18662306a36Sopenharmony_ci	return ret;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/**
19062306a36Sopenharmony_ci * vmw_simple_resource_lookup - Look up a simple resource from its user-space
19162306a36Sopenharmony_ci * handle.
19262306a36Sopenharmony_ci *
19362306a36Sopenharmony_ci * @tfile: struct ttm_object_file identifying the caller.
19462306a36Sopenharmony_ci * @handle: The user-space handle.
19562306a36Sopenharmony_ci * @func: The struct vmw_simple_resource_func identifying the simple resource
19662306a36Sopenharmony_ci * type.
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * Returns: Refcounted pointer to the embedded struct vmw_resource if
19962306a36Sopenharmony_ci * successful. Error pointer otherwise.
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistruct vmw_resource *
20262306a36Sopenharmony_civmw_simple_resource_lookup(struct ttm_object_file *tfile,
20362306a36Sopenharmony_ci			   uint32_t handle,
20462306a36Sopenharmony_ci			   const struct vmw_simple_resource_func *func)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct vmw_user_simple_resource *usimple;
20762306a36Sopenharmony_ci	struct ttm_base_object *base;
20862306a36Sopenharmony_ci	struct vmw_resource *res;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	base = ttm_base_object_lookup(tfile, handle);
21162306a36Sopenharmony_ci	if (!base) {
21262306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid %s handle 0x%08lx.\n",
21362306a36Sopenharmony_ci			       func->res_func.type_name,
21462306a36Sopenharmony_ci			       (unsigned long) handle);
21562306a36Sopenharmony_ci		return ERR_PTR(-ESRCH);
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (ttm_base_object_type(base) != func->ttm_res_type) {
21962306a36Sopenharmony_ci		ttm_base_object_unref(&base);
22062306a36Sopenharmony_ci		VMW_DEBUG_USER("Invalid type of %s handle 0x%08lx.\n",
22162306a36Sopenharmony_ci			       func->res_func.type_name,
22262306a36Sopenharmony_ci			       (unsigned long) handle);
22362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	usimple = container_of(base, typeof(*usimple), base);
22762306a36Sopenharmony_ci	res = vmw_resource_reference(&usimple->simple.res);
22862306a36Sopenharmony_ci	ttm_base_object_unref(&base);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return res;
23162306a36Sopenharmony_ci}
232