1*677dec6eSriastradh /*	$NetBSD: vmwgfx_shader.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $	*/
2d350ecf5Sriastradh 
3*677dec6eSriastradh // SPDX-License-Identifier: GPL-2.0 OR MIT
4cb459498Sriastradh /**************************************************************************
5cb459498Sriastradh  *
6*677dec6eSriastradh  * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
7cb459498Sriastradh  *
8cb459498Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
9cb459498Sriastradh  * copy of this software and associated documentation files (the
10cb459498Sriastradh  * "Software"), to deal in the Software without restriction, including
11cb459498Sriastradh  * without limitation the rights to use, copy, modify, merge, publish,
12cb459498Sriastradh  * distribute, sub license, and/or sell copies of the Software, and to
13cb459498Sriastradh  * permit persons to whom the Software is furnished to do so, subject to
14cb459498Sriastradh  * the following conditions:
15cb459498Sriastradh  *
16cb459498Sriastradh  * The above copyright notice and this permission notice (including the
17cb459498Sriastradh  * next paragraph) shall be included in all copies or substantial portions
18cb459498Sriastradh  * of the Software.
19cb459498Sriastradh  *
20cb459498Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21cb459498Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22cb459498Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
23cb459498Sriastradh  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
24cb459498Sriastradh  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25cb459498Sriastradh  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26cb459498Sriastradh  * USE OR OTHER DEALINGS IN THE SOFTWARE.
27cb459498Sriastradh  *
28cb459498Sriastradh  **************************************************************************/
29cb459498Sriastradh 
30d350ecf5Sriastradh #include <sys/cdefs.h>
31*677dec6eSriastradh __KERNEL_RCSID(0, "$NetBSD: vmwgfx_shader.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $");
32*677dec6eSriastradh 
33*677dec6eSriastradh #include <drm/ttm/ttm_placement.h>
34d350ecf5Sriastradh 
35cb459498Sriastradh #include "vmwgfx_drv.h"
36cb459498Sriastradh #include "vmwgfx_resource_priv.h"
37d350ecf5Sriastradh #include "vmwgfx_binding.h"
38cb459498Sriastradh 
39cb459498Sriastradh struct vmw_shader {
40cb459498Sriastradh 	struct vmw_resource res;
41cb459498Sriastradh 	SVGA3dShaderType type;
42cb459498Sriastradh 	uint32_t size;
43d350ecf5Sriastradh 	uint8_t num_input_sig;
44d350ecf5Sriastradh 	uint8_t num_output_sig;
45cb459498Sriastradh };
46cb459498Sriastradh 
47cb459498Sriastradh struct vmw_user_shader {
48cb459498Sriastradh 	struct ttm_base_object base;
49cb459498Sriastradh 	struct vmw_shader shader;
50cb459498Sriastradh };
51cb459498Sriastradh 
52d350ecf5Sriastradh struct vmw_dx_shader {
53d350ecf5Sriastradh 	struct vmw_resource res;
54d350ecf5Sriastradh 	struct vmw_resource *ctx;
55d350ecf5Sriastradh 	struct vmw_resource *cotable;
56d350ecf5Sriastradh 	u32 id;
57d350ecf5Sriastradh 	bool committed;
58d350ecf5Sriastradh 	struct list_head cotable_head;
59cb459498Sriastradh };
60cb459498Sriastradh 
61d350ecf5Sriastradh static uint64_t vmw_user_shader_size;
62d350ecf5Sriastradh static uint64_t vmw_shader_size;
63d350ecf5Sriastradh static size_t vmw_shader_dx_size;
64cb459498Sriastradh 
65cb459498Sriastradh static void vmw_user_shader_free(struct vmw_resource *res);
66cb459498Sriastradh static struct vmw_resource *
67cb459498Sriastradh vmw_user_shader_base_to_res(struct ttm_base_object *base);
68cb459498Sriastradh 
69cb459498Sriastradh static int vmw_gb_shader_create(struct vmw_resource *res);
70cb459498Sriastradh static int vmw_gb_shader_bind(struct vmw_resource *res,
71cb459498Sriastradh 			       struct ttm_validate_buffer *val_buf);
72cb459498Sriastradh static int vmw_gb_shader_unbind(struct vmw_resource *res,
73cb459498Sriastradh 				 bool readback,
74cb459498Sriastradh 				 struct ttm_validate_buffer *val_buf);
75cb459498Sriastradh static int vmw_gb_shader_destroy(struct vmw_resource *res);
76cb459498Sriastradh 
77d350ecf5Sriastradh static int vmw_dx_shader_create(struct vmw_resource *res);
78d350ecf5Sriastradh static int vmw_dx_shader_bind(struct vmw_resource *res,
79d350ecf5Sriastradh 			       struct ttm_validate_buffer *val_buf);
80d350ecf5Sriastradh static int vmw_dx_shader_unbind(struct vmw_resource *res,
81d350ecf5Sriastradh 				 bool readback,
82d350ecf5Sriastradh 				 struct ttm_validate_buffer *val_buf);
83d350ecf5Sriastradh static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
84d350ecf5Sriastradh 					enum vmw_cmdbuf_res_state state);
85d350ecf5Sriastradh static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
86d350ecf5Sriastradh static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
87cb459498Sriastradh static uint64_t vmw_user_shader_size;
88cb459498Sriastradh 
89cb459498Sriastradh static const struct vmw_user_resource_conv user_shader_conv = {
90cb459498Sriastradh 	.object_type = VMW_RES_SHADER,
91cb459498Sriastradh 	.base_obj_to_res = vmw_user_shader_base_to_res,
92cb459498Sriastradh 	.res_free = vmw_user_shader_free
93cb459498Sriastradh };
94cb459498Sriastradh 
95cb459498Sriastradh const struct vmw_user_resource_conv *user_shader_converter =
96cb459498Sriastradh 	&user_shader_conv;
97cb459498Sriastradh 
98cb459498Sriastradh 
99cb459498Sriastradh static const struct vmw_res_func vmw_gb_shader_func = {
100cb459498Sriastradh 	.res_type = vmw_res_shader,
101cb459498Sriastradh 	.needs_backup = true,
102cb459498Sriastradh 	.may_evict = true,
103*677dec6eSriastradh 	.prio = 3,
104*677dec6eSriastradh 	.dirty_prio = 3,
105cb459498Sriastradh 	.type_name = "guest backed shaders",
106cb459498Sriastradh 	.backup_placement = &vmw_mob_placement,
107cb459498Sriastradh 	.create = vmw_gb_shader_create,
108cb459498Sriastradh 	.destroy = vmw_gb_shader_destroy,
109cb459498Sriastradh 	.bind = vmw_gb_shader_bind,
110cb459498Sriastradh 	.unbind = vmw_gb_shader_unbind
111cb459498Sriastradh };
112cb459498Sriastradh 
113d350ecf5Sriastradh static const struct vmw_res_func vmw_dx_shader_func = {
114d350ecf5Sriastradh 	.res_type = vmw_res_shader,
115d350ecf5Sriastradh 	.needs_backup = true,
116*677dec6eSriastradh 	.may_evict = true,
117*677dec6eSriastradh 	.prio = 3,
118*677dec6eSriastradh 	.dirty_prio = 3,
119d350ecf5Sriastradh 	.type_name = "dx shaders",
120d350ecf5Sriastradh 	.backup_placement = &vmw_mob_placement,
121d350ecf5Sriastradh 	.create = vmw_dx_shader_create,
122d350ecf5Sriastradh 	/*
123d350ecf5Sriastradh 	 * The destroy callback is only called with a committed resource on
124d350ecf5Sriastradh 	 * context destroy, in which case we destroy the cotable anyway,
125d350ecf5Sriastradh 	 * so there's no need to destroy DX shaders separately.
126d350ecf5Sriastradh 	 */
127d350ecf5Sriastradh 	.destroy = NULL,
128d350ecf5Sriastradh 	.bind = vmw_dx_shader_bind,
129d350ecf5Sriastradh 	.unbind = vmw_dx_shader_unbind,
130d350ecf5Sriastradh 	.commit_notify = vmw_dx_shader_commit_notify,
131d350ecf5Sriastradh };
132d350ecf5Sriastradh 
133cb459498Sriastradh /**
134cb459498Sriastradh  * Shader management:
135cb459498Sriastradh  */
136cb459498Sriastradh 
137cb459498Sriastradh static inline struct vmw_shader *
vmw_res_to_shader(struct vmw_resource * res)138cb459498Sriastradh vmw_res_to_shader(struct vmw_resource *res)
139cb459498Sriastradh {
140cb459498Sriastradh 	return container_of(res, struct vmw_shader, res);
141cb459498Sriastradh }
142cb459498Sriastradh 
143d350ecf5Sriastradh /**
144d350ecf5Sriastradh  * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
145d350ecf5Sriastradh  * struct vmw_dx_shader
146d350ecf5Sriastradh  *
147d350ecf5Sriastradh  * @res: Pointer to the struct vmw_resource.
148d350ecf5Sriastradh  */
149d350ecf5Sriastradh static inline struct vmw_dx_shader *
vmw_res_to_dx_shader(struct vmw_resource * res)150d350ecf5Sriastradh vmw_res_to_dx_shader(struct vmw_resource *res)
151d350ecf5Sriastradh {
152d350ecf5Sriastradh 	return container_of(res, struct vmw_dx_shader, res);
153d350ecf5Sriastradh }
154d350ecf5Sriastradh 
vmw_hw_shader_destroy(struct vmw_resource * res)155cb459498Sriastradh static void vmw_hw_shader_destroy(struct vmw_resource *res)
156cb459498Sriastradh {
157d350ecf5Sriastradh 	if (likely(res->func->destroy))
158d350ecf5Sriastradh 		(void) res->func->destroy(res);
159d350ecf5Sriastradh 	else
160d350ecf5Sriastradh 		res->id = -1;
161cb459498Sriastradh }
162cb459498Sriastradh 
163d350ecf5Sriastradh 
vmw_gb_shader_init(struct vmw_private * dev_priv,struct vmw_resource * res,uint32_t size,uint64_t offset,SVGA3dShaderType type,uint8_t num_input_sig,uint8_t num_output_sig,struct vmw_buffer_object * byte_code,void (* res_free)(struct vmw_resource * res))164cb459498Sriastradh static int vmw_gb_shader_init(struct vmw_private *dev_priv,
165cb459498Sriastradh 			      struct vmw_resource *res,
166cb459498Sriastradh 			      uint32_t size,
167cb459498Sriastradh 			      uint64_t offset,
168cb459498Sriastradh 			      SVGA3dShaderType type,
169d350ecf5Sriastradh 			      uint8_t num_input_sig,
170d350ecf5Sriastradh 			      uint8_t num_output_sig,
171*677dec6eSriastradh 			      struct vmw_buffer_object *byte_code,
172cb459498Sriastradh 			      void (*res_free) (struct vmw_resource *res))
173cb459498Sriastradh {
174cb459498Sriastradh 	struct vmw_shader *shader = vmw_res_to_shader(res);
175cb459498Sriastradh 	int ret;
176cb459498Sriastradh 
177d350ecf5Sriastradh 	ret = vmw_resource_init(dev_priv, res, true, res_free,
178d350ecf5Sriastradh 				&vmw_gb_shader_func);
179cb459498Sriastradh 
180cb459498Sriastradh 	if (unlikely(ret != 0)) {
181cb459498Sriastradh 		if (res_free)
182cb459498Sriastradh 			res_free(res);
183cb459498Sriastradh 		else
184cb459498Sriastradh 			kfree(res);
185cb459498Sriastradh 		return ret;
186cb459498Sriastradh 	}
187cb459498Sriastradh 
188cb459498Sriastradh 	res->backup_size = size;
189cb459498Sriastradh 	if (byte_code) {
190*677dec6eSriastradh 		res->backup = vmw_bo_reference(byte_code);
191cb459498Sriastradh 		res->backup_offset = offset;
192cb459498Sriastradh 	}
193cb459498Sriastradh 	shader->size = size;
194cb459498Sriastradh 	shader->type = type;
195d350ecf5Sriastradh 	shader->num_input_sig = num_input_sig;
196d350ecf5Sriastradh 	shader->num_output_sig = num_output_sig;
197cb459498Sriastradh 
198*677dec6eSriastradh 	res->hw_destroy = vmw_hw_shader_destroy;
199cb459498Sriastradh 	return 0;
200cb459498Sriastradh }
201cb459498Sriastradh 
202d350ecf5Sriastradh /*
203d350ecf5Sriastradh  * GB shader code:
204d350ecf5Sriastradh  */
205d350ecf5Sriastradh 
vmw_gb_shader_create(struct vmw_resource * res)206cb459498Sriastradh static int vmw_gb_shader_create(struct vmw_resource *res)
207cb459498Sriastradh {
208cb459498Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
209cb459498Sriastradh 	struct vmw_shader *shader = vmw_res_to_shader(res);
210cb459498Sriastradh 	int ret;
211cb459498Sriastradh 	struct {
212cb459498Sriastradh 		SVGA3dCmdHeader header;
213cb459498Sriastradh 		SVGA3dCmdDefineGBShader body;
214cb459498Sriastradh 	} *cmd;
215cb459498Sriastradh 
216cb459498Sriastradh 	if (likely(res->id != -1))
217cb459498Sriastradh 		return 0;
218cb459498Sriastradh 
219cb459498Sriastradh 	ret = vmw_resource_alloc_id(res);
220cb459498Sriastradh 	if (unlikely(ret != 0)) {
221cb459498Sriastradh 		DRM_ERROR("Failed to allocate a shader id.\n");
222cb459498Sriastradh 		goto out_no_id;
223cb459498Sriastradh 	}
224cb459498Sriastradh 
225cb459498Sriastradh 	if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
226cb459498Sriastradh 		ret = -EBUSY;
227cb459498Sriastradh 		goto out_no_fifo;
228cb459498Sriastradh 	}
229cb459498Sriastradh 
230*677dec6eSriastradh 	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
231cb459498Sriastradh 	if (unlikely(cmd == NULL)) {
232cb459498Sriastradh 		ret = -ENOMEM;
233cb459498Sriastradh 		goto out_no_fifo;
234cb459498Sriastradh 	}
235cb459498Sriastradh 
236cb459498Sriastradh 	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
237cb459498Sriastradh 	cmd->header.size = sizeof(cmd->body);
238cb459498Sriastradh 	cmd->body.shid = res->id;
239cb459498Sriastradh 	cmd->body.type = shader->type;
240cb459498Sriastradh 	cmd->body.sizeInBytes = shader->size;
241cb459498Sriastradh 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
242d350ecf5Sriastradh 	vmw_fifo_resource_inc(dev_priv);
243cb459498Sriastradh 
244cb459498Sriastradh 	return 0;
245cb459498Sriastradh 
246cb459498Sriastradh out_no_fifo:
247cb459498Sriastradh 	vmw_resource_release_id(res);
248cb459498Sriastradh out_no_id:
249cb459498Sriastradh 	return ret;
250cb459498Sriastradh }
251cb459498Sriastradh 
vmw_gb_shader_bind(struct vmw_resource * res,struct ttm_validate_buffer * val_buf)252cb459498Sriastradh static int vmw_gb_shader_bind(struct vmw_resource *res,
253cb459498Sriastradh 			      struct ttm_validate_buffer *val_buf)
254cb459498Sriastradh {
255cb459498Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
256cb459498Sriastradh 	struct {
257cb459498Sriastradh 		SVGA3dCmdHeader header;
258cb459498Sriastradh 		SVGA3dCmdBindGBShader body;
259cb459498Sriastradh 	} *cmd;
260cb459498Sriastradh 	struct ttm_buffer_object *bo = val_buf->bo;
261cb459498Sriastradh 
262cb459498Sriastradh 	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
263cb459498Sriastradh 
264*677dec6eSriastradh 	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
265*677dec6eSriastradh 	if (unlikely(cmd == NULL))
266cb459498Sriastradh 		return -ENOMEM;
267cb459498Sriastradh 
268cb459498Sriastradh 	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
269cb459498Sriastradh 	cmd->header.size = sizeof(cmd->body);
270cb459498Sriastradh 	cmd->body.shid = res->id;
271cb459498Sriastradh 	cmd->body.mobid = bo->mem.start;
272d350ecf5Sriastradh 	cmd->body.offsetInBytes = res->backup_offset;
273cb459498Sriastradh 	res->backup_dirty = false;
274cb459498Sriastradh 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
275cb459498Sriastradh 
276cb459498Sriastradh 	return 0;
277cb459498Sriastradh }
278cb459498Sriastradh 
vmw_gb_shader_unbind(struct vmw_resource * res,bool readback,struct ttm_validate_buffer * val_buf)279cb459498Sriastradh static int vmw_gb_shader_unbind(struct vmw_resource *res,
280cb459498Sriastradh 				bool readback,
281cb459498Sriastradh 				struct ttm_validate_buffer *val_buf)
282cb459498Sriastradh {
283cb459498Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
284cb459498Sriastradh 	struct {
285cb459498Sriastradh 		SVGA3dCmdHeader header;
286cb459498Sriastradh 		SVGA3dCmdBindGBShader body;
287cb459498Sriastradh 	} *cmd;
288cb459498Sriastradh 	struct vmw_fence_obj *fence;
289cb459498Sriastradh 
290cb459498Sriastradh 	BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
291cb459498Sriastradh 
292*677dec6eSriastradh 	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
293*677dec6eSriastradh 	if (unlikely(cmd == NULL))
294cb459498Sriastradh 		return -ENOMEM;
295cb459498Sriastradh 
296cb459498Sriastradh 	cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
297cb459498Sriastradh 	cmd->header.size = sizeof(cmd->body);
298cb459498Sriastradh 	cmd->body.shid = res->id;
299cb459498Sriastradh 	cmd->body.mobid = SVGA3D_INVALID_ID;
300cb459498Sriastradh 	cmd->body.offsetInBytes = 0;
301cb459498Sriastradh 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
302cb459498Sriastradh 
303cb459498Sriastradh 	/*
304cb459498Sriastradh 	 * Create a fence object and fence the backup buffer.
305cb459498Sriastradh 	 */
306cb459498Sriastradh 
307cb459498Sriastradh 	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
308cb459498Sriastradh 					  &fence, NULL);
309cb459498Sriastradh 
310*677dec6eSriastradh 	vmw_bo_fence_single(val_buf->bo, fence);
311cb459498Sriastradh 
312cb459498Sriastradh 	if (likely(fence != NULL))
313cb459498Sriastradh 		vmw_fence_obj_unreference(&fence);
314cb459498Sriastradh 
315cb459498Sriastradh 	return 0;
316cb459498Sriastradh }
317cb459498Sriastradh 
vmw_gb_shader_destroy(struct vmw_resource * res)318cb459498Sriastradh static int vmw_gb_shader_destroy(struct vmw_resource *res)
319cb459498Sriastradh {
320cb459498Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
321cb459498Sriastradh 	struct {
322cb459498Sriastradh 		SVGA3dCmdHeader header;
323cb459498Sriastradh 		SVGA3dCmdDestroyGBShader body;
324cb459498Sriastradh 	} *cmd;
325cb459498Sriastradh 
326cb459498Sriastradh 	if (likely(res->id == -1))
327cb459498Sriastradh 		return 0;
328cb459498Sriastradh 
329cb459498Sriastradh 	mutex_lock(&dev_priv->binding_mutex);
330d350ecf5Sriastradh 	vmw_binding_res_list_scrub(&res->binding_head);
331cb459498Sriastradh 
332*677dec6eSriastradh 	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
333cb459498Sriastradh 	if (unlikely(cmd == NULL)) {
334cb459498Sriastradh 		mutex_unlock(&dev_priv->binding_mutex);
335cb459498Sriastradh 		return -ENOMEM;
336cb459498Sriastradh 	}
337cb459498Sriastradh 
338cb459498Sriastradh 	cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
339cb459498Sriastradh 	cmd->header.size = sizeof(cmd->body);
340cb459498Sriastradh 	cmd->body.shid = res->id;
341cb459498Sriastradh 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
342cb459498Sriastradh 	mutex_unlock(&dev_priv->binding_mutex);
343cb459498Sriastradh 	vmw_resource_release_id(res);
344d350ecf5Sriastradh 	vmw_fifo_resource_dec(dev_priv);
345cb459498Sriastradh 
346cb459498Sriastradh 	return 0;
347cb459498Sriastradh }
348cb459498Sriastradh 
349d350ecf5Sriastradh /*
350d350ecf5Sriastradh  * DX shader code:
351d350ecf5Sriastradh  */
352d350ecf5Sriastradh 
353d350ecf5Sriastradh /**
354d350ecf5Sriastradh  * vmw_dx_shader_commit_notify - Notify that a shader operation has been
355d350ecf5Sriastradh  * committed to hardware from a user-supplied command stream.
356d350ecf5Sriastradh  *
357d350ecf5Sriastradh  * @res: Pointer to the shader resource.
358d350ecf5Sriastradh  * @state: Indicating whether a creation or removal has been committed.
359d350ecf5Sriastradh  *
360d350ecf5Sriastradh  */
vmw_dx_shader_commit_notify(struct vmw_resource * res,enum vmw_cmdbuf_res_state state)361d350ecf5Sriastradh static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
362d350ecf5Sriastradh 					enum vmw_cmdbuf_res_state state)
363d350ecf5Sriastradh {
364d350ecf5Sriastradh 	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
365d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
366d350ecf5Sriastradh 
367d350ecf5Sriastradh 	if (state == VMW_CMDBUF_RES_ADD) {
368d350ecf5Sriastradh 		mutex_lock(&dev_priv->binding_mutex);
369d350ecf5Sriastradh 		vmw_cotable_add_resource(shader->cotable,
370d350ecf5Sriastradh 					 &shader->cotable_head);
371d350ecf5Sriastradh 		shader->committed = true;
372d350ecf5Sriastradh 		res->id = shader->id;
373d350ecf5Sriastradh 		mutex_unlock(&dev_priv->binding_mutex);
374d350ecf5Sriastradh 	} else {
375d350ecf5Sriastradh 		mutex_lock(&dev_priv->binding_mutex);
376d350ecf5Sriastradh 		list_del_init(&shader->cotable_head);
377d350ecf5Sriastradh 		shader->committed = false;
378d350ecf5Sriastradh 		res->id = -1;
379d350ecf5Sriastradh 		mutex_unlock(&dev_priv->binding_mutex);
380d350ecf5Sriastradh 	}
381d350ecf5Sriastradh }
382d350ecf5Sriastradh 
383d350ecf5Sriastradh /**
384d350ecf5Sriastradh  * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
385d350ecf5Sriastradh  *
386d350ecf5Sriastradh  * @res: The shader resource
387d350ecf5Sriastradh  *
388d350ecf5Sriastradh  * This function reverts a scrub operation.
389d350ecf5Sriastradh  */
vmw_dx_shader_unscrub(struct vmw_resource * res)390d350ecf5Sriastradh static int vmw_dx_shader_unscrub(struct vmw_resource *res)
391d350ecf5Sriastradh {
392d350ecf5Sriastradh 	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
393d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
394d350ecf5Sriastradh 	struct {
395d350ecf5Sriastradh 		SVGA3dCmdHeader header;
396d350ecf5Sriastradh 		SVGA3dCmdDXBindShader body;
397d350ecf5Sriastradh 	} *cmd;
398d350ecf5Sriastradh 
399d350ecf5Sriastradh 	if (!list_empty(&shader->cotable_head) || !shader->committed)
400d350ecf5Sriastradh 		return 0;
401d350ecf5Sriastradh 
402*677dec6eSriastradh 	cmd = VMW_FIFO_RESERVE_DX(dev_priv, sizeof(*cmd), shader->ctx->id);
403*677dec6eSriastradh 	if (unlikely(cmd == NULL))
404d350ecf5Sriastradh 		return -ENOMEM;
405d350ecf5Sriastradh 
406d350ecf5Sriastradh 	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
407d350ecf5Sriastradh 	cmd->header.size = sizeof(cmd->body);
408d350ecf5Sriastradh 	cmd->body.cid = shader->ctx->id;
409d350ecf5Sriastradh 	cmd->body.shid = shader->id;
410d350ecf5Sriastradh 	cmd->body.mobid = res->backup->base.mem.start;
411d350ecf5Sriastradh 	cmd->body.offsetInBytes = res->backup_offset;
412d350ecf5Sriastradh 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
413d350ecf5Sriastradh 
414d350ecf5Sriastradh 	vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
415d350ecf5Sriastradh 
416d350ecf5Sriastradh 	return 0;
417d350ecf5Sriastradh }
418d350ecf5Sriastradh 
419d350ecf5Sriastradh /**
420d350ecf5Sriastradh  * vmw_dx_shader_create - The DX shader create callback
421d350ecf5Sriastradh  *
422d350ecf5Sriastradh  * @res: The DX shader resource
423d350ecf5Sriastradh  *
424d350ecf5Sriastradh  * The create callback is called as part of resource validation and
425d350ecf5Sriastradh  * makes sure that we unscrub the shader if it's previously been scrubbed.
426d350ecf5Sriastradh  */
vmw_dx_shader_create(struct vmw_resource * res)427d350ecf5Sriastradh static int vmw_dx_shader_create(struct vmw_resource *res)
428d350ecf5Sriastradh {
429d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
430d350ecf5Sriastradh 	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
431d350ecf5Sriastradh 	int ret = 0;
432d350ecf5Sriastradh 
433d350ecf5Sriastradh 	WARN_ON_ONCE(!shader->committed);
434d350ecf5Sriastradh 
435*677dec6eSriastradh 	if (vmw_resource_mob_attached(res)) {
436d350ecf5Sriastradh 		mutex_lock(&dev_priv->binding_mutex);
437d350ecf5Sriastradh 		ret = vmw_dx_shader_unscrub(res);
438d350ecf5Sriastradh 		mutex_unlock(&dev_priv->binding_mutex);
439d350ecf5Sriastradh 	}
440d350ecf5Sriastradh 
441d350ecf5Sriastradh 	res->id = shader->id;
442d350ecf5Sriastradh 	return ret;
443d350ecf5Sriastradh }
444d350ecf5Sriastradh 
445d350ecf5Sriastradh /**
446d350ecf5Sriastradh  * vmw_dx_shader_bind - The DX shader bind callback
447d350ecf5Sriastradh  *
448d350ecf5Sriastradh  * @res: The DX shader resource
449d350ecf5Sriastradh  * @val_buf: Pointer to the validate buffer.
450d350ecf5Sriastradh  *
451d350ecf5Sriastradh  */
vmw_dx_shader_bind(struct vmw_resource * res,struct ttm_validate_buffer * val_buf)452d350ecf5Sriastradh static int vmw_dx_shader_bind(struct vmw_resource *res,
453d350ecf5Sriastradh 			      struct ttm_validate_buffer *val_buf)
454d350ecf5Sriastradh {
455d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
456d350ecf5Sriastradh 	struct ttm_buffer_object *bo = val_buf->bo;
457d350ecf5Sriastradh 
458d350ecf5Sriastradh 	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
459d350ecf5Sriastradh 	mutex_lock(&dev_priv->binding_mutex);
460d350ecf5Sriastradh 	vmw_dx_shader_unscrub(res);
461d350ecf5Sriastradh 	mutex_unlock(&dev_priv->binding_mutex);
462d350ecf5Sriastradh 
463d350ecf5Sriastradh 	return 0;
464d350ecf5Sriastradh }
465d350ecf5Sriastradh 
466d350ecf5Sriastradh /**
467d350ecf5Sriastradh  * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
468d350ecf5Sriastradh  *
469d350ecf5Sriastradh  * @res: The shader resource
470d350ecf5Sriastradh  *
471d350ecf5Sriastradh  * This function unbinds a MOB from the DX shader without requiring the
472d350ecf5Sriastradh  * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
473d350ecf5Sriastradh  * However, once the driver eventually decides to unbind the MOB, it doesn't
474d350ecf5Sriastradh  * need to access the context.
475d350ecf5Sriastradh  */
vmw_dx_shader_scrub(struct vmw_resource * res)476d350ecf5Sriastradh static int vmw_dx_shader_scrub(struct vmw_resource *res)
477d350ecf5Sriastradh {
478d350ecf5Sriastradh 	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
479d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
480d350ecf5Sriastradh 	struct {
481d350ecf5Sriastradh 		SVGA3dCmdHeader header;
482d350ecf5Sriastradh 		SVGA3dCmdDXBindShader body;
483d350ecf5Sriastradh 	} *cmd;
484d350ecf5Sriastradh 
485d350ecf5Sriastradh 	if (list_empty(&shader->cotable_head))
486d350ecf5Sriastradh 		return 0;
487d350ecf5Sriastradh 
488d350ecf5Sriastradh 	WARN_ON_ONCE(!shader->committed);
489*677dec6eSriastradh 	cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
490*677dec6eSriastradh 	if (unlikely(cmd == NULL))
491d350ecf5Sriastradh 		return -ENOMEM;
492d350ecf5Sriastradh 
493d350ecf5Sriastradh 	cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
494d350ecf5Sriastradh 	cmd->header.size = sizeof(cmd->body);
495d350ecf5Sriastradh 	cmd->body.cid = shader->ctx->id;
496d350ecf5Sriastradh 	cmd->body.shid = res->id;
497d350ecf5Sriastradh 	cmd->body.mobid = SVGA3D_INVALID_ID;
498d350ecf5Sriastradh 	cmd->body.offsetInBytes = 0;
499d350ecf5Sriastradh 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
500d350ecf5Sriastradh 	res->id = -1;
501d350ecf5Sriastradh 	list_del_init(&shader->cotable_head);
502d350ecf5Sriastradh 
503d350ecf5Sriastradh 	return 0;
504d350ecf5Sriastradh }
505d350ecf5Sriastradh 
506d350ecf5Sriastradh /**
507d350ecf5Sriastradh  * vmw_dx_shader_unbind - The dx shader unbind callback.
508d350ecf5Sriastradh  *
509d350ecf5Sriastradh  * @res: The shader resource
510d350ecf5Sriastradh  * @readback: Whether this is a readback unbind. Currently unused.
511d350ecf5Sriastradh  * @val_buf: MOB buffer information.
512d350ecf5Sriastradh  */
vmw_dx_shader_unbind(struct vmw_resource * res,bool readback,struct ttm_validate_buffer * val_buf)513d350ecf5Sriastradh static int vmw_dx_shader_unbind(struct vmw_resource *res,
514d350ecf5Sriastradh 				bool readback,
515d350ecf5Sriastradh 				struct ttm_validate_buffer *val_buf)
516d350ecf5Sriastradh {
517d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
518d350ecf5Sriastradh 	struct vmw_fence_obj *fence;
519d350ecf5Sriastradh 	int ret;
520d350ecf5Sriastradh 
521d350ecf5Sriastradh 	BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
522d350ecf5Sriastradh 
523d350ecf5Sriastradh 	mutex_lock(&dev_priv->binding_mutex);
524d350ecf5Sriastradh 	ret = vmw_dx_shader_scrub(res);
525d350ecf5Sriastradh 	mutex_unlock(&dev_priv->binding_mutex);
526d350ecf5Sriastradh 
527d350ecf5Sriastradh 	if (ret)
528d350ecf5Sriastradh 		return ret;
529d350ecf5Sriastradh 
530d350ecf5Sriastradh 	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
531d350ecf5Sriastradh 					  &fence, NULL);
532*677dec6eSriastradh 	vmw_bo_fence_single(val_buf->bo, fence);
533d350ecf5Sriastradh 
534d350ecf5Sriastradh 	if (likely(fence != NULL))
535d350ecf5Sriastradh 		vmw_fence_obj_unreference(&fence);
536d350ecf5Sriastradh 
537d350ecf5Sriastradh 	return 0;
538d350ecf5Sriastradh }
539d350ecf5Sriastradh 
540d350ecf5Sriastradh /**
541d350ecf5Sriastradh  * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
542d350ecf5Sriastradh  * DX shaders.
543d350ecf5Sriastradh  *
544d350ecf5Sriastradh  * @dev_priv: Pointer to device private structure.
545d350ecf5Sriastradh  * @list: The list of cotable resources.
546d350ecf5Sriastradh  * @readback: Whether the call was part of a readback unbind.
547d350ecf5Sriastradh  *
548d350ecf5Sriastradh  * Scrubs all shader MOBs so that any subsequent shader unbind or shader
549d350ecf5Sriastradh  * destroy operation won't need to swap in the context.
550d350ecf5Sriastradh  */
vmw_dx_shader_cotable_list_scrub(struct vmw_private * dev_priv,struct list_head * list,bool readback)551d350ecf5Sriastradh void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
552d350ecf5Sriastradh 				      struct list_head *list,
553d350ecf5Sriastradh 				      bool readback)
554d350ecf5Sriastradh {
555d350ecf5Sriastradh 	struct vmw_dx_shader *entry, *next;
556d350ecf5Sriastradh 
557*677dec6eSriastradh 	lockdep_assert_held_once(&dev_priv->binding_mutex);
558d350ecf5Sriastradh 
559d350ecf5Sriastradh 	list_for_each_entry_safe(entry, next, list, cotable_head) {
560d350ecf5Sriastradh 		WARN_ON(vmw_dx_shader_scrub(&entry->res));
561d350ecf5Sriastradh 		if (!readback)
562d350ecf5Sriastradh 			entry->committed = false;
563d350ecf5Sriastradh 	}
564d350ecf5Sriastradh }
565d350ecf5Sriastradh 
566d350ecf5Sriastradh /**
567d350ecf5Sriastradh  * vmw_dx_shader_res_free - The DX shader free callback
568d350ecf5Sriastradh  *
569d350ecf5Sriastradh  * @res: The shader resource
570d350ecf5Sriastradh  *
571d350ecf5Sriastradh  * Frees the DX shader resource and updates memory accounting.
572d350ecf5Sriastradh  */
vmw_dx_shader_res_free(struct vmw_resource * res)573d350ecf5Sriastradh static void vmw_dx_shader_res_free(struct vmw_resource *res)
574d350ecf5Sriastradh {
575d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
576d350ecf5Sriastradh 	struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
577d350ecf5Sriastradh 
578d350ecf5Sriastradh 	vmw_resource_unreference(&shader->cotable);
579d350ecf5Sriastradh 	kfree(shader);
580d350ecf5Sriastradh 	ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
581d350ecf5Sriastradh }
582d350ecf5Sriastradh 
583d350ecf5Sriastradh /**
584d350ecf5Sriastradh  * vmw_dx_shader_add - Add a shader resource as a command buffer managed
585d350ecf5Sriastradh  * resource.
586d350ecf5Sriastradh  *
587d350ecf5Sriastradh  * @man: The command buffer resource manager.
588d350ecf5Sriastradh  * @ctx: Pointer to the context resource.
589d350ecf5Sriastradh  * @user_key: The id used for this shader.
590d350ecf5Sriastradh  * @shader_type: The shader type.
591d350ecf5Sriastradh  * @list: The list of staged command buffer managed resources.
592d350ecf5Sriastradh  */
vmw_dx_shader_add(struct vmw_cmdbuf_res_manager * man,struct vmw_resource * ctx,u32 user_key,SVGA3dShaderType shader_type,struct list_head * list)593d350ecf5Sriastradh int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
594d350ecf5Sriastradh 		      struct vmw_resource *ctx,
595d350ecf5Sriastradh 		      u32 user_key,
596d350ecf5Sriastradh 		      SVGA3dShaderType shader_type,
597d350ecf5Sriastradh 		      struct list_head *list)
598d350ecf5Sriastradh {
599d350ecf5Sriastradh 	struct vmw_dx_shader *shader;
600d350ecf5Sriastradh 	struct vmw_resource *res;
601d350ecf5Sriastradh 	struct vmw_private *dev_priv = ctx->dev_priv;
602*677dec6eSriastradh 	struct ttm_operation_ctx ttm_opt_ctx = {
603*677dec6eSriastradh 		.interruptible = true,
604*677dec6eSriastradh 		.no_wait_gpu = false
605*677dec6eSriastradh 	};
606d350ecf5Sriastradh 	int ret;
607d350ecf5Sriastradh 
608d350ecf5Sriastradh 	if (!vmw_shader_dx_size)
609d350ecf5Sriastradh 		vmw_shader_dx_size = ttm_round_pot(sizeof(*shader));
610d350ecf5Sriastradh 
611d350ecf5Sriastradh 	if (!vmw_shader_id_ok(user_key, shader_type))
612d350ecf5Sriastradh 		return -EINVAL;
613d350ecf5Sriastradh 
614d350ecf5Sriastradh 	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_shader_dx_size,
615*677dec6eSriastradh 				   &ttm_opt_ctx);
616d350ecf5Sriastradh 	if (ret) {
617d350ecf5Sriastradh 		if (ret != -ERESTARTSYS)
618d350ecf5Sriastradh 			DRM_ERROR("Out of graphics memory for shader "
619d350ecf5Sriastradh 				  "creation.\n");
620d350ecf5Sriastradh 		return ret;
621d350ecf5Sriastradh 	}
622d350ecf5Sriastradh 
623d350ecf5Sriastradh 	shader = kmalloc(sizeof(*shader), GFP_KERNEL);
624d350ecf5Sriastradh 	if (!shader) {
625d350ecf5Sriastradh 		ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
626d350ecf5Sriastradh 		return -ENOMEM;
627d350ecf5Sriastradh 	}
628d350ecf5Sriastradh 
629d350ecf5Sriastradh 	res = &shader->res;
630d350ecf5Sriastradh 	shader->ctx = ctx;
631*677dec6eSriastradh 	shader->cotable = vmw_resource_reference
632*677dec6eSriastradh 		(vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
633d350ecf5Sriastradh 	shader->id = user_key;
634d350ecf5Sriastradh 	shader->committed = false;
635d350ecf5Sriastradh 	INIT_LIST_HEAD(&shader->cotable_head);
636d350ecf5Sriastradh 	ret = vmw_resource_init(dev_priv, res, true,
637d350ecf5Sriastradh 				vmw_dx_shader_res_free, &vmw_dx_shader_func);
638d350ecf5Sriastradh 	if (ret)
639d350ecf5Sriastradh 		goto out_resource_init;
640d350ecf5Sriastradh 
641d350ecf5Sriastradh 	/*
642d350ecf5Sriastradh 	 * The user_key name-space is not per shader type for DX shaders,
643d350ecf5Sriastradh 	 * so when hashing, use a single zero shader type.
644d350ecf5Sriastradh 	 */
645d350ecf5Sriastradh 	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
646d350ecf5Sriastradh 				 vmw_shader_key(user_key, 0),
647d350ecf5Sriastradh 				 res, list);
648d350ecf5Sriastradh 	if (ret)
649d350ecf5Sriastradh 		goto out_resource_init;
650d350ecf5Sriastradh 
651d350ecf5Sriastradh 	res->id = shader->id;
652*677dec6eSriastradh 	res->hw_destroy = vmw_hw_shader_destroy;
653d350ecf5Sriastradh 
654d350ecf5Sriastradh out_resource_init:
655d350ecf5Sriastradh 	vmw_resource_unreference(&res);
656d350ecf5Sriastradh 
657d350ecf5Sriastradh 	return ret;
658d350ecf5Sriastradh }
659d350ecf5Sriastradh 
660d350ecf5Sriastradh 
661d350ecf5Sriastradh 
662cb459498Sriastradh /**
663cb459498Sriastradh  * User-space shader management:
664cb459498Sriastradh  */
665cb459498Sriastradh 
666cb459498Sriastradh static struct vmw_resource *
vmw_user_shader_base_to_res(struct ttm_base_object * base)667cb459498Sriastradh vmw_user_shader_base_to_res(struct ttm_base_object *base)
668cb459498Sriastradh {
669cb459498Sriastradh 	return &(container_of(base, struct vmw_user_shader, base)->
670cb459498Sriastradh 		 shader.res);
671cb459498Sriastradh }
672cb459498Sriastradh 
vmw_user_shader_free(struct vmw_resource * res)673cb459498Sriastradh static void vmw_user_shader_free(struct vmw_resource *res)
674cb459498Sriastradh {
675cb459498Sriastradh 	struct vmw_user_shader *ushader =
676cb459498Sriastradh 		container_of(res, struct vmw_user_shader, shader.res);
677cb459498Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
678cb459498Sriastradh 
679cb459498Sriastradh 	ttm_base_object_kfree(ushader, base);
680cb459498Sriastradh 	ttm_mem_global_free(vmw_mem_glob(dev_priv),
681cb459498Sriastradh 			    vmw_user_shader_size);
682cb459498Sriastradh }
683cb459498Sriastradh 
vmw_shader_free(struct vmw_resource * res)684d350ecf5Sriastradh static void vmw_shader_free(struct vmw_resource *res)
685d350ecf5Sriastradh {
686d350ecf5Sriastradh 	struct vmw_shader *shader = vmw_res_to_shader(res);
687d350ecf5Sriastradh 	struct vmw_private *dev_priv = res->dev_priv;
688d350ecf5Sriastradh 
689d350ecf5Sriastradh 	kfree(shader);
690d350ecf5Sriastradh 	ttm_mem_global_free(vmw_mem_glob(dev_priv),
691d350ecf5Sriastradh 			    vmw_shader_size);
692d350ecf5Sriastradh }
693d350ecf5Sriastradh 
694cb459498Sriastradh /**
695cb459498Sriastradh  * This function is called when user space has no more references on the
696cb459498Sriastradh  * base object. It releases the base-object's reference on the resource object.
697cb459498Sriastradh  */
698cb459498Sriastradh 
vmw_user_shader_base_release(struct ttm_base_object ** p_base)699cb459498Sriastradh static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
700cb459498Sriastradh {
701cb459498Sriastradh 	struct ttm_base_object *base = *p_base;
702cb459498Sriastradh 	struct vmw_resource *res = vmw_user_shader_base_to_res(base);
703cb459498Sriastradh 
704cb459498Sriastradh 	*p_base = NULL;
705cb459498Sriastradh 	vmw_resource_unreference(&res);
706cb459498Sriastradh }
707cb459498Sriastradh 
vmw_shader_destroy_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)708cb459498Sriastradh int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
709cb459498Sriastradh 			      struct drm_file *file_priv)
710cb459498Sriastradh {
711cb459498Sriastradh 	struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
712cb459498Sriastradh 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
713cb459498Sriastradh 
714cb459498Sriastradh 	return ttm_ref_object_base_unref(tfile, arg->handle,
715cb459498Sriastradh 					 TTM_REF_USAGE);
716cb459498Sriastradh }
717cb459498Sriastradh 
vmw_user_shader_alloc(struct vmw_private * dev_priv,struct vmw_buffer_object * buffer,size_t shader_size,size_t offset,SVGA3dShaderType shader_type,uint8_t num_input_sig,uint8_t num_output_sig,struct ttm_object_file * tfile,u32 * handle)718d350ecf5Sriastradh static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
719*677dec6eSriastradh 				 struct vmw_buffer_object *buffer,
720cb459498Sriastradh 				 size_t shader_size,
721cb459498Sriastradh 				 size_t offset,
722cb459498Sriastradh 				 SVGA3dShaderType shader_type,
723d350ecf5Sriastradh 				 uint8_t num_input_sig,
724d350ecf5Sriastradh 				 uint8_t num_output_sig,
725cb459498Sriastradh 				 struct ttm_object_file *tfile,
726cb459498Sriastradh 				 u32 *handle)
727cb459498Sriastradh {
728cb459498Sriastradh 	struct vmw_user_shader *ushader;
729cb459498Sriastradh 	struct vmw_resource *res, *tmp;
730*677dec6eSriastradh 	struct ttm_operation_ctx ctx = {
731*677dec6eSriastradh 		.interruptible = true,
732*677dec6eSriastradh 		.no_wait_gpu = false
733*677dec6eSriastradh 	};
734cb459498Sriastradh 	int ret;
735cb459498Sriastradh 
736cb459498Sriastradh 	if (unlikely(vmw_user_shader_size == 0))
737cb459498Sriastradh 		vmw_user_shader_size =
738*677dec6eSriastradh 			ttm_round_pot(sizeof(struct vmw_user_shader)) +
739*677dec6eSriastradh 			VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE;
740cb459498Sriastradh 
741cb459498Sriastradh 	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
742cb459498Sriastradh 				   vmw_user_shader_size,
743*677dec6eSriastradh 				   &ctx);
744cb459498Sriastradh 	if (unlikely(ret != 0)) {
745cb459498Sriastradh 		if (ret != -ERESTARTSYS)
746cb459498Sriastradh 			DRM_ERROR("Out of graphics memory for shader "
747cb459498Sriastradh 				  "creation.\n");
748cb459498Sriastradh 		goto out;
749cb459498Sriastradh 	}
750cb459498Sriastradh 
751cb459498Sriastradh 	ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
752*677dec6eSriastradh 	if (unlikely(!ushader)) {
753cb459498Sriastradh 		ttm_mem_global_free(vmw_mem_glob(dev_priv),
754cb459498Sriastradh 				    vmw_user_shader_size);
755cb459498Sriastradh 		ret = -ENOMEM;
756cb459498Sriastradh 		goto out;
757cb459498Sriastradh 	}
758cb459498Sriastradh 
759cb459498Sriastradh 	res = &ushader->shader.res;
760cb459498Sriastradh 	ushader->base.shareable = false;
761cb459498Sriastradh 	ushader->base.tfile = NULL;
762cb459498Sriastradh 
763cb459498Sriastradh 	/*
764cb459498Sriastradh 	 * From here on, the destructor takes over resource freeing.
765cb459498Sriastradh 	 */
766cb459498Sriastradh 
767cb459498Sriastradh 	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
768d350ecf5Sriastradh 				 offset, shader_type, num_input_sig,
769d350ecf5Sriastradh 				 num_output_sig, buffer,
770cb459498Sriastradh 				 vmw_user_shader_free);
771cb459498Sriastradh 	if (unlikely(ret != 0))
772cb459498Sriastradh 		goto out;
773cb459498Sriastradh 
774cb459498Sriastradh 	tmp = vmw_resource_reference(res);
775cb459498Sriastradh 	ret = ttm_base_object_init(tfile, &ushader->base, false,
776cb459498Sriastradh 				   VMW_RES_SHADER,
777cb459498Sriastradh 				   &vmw_user_shader_base_release, NULL);
778cb459498Sriastradh 
779cb459498Sriastradh 	if (unlikely(ret != 0)) {
780cb459498Sriastradh 		vmw_resource_unreference(&tmp);
781cb459498Sriastradh 		goto out_err;
782cb459498Sriastradh 	}
783cb459498Sriastradh 
784cb459498Sriastradh 	if (handle)
785*677dec6eSriastradh 		*handle = ushader->base.handle;
786cb459498Sriastradh out_err:
787cb459498Sriastradh 	vmw_resource_unreference(&res);
788cb459498Sriastradh out:
789cb459498Sriastradh 	return ret;
790cb459498Sriastradh }
791cb459498Sriastradh 
792cb459498Sriastradh 
vmw_shader_alloc(struct vmw_private * dev_priv,struct vmw_buffer_object * buffer,size_t shader_size,size_t offset,SVGA3dShaderType shader_type)793d350ecf5Sriastradh static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
794*677dec6eSriastradh 					     struct vmw_buffer_object *buffer,
795d350ecf5Sriastradh 					     size_t shader_size,
796d350ecf5Sriastradh 					     size_t offset,
797d350ecf5Sriastradh 					     SVGA3dShaderType shader_type)
798d350ecf5Sriastradh {
799d350ecf5Sriastradh 	struct vmw_shader *shader;
800d350ecf5Sriastradh 	struct vmw_resource *res;
801*677dec6eSriastradh 	struct ttm_operation_ctx ctx = {
802*677dec6eSriastradh 		.interruptible = true,
803*677dec6eSriastradh 		.no_wait_gpu = false
804*677dec6eSriastradh 	};
805d350ecf5Sriastradh 	int ret;
806d350ecf5Sriastradh 
807d350ecf5Sriastradh 	if (unlikely(vmw_shader_size == 0))
808d350ecf5Sriastradh 		vmw_shader_size =
809*677dec6eSriastradh 			ttm_round_pot(sizeof(struct vmw_shader)) +
810*677dec6eSriastradh 			VMW_IDA_ACC_SIZE;
811d350ecf5Sriastradh 
812d350ecf5Sriastradh 	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
813d350ecf5Sriastradh 				   vmw_shader_size,
814*677dec6eSriastradh 				   &ctx);
815d350ecf5Sriastradh 	if (unlikely(ret != 0)) {
816d350ecf5Sriastradh 		if (ret != -ERESTARTSYS)
817d350ecf5Sriastradh 			DRM_ERROR("Out of graphics memory for shader "
818d350ecf5Sriastradh 				  "creation.\n");
819d350ecf5Sriastradh 		goto out_err;
820d350ecf5Sriastradh 	}
821d350ecf5Sriastradh 
822d350ecf5Sriastradh 	shader = kzalloc(sizeof(*shader), GFP_KERNEL);
823*677dec6eSriastradh 	if (unlikely(!shader)) {
824d350ecf5Sriastradh 		ttm_mem_global_free(vmw_mem_glob(dev_priv),
825d350ecf5Sriastradh 				    vmw_shader_size);
826d350ecf5Sriastradh 		ret = -ENOMEM;
827d350ecf5Sriastradh 		goto out_err;
828d350ecf5Sriastradh 	}
829d350ecf5Sriastradh 
830d350ecf5Sriastradh 	res = &shader->res;
831d350ecf5Sriastradh 
832d350ecf5Sriastradh 	/*
833d350ecf5Sriastradh 	 * From here on, the destructor takes over resource freeing.
834d350ecf5Sriastradh 	 */
835d350ecf5Sriastradh 	ret = vmw_gb_shader_init(dev_priv, res, shader_size,
836d350ecf5Sriastradh 				 offset, shader_type, 0, 0, buffer,
837d350ecf5Sriastradh 				 vmw_shader_free);
838d350ecf5Sriastradh 
839d350ecf5Sriastradh out_err:
840d350ecf5Sriastradh 	return ret ? ERR_PTR(ret) : res;
841d350ecf5Sriastradh }
842d350ecf5Sriastradh 
843d350ecf5Sriastradh 
vmw_shader_define(struct drm_device * dev,struct drm_file * file_priv,enum drm_vmw_shader_type shader_type_drm,u32 buffer_handle,size_t size,size_t offset,uint8_t num_input_sig,uint8_t num_output_sig,uint32_t * shader_handle)844d350ecf5Sriastradh static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
845d350ecf5Sriastradh 			     enum drm_vmw_shader_type shader_type_drm,
846d350ecf5Sriastradh 			     u32 buffer_handle, size_t size, size_t offset,
847d350ecf5Sriastradh 			     uint8_t num_input_sig, uint8_t num_output_sig,
848d350ecf5Sriastradh 			     uint32_t *shader_handle)
849cb459498Sriastradh {
850cb459498Sriastradh 	struct vmw_private *dev_priv = vmw_priv(dev);
851cb459498Sriastradh 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
852*677dec6eSriastradh 	struct vmw_buffer_object *buffer = NULL;
853cb459498Sriastradh 	SVGA3dShaderType shader_type;
854cb459498Sriastradh 	int ret;
855cb459498Sriastradh 
856d350ecf5Sriastradh 	if (buffer_handle != SVGA3D_INVALID_ID) {
857*677dec6eSriastradh 		ret = vmw_user_bo_lookup(tfile, buffer_handle,
858d350ecf5Sriastradh 					     &buffer, NULL);
859cb459498Sriastradh 		if (unlikely(ret != 0)) {
860*677dec6eSriastradh 			VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
861cb459498Sriastradh 			return ret;
862cb459498Sriastradh 		}
863cb459498Sriastradh 
864cb459498Sriastradh 		if ((u64)buffer->base.num_pages * PAGE_SIZE <
865d350ecf5Sriastradh 		    (u64)size + (u64)offset) {
866*677dec6eSriastradh 			VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
867cb459498Sriastradh 			ret = -EINVAL;
868cb459498Sriastradh 			goto out_bad_arg;
869cb459498Sriastradh 		}
870cb459498Sriastradh 	}
871cb459498Sriastradh 
872d350ecf5Sriastradh 	switch (shader_type_drm) {
873cb459498Sriastradh 	case drm_vmw_shader_type_vs:
874cb459498Sriastradh 		shader_type = SVGA3D_SHADERTYPE_VS;
875cb459498Sriastradh 		break;
876cb459498Sriastradh 	case drm_vmw_shader_type_ps:
877cb459498Sriastradh 		shader_type = SVGA3D_SHADERTYPE_PS;
878cb459498Sriastradh 		break;
879cb459498Sriastradh 	default:
880*677dec6eSriastradh 		VMW_DEBUG_USER("Illegal shader type.\n");
881cb459498Sriastradh 		ret = -EINVAL;
882cb459498Sriastradh 		goto out_bad_arg;
883cb459498Sriastradh 	}
884cb459498Sriastradh 
885cb459498Sriastradh 	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
886cb459498Sriastradh 	if (unlikely(ret != 0))
887cb459498Sriastradh 		goto out_bad_arg;
888cb459498Sriastradh 
889d350ecf5Sriastradh 	ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
890d350ecf5Sriastradh 				    shader_type, num_input_sig,
891d350ecf5Sriastradh 				    num_output_sig, tfile, shader_handle);
892cb459498Sriastradh 
893cb459498Sriastradh 	ttm_read_unlock(&dev_priv->reservation_sem);
894cb459498Sriastradh out_bad_arg:
895*677dec6eSriastradh 	vmw_bo_unreference(&buffer);
896cb459498Sriastradh 	return ret;
897cb459498Sriastradh }
898cb459498Sriastradh 
899cb459498Sriastradh /**
900d350ecf5Sriastradh  * vmw_shader_id_ok - Check whether a compat shader user key and
901d350ecf5Sriastradh  * shader type are within valid bounds.
902cb459498Sriastradh  *
903d350ecf5Sriastradh  * @user_key: User space id of the shader.
904d350ecf5Sriastradh  * @shader_type: Shader type.
905cb459498Sriastradh  *
906d350ecf5Sriastradh  * Returns true if valid false if not.
907cb459498Sriastradh  */
vmw_shader_id_ok(u32 user_key,SVGA3dShaderType shader_type)908d350ecf5Sriastradh static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
909cb459498Sriastradh {
910d350ecf5Sriastradh 	return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
911cb459498Sriastradh }
912cb459498Sriastradh 
913cb459498Sriastradh /**
914d350ecf5Sriastradh  * vmw_shader_key - Compute a hash key suitable for a compat shader.
915cb459498Sriastradh  *
916d350ecf5Sriastradh  * @user_key: User space id of the shader.
917d350ecf5Sriastradh  * @shader_type: Shader type.
918cb459498Sriastradh  *
919d350ecf5Sriastradh  * Returns a hash key suitable for a command buffer managed resource
920d350ecf5Sriastradh  * manager hash table.
921cb459498Sriastradh  */
vmw_shader_key(u32 user_key,SVGA3dShaderType shader_type)922d350ecf5Sriastradh static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
923cb459498Sriastradh {
924d350ecf5Sriastradh 	return user_key | (shader_type << 20);
925cb459498Sriastradh }
926cb459498Sriastradh 
927cb459498Sriastradh /**
928d350ecf5Sriastradh  * vmw_shader_remove - Stage a compat shader for removal.
929cb459498Sriastradh  *
930d350ecf5Sriastradh  * @man: Pointer to the compat shader manager identifying the shader namespace.
931cb459498Sriastradh  * @user_key: The key that is used to identify the shader. The key is
932cb459498Sriastradh  * unique to the shader type.
933cb459498Sriastradh  * @shader_type: Shader type.
934d350ecf5Sriastradh  * @list: Caller's list of staged command buffer resource actions.
935cb459498Sriastradh  */
vmw_shader_remove(struct vmw_cmdbuf_res_manager * man,u32 user_key,SVGA3dShaderType shader_type,struct list_head * list)936d350ecf5Sriastradh int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
937cb459498Sriastradh 		      u32 user_key, SVGA3dShaderType shader_type,
938cb459498Sriastradh 		      struct list_head *list)
939cb459498Sriastradh {
940d350ecf5Sriastradh 	struct vmw_resource *dummy;
941cb459498Sriastradh 
942d350ecf5Sriastradh 	if (!vmw_shader_id_ok(user_key, shader_type))
943cb459498Sriastradh 		return -EINVAL;
944cb459498Sriastradh 
945d350ecf5Sriastradh 	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
946d350ecf5Sriastradh 				     vmw_shader_key(user_key, shader_type),
947d350ecf5Sriastradh 				     list, &dummy);
948cb459498Sriastradh }
949cb459498Sriastradh 
950cb459498Sriastradh /**
951d350ecf5Sriastradh  * vmw_compat_shader_add - Create a compat shader and stage it for addition
952d350ecf5Sriastradh  * as a command buffer managed resource.
953cb459498Sriastradh  *
954d350ecf5Sriastradh  * @man: Pointer to the compat shader manager identifying the shader namespace.
955cb459498Sriastradh  * @user_key: The key that is used to identify the shader. The key is
956cb459498Sriastradh  * unique to the shader type.
957cb459498Sriastradh  * @bytecode: Pointer to the bytecode of the shader.
958cb459498Sriastradh  * @shader_type: Shader type.
959cb459498Sriastradh  * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is
960cb459498Sriastradh  * to be created with.
961d350ecf5Sriastradh  * @list: Caller's list of staged command buffer resource actions.
962cb459498Sriastradh  *
963cb459498Sriastradh  */
vmw_compat_shader_add(struct vmw_private * dev_priv,struct vmw_cmdbuf_res_manager * man,u32 user_key,const void * bytecode,SVGA3dShaderType shader_type,size_t size,struct list_head * list)964d350ecf5Sriastradh int vmw_compat_shader_add(struct vmw_private *dev_priv,
965d350ecf5Sriastradh 			  struct vmw_cmdbuf_res_manager *man,
966cb459498Sriastradh 			  u32 user_key, const void *bytecode,
967cb459498Sriastradh 			  SVGA3dShaderType shader_type,
968cb459498Sriastradh 			  size_t size,
969cb459498Sriastradh 			  struct list_head *list)
970cb459498Sriastradh {
971*677dec6eSriastradh 	struct ttm_operation_ctx ctx = { false, true };
972*677dec6eSriastradh 	struct vmw_buffer_object *buf;
973cb459498Sriastradh 	struct ttm_bo_kmap_obj map;
974cb459498Sriastradh 	bool is_iomem;
975cb459498Sriastradh 	int ret;
976d350ecf5Sriastradh 	struct vmw_resource *res;
977cb459498Sriastradh 
978d350ecf5Sriastradh 	if (!vmw_shader_id_ok(user_key, shader_type))
979cb459498Sriastradh 		return -EINVAL;
980cb459498Sriastradh 
981cb459498Sriastradh 	/* Allocate and pin a DMA buffer */
982cb459498Sriastradh 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
983*677dec6eSriastradh 	if (unlikely(!buf))
984cb459498Sriastradh 		return -ENOMEM;
985cb459498Sriastradh 
986*677dec6eSriastradh 	ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_ne_placement,
987*677dec6eSriastradh 			      true, vmw_bo_bo_free);
988cb459498Sriastradh 	if (unlikely(ret != 0))
989cb459498Sriastradh 		goto out;
990cb459498Sriastradh 
991*677dec6eSriastradh 	ret = ttm_bo_reserve(&buf->base, false, true, NULL);
992cb459498Sriastradh 	if (unlikely(ret != 0))
993cb459498Sriastradh 		goto no_reserve;
994cb459498Sriastradh 
995cb459498Sriastradh 	/* Map and copy shader bytecode. */
996cb459498Sriastradh 	ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT,
997cb459498Sriastradh 			  &map);
998cb459498Sriastradh 	if (unlikely(ret != 0)) {
999cb459498Sriastradh 		ttm_bo_unreserve(&buf->base);
1000cb459498Sriastradh 		goto no_reserve;
1001cb459498Sriastradh 	}
1002cb459498Sriastradh 
1003cb459498Sriastradh 	memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
1004cb459498Sriastradh 	WARN_ON(is_iomem);
1005cb459498Sriastradh 
1006cb459498Sriastradh 	ttm_bo_kunmap(&map);
1007*677dec6eSriastradh 	ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx);
1008cb459498Sriastradh 	WARN_ON(ret != 0);
1009cb459498Sriastradh 	ttm_bo_unreserve(&buf->base);
1010cb459498Sriastradh 
1011d350ecf5Sriastradh 	res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
1012cb459498Sriastradh 	if (unlikely(ret != 0))
1013cb459498Sriastradh 		goto no_reserve;
1014cb459498Sriastradh 
1015d350ecf5Sriastradh 	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
1016d350ecf5Sriastradh 				 vmw_shader_key(user_key, shader_type),
1017d350ecf5Sriastradh 				 res, list);
1018d350ecf5Sriastradh 	vmw_resource_unreference(&res);
1019cb459498Sriastradh no_reserve:
1020*677dec6eSriastradh 	vmw_bo_unreference(&buf);
1021cb459498Sriastradh out:
1022cb459498Sriastradh 	return ret;
1023cb459498Sriastradh }
1024cb459498Sriastradh 
1025cb459498Sriastradh /**
1026d350ecf5Sriastradh  * vmw_shader_lookup - Look up a compat shader
1027cb459498Sriastradh  *
1028d350ecf5Sriastradh  * @man: Pointer to the command buffer managed resource manager identifying
1029d350ecf5Sriastradh  * the shader namespace.
1030d350ecf5Sriastradh  * @user_key: The user space id of the shader.
1031d350ecf5Sriastradh  * @shader_type: The shader type.
1032cb459498Sriastradh  *
1033d350ecf5Sriastradh  * Returns a refcounted pointer to a struct vmw_resource if the shader was
1034d350ecf5Sriastradh  * found. An error pointer otherwise.
1035cb459498Sriastradh  */
1036d350ecf5Sriastradh struct vmw_resource *
vmw_shader_lookup(struct vmw_cmdbuf_res_manager * man,u32 user_key,SVGA3dShaderType shader_type)1037d350ecf5Sriastradh vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
1038d350ecf5Sriastradh 		  u32 user_key,
1039d350ecf5Sriastradh 		  SVGA3dShaderType shader_type)
1040cb459498Sriastradh {
1041d350ecf5Sriastradh 	if (!vmw_shader_id_ok(user_key, shader_type))
1042d350ecf5Sriastradh 		return ERR_PTR(-EINVAL);
1043cb459498Sriastradh 
1044d350ecf5Sriastradh 	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
1045d350ecf5Sriastradh 				     vmw_shader_key(user_key, shader_type));
1046cb459498Sriastradh }
1047cb459498Sriastradh 
vmw_shader_define_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)1048d350ecf5Sriastradh int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
1049d350ecf5Sriastradh 			     struct drm_file *file_priv)
1050cb459498Sriastradh {
1051d350ecf5Sriastradh 	struct drm_vmw_shader_create_arg *arg =
1052d350ecf5Sriastradh 		(struct drm_vmw_shader_create_arg *)data;
1053cb459498Sriastradh 
1054d350ecf5Sriastradh 	return vmw_shader_define(dev, file_priv, arg->shader_type,
1055d350ecf5Sriastradh 				 arg->buffer_handle,
1056d350ecf5Sriastradh 				 arg->size, arg->offset,
1057d350ecf5Sriastradh 				 0, 0,
1058d350ecf5Sriastradh 				 &arg->shader_handle);
1059cb459498Sriastradh }
1060