162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright © 2018-2023 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
862306a36Sopenharmony_ci * copy of this software and associated documentation files (the
962306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
1062306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1162306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1262306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1362306a36Sopenharmony_ci * the following conditions:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1662306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1762306a36Sopenharmony_ci * of the Software.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2062306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2162306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2262306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2362306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2462306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2562306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci **************************************************************************/
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "vmwgfx_binding.h"
3062306a36Sopenharmony_ci#include "vmwgfx_bo.h"
3162306a36Sopenharmony_ci#include "vmwgfx_drv.h"
3262306a36Sopenharmony_ci#include "vmwgfx_resource_priv.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/**
3762306a36Sopenharmony_ci * struct vmw_dx_streamoutput - Streamoutput resource metadata.
3862306a36Sopenharmony_ci * @res: Base resource struct.
3962306a36Sopenharmony_ci * @ctx: Non-refcounted context to which @res belong.
4062306a36Sopenharmony_ci * @cotable: Refcounted cotable holding this Streamoutput.
4162306a36Sopenharmony_ci * @cotable_head: List head for cotable-so_res list.
4262306a36Sopenharmony_ci * @id: User-space provided identifier.
4362306a36Sopenharmony_ci * @size: User-space provided mob size.
4462306a36Sopenharmony_ci * @committed: Whether streamoutput is actually created or pending creation.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_cistruct vmw_dx_streamoutput {
4762306a36Sopenharmony_ci	struct vmw_resource res;
4862306a36Sopenharmony_ci	struct vmw_resource *ctx;
4962306a36Sopenharmony_ci	struct vmw_resource *cotable;
5062306a36Sopenharmony_ci	struct list_head cotable_head;
5162306a36Sopenharmony_ci	u32 id;
5262306a36Sopenharmony_ci	u32 size;
5362306a36Sopenharmony_ci	bool committed;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int vmw_dx_streamoutput_create(struct vmw_resource *res);
5762306a36Sopenharmony_cistatic int vmw_dx_streamoutput_bind(struct vmw_resource *res,
5862306a36Sopenharmony_ci				    struct ttm_validate_buffer *val_buf);
5962306a36Sopenharmony_cistatic int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
6062306a36Sopenharmony_ci				      struct ttm_validate_buffer *val_buf);
6162306a36Sopenharmony_cistatic void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
6262306a36Sopenharmony_ci					      enum vmw_cmdbuf_res_state state);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct vmw_res_func vmw_dx_streamoutput_func = {
6562306a36Sopenharmony_ci	.res_type = vmw_res_streamoutput,
6662306a36Sopenharmony_ci	.needs_guest_memory = true,
6762306a36Sopenharmony_ci	.may_evict = false,
6862306a36Sopenharmony_ci	.type_name = "DX streamoutput",
6962306a36Sopenharmony_ci	.domain = VMW_BO_DOMAIN_MOB,
7062306a36Sopenharmony_ci	.busy_domain = VMW_BO_DOMAIN_MOB,
7162306a36Sopenharmony_ci	.create = vmw_dx_streamoutput_create,
7262306a36Sopenharmony_ci	.destroy = NULL, /* Command buffer managed resource. */
7362306a36Sopenharmony_ci	.bind = vmw_dx_streamoutput_bind,
7462306a36Sopenharmony_ci	.unbind = vmw_dx_streamoutput_unbind,
7562306a36Sopenharmony_ci	.commit_notify = vmw_dx_streamoutput_commit_notify,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline struct vmw_dx_streamoutput *
7962306a36Sopenharmony_civmw_res_to_dx_streamoutput(struct vmw_resource *res)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	return container_of(res, struct vmw_dx_streamoutput, res);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci * vmw_dx_streamoutput_unscrub - Reattach the MOB to streamoutput.
8662306a36Sopenharmony_ci * @res: The streamoutput resource.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure.
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cistatic int vmw_dx_streamoutput_unscrub(struct vmw_resource *res)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
9362306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
9462306a36Sopenharmony_ci	struct {
9562306a36Sopenharmony_ci		SVGA3dCmdHeader header;
9662306a36Sopenharmony_ci		SVGA3dCmdDXBindStreamOutput body;
9762306a36Sopenharmony_ci	} *cmd;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (!list_empty(&so->cotable_head) || !so->committed )
10062306a36Sopenharmony_ci		return 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
10362306a36Sopenharmony_ci	if (!cmd)
10462306a36Sopenharmony_ci		return -ENOMEM;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
10762306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
10862306a36Sopenharmony_ci	cmd->body.soid = so->id;
10962306a36Sopenharmony_ci	cmd->body.mobid = res->guest_memory_bo->tbo.resource->start;
11062306a36Sopenharmony_ci	cmd->body.offsetInBytes = res->guest_memory_offset;
11162306a36Sopenharmony_ci	cmd->body.sizeInBytes = so->size;
11262306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	vmw_cotable_add_resource(so->cotable, &so->cotable_head);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int vmw_dx_streamoutput_create(struct vmw_resource *res)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
12262306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
12362306a36Sopenharmony_ci	int ret = 0;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	WARN_ON_ONCE(!so->committed);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (vmw_resource_mob_attached(res)) {
12862306a36Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
12962306a36Sopenharmony_ci		ret = vmw_dx_streamoutput_unscrub(res);
13062306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	res->id = so->id;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return ret;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int vmw_dx_streamoutput_bind(struct vmw_resource *res,
13962306a36Sopenharmony_ci				    struct ttm_validate_buffer *val_buf)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
14262306a36Sopenharmony_ci	struct ttm_buffer_object *bo = val_buf->bo;
14362306a36Sopenharmony_ci	int ret;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (WARN_ON(bo->resource->mem_type != VMW_PL_MOB))
14662306a36Sopenharmony_ci		return -EINVAL;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
14962306a36Sopenharmony_ci	ret = vmw_dx_streamoutput_unscrub(res);
15062306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return ret;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/**
15662306a36Sopenharmony_ci * vmw_dx_streamoutput_scrub - Unbind the MOB from streamoutput.
15762306a36Sopenharmony_ci * @res: The streamoutput resource.
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure.
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cistatic int vmw_dx_streamoutput_scrub(struct vmw_resource *res)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
16462306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
16562306a36Sopenharmony_ci	struct {
16662306a36Sopenharmony_ci		SVGA3dCmdHeader header;
16762306a36Sopenharmony_ci		SVGA3dCmdDXBindStreamOutput body;
16862306a36Sopenharmony_ci	} *cmd;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (list_empty(&so->cotable_head))
17162306a36Sopenharmony_ci		return 0;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	WARN_ON_ONCE(!so->committed);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
17662306a36Sopenharmony_ci	if (!cmd)
17762306a36Sopenharmony_ci		return -ENOMEM;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
18062306a36Sopenharmony_ci	cmd->header.size = sizeof(cmd->body);
18162306a36Sopenharmony_ci	cmd->body.soid = res->id;
18262306a36Sopenharmony_ci	cmd->body.mobid = SVGA3D_INVALID_ID;
18362306a36Sopenharmony_ci	cmd->body.offsetInBytes = 0;
18462306a36Sopenharmony_ci	cmd->body.sizeInBytes = so->size;
18562306a36Sopenharmony_ci	vmw_cmd_commit(dev_priv, sizeof(*cmd));
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	res->id = -1;
18862306a36Sopenharmony_ci	list_del_init(&so->cotable_head);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return 0;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
19462306a36Sopenharmony_ci				      struct ttm_validate_buffer *val_buf)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
19762306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (WARN_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB))
20162306a36Sopenharmony_ci		return -EINVAL;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	mutex_lock(&dev_priv->binding_mutex);
20462306a36Sopenharmony_ci	ret = vmw_dx_streamoutput_scrub(res);
20562306a36Sopenharmony_ci	mutex_unlock(&dev_priv->binding_mutex);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (ret)
20862306a36Sopenharmony_ci		return ret;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	(void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
21162306a36Sopenharmony_ci	vmw_bo_fence_single(val_buf->bo, fence);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (fence != NULL)
21462306a36Sopenharmony_ci		vmw_fence_obj_unreference(&fence);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return 0;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
22062306a36Sopenharmony_ci					   enum vmw_cmdbuf_res_state state)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct vmw_private *dev_priv = res->dev_priv;
22362306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (state == VMW_CMDBUF_RES_ADD) {
22662306a36Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
22762306a36Sopenharmony_ci		vmw_cotable_add_resource(so->cotable, &so->cotable_head);
22862306a36Sopenharmony_ci		so->committed = true;
22962306a36Sopenharmony_ci		res->id = so->id;
23062306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
23162306a36Sopenharmony_ci	} else {
23262306a36Sopenharmony_ci		mutex_lock(&dev_priv->binding_mutex);
23362306a36Sopenharmony_ci		list_del_init(&so->cotable_head);
23462306a36Sopenharmony_ci		so->committed = false;
23562306a36Sopenharmony_ci		res->id = -1;
23662306a36Sopenharmony_ci		mutex_unlock(&dev_priv->binding_mutex);
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/**
24162306a36Sopenharmony_ci * vmw_dx_streamoutput_lookup - Do a streamoutput resource lookup by user key.
24262306a36Sopenharmony_ci * @man: Command buffer managed resource manager for current context.
24362306a36Sopenharmony_ci * @user_key: User-space identifier for lookup.
24462306a36Sopenharmony_ci *
24562306a36Sopenharmony_ci * Return: Valid refcounted vmw_resource on success, error pointer on failure.
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistruct vmw_resource *
24862306a36Sopenharmony_civmw_dx_streamoutput_lookup(struct vmw_cmdbuf_res_manager *man,
24962306a36Sopenharmony_ci			   u32 user_key)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_streamoutput,
25262306a36Sopenharmony_ci				     user_key);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic void vmw_dx_streamoutput_res_free(struct vmw_resource *res)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	vmw_resource_unreference(&so->cotable);
26062306a36Sopenharmony_ci	kfree(so);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic void vmw_dx_streamoutput_hw_destroy(struct vmw_resource *res)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	/* Destroyed by user-space cmd buf or as part of context takedown. */
26662306a36Sopenharmony_ci	res->id = -1;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/**
27062306a36Sopenharmony_ci * vmw_dx_streamoutput_add - Add a streamoutput as a cmd buf managed resource.
27162306a36Sopenharmony_ci * @man: Command buffer managed resource manager for current context.
27262306a36Sopenharmony_ci * @ctx: Pointer to context resource.
27362306a36Sopenharmony_ci * @user_key: The identifier for this streamoutput.
27462306a36Sopenharmony_ci * @list: The list of staged command buffer managed resources.
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure.
27762306a36Sopenharmony_ci */
27862306a36Sopenharmony_ciint vmw_dx_streamoutput_add(struct vmw_cmdbuf_res_manager *man,
27962306a36Sopenharmony_ci			    struct vmw_resource *ctx, u32 user_key,
28062306a36Sopenharmony_ci			    struct list_head *list)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so;
28362306a36Sopenharmony_ci	struct vmw_resource *res;
28462306a36Sopenharmony_ci	struct vmw_private *dev_priv = ctx->dev_priv;
28562306a36Sopenharmony_ci	int ret;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	so = kmalloc(sizeof(*so), GFP_KERNEL);
28862306a36Sopenharmony_ci	if (!so) {
28962306a36Sopenharmony_ci		return -ENOMEM;
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	res = &so->res;
29362306a36Sopenharmony_ci	so->ctx = ctx;
29462306a36Sopenharmony_ci	so->cotable = vmw_resource_reference
29562306a36Sopenharmony_ci		(vmw_context_cotable(ctx, SVGA_COTABLE_STREAMOUTPUT));
29662306a36Sopenharmony_ci	so->id = user_key;
29762306a36Sopenharmony_ci	so->committed = false;
29862306a36Sopenharmony_ci	INIT_LIST_HEAD(&so->cotable_head);
29962306a36Sopenharmony_ci	ret = vmw_resource_init(dev_priv, res, true,
30062306a36Sopenharmony_ci				vmw_dx_streamoutput_res_free,
30162306a36Sopenharmony_ci				&vmw_dx_streamoutput_func);
30262306a36Sopenharmony_ci	if (ret)
30362306a36Sopenharmony_ci		goto out_resource_init;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_streamoutput, user_key,
30662306a36Sopenharmony_ci				 res, list);
30762306a36Sopenharmony_ci	if (ret)
30862306a36Sopenharmony_ci		goto out_resource_init;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	res->id = so->id;
31162306a36Sopenharmony_ci	res->hw_destroy = vmw_dx_streamoutput_hw_destroy;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciout_resource_init:
31462306a36Sopenharmony_ci	vmw_resource_unreference(&res);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return ret;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/**
32062306a36Sopenharmony_ci * vmw_dx_streamoutput_set_size - Sets streamoutput mob size in res struct.
32162306a36Sopenharmony_ci * @res: The streamoutput res for which need to set size.
32262306a36Sopenharmony_ci * @size: The size provided by user-space to set.
32362306a36Sopenharmony_ci */
32462306a36Sopenharmony_civoid vmw_dx_streamoutput_set_size(struct vmw_resource *res, u32 size)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	so->size = size;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/**
33262306a36Sopenharmony_ci * vmw_dx_streamoutput_remove - Stage streamoutput for removal.
33362306a36Sopenharmony_ci * @man: Command buffer managed resource manager for current context.
33462306a36Sopenharmony_ci * @user_key: The identifier for this streamoutput.
33562306a36Sopenharmony_ci * @list: The list of staged command buffer managed resources.
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure.
33862306a36Sopenharmony_ci */
33962306a36Sopenharmony_ciint vmw_dx_streamoutput_remove(struct vmw_cmdbuf_res_manager *man,
34062306a36Sopenharmony_ci			       u32 user_key,
34162306a36Sopenharmony_ci			       struct list_head *list)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct vmw_resource *r;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_streamoutput,
34662306a36Sopenharmony_ci				     (u32)user_key, list, &r);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/**
35062306a36Sopenharmony_ci * vmw_dx_streamoutput_cotable_list_scrub - cotable unbind_func callback.
35162306a36Sopenharmony_ci * @dev_priv: Device private.
35262306a36Sopenharmony_ci * @list: The list of cotable resources.
35362306a36Sopenharmony_ci * @readback: Whether the call was part of a readback unbind.
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_civoid vmw_dx_streamoutput_cotable_list_scrub(struct vmw_private *dev_priv,
35662306a36Sopenharmony_ci					    struct list_head *list,
35762306a36Sopenharmony_ci					    bool readback)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct vmw_dx_streamoutput *entry, *next;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	lockdep_assert_held_once(&dev_priv->binding_mutex);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, list, cotable_head) {
36462306a36Sopenharmony_ci		WARN_ON(vmw_dx_streamoutput_scrub(&entry->res));
36562306a36Sopenharmony_ci		if (!readback)
36662306a36Sopenharmony_ci			entry->committed =false;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci}
369