xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/vmwgfx/vmwgfx_so.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0 OR MIT
2*4882a593Smuzhiyun /**************************************************************************
3*4882a593Smuzhiyun  * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
6*4882a593Smuzhiyun  * copy of this software and associated documentation files (the
7*4882a593Smuzhiyun  * "Software"), to deal in the Software without restriction, including
8*4882a593Smuzhiyun  * without limitation the rights to use, copy, modify, merge, publish,
9*4882a593Smuzhiyun  * distribute, sub license, and/or sell copies of the Software, and to
10*4882a593Smuzhiyun  * permit persons to whom the Software is furnished to do so, subject to
11*4882a593Smuzhiyun  * the following conditions:
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the
14*4882a593Smuzhiyun  * next paragraph) shall be included in all copies or substantial portions
15*4882a593Smuzhiyun  * of the Software.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20*4882a593Smuzhiyun  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21*4882a593Smuzhiyun  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22*4882a593Smuzhiyun  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23*4882a593Smuzhiyun  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  **************************************************************************/
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "vmwgfx_drv.h"
28*4882a593Smuzhiyun #include "vmwgfx_resource_priv.h"
29*4882a593Smuzhiyun #include "vmwgfx_so.h"
30*4882a593Smuzhiyun #include "vmwgfx_binding.h"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * The currently only reason we need to keep track of views is that if we
34*4882a593Smuzhiyun  * destroy a hardware surface, all views pointing to it must also be destroyed,
35*4882a593Smuzhiyun  * otherwise the device will error.
36*4882a593Smuzhiyun  * So in particuar if a surface is evicted, we must destroy all views pointing
37*4882a593Smuzhiyun  * to it, and all context bindings of that view. Similarly we must restore
38*4882a593Smuzhiyun  * the view bindings, views and surfaces pointed to by the views when a
39*4882a593Smuzhiyun  * context is referenced in the command stream.
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /**
43*4882a593Smuzhiyun  * struct vmw_view - view metadata
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * @res: The struct vmw_resource we derive from
46*4882a593Smuzhiyun  * @ctx: Non-refcounted pointer to the context this view belongs to.
47*4882a593Smuzhiyun  * @srf: Refcounted pointer to the surface pointed to by this view.
48*4882a593Smuzhiyun  * @cotable: Refcounted pointer to the cotable holding this view.
49*4882a593Smuzhiyun  * @srf_head: List head for the surface-to-view list.
50*4882a593Smuzhiyun  * @cotable_head: List head for the cotable-to_view list.
51*4882a593Smuzhiyun  * @view_type: View type.
52*4882a593Smuzhiyun  * @view_id: User-space per context view id. Currently used also as per
53*4882a593Smuzhiyun  * context device view id.
54*4882a593Smuzhiyun  * @cmd_size: Size of the SVGA3D define view command that we've copied from the
55*4882a593Smuzhiyun  * command stream.
56*4882a593Smuzhiyun  * @committed: Whether the view is actually created or pending creation at the
57*4882a593Smuzhiyun  * device level.
58*4882a593Smuzhiyun  * @cmd: The SVGA3D define view command copied from the command stream.
59*4882a593Smuzhiyun  */
60*4882a593Smuzhiyun struct vmw_view {
61*4882a593Smuzhiyun 	struct rcu_head rcu;
62*4882a593Smuzhiyun 	struct vmw_resource res;
63*4882a593Smuzhiyun 	struct vmw_resource *ctx;      /* Immutable */
64*4882a593Smuzhiyun 	struct vmw_resource *srf;      /* Immutable */
65*4882a593Smuzhiyun 	struct vmw_resource *cotable;  /* Immutable */
66*4882a593Smuzhiyun 	struct list_head srf_head;     /* Protected by binding_mutex */
67*4882a593Smuzhiyun 	struct list_head cotable_head; /* Protected by binding_mutex */
68*4882a593Smuzhiyun 	unsigned view_type;            /* Immutable */
69*4882a593Smuzhiyun 	unsigned view_id;              /* Immutable */
70*4882a593Smuzhiyun 	u32 cmd_size;                  /* Immutable */
71*4882a593Smuzhiyun 	bool committed;                /* Protected by binding_mutex */
72*4882a593Smuzhiyun 	u32 cmd[1];                    /* Immutable */
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun static int vmw_view_create(struct vmw_resource *res);
76*4882a593Smuzhiyun static int vmw_view_destroy(struct vmw_resource *res);
77*4882a593Smuzhiyun static void vmw_hw_view_destroy(struct vmw_resource *res);
78*4882a593Smuzhiyun static void vmw_view_commit_notify(struct vmw_resource *res,
79*4882a593Smuzhiyun 				   enum vmw_cmdbuf_res_state state);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static const struct vmw_res_func vmw_view_func = {
82*4882a593Smuzhiyun 	.res_type = vmw_res_view,
83*4882a593Smuzhiyun 	.needs_backup = false,
84*4882a593Smuzhiyun 	.may_evict = false,
85*4882a593Smuzhiyun 	.type_name = "DX view",
86*4882a593Smuzhiyun 	.backup_placement = NULL,
87*4882a593Smuzhiyun 	.create = vmw_view_create,
88*4882a593Smuzhiyun 	.commit_notify = vmw_view_commit_notify,
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /**
92*4882a593Smuzhiyun  * struct vmw_view - view define command body stub
93*4882a593Smuzhiyun  *
94*4882a593Smuzhiyun  * @view_id: The device id of the view being defined
95*4882a593Smuzhiyun  * @sid: The surface id of the view being defined
96*4882a593Smuzhiyun  *
97*4882a593Smuzhiyun  * This generic struct is used by the code to change @view_id and @sid of a
98*4882a593Smuzhiyun  * saved view define command.
99*4882a593Smuzhiyun  */
100*4882a593Smuzhiyun struct vmw_view_define {
101*4882a593Smuzhiyun 	uint32 view_id;
102*4882a593Smuzhiyun 	uint32 sid;
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /**
106*4882a593Smuzhiyun  * vmw_view - Convert a struct vmw_resource to a struct vmw_view
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  * @res: Pointer to the resource to convert.
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * Returns a pointer to a struct vmw_view.
111*4882a593Smuzhiyun  */
vmw_view(struct vmw_resource * res)112*4882a593Smuzhiyun static struct vmw_view *vmw_view(struct vmw_resource *res)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	return container_of(res, struct vmw_view, res);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /**
118*4882a593Smuzhiyun  * vmw_view_commit_notify - Notify that a view operation has been committed to
119*4882a593Smuzhiyun  * hardware from a user-supplied command stream.
120*4882a593Smuzhiyun  *
121*4882a593Smuzhiyun  * @res: Pointer to the view resource.
122*4882a593Smuzhiyun  * @state: Indicating whether a creation or removal has been committed.
123*4882a593Smuzhiyun  *
124*4882a593Smuzhiyun  */
vmw_view_commit_notify(struct vmw_resource * res,enum vmw_cmdbuf_res_state state)125*4882a593Smuzhiyun static void vmw_view_commit_notify(struct vmw_resource *res,
126*4882a593Smuzhiyun 				   enum vmw_cmdbuf_res_state state)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct vmw_view *view = vmw_view(res);
129*4882a593Smuzhiyun 	struct vmw_private *dev_priv = res->dev_priv;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	mutex_lock(&dev_priv->binding_mutex);
132*4882a593Smuzhiyun 	if (state == VMW_CMDBUF_RES_ADD) {
133*4882a593Smuzhiyun 		struct vmw_surface *srf = vmw_res_to_srf(view->srf);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		list_add_tail(&view->srf_head, &srf->view_list);
136*4882a593Smuzhiyun 		vmw_cotable_add_resource(view->cotable, &view->cotable_head);
137*4882a593Smuzhiyun 		view->committed = true;
138*4882a593Smuzhiyun 		res->id = view->view_id;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	} else {
141*4882a593Smuzhiyun 		list_del_init(&view->cotable_head);
142*4882a593Smuzhiyun 		list_del_init(&view->srf_head);
143*4882a593Smuzhiyun 		view->committed = false;
144*4882a593Smuzhiyun 		res->id = -1;
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 	mutex_unlock(&dev_priv->binding_mutex);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun /**
150*4882a593Smuzhiyun  * vmw_view_create - Create a hardware view.
151*4882a593Smuzhiyun  *
152*4882a593Smuzhiyun  * @res: Pointer to the view resource.
153*4882a593Smuzhiyun  *
154*4882a593Smuzhiyun  * Create a hardware view. Typically used if that view has previously been
155*4882a593Smuzhiyun  * destroyed by an eviction operation.
156*4882a593Smuzhiyun  */
vmw_view_create(struct vmw_resource * res)157*4882a593Smuzhiyun static int vmw_view_create(struct vmw_resource *res)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	struct vmw_view *view = vmw_view(res);
160*4882a593Smuzhiyun 	struct vmw_surface *srf = vmw_res_to_srf(view->srf);
161*4882a593Smuzhiyun 	struct vmw_private *dev_priv = res->dev_priv;
162*4882a593Smuzhiyun 	struct {
163*4882a593Smuzhiyun 		SVGA3dCmdHeader header;
164*4882a593Smuzhiyun 		struct vmw_view_define body;
165*4882a593Smuzhiyun 	} *cmd;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	mutex_lock(&dev_priv->binding_mutex);
168*4882a593Smuzhiyun 	if (!view->committed) {
169*4882a593Smuzhiyun 		mutex_unlock(&dev_priv->binding_mutex);
170*4882a593Smuzhiyun 		return 0;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	cmd = VMW_FIFO_RESERVE_DX(res->dev_priv, view->cmd_size, view->ctx->id);
174*4882a593Smuzhiyun 	if (!cmd) {
175*4882a593Smuzhiyun 		mutex_unlock(&dev_priv->binding_mutex);
176*4882a593Smuzhiyun 		return -ENOMEM;
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	memcpy(cmd, &view->cmd, view->cmd_size);
180*4882a593Smuzhiyun 	WARN_ON(cmd->body.view_id != view->view_id);
181*4882a593Smuzhiyun 	/* Sid may have changed due to surface eviction. */
182*4882a593Smuzhiyun 	WARN_ON(view->srf->id == SVGA3D_INVALID_ID);
183*4882a593Smuzhiyun 	cmd->body.sid = view->srf->id;
184*4882a593Smuzhiyun 	vmw_fifo_commit(res->dev_priv, view->cmd_size);
185*4882a593Smuzhiyun 	res->id = view->view_id;
186*4882a593Smuzhiyun 	list_add_tail(&view->srf_head, &srf->view_list);
187*4882a593Smuzhiyun 	vmw_cotable_add_resource(view->cotable, &view->cotable_head);
188*4882a593Smuzhiyun 	mutex_unlock(&dev_priv->binding_mutex);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	return 0;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun /**
194*4882a593Smuzhiyun  * vmw_view_destroy - Destroy a hardware view.
195*4882a593Smuzhiyun  *
196*4882a593Smuzhiyun  * @res: Pointer to the view resource.
197*4882a593Smuzhiyun  *
198*4882a593Smuzhiyun  * Destroy a hardware view. Typically used on unexpected termination of the
199*4882a593Smuzhiyun  * owning process or if the surface the view is pointing to is destroyed.
200*4882a593Smuzhiyun  */
vmw_view_destroy(struct vmw_resource * res)201*4882a593Smuzhiyun static int vmw_view_destroy(struct vmw_resource *res)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct vmw_private *dev_priv = res->dev_priv;
204*4882a593Smuzhiyun 	struct vmw_view *view = vmw_view(res);
205*4882a593Smuzhiyun 	struct {
206*4882a593Smuzhiyun 		SVGA3dCmdHeader header;
207*4882a593Smuzhiyun 		union vmw_view_destroy body;
208*4882a593Smuzhiyun 	} *cmd;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	lockdep_assert_held_once(&dev_priv->binding_mutex);
211*4882a593Smuzhiyun 	vmw_binding_res_list_scrub(&res->binding_head);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (!view->committed || res->id == -1)
214*4882a593Smuzhiyun 		return 0;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	cmd = VMW_FIFO_RESERVE_DX(dev_priv, sizeof(*cmd), view->ctx->id);
217*4882a593Smuzhiyun 	if (!cmd)
218*4882a593Smuzhiyun 		return -ENOMEM;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	cmd->header.id = vmw_view_destroy_cmds[view->view_type];
221*4882a593Smuzhiyun 	cmd->header.size = sizeof(cmd->body);
222*4882a593Smuzhiyun 	cmd->body.view_id = view->view_id;
223*4882a593Smuzhiyun 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
224*4882a593Smuzhiyun 	res->id = -1;
225*4882a593Smuzhiyun 	list_del_init(&view->cotable_head);
226*4882a593Smuzhiyun 	list_del_init(&view->srf_head);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	return 0;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun /**
232*4882a593Smuzhiyun  * vmw_hw_view_destroy - Destroy a hardware view as part of resource cleanup.
233*4882a593Smuzhiyun  *
234*4882a593Smuzhiyun  * @res: Pointer to the view resource.
235*4882a593Smuzhiyun  *
236*4882a593Smuzhiyun  * Destroy a hardware view if it's still present.
237*4882a593Smuzhiyun  */
vmw_hw_view_destroy(struct vmw_resource * res)238*4882a593Smuzhiyun static void vmw_hw_view_destroy(struct vmw_resource *res)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct vmw_private *dev_priv = res->dev_priv;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	mutex_lock(&dev_priv->binding_mutex);
243*4882a593Smuzhiyun 	WARN_ON(vmw_view_destroy(res));
244*4882a593Smuzhiyun 	res->id = -1;
245*4882a593Smuzhiyun 	mutex_unlock(&dev_priv->binding_mutex);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun /**
249*4882a593Smuzhiyun  * vmw_view_key - Compute a view key suitable for the cmdbuf resource manager
250*4882a593Smuzhiyun  *
251*4882a593Smuzhiyun  * @user_key: The user-space id used for the view.
252*4882a593Smuzhiyun  * @view_type: The view type.
253*4882a593Smuzhiyun  *
254*4882a593Smuzhiyun  * Destroy a hardware view if it's still present.
255*4882a593Smuzhiyun  */
vmw_view_key(u32 user_key,enum vmw_view_type view_type)256*4882a593Smuzhiyun static u32 vmw_view_key(u32 user_key, enum vmw_view_type view_type)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	return user_key | (view_type << 20);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun /**
262*4882a593Smuzhiyun  * vmw_view_id_ok - Basic view id and type range checks.
263*4882a593Smuzhiyun  *
264*4882a593Smuzhiyun  * @user_key: The user-space id used for the view.
265*4882a593Smuzhiyun  * @view_type: The view type.
266*4882a593Smuzhiyun  *
267*4882a593Smuzhiyun  * Checks that the view id and type (typically provided by user-space) is
268*4882a593Smuzhiyun  * valid.
269*4882a593Smuzhiyun  */
vmw_view_id_ok(u32 user_key,enum vmw_view_type view_type)270*4882a593Smuzhiyun static bool vmw_view_id_ok(u32 user_key, enum vmw_view_type view_type)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	return (user_key < SVGA_COTABLE_MAX_IDS &&
273*4882a593Smuzhiyun 		view_type < vmw_view_max);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun /**
277*4882a593Smuzhiyun  * vmw_view_res_free - resource res_free callback for view resources
278*4882a593Smuzhiyun  *
279*4882a593Smuzhiyun  * @res: Pointer to a struct vmw_resource
280*4882a593Smuzhiyun  *
281*4882a593Smuzhiyun  * Frees memory and memory accounting held by a struct vmw_view.
282*4882a593Smuzhiyun  */
vmw_view_res_free(struct vmw_resource * res)283*4882a593Smuzhiyun static void vmw_view_res_free(struct vmw_resource *res)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct vmw_view *view = vmw_view(res);
286*4882a593Smuzhiyun 	size_t size = offsetof(struct vmw_view, cmd) + view->cmd_size;
287*4882a593Smuzhiyun 	struct vmw_private *dev_priv = res->dev_priv;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	vmw_resource_unreference(&view->cotable);
290*4882a593Smuzhiyun 	vmw_resource_unreference(&view->srf);
291*4882a593Smuzhiyun 	kfree_rcu(view, rcu);
292*4882a593Smuzhiyun 	ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /**
296*4882a593Smuzhiyun  * vmw_view_add - Create a view resource and stage it for addition
297*4882a593Smuzhiyun  * as a command buffer managed resource.
298*4882a593Smuzhiyun  *
299*4882a593Smuzhiyun  * @man: Pointer to the compat shader manager identifying the shader namespace.
300*4882a593Smuzhiyun  * @ctx: Pointer to a struct vmw_resource identifying the active context.
301*4882a593Smuzhiyun  * @srf: Pointer to a struct vmw_resource identifying the surface the view
302*4882a593Smuzhiyun  * points to.
303*4882a593Smuzhiyun  * @view_type: The view type deduced from the view create command.
304*4882a593Smuzhiyun  * @user_key: The key that is used to identify the shader. The key is
305*4882a593Smuzhiyun  * unique to the view type and to the context.
306*4882a593Smuzhiyun  * @cmd: Pointer to the view create command in the command stream.
307*4882a593Smuzhiyun  * @cmd_size: Size of the view create command in the command stream.
308*4882a593Smuzhiyun  * @list: Caller's list of staged command buffer resource actions.
309*4882a593Smuzhiyun  */
vmw_view_add(struct vmw_cmdbuf_res_manager * man,struct vmw_resource * ctx,struct vmw_resource * srf,enum vmw_view_type view_type,u32 user_key,const void * cmd,size_t cmd_size,struct list_head * list)310*4882a593Smuzhiyun int vmw_view_add(struct vmw_cmdbuf_res_manager *man,
311*4882a593Smuzhiyun 		 struct vmw_resource *ctx,
312*4882a593Smuzhiyun 		 struct vmw_resource *srf,
313*4882a593Smuzhiyun 		 enum vmw_view_type view_type,
314*4882a593Smuzhiyun 		 u32 user_key,
315*4882a593Smuzhiyun 		 const void *cmd,
316*4882a593Smuzhiyun 		 size_t cmd_size,
317*4882a593Smuzhiyun 		 struct list_head *list)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	static const size_t vmw_view_define_sizes[] = {
320*4882a593Smuzhiyun 		[vmw_view_sr] = sizeof(SVGA3dCmdDXDefineShaderResourceView),
321*4882a593Smuzhiyun 		[vmw_view_rt] = sizeof(SVGA3dCmdDXDefineRenderTargetView),
322*4882a593Smuzhiyun 		[vmw_view_ds] = sizeof(SVGA3dCmdDXDefineDepthStencilView),
323*4882a593Smuzhiyun 		[vmw_view_ua] = sizeof(SVGA3dCmdDXDefineUAView)
324*4882a593Smuzhiyun 	};
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	struct vmw_private *dev_priv = ctx->dev_priv;
327*4882a593Smuzhiyun 	struct vmw_resource *res;
328*4882a593Smuzhiyun 	struct vmw_view *view;
329*4882a593Smuzhiyun 	struct ttm_operation_ctx ttm_opt_ctx = {
330*4882a593Smuzhiyun 		.interruptible = true,
331*4882a593Smuzhiyun 		.no_wait_gpu = false
332*4882a593Smuzhiyun 	};
333*4882a593Smuzhiyun 	size_t size;
334*4882a593Smuzhiyun 	int ret;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (cmd_size != vmw_view_define_sizes[view_type] +
337*4882a593Smuzhiyun 	    sizeof(SVGA3dCmdHeader)) {
338*4882a593Smuzhiyun 		VMW_DEBUG_USER("Illegal view create command size.\n");
339*4882a593Smuzhiyun 		return -EINVAL;
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (!vmw_view_id_ok(user_key, view_type)) {
343*4882a593Smuzhiyun 		VMW_DEBUG_USER("Illegal view add view id.\n");
344*4882a593Smuzhiyun 		return -EINVAL;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	size = offsetof(struct vmw_view, cmd) + cmd_size;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), size, &ttm_opt_ctx);
350*4882a593Smuzhiyun 	if (ret) {
351*4882a593Smuzhiyun 		if (ret != -ERESTARTSYS)
352*4882a593Smuzhiyun 			DRM_ERROR("Out of graphics memory for view creation\n");
353*4882a593Smuzhiyun 		return ret;
354*4882a593Smuzhiyun 	}
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	view = kmalloc(size, GFP_KERNEL);
357*4882a593Smuzhiyun 	if (!view) {
358*4882a593Smuzhiyun 		ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
359*4882a593Smuzhiyun 		return -ENOMEM;
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	res = &view->res;
363*4882a593Smuzhiyun 	view->ctx = ctx;
364*4882a593Smuzhiyun 	view->srf = vmw_resource_reference(srf);
365*4882a593Smuzhiyun 	view->cotable = vmw_resource_reference
366*4882a593Smuzhiyun 		(vmw_context_cotable(ctx, vmw_view_cotables[view_type]));
367*4882a593Smuzhiyun 	view->view_type = view_type;
368*4882a593Smuzhiyun 	view->view_id = user_key;
369*4882a593Smuzhiyun 	view->cmd_size = cmd_size;
370*4882a593Smuzhiyun 	view->committed = false;
371*4882a593Smuzhiyun 	INIT_LIST_HEAD(&view->srf_head);
372*4882a593Smuzhiyun 	INIT_LIST_HEAD(&view->cotable_head);
373*4882a593Smuzhiyun 	memcpy(&view->cmd, cmd, cmd_size);
374*4882a593Smuzhiyun 	ret = vmw_resource_init(dev_priv, res, true,
375*4882a593Smuzhiyun 				vmw_view_res_free, &vmw_view_func);
376*4882a593Smuzhiyun 	if (ret)
377*4882a593Smuzhiyun 		goto out_resource_init;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_view,
380*4882a593Smuzhiyun 				 vmw_view_key(user_key, view_type),
381*4882a593Smuzhiyun 				 res, list);
382*4882a593Smuzhiyun 	if (ret)
383*4882a593Smuzhiyun 		goto out_resource_init;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	res->id = view->view_id;
386*4882a593Smuzhiyun 	res->hw_destroy = vmw_hw_view_destroy;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun out_resource_init:
389*4882a593Smuzhiyun 	vmw_resource_unreference(&res);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	return ret;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun /**
395*4882a593Smuzhiyun  * vmw_view_remove - Stage a view for removal.
396*4882a593Smuzhiyun  *
397*4882a593Smuzhiyun  * @man: Pointer to the view manager identifying the shader namespace.
398*4882a593Smuzhiyun  * @user_key: The key that is used to identify the view. The key is
399*4882a593Smuzhiyun  * unique to the view type.
400*4882a593Smuzhiyun  * @view_type: View type
401*4882a593Smuzhiyun  * @list: Caller's list of staged command buffer resource actions.
402*4882a593Smuzhiyun  * @res_p: If the resource is in an already committed state, points to the
403*4882a593Smuzhiyun  * struct vmw_resource on successful return. The pointer will be
404*4882a593Smuzhiyun  * non ref-counted.
405*4882a593Smuzhiyun  */
vmw_view_remove(struct vmw_cmdbuf_res_manager * man,u32 user_key,enum vmw_view_type view_type,struct list_head * list,struct vmw_resource ** res_p)406*4882a593Smuzhiyun int vmw_view_remove(struct vmw_cmdbuf_res_manager *man,
407*4882a593Smuzhiyun 		    u32 user_key, enum vmw_view_type view_type,
408*4882a593Smuzhiyun 		    struct list_head *list,
409*4882a593Smuzhiyun 		    struct vmw_resource **res_p)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun 	if (!vmw_view_id_ok(user_key, view_type)) {
412*4882a593Smuzhiyun 		VMW_DEBUG_USER("Illegal view remove view id.\n");
413*4882a593Smuzhiyun 		return -EINVAL;
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_view,
417*4882a593Smuzhiyun 				     vmw_view_key(user_key, view_type),
418*4882a593Smuzhiyun 				     list, res_p);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /**
422*4882a593Smuzhiyun  * vmw_view_cotable_list_destroy - Evict all views belonging to a cotable.
423*4882a593Smuzhiyun  *
424*4882a593Smuzhiyun  * @dev_priv: Pointer to a device private struct.
425*4882a593Smuzhiyun  * @list: List of views belonging to a cotable.
426*4882a593Smuzhiyun  * @readback: Unused. Needed for function interface only.
427*4882a593Smuzhiyun  *
428*4882a593Smuzhiyun  * This function evicts all views belonging to a cotable.
429*4882a593Smuzhiyun  * It must be called with the binding_mutex held, and the caller must hold
430*4882a593Smuzhiyun  * a reference to the view resource. This is typically called before the
431*4882a593Smuzhiyun  * cotable is paged out.
432*4882a593Smuzhiyun  */
vmw_view_cotable_list_destroy(struct vmw_private * dev_priv,struct list_head * list,bool readback)433*4882a593Smuzhiyun void vmw_view_cotable_list_destroy(struct vmw_private *dev_priv,
434*4882a593Smuzhiyun 				   struct list_head *list,
435*4882a593Smuzhiyun 				   bool readback)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	struct vmw_view *entry, *next;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	lockdep_assert_held_once(&dev_priv->binding_mutex);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	list_for_each_entry_safe(entry, next, list, cotable_head)
442*4882a593Smuzhiyun 		WARN_ON(vmw_view_destroy(&entry->res));
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun /**
446*4882a593Smuzhiyun  * vmw_view_surface_list_destroy - Evict all views pointing to a surface
447*4882a593Smuzhiyun  *
448*4882a593Smuzhiyun  * @dev_priv: Pointer to a device private struct.
449*4882a593Smuzhiyun  * @list: List of views pointing to a surface.
450*4882a593Smuzhiyun  *
451*4882a593Smuzhiyun  * This function evicts all views pointing to a surface. This is typically
452*4882a593Smuzhiyun  * called before the surface is evicted.
453*4882a593Smuzhiyun  */
vmw_view_surface_list_destroy(struct vmw_private * dev_priv,struct list_head * list)454*4882a593Smuzhiyun void vmw_view_surface_list_destroy(struct vmw_private *dev_priv,
455*4882a593Smuzhiyun 				   struct list_head *list)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	struct vmw_view *entry, *next;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	lockdep_assert_held_once(&dev_priv->binding_mutex);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	list_for_each_entry_safe(entry, next, list, srf_head)
462*4882a593Smuzhiyun 		WARN_ON(vmw_view_destroy(&entry->res));
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun /**
466*4882a593Smuzhiyun  * vmw_view_srf - Return a non-refcounted pointer to the surface a view is
467*4882a593Smuzhiyun  * pointing to.
468*4882a593Smuzhiyun  *
469*4882a593Smuzhiyun  * @res: pointer to a view resource.
470*4882a593Smuzhiyun  *
471*4882a593Smuzhiyun  * Note that the view itself is holding a reference, so as long
472*4882a593Smuzhiyun  * the view resource is alive, the surface resource will be.
473*4882a593Smuzhiyun  */
vmw_view_srf(struct vmw_resource * res)474*4882a593Smuzhiyun struct vmw_resource *vmw_view_srf(struct vmw_resource *res)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	return vmw_view(res)->srf;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun /**
480*4882a593Smuzhiyun  * vmw_view_lookup - Look up a view.
481*4882a593Smuzhiyun  *
482*4882a593Smuzhiyun  * @man: The context's cmdbuf ref manager.
483*4882a593Smuzhiyun  * @view_type: The view type.
484*4882a593Smuzhiyun  * @user_key: The view user id.
485*4882a593Smuzhiyun  *
486*4882a593Smuzhiyun  * returns a refcounted pointer to a view or an error pointer if not found.
487*4882a593Smuzhiyun  */
vmw_view_lookup(struct vmw_cmdbuf_res_manager * man,enum vmw_view_type view_type,u32 user_key)488*4882a593Smuzhiyun struct vmw_resource *vmw_view_lookup(struct vmw_cmdbuf_res_manager *man,
489*4882a593Smuzhiyun 				     enum vmw_view_type view_type,
490*4882a593Smuzhiyun 				     u32 user_key)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_view,
493*4882a593Smuzhiyun 				     vmw_view_key(user_key, view_type));
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun /**
497*4882a593Smuzhiyun  * vmw_view_dirtying - Return whether a view type is dirtying its resource
498*4882a593Smuzhiyun  * @res: Pointer to the view
499*4882a593Smuzhiyun  *
500*4882a593Smuzhiyun  * Each time a resource is put on the validation list as the result of a
501*4882a593Smuzhiyun  * view pointing to it, we need to determine whether that resource will
502*4882a593Smuzhiyun  * be dirtied (written to by the GPU) as a result of the corresponding
503*4882a593Smuzhiyun  * GPU operation. Currently only rendertarget-, depth-stencil and unordered
504*4882a593Smuzhiyun  * access views are capable of dirtying its resource.
505*4882a593Smuzhiyun  *
506*4882a593Smuzhiyun  * Return: Whether the view type of @res dirties the resource it points to.
507*4882a593Smuzhiyun  */
vmw_view_dirtying(struct vmw_resource * res)508*4882a593Smuzhiyun u32 vmw_view_dirtying(struct vmw_resource *res)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	static u32 view_is_dirtying[vmw_view_max] = {
511*4882a593Smuzhiyun 		[vmw_view_rt] = VMW_RES_DIRTY_SET,
512*4882a593Smuzhiyun 		[vmw_view_ds] = VMW_RES_DIRTY_SET,
513*4882a593Smuzhiyun 		[vmw_view_ua] = VMW_RES_DIRTY_SET,
514*4882a593Smuzhiyun 	};
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	/* Update this function as we add more view types */
517*4882a593Smuzhiyun 	BUILD_BUG_ON(vmw_view_max != 4);
518*4882a593Smuzhiyun 	return view_is_dirtying[vmw_view(res)->view_type];
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun const u32 vmw_view_destroy_cmds[] = {
522*4882a593Smuzhiyun 	[vmw_view_sr] = SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW,
523*4882a593Smuzhiyun 	[vmw_view_rt] = SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW,
524*4882a593Smuzhiyun 	[vmw_view_ds] = SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW,
525*4882a593Smuzhiyun 	[vmw_view_ua] = SVGA_3D_CMD_DX_DESTROY_UA_VIEW,
526*4882a593Smuzhiyun };
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun const SVGACOTableType vmw_view_cotables[] = {
529*4882a593Smuzhiyun 	[vmw_view_sr] = SVGA_COTABLE_SRVIEW,
530*4882a593Smuzhiyun 	[vmw_view_rt] = SVGA_COTABLE_RTVIEW,
531*4882a593Smuzhiyun 	[vmw_view_ds] = SVGA_COTABLE_DSVIEW,
532*4882a593Smuzhiyun 	[vmw_view_ua] = SVGA_COTABLE_UAVIEW,
533*4882a593Smuzhiyun };
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun const SVGACOTableType vmw_so_cotables[] = {
536*4882a593Smuzhiyun 	[vmw_so_el] = SVGA_COTABLE_ELEMENTLAYOUT,
537*4882a593Smuzhiyun 	[vmw_so_bs] = SVGA_COTABLE_BLENDSTATE,
538*4882a593Smuzhiyun 	[vmw_so_ds] = SVGA_COTABLE_DEPTHSTENCIL,
539*4882a593Smuzhiyun 	[vmw_so_rs] = SVGA_COTABLE_RASTERIZERSTATE,
540*4882a593Smuzhiyun 	[vmw_so_ss] = SVGA_COTABLE_SAMPLER,
541*4882a593Smuzhiyun 	[vmw_so_so] = SVGA_COTABLE_STREAMOUTPUT
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun /* To remove unused function warning */
546*4882a593Smuzhiyun static void vmw_so_build_asserts(void) __attribute__((used));
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun /*
550*4882a593Smuzhiyun  * This function is unused at run-time, and only used to dump various build
551*4882a593Smuzhiyun  * asserts important for code optimization assumptions.
552*4882a593Smuzhiyun  */
vmw_so_build_asserts(void)553*4882a593Smuzhiyun static void vmw_so_build_asserts(void)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun 	/* Assert that our vmw_view_cmd_to_type() function is correct. */
556*4882a593Smuzhiyun 	BUILD_BUG_ON(SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW !=
557*4882a593Smuzhiyun 		     SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 1);
558*4882a593Smuzhiyun 	BUILD_BUG_ON(SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW !=
559*4882a593Smuzhiyun 		     SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 2);
560*4882a593Smuzhiyun 	BUILD_BUG_ON(SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW !=
561*4882a593Smuzhiyun 		     SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 3);
562*4882a593Smuzhiyun 	BUILD_BUG_ON(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW !=
563*4882a593Smuzhiyun 		     SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 4);
564*4882a593Smuzhiyun 	BUILD_BUG_ON(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW !=
565*4882a593Smuzhiyun 		     SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW + 5);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Assert that our "one body fits all" assumption is valid */
568*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(union vmw_view_destroy) != sizeof(u32));
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* Assert that the view key space can hold all view ids. */
571*4882a593Smuzhiyun 	BUILD_BUG_ON(SVGA_COTABLE_MAX_IDS >= ((1 << 20) - 1));
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	/*
574*4882a593Smuzhiyun 	 * Assert that the offset of sid in all view define commands
575*4882a593Smuzhiyun 	 * is what we assume it to be.
576*4882a593Smuzhiyun 	 */
577*4882a593Smuzhiyun 	BUILD_BUG_ON(offsetof(struct vmw_view_define, sid) !=
578*4882a593Smuzhiyun 		     offsetof(SVGA3dCmdDXDefineShaderResourceView, sid));
579*4882a593Smuzhiyun 	BUILD_BUG_ON(offsetof(struct vmw_view_define, sid) !=
580*4882a593Smuzhiyun 		     offsetof(SVGA3dCmdDXDefineRenderTargetView, sid));
581*4882a593Smuzhiyun 	BUILD_BUG_ON(offsetof(struct vmw_view_define, sid) !=
582*4882a593Smuzhiyun 		     offsetof(SVGA3dCmdDXDefineDepthStencilView, sid));
583*4882a593Smuzhiyun }
584