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