1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
4 * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 #include <drm/ttm/ttm_placement.h>
30 #include "vmwgfx_binding.h"
31 #include "vmwgfx_bo.h"
32 #include "vmwgfx_drv.h"
33 #include "vmwgfx_resource_priv.h"
36 struct vmw_resource res
;
37 SVGA3dShaderType type
;
39 uint8_t num_input_sig
;
40 uint8_t num_output_sig
;
43 struct vmw_user_shader
{
44 struct ttm_base_object base
;
45 struct vmw_shader shader
;
48 struct vmw_dx_shader
{
49 struct vmw_resource res
;
50 struct vmw_resource
*ctx
;
51 struct vmw_resource
*cotable
;
54 struct list_head cotable_head
;
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
);
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
,
66 struct ttm_validate_buffer
*val_buf
);
67 static int vmw_gb_shader_destroy(struct vmw_resource
*res
);
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
,
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
);
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
86 const struct vmw_user_resource_conv
*user_shader_converter
=
90 static const struct vmw_res_func vmw_gb_shader_func
= {
91 .res_type
= vmw_res_shader
,
92 .needs_guest_memory
= true,
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
105 static const struct vmw_res_func vmw_dx_shader_func
= {
106 .res_type
= vmw_res_shader
,
107 .needs_guest_memory
= true,
111 .type_name
= "dx shaders",
112 .domain
= VMW_BO_DOMAIN_MOB
,
113 .busy_domain
= VMW_BO_DOMAIN_MOB
,
114 .create
= vmw_dx_shader_create
,
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.
121 .bind
= vmw_dx_shader_bind
,
122 .unbind
= vmw_dx_shader_unbind
,
123 .commit_notify
= vmw_dx_shader_commit_notify
,
130 static inline struct vmw_shader
*
131 vmw_res_to_shader(struct vmw_resource
*res
)
133 return container_of(res
, struct vmw_shader
, res
);
137 * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
138 * struct vmw_dx_shader
140 * @res: Pointer to the struct vmw_resource.
142 static inline struct vmw_dx_shader
*
143 vmw_res_to_dx_shader(struct vmw_resource
*res
)
145 return container_of(res
, struct vmw_dx_shader
, res
);
148 static void vmw_hw_shader_destroy(struct vmw_resource
*res
)
150 if (likely(res
->func
->destroy
))
151 (void) res
->func
->destroy(res
);
157 static int vmw_gb_shader_init(struct vmw_private
*dev_priv
,
158 struct vmw_resource
*res
,
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
))
167 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
170 ret
= vmw_resource_init(dev_priv
, res
, true, res_free
,
171 &vmw_gb_shader_func
);
173 if (unlikely(ret
!= 0)) {
181 res
->guest_memory_size
= size
;
183 res
->guest_memory_bo
= vmw_bo_reference(byte_code
);
184 res
->guest_memory_offset
= offset
;
188 shader
->num_input_sig
= num_input_sig
;
189 shader
->num_output_sig
= num_output_sig
;
191 res
->hw_destroy
= vmw_hw_shader_destroy
;
199 static int vmw_gb_shader_create(struct vmw_resource
*res
)
201 struct vmw_private
*dev_priv
= res
->dev_priv
;
202 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
205 SVGA3dCmdHeader header
;
206 SVGA3dCmdDefineGBShader body
;
209 if (likely(res
->id
!= -1))
212 ret
= vmw_resource_alloc_id(res
);
213 if (unlikely(ret
!= 0)) {
214 DRM_ERROR("Failed to allocate a shader id.\n");
218 if (unlikely(res
->id
>= VMWGFX_NUM_GB_SHADER
)) {
223 cmd
= VMW_CMD_RESERVE(dev_priv
, sizeof(*cmd
));
224 if (unlikely(cmd
== NULL
)) {
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
);
240 vmw_resource_release_id(res
);
245 static int vmw_gb_shader_bind(struct vmw_resource
*res
,
246 struct ttm_validate_buffer
*val_buf
)
248 struct vmw_private
*dev_priv
= res
->dev_priv
;
250 SVGA3dCmdHeader header
;
251 SVGA3dCmdBindGBShader body
;
253 struct ttm_buffer_object
*bo
= val_buf
->bo
;
255 BUG_ON(bo
->resource
->mem_type
!= VMW_PL_MOB
);
257 cmd
= VMW_CMD_RESERVE(dev_priv
, sizeof(*cmd
));
258 if (unlikely(cmd
== NULL
))
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
));
272 static int vmw_gb_shader_unbind(struct vmw_resource
*res
,
274 struct ttm_validate_buffer
*val_buf
)
276 struct vmw_private
*dev_priv
= res
->dev_priv
;
278 SVGA3dCmdHeader header
;
279 SVGA3dCmdBindGBShader body
;
281 struct vmw_fence_obj
*fence
;
283 BUG_ON(res
->guest_memory_bo
->tbo
.resource
->mem_type
!= VMW_PL_MOB
);
285 cmd
= VMW_CMD_RESERVE(dev_priv
, sizeof(*cmd
));
286 if (unlikely(cmd
== NULL
))
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
));
297 * Create a fence object and fence the backup buffer.
300 (void) vmw_execbuf_fence_commands(NULL
, dev_priv
,
303 vmw_bo_fence_single(val_buf
->bo
, fence
);
305 if (likely(fence
!= NULL
))
306 vmw_fence_obj_unreference(&fence
);
311 static int vmw_gb_shader_destroy(struct vmw_resource
*res
)
313 struct vmw_private
*dev_priv
= res
->dev_priv
;
315 SVGA3dCmdHeader header
;
316 SVGA3dCmdDestroyGBShader body
;
319 if (likely(res
->id
== -1))
322 mutex_lock(&dev_priv
->binding_mutex
);
323 vmw_binding_res_list_scrub(&res
->binding_head
);
325 cmd
= VMW_CMD_RESERVE(dev_priv
, sizeof(*cmd
));
326 if (unlikely(cmd
== NULL
)) {
327 mutex_unlock(&dev_priv
->binding_mutex
);
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
);
347 * vmw_dx_shader_commit_notify - Notify that a shader operation has been
348 * committed to hardware from a user-supplied command stream.
350 * @res: Pointer to the shader resource.
351 * @state: Indicating whether a creation or removal has been committed.
354 static void vmw_dx_shader_commit_notify(struct vmw_resource
*res
,
355 enum vmw_cmdbuf_res_state state
)
357 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
358 struct vmw_private
*dev_priv
= res
->dev_priv
;
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
);
368 mutex_lock(&dev_priv
->binding_mutex
);
369 list_del_init(&shader
->cotable_head
);
370 shader
->committed
= false;
372 mutex_unlock(&dev_priv
->binding_mutex
);
377 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
379 * @res: The shader resource
381 * This function reverts a scrub operation.
383 static int vmw_dx_shader_unscrub(struct vmw_resource
*res
)
385 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
386 struct vmw_private
*dev_priv
= res
->dev_priv
;
388 SVGA3dCmdHeader header
;
389 SVGA3dCmdDXBindShader body
;
392 if (!list_empty(&shader
->cotable_head
) || !shader
->committed
)
395 cmd
= VMW_CMD_CTX_RESERVE(dev_priv
, sizeof(*cmd
), shader
->ctx
->id
);
396 if (unlikely(cmd
== NULL
))
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
));
407 vmw_cotable_add_resource(shader
->cotable
, &shader
->cotable_head
);
413 * vmw_dx_shader_create - The DX shader create callback
415 * @res: The DX shader resource
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.
420 static int vmw_dx_shader_create(struct vmw_resource
*res
)
422 struct vmw_private
*dev_priv
= res
->dev_priv
;
423 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
426 WARN_ON_ONCE(!shader
->committed
);
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
);
434 res
->id
= shader
->id
;
439 * vmw_dx_shader_bind - The DX shader bind callback
441 * @res: The DX shader resource
442 * @val_buf: Pointer to the validate buffer.
445 static int vmw_dx_shader_bind(struct vmw_resource
*res
,
446 struct ttm_validate_buffer
*val_buf
)
448 struct vmw_private
*dev_priv
= res
->dev_priv
;
449 struct ttm_buffer_object
*bo
= val_buf
->bo
;
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
);
460 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
462 * @res: The shader resource
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.
469 static int vmw_dx_shader_scrub(struct vmw_resource
*res
)
471 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
472 struct vmw_private
*dev_priv
= res
->dev_priv
;
474 SVGA3dCmdHeader header
;
475 SVGA3dCmdDXBindShader body
;
478 if (list_empty(&shader
->cotable_head
))
481 WARN_ON_ONCE(!shader
->committed
);
482 cmd
= VMW_CMD_RESERVE(dev_priv
, sizeof(*cmd
));
483 if (unlikely(cmd
== NULL
))
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
));
494 list_del_init(&shader
->cotable_head
);
500 * vmw_dx_shader_unbind - The dx shader unbind callback.
502 * @res: The shader resource
503 * @readback: Whether this is a readback unbind. Currently unused.
504 * @val_buf: MOB buffer information.
506 static int vmw_dx_shader_unbind(struct vmw_resource
*res
,
508 struct ttm_validate_buffer
*val_buf
)
510 struct vmw_private
*dev_priv
= res
->dev_priv
;
511 struct vmw_fence_obj
*fence
;
514 BUG_ON(res
->guest_memory_bo
->tbo
.resource
->mem_type
!= VMW_PL_MOB
);
516 mutex_lock(&dev_priv
->binding_mutex
);
517 ret
= vmw_dx_shader_scrub(res
);
518 mutex_unlock(&dev_priv
->binding_mutex
);
523 (void) vmw_execbuf_fence_commands(NULL
, dev_priv
,
525 vmw_bo_fence_single(val_buf
->bo
, fence
);
527 if (likely(fence
!= NULL
))
528 vmw_fence_obj_unreference(&fence
);
534 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
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.
541 * Scrubs all shader MOBs so that any subsequent shader unbind or shader
542 * destroy operation won't need to swap in the context.
544 void vmw_dx_shader_cotable_list_scrub(struct vmw_private
*dev_priv
,
545 struct list_head
*list
,
548 struct vmw_dx_shader
*entry
, *next
;
550 lockdep_assert_held_once(&dev_priv
->binding_mutex
);
552 list_for_each_entry_safe(entry
, next
, list
, cotable_head
) {
553 WARN_ON(vmw_dx_shader_scrub(&entry
->res
));
555 entry
->committed
= false;
560 * vmw_dx_shader_res_free - The DX shader free callback
562 * @res: The shader resource
564 * Frees the DX shader resource.
566 static void vmw_dx_shader_res_free(struct vmw_resource
*res
)
568 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
570 vmw_resource_unreference(&shader
->cotable
);
575 * vmw_dx_shader_add - Add a shader resource as a command buffer managed
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.
584 int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager
*man
,
585 struct vmw_resource
*ctx
,
587 SVGA3dShaderType shader_type
,
588 struct list_head
*list
)
590 struct vmw_dx_shader
*shader
;
591 struct vmw_resource
*res
;
592 struct vmw_private
*dev_priv
= ctx
->dev_priv
;
595 if (!vmw_shader_id_ok(user_key
, shader_type
))
598 shader
= kmalloc(sizeof(*shader
), GFP_KERNEL
);
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
);
613 goto out_resource_init
;
616 * The user_key name-space is not per shader type for DX shaders,
617 * so when hashing, use a single zero shader type.
619 ret
= vmw_cmdbuf_res_add(man
, vmw_cmdbuf_res_shader
,
620 vmw_shader_key(user_key
, 0),
623 goto out_resource_init
;
625 res
->id
= shader
->id
;
626 res
->hw_destroy
= vmw_hw_shader_destroy
;
629 vmw_resource_unreference(&res
);
637 * User-space shader management:
640 static struct vmw_resource
*
641 vmw_user_shader_base_to_res(struct ttm_base_object
*base
)
643 return &(container_of(base
, struct vmw_user_shader
, base
)->
647 static void vmw_user_shader_free(struct vmw_resource
*res
)
649 struct vmw_user_shader
*ushader
=
650 container_of(res
, struct vmw_user_shader
, shader
.res
);
652 ttm_base_object_kfree(ushader
, base
);
655 static void vmw_shader_free(struct vmw_resource
*res
)
657 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
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.
667 static void vmw_user_shader_base_release(struct ttm_base_object
**p_base
)
669 struct ttm_base_object
*base
= *p_base
;
670 struct vmw_resource
*res
= vmw_user_shader_base_to_res(base
);
673 vmw_resource_unreference(&res
);
676 int vmw_shader_destroy_ioctl(struct drm_device
*dev
, void *data
,
677 struct drm_file
*file_priv
)
679 struct drm_vmw_shader_arg
*arg
= (struct drm_vmw_shader_arg
*)data
;
680 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
682 return ttm_ref_object_base_unref(tfile
, arg
->handle
);
685 static int vmw_user_shader_alloc(struct vmw_private
*dev_priv
,
686 struct vmw_bo
*buffer
,
689 SVGA3dShaderType shader_type
,
690 uint8_t num_input_sig
,
691 uint8_t num_output_sig
,
692 struct ttm_object_file
*tfile
,
695 struct vmw_user_shader
*ushader
;
696 struct vmw_resource
*res
, *tmp
;
699 ushader
= kzalloc(sizeof(*ushader
), GFP_KERNEL
);
700 if (unlikely(!ushader
)) {
705 res
= &ushader
->shader
.res
;
706 ushader
->base
.shareable
= false;
707 ushader
->base
.tfile
= NULL
;
710 * From here on, the destructor takes over resource freeing.
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))
720 tmp
= vmw_resource_reference(res
);
721 ret
= ttm_base_object_init(tfile
, &ushader
->base
, false,
723 &vmw_user_shader_base_release
);
725 if (unlikely(ret
!= 0)) {
726 vmw_resource_unreference(&tmp
);
731 *handle
= ushader
->base
.handle
;
733 vmw_resource_unreference(&res
);
739 static struct vmw_resource
*vmw_shader_alloc(struct vmw_private
*dev_priv
,
740 struct vmw_bo
*buffer
,
743 SVGA3dShaderType shader_type
)
745 struct vmw_shader
*shader
;
746 struct vmw_resource
*res
;
749 shader
= kzalloc(sizeof(*shader
), GFP_KERNEL
);
750 if (unlikely(!shader
)) {
758 * From here on, the destructor takes over resource freeing.
760 ret
= vmw_gb_shader_init(dev_priv
, res
, shader_size
,
761 offset
, shader_type
, 0, 0, buffer
,
765 return ret
? ERR_PTR(ret
) : res
;
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
)
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
;
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");
788 if ((u64
)buffer
->tbo
.base
.size
< (u64
)size
+ (u64
)offset
) {
789 VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
795 switch (shader_type_drm
) {
796 case drm_vmw_shader_type_vs
:
797 shader_type
= SVGA3D_SHADERTYPE_VS
;
799 case drm_vmw_shader_type_ps
:
800 shader_type
= SVGA3D_SHADERTYPE_PS
;
803 VMW_DEBUG_USER("Illegal shader type.\n");
808 ret
= vmw_user_shader_alloc(dev_priv
, buffer
, size
, offset
,
809 shader_type
, num_input_sig
,
810 num_output_sig
, tfile
, shader_handle
);
812 vmw_user_bo_unref(buffer
);
817 * vmw_shader_id_ok - Check whether a compat shader user key and
818 * shader type are within valid bounds.
820 * @user_key: User space id of the shader.
821 * @shader_type: Shader type.
823 * Returns true if valid false if not.
825 static bool vmw_shader_id_ok(u32 user_key
, SVGA3dShaderType shader_type
)
827 return user_key
<= ((1 << 20) - 1) && (unsigned) shader_type
< 16;
831 * vmw_shader_key - Compute a hash key suitable for a compat shader.
833 * @user_key: User space id of the shader.
834 * @shader_type: Shader type.
836 * Returns a hash key suitable for a command buffer managed resource
837 * manager hash table.
839 static u32
vmw_shader_key(u32 user_key
, SVGA3dShaderType shader_type
)
841 return user_key
| (shader_type
<< 20);
845 * vmw_shader_remove - Stage a compat shader for removal.
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.
853 int vmw_shader_remove(struct vmw_cmdbuf_res_manager
*man
,
854 u32 user_key
, SVGA3dShaderType shader_type
,
855 struct list_head
*list
)
857 struct vmw_resource
*dummy
;
859 if (!vmw_shader_id_ok(user_key
, shader_type
))
862 return vmw_cmdbuf_res_remove(man
, vmw_cmdbuf_res_shader
,
863 vmw_shader_key(user_key
, shader_type
),
868 * vmw_compat_shader_add - Create a compat shader and stage it for addition
869 * as a command buffer managed resource.
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.
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
,
886 struct list_head
*list
)
888 struct ttm_operation_ctx ctx
= { false, true };
890 struct ttm_bo_kmap_obj map
;
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
,
902 if (!vmw_shader_id_ok(user_key
, shader_type
))
905 ret
= vmw_bo_create(dev_priv
, &bo_params
, &buf
);
906 if (unlikely(ret
!= 0))
909 ret
= ttm_bo_reserve(&buf
->tbo
, false, true, NULL
);
910 if (unlikely(ret
!= 0))
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
);
920 memcpy(ttm_kmap_obj_virtual(&map
, &is_iomem
), bytecode
, size
);
924 ret
= ttm_bo_validate(&buf
->tbo
, &buf
->placement
, &ctx
);
926 ttm_bo_unreserve(&buf
->tbo
);
928 res
= vmw_shader_alloc(dev_priv
, buf
, size
, 0, shader_type
);
929 if (unlikely(ret
!= 0))
932 ret
= vmw_cmdbuf_res_add(man
, vmw_cmdbuf_res_shader
,
933 vmw_shader_key(user_key
, shader_type
),
935 vmw_resource_unreference(&res
);
937 vmw_bo_unreference(&buf
);
943 * vmw_shader_lookup - Look up a compat shader
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.
950 * Returns a refcounted pointer to a struct vmw_resource if the shader was
951 * found. An error pointer otherwise.
953 struct vmw_resource
*
954 vmw_shader_lookup(struct vmw_cmdbuf_res_manager
*man
,
956 SVGA3dShaderType shader_type
)
958 if (!vmw_shader_id_ok(user_key
, shader_type
))
959 return ERR_PTR(-EINVAL
);
961 return vmw_cmdbuf_res_lookup(man
, vmw_cmdbuf_res_shader
,
962 vmw_shader_key(user_key
, shader_type
));
965 int vmw_shader_define_ioctl(struct drm_device
*dev
, void *data
,
966 struct drm_file
*file_priv
)
968 struct drm_vmw_shader_create_arg
*arg
=
969 (struct drm_vmw_shader_create_arg
*)data
;
971 return vmw_shader_define(dev
, file_priv
, arg
->shader_type
,
973 arg
->size
, arg
->offset
,
975 &arg
->shader_handle
);