1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
4 * Copyright 2009-2015 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_drv.h"
31 #include "vmwgfx_resource_priv.h"
32 #include "vmwgfx_binding.h"
35 struct vmw_resource res
;
36 SVGA3dShaderType type
;
38 uint8_t num_input_sig
;
39 uint8_t num_output_sig
;
42 struct vmw_user_shader
{
43 struct ttm_base_object base
;
44 struct vmw_shader shader
;
47 struct vmw_dx_shader
{
48 struct vmw_resource res
;
49 struct vmw_resource
*ctx
;
50 struct vmw_resource
*cotable
;
53 struct list_head cotable_head
;
56 static uint64_t vmw_user_shader_size
;
57 static uint64_t vmw_shader_size
;
58 static size_t vmw_shader_dx_size
;
60 static void vmw_user_shader_free(struct vmw_resource
*res
);
61 static struct vmw_resource
*
62 vmw_user_shader_base_to_res(struct ttm_base_object
*base
);
64 static int vmw_gb_shader_create(struct vmw_resource
*res
);
65 static int vmw_gb_shader_bind(struct vmw_resource
*res
,
66 struct ttm_validate_buffer
*val_buf
);
67 static int vmw_gb_shader_unbind(struct vmw_resource
*res
,
69 struct ttm_validate_buffer
*val_buf
);
70 static int vmw_gb_shader_destroy(struct vmw_resource
*res
);
72 static int vmw_dx_shader_create(struct vmw_resource
*res
);
73 static int vmw_dx_shader_bind(struct vmw_resource
*res
,
74 struct ttm_validate_buffer
*val_buf
);
75 static int vmw_dx_shader_unbind(struct vmw_resource
*res
,
77 struct ttm_validate_buffer
*val_buf
);
78 static void vmw_dx_shader_commit_notify(struct vmw_resource
*res
,
79 enum vmw_cmdbuf_res_state state
);
80 static bool vmw_shader_id_ok(u32 user_key
, SVGA3dShaderType shader_type
);
81 static u32
vmw_shader_key(u32 user_key
, SVGA3dShaderType shader_type
);
82 static uint64_t vmw_user_shader_size
;
84 static const struct vmw_user_resource_conv user_shader_conv
= {
85 .object_type
= VMW_RES_SHADER
,
86 .base_obj_to_res
= vmw_user_shader_base_to_res
,
87 .res_free
= vmw_user_shader_free
90 const struct vmw_user_resource_conv
*user_shader_converter
=
94 static const struct vmw_res_func vmw_gb_shader_func
= {
95 .res_type
= vmw_res_shader
,
98 .type_name
= "guest backed shaders",
99 .backup_placement
= &vmw_mob_placement
,
100 .create
= vmw_gb_shader_create
,
101 .destroy
= vmw_gb_shader_destroy
,
102 .bind
= vmw_gb_shader_bind
,
103 .unbind
= vmw_gb_shader_unbind
106 static const struct vmw_res_func vmw_dx_shader_func
= {
107 .res_type
= vmw_res_shader
,
108 .needs_backup
= true,
110 .type_name
= "dx shaders",
111 .backup_placement
= &vmw_mob_placement
,
112 .create
= vmw_dx_shader_create
,
114 * The destroy callback is only called with a committed resource on
115 * context destroy, in which case we destroy the cotable anyway,
116 * so there's no need to destroy DX shaders separately.
119 .bind
= vmw_dx_shader_bind
,
120 .unbind
= vmw_dx_shader_unbind
,
121 .commit_notify
= vmw_dx_shader_commit_notify
,
128 static inline struct vmw_shader
*
129 vmw_res_to_shader(struct vmw_resource
*res
)
131 return container_of(res
, struct vmw_shader
, res
);
135 * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
136 * struct vmw_dx_shader
138 * @res: Pointer to the struct vmw_resource.
140 static inline struct vmw_dx_shader
*
141 vmw_res_to_dx_shader(struct vmw_resource
*res
)
143 return container_of(res
, struct vmw_dx_shader
, res
);
146 static void vmw_hw_shader_destroy(struct vmw_resource
*res
)
148 if (likely(res
->func
->destroy
))
149 (void) res
->func
->destroy(res
);
155 static int vmw_gb_shader_init(struct vmw_private
*dev_priv
,
156 struct vmw_resource
*res
,
159 SVGA3dShaderType type
,
160 uint8_t num_input_sig
,
161 uint8_t num_output_sig
,
162 struct vmw_buffer_object
*byte_code
,
163 void (*res_free
) (struct vmw_resource
*res
))
165 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
168 ret
= vmw_resource_init(dev_priv
, res
, true, res_free
,
169 &vmw_gb_shader_func
);
171 if (unlikely(ret
!= 0)) {
179 res
->backup_size
= size
;
181 res
->backup
= vmw_bo_reference(byte_code
);
182 res
->backup_offset
= offset
;
186 shader
->num_input_sig
= num_input_sig
;
187 shader
->num_output_sig
= num_output_sig
;
189 vmw_resource_activate(res
, vmw_hw_shader_destroy
);
197 static int vmw_gb_shader_create(struct vmw_resource
*res
)
199 struct vmw_private
*dev_priv
= res
->dev_priv
;
200 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
203 SVGA3dCmdHeader header
;
204 SVGA3dCmdDefineGBShader body
;
207 if (likely(res
->id
!= -1))
210 ret
= vmw_resource_alloc_id(res
);
211 if (unlikely(ret
!= 0)) {
212 DRM_ERROR("Failed to allocate a shader id.\n");
216 if (unlikely(res
->id
>= VMWGFX_NUM_GB_SHADER
)) {
221 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
222 if (unlikely(cmd
== NULL
)) {
223 DRM_ERROR("Failed reserving FIFO space for shader "
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_fifo_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
->mem
.mem_type
!= VMW_PL_MOB
);
257 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
258 if (unlikely(cmd
== NULL
)) {
259 DRM_ERROR("Failed reserving FIFO space for shader "
264 cmd
->header
.id
= SVGA_3D_CMD_BIND_GB_SHADER
;
265 cmd
->header
.size
= sizeof(cmd
->body
);
266 cmd
->body
.shid
= res
->id
;
267 cmd
->body
.mobid
= bo
->mem
.start
;
268 cmd
->body
.offsetInBytes
= res
->backup_offset
;
269 res
->backup_dirty
= false;
270 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
275 static int vmw_gb_shader_unbind(struct vmw_resource
*res
,
277 struct ttm_validate_buffer
*val_buf
)
279 struct vmw_private
*dev_priv
= res
->dev_priv
;
281 SVGA3dCmdHeader header
;
282 SVGA3dCmdBindGBShader body
;
284 struct vmw_fence_obj
*fence
;
286 BUG_ON(res
->backup
->base
.mem
.mem_type
!= VMW_PL_MOB
);
288 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
289 if (unlikely(cmd
== NULL
)) {
290 DRM_ERROR("Failed reserving FIFO space for shader "
295 cmd
->header
.id
= SVGA_3D_CMD_BIND_GB_SHADER
;
296 cmd
->header
.size
= sizeof(cmd
->body
);
297 cmd
->body
.shid
= res
->id
;
298 cmd
->body
.mobid
= SVGA3D_INVALID_ID
;
299 cmd
->body
.offsetInBytes
= 0;
300 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
303 * Create a fence object and fence the backup buffer.
306 (void) vmw_execbuf_fence_commands(NULL
, dev_priv
,
309 vmw_bo_fence_single(val_buf
->bo
, fence
);
311 if (likely(fence
!= NULL
))
312 vmw_fence_obj_unreference(&fence
);
317 static int vmw_gb_shader_destroy(struct vmw_resource
*res
)
319 struct vmw_private
*dev_priv
= res
->dev_priv
;
321 SVGA3dCmdHeader header
;
322 SVGA3dCmdDestroyGBShader body
;
325 if (likely(res
->id
== -1))
328 mutex_lock(&dev_priv
->binding_mutex
);
329 vmw_binding_res_list_scrub(&res
->binding_head
);
331 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
332 if (unlikely(cmd
== NULL
)) {
333 DRM_ERROR("Failed reserving FIFO space for shader "
335 mutex_unlock(&dev_priv
->binding_mutex
);
339 cmd
->header
.id
= SVGA_3D_CMD_DESTROY_GB_SHADER
;
340 cmd
->header
.size
= sizeof(cmd
->body
);
341 cmd
->body
.shid
= res
->id
;
342 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
343 mutex_unlock(&dev_priv
->binding_mutex
);
344 vmw_resource_release_id(res
);
345 vmw_fifo_resource_dec(dev_priv
);
355 * vmw_dx_shader_commit_notify - Notify that a shader operation has been
356 * committed to hardware from a user-supplied command stream.
358 * @res: Pointer to the shader resource.
359 * @state: Indicating whether a creation or removal has been committed.
362 static void vmw_dx_shader_commit_notify(struct vmw_resource
*res
,
363 enum vmw_cmdbuf_res_state state
)
365 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
366 struct vmw_private
*dev_priv
= res
->dev_priv
;
368 if (state
== VMW_CMDBUF_RES_ADD
) {
369 mutex_lock(&dev_priv
->binding_mutex
);
370 vmw_cotable_add_resource(shader
->cotable
,
371 &shader
->cotable_head
);
372 shader
->committed
= true;
373 res
->id
= shader
->id
;
374 mutex_unlock(&dev_priv
->binding_mutex
);
376 mutex_lock(&dev_priv
->binding_mutex
);
377 list_del_init(&shader
->cotable_head
);
378 shader
->committed
= false;
380 mutex_unlock(&dev_priv
->binding_mutex
);
385 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
387 * @res: The shader resource
389 * This function reverts a scrub operation.
391 static int vmw_dx_shader_unscrub(struct vmw_resource
*res
)
393 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
394 struct vmw_private
*dev_priv
= res
->dev_priv
;
396 SVGA3dCmdHeader header
;
397 SVGA3dCmdDXBindShader body
;
400 if (!list_empty(&shader
->cotable_head
) || !shader
->committed
)
403 cmd
= vmw_fifo_reserve_dx(dev_priv
, sizeof(*cmd
),
405 if (unlikely(cmd
== NULL
)) {
406 DRM_ERROR("Failed reserving FIFO space for shader "
411 cmd
->header
.id
= SVGA_3D_CMD_DX_BIND_SHADER
;
412 cmd
->header
.size
= sizeof(cmd
->body
);
413 cmd
->body
.cid
= shader
->ctx
->id
;
414 cmd
->body
.shid
= shader
->id
;
415 cmd
->body
.mobid
= res
->backup
->base
.mem
.start
;
416 cmd
->body
.offsetInBytes
= res
->backup_offset
;
417 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
419 vmw_cotable_add_resource(shader
->cotable
, &shader
->cotable_head
);
425 * vmw_dx_shader_create - The DX shader create callback
427 * @res: The DX shader resource
429 * The create callback is called as part of resource validation and
430 * makes sure that we unscrub the shader if it's previously been scrubbed.
432 static int vmw_dx_shader_create(struct vmw_resource
*res
)
434 struct vmw_private
*dev_priv
= res
->dev_priv
;
435 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
438 WARN_ON_ONCE(!shader
->committed
);
440 if (!list_empty(&res
->mob_head
)) {
441 mutex_lock(&dev_priv
->binding_mutex
);
442 ret
= vmw_dx_shader_unscrub(res
);
443 mutex_unlock(&dev_priv
->binding_mutex
);
446 res
->id
= shader
->id
;
451 * vmw_dx_shader_bind - The DX shader bind callback
453 * @res: The DX shader resource
454 * @val_buf: Pointer to the validate buffer.
457 static int vmw_dx_shader_bind(struct vmw_resource
*res
,
458 struct ttm_validate_buffer
*val_buf
)
460 struct vmw_private
*dev_priv
= res
->dev_priv
;
461 struct ttm_buffer_object
*bo
= val_buf
->bo
;
463 BUG_ON(bo
->mem
.mem_type
!= VMW_PL_MOB
);
464 mutex_lock(&dev_priv
->binding_mutex
);
465 vmw_dx_shader_unscrub(res
);
466 mutex_unlock(&dev_priv
->binding_mutex
);
472 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
474 * @res: The shader resource
476 * This function unbinds a MOB from the DX shader without requiring the
477 * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
478 * However, once the driver eventually decides to unbind the MOB, it doesn't
479 * need to access the context.
481 static int vmw_dx_shader_scrub(struct vmw_resource
*res
)
483 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
484 struct vmw_private
*dev_priv
= res
->dev_priv
;
486 SVGA3dCmdHeader header
;
487 SVGA3dCmdDXBindShader body
;
490 if (list_empty(&shader
->cotable_head
))
493 WARN_ON_ONCE(!shader
->committed
);
494 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
495 if (unlikely(cmd
== NULL
)) {
496 DRM_ERROR("Failed reserving FIFO space for shader "
501 cmd
->header
.id
= SVGA_3D_CMD_DX_BIND_SHADER
;
502 cmd
->header
.size
= sizeof(cmd
->body
);
503 cmd
->body
.cid
= shader
->ctx
->id
;
504 cmd
->body
.shid
= res
->id
;
505 cmd
->body
.mobid
= SVGA3D_INVALID_ID
;
506 cmd
->body
.offsetInBytes
= 0;
507 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
509 list_del_init(&shader
->cotable_head
);
515 * vmw_dx_shader_unbind - The dx shader unbind callback.
517 * @res: The shader resource
518 * @readback: Whether this is a readback unbind. Currently unused.
519 * @val_buf: MOB buffer information.
521 static int vmw_dx_shader_unbind(struct vmw_resource
*res
,
523 struct ttm_validate_buffer
*val_buf
)
525 struct vmw_private
*dev_priv
= res
->dev_priv
;
526 struct vmw_fence_obj
*fence
;
529 BUG_ON(res
->backup
->base
.mem
.mem_type
!= VMW_PL_MOB
);
531 mutex_lock(&dev_priv
->binding_mutex
);
532 ret
= vmw_dx_shader_scrub(res
);
533 mutex_unlock(&dev_priv
->binding_mutex
);
538 (void) vmw_execbuf_fence_commands(NULL
, dev_priv
,
540 vmw_bo_fence_single(val_buf
->bo
, fence
);
542 if (likely(fence
!= NULL
))
543 vmw_fence_obj_unreference(&fence
);
549 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
552 * @dev_priv: Pointer to device private structure.
553 * @list: The list of cotable resources.
554 * @readback: Whether the call was part of a readback unbind.
556 * Scrubs all shader MOBs so that any subsequent shader unbind or shader
557 * destroy operation won't need to swap in the context.
559 void vmw_dx_shader_cotable_list_scrub(struct vmw_private
*dev_priv
,
560 struct list_head
*list
,
563 struct vmw_dx_shader
*entry
, *next
;
565 WARN_ON_ONCE(!mutex_is_locked(&dev_priv
->binding_mutex
));
567 list_for_each_entry_safe(entry
, next
, list
, cotable_head
) {
568 WARN_ON(vmw_dx_shader_scrub(&entry
->res
));
570 entry
->committed
= false;
575 * vmw_dx_shader_res_free - The DX shader free callback
577 * @res: The shader resource
579 * Frees the DX shader resource and updates memory accounting.
581 static void vmw_dx_shader_res_free(struct vmw_resource
*res
)
583 struct vmw_private
*dev_priv
= res
->dev_priv
;
584 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
586 vmw_resource_unreference(&shader
->cotable
);
588 ttm_mem_global_free(vmw_mem_glob(dev_priv
), vmw_shader_dx_size
);
592 * vmw_dx_shader_add - Add a shader resource as a command buffer managed
595 * @man: The command buffer resource manager.
596 * @ctx: Pointer to the context resource.
597 * @user_key: The id used for this shader.
598 * @shader_type: The shader type.
599 * @list: The list of staged command buffer managed resources.
601 int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager
*man
,
602 struct vmw_resource
*ctx
,
604 SVGA3dShaderType shader_type
,
605 struct list_head
*list
)
607 struct vmw_dx_shader
*shader
;
608 struct vmw_resource
*res
;
609 struct vmw_private
*dev_priv
= ctx
->dev_priv
;
610 struct ttm_operation_ctx ttm_opt_ctx
= {
611 .interruptible
= true,
616 if (!vmw_shader_dx_size
)
617 vmw_shader_dx_size
= ttm_round_pot(sizeof(*shader
));
619 if (!vmw_shader_id_ok(user_key
, shader_type
))
622 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
), vmw_shader_dx_size
,
625 if (ret
!= -ERESTARTSYS
)
626 DRM_ERROR("Out of graphics memory for shader "
631 shader
= kmalloc(sizeof(*shader
), GFP_KERNEL
);
633 ttm_mem_global_free(vmw_mem_glob(dev_priv
), vmw_shader_dx_size
);
639 shader
->cotable
= vmw_context_cotable(ctx
, SVGA_COTABLE_DXSHADER
);
640 shader
->id
= user_key
;
641 shader
->committed
= false;
642 INIT_LIST_HEAD(&shader
->cotable_head
);
643 ret
= vmw_resource_init(dev_priv
, res
, true,
644 vmw_dx_shader_res_free
, &vmw_dx_shader_func
);
646 goto out_resource_init
;
649 * The user_key name-space is not per shader type for DX shaders,
650 * so when hashing, use a single zero shader type.
652 ret
= vmw_cmdbuf_res_add(man
, vmw_cmdbuf_res_shader
,
653 vmw_shader_key(user_key
, 0),
656 goto out_resource_init
;
658 res
->id
= shader
->id
;
659 vmw_resource_activate(res
, vmw_hw_shader_destroy
);
662 vmw_resource_unreference(&res
);
670 * User-space shader management:
673 static struct vmw_resource
*
674 vmw_user_shader_base_to_res(struct ttm_base_object
*base
)
676 return &(container_of(base
, struct vmw_user_shader
, base
)->
680 static void vmw_user_shader_free(struct vmw_resource
*res
)
682 struct vmw_user_shader
*ushader
=
683 container_of(res
, struct vmw_user_shader
, shader
.res
);
684 struct vmw_private
*dev_priv
= res
->dev_priv
;
686 ttm_base_object_kfree(ushader
, base
);
687 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
688 vmw_user_shader_size
);
691 static void vmw_shader_free(struct vmw_resource
*res
)
693 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
694 struct vmw_private
*dev_priv
= res
->dev_priv
;
697 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
702 * This function is called when user space has no more references on the
703 * base object. It releases the base-object's reference on the resource object.
706 static void vmw_user_shader_base_release(struct ttm_base_object
**p_base
)
708 struct ttm_base_object
*base
= *p_base
;
709 struct vmw_resource
*res
= vmw_user_shader_base_to_res(base
);
712 vmw_resource_unreference(&res
);
715 int vmw_shader_destroy_ioctl(struct drm_device
*dev
, void *data
,
716 struct drm_file
*file_priv
)
718 struct drm_vmw_shader_arg
*arg
= (struct drm_vmw_shader_arg
*)data
;
719 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
721 return ttm_ref_object_base_unref(tfile
, arg
->handle
,
725 static int vmw_user_shader_alloc(struct vmw_private
*dev_priv
,
726 struct vmw_buffer_object
*buffer
,
729 SVGA3dShaderType shader_type
,
730 uint8_t num_input_sig
,
731 uint8_t num_output_sig
,
732 struct ttm_object_file
*tfile
,
735 struct vmw_user_shader
*ushader
;
736 struct vmw_resource
*res
, *tmp
;
737 struct ttm_operation_ctx ctx
= {
738 .interruptible
= true,
744 * Approximate idr memory usage with 128 bytes. It will be limited
745 * by maximum number_of shaders anyway.
747 if (unlikely(vmw_user_shader_size
== 0))
748 vmw_user_shader_size
=
749 ttm_round_pot(sizeof(struct vmw_user_shader
)) + 128;
751 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
),
752 vmw_user_shader_size
,
754 if (unlikely(ret
!= 0)) {
755 if (ret
!= -ERESTARTSYS
)
756 DRM_ERROR("Out of graphics memory for shader "
761 ushader
= kzalloc(sizeof(*ushader
), GFP_KERNEL
);
762 if (unlikely(!ushader
)) {
763 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
764 vmw_user_shader_size
);
769 res
= &ushader
->shader
.res
;
770 ushader
->base
.shareable
= false;
771 ushader
->base
.tfile
= NULL
;
774 * From here on, the destructor takes over resource freeing.
777 ret
= vmw_gb_shader_init(dev_priv
, res
, shader_size
,
778 offset
, shader_type
, num_input_sig
,
779 num_output_sig
, buffer
,
780 vmw_user_shader_free
);
781 if (unlikely(ret
!= 0))
784 tmp
= vmw_resource_reference(res
);
785 ret
= ttm_base_object_init(tfile
, &ushader
->base
, false,
787 &vmw_user_shader_base_release
, NULL
);
789 if (unlikely(ret
!= 0)) {
790 vmw_resource_unreference(&tmp
);
795 *handle
= ushader
->base
.hash
.key
;
797 vmw_resource_unreference(&res
);
803 static struct vmw_resource
*vmw_shader_alloc(struct vmw_private
*dev_priv
,
804 struct vmw_buffer_object
*buffer
,
807 SVGA3dShaderType shader_type
)
809 struct vmw_shader
*shader
;
810 struct vmw_resource
*res
;
811 struct ttm_operation_ctx ctx
= {
812 .interruptible
= true,
818 * Approximate idr memory usage with 128 bytes. It will be limited
819 * by maximum number_of shaders anyway.
821 if (unlikely(vmw_shader_size
== 0))
823 ttm_round_pot(sizeof(struct vmw_shader
)) + 128;
825 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
),
828 if (unlikely(ret
!= 0)) {
829 if (ret
!= -ERESTARTSYS
)
830 DRM_ERROR("Out of graphics memory for shader "
835 shader
= kzalloc(sizeof(*shader
), GFP_KERNEL
);
836 if (unlikely(!shader
)) {
837 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
846 * From here on, the destructor takes over resource freeing.
848 ret
= vmw_gb_shader_init(dev_priv
, res
, shader_size
,
849 offset
, shader_type
, 0, 0, buffer
,
853 return ret
? ERR_PTR(ret
) : res
;
857 static int vmw_shader_define(struct drm_device
*dev
, struct drm_file
*file_priv
,
858 enum drm_vmw_shader_type shader_type_drm
,
859 u32 buffer_handle
, size_t size
, size_t offset
,
860 uint8_t num_input_sig
, uint8_t num_output_sig
,
861 uint32_t *shader_handle
)
863 struct vmw_private
*dev_priv
= vmw_priv(dev
);
864 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
865 struct vmw_buffer_object
*buffer
= NULL
;
866 SVGA3dShaderType shader_type
;
869 if (buffer_handle
!= SVGA3D_INVALID_ID
) {
870 ret
= vmw_user_bo_lookup(tfile
, buffer_handle
,
872 if (unlikely(ret
!= 0)) {
873 DRM_ERROR("Could not find buffer for shader "
878 if ((u64
)buffer
->base
.num_pages
* PAGE_SIZE
<
879 (u64
)size
+ (u64
)offset
) {
880 DRM_ERROR("Illegal buffer- or shader size.\n");
886 switch (shader_type_drm
) {
887 case drm_vmw_shader_type_vs
:
888 shader_type
= SVGA3D_SHADERTYPE_VS
;
890 case drm_vmw_shader_type_ps
:
891 shader_type
= SVGA3D_SHADERTYPE_PS
;
894 DRM_ERROR("Illegal shader type.\n");
899 ret
= ttm_read_lock(&dev_priv
->reservation_sem
, true);
900 if (unlikely(ret
!= 0))
903 ret
= vmw_user_shader_alloc(dev_priv
, buffer
, size
, offset
,
904 shader_type
, num_input_sig
,
905 num_output_sig
, tfile
, shader_handle
);
907 ttm_read_unlock(&dev_priv
->reservation_sem
);
909 vmw_bo_unreference(&buffer
);
914 * vmw_shader_id_ok - Check whether a compat shader user key and
915 * shader type are within valid bounds.
917 * @user_key: User space id of the shader.
918 * @shader_type: Shader type.
920 * Returns true if valid false if not.
922 static bool vmw_shader_id_ok(u32 user_key
, SVGA3dShaderType shader_type
)
924 return user_key
<= ((1 << 20) - 1) && (unsigned) shader_type
< 16;
928 * vmw_shader_key - Compute a hash key suitable for a compat shader.
930 * @user_key: User space id of the shader.
931 * @shader_type: Shader type.
933 * Returns a hash key suitable for a command buffer managed resource
934 * manager hash table.
936 static u32
vmw_shader_key(u32 user_key
, SVGA3dShaderType shader_type
)
938 return user_key
| (shader_type
<< 20);
942 * vmw_shader_remove - Stage a compat shader for removal.
944 * @man: Pointer to the compat shader manager identifying the shader namespace.
945 * @user_key: The key that is used to identify the shader. The key is
946 * unique to the shader type.
947 * @shader_type: Shader type.
948 * @list: Caller's list of staged command buffer resource actions.
950 int vmw_shader_remove(struct vmw_cmdbuf_res_manager
*man
,
951 u32 user_key
, SVGA3dShaderType shader_type
,
952 struct list_head
*list
)
954 struct vmw_resource
*dummy
;
956 if (!vmw_shader_id_ok(user_key
, shader_type
))
959 return vmw_cmdbuf_res_remove(man
, vmw_cmdbuf_res_shader
,
960 vmw_shader_key(user_key
, shader_type
),
965 * vmw_compat_shader_add - Create a compat shader and stage it for addition
966 * as a command buffer managed resource.
968 * @man: Pointer to the compat shader manager identifying the shader namespace.
969 * @user_key: The key that is used to identify the shader. The key is
970 * unique to the shader type.
971 * @bytecode: Pointer to the bytecode of the shader.
972 * @shader_type: Shader type.
973 * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is
974 * to be created with.
975 * @list: Caller's list of staged command buffer resource actions.
978 int vmw_compat_shader_add(struct vmw_private
*dev_priv
,
979 struct vmw_cmdbuf_res_manager
*man
,
980 u32 user_key
, const void *bytecode
,
981 SVGA3dShaderType shader_type
,
983 struct list_head
*list
)
985 struct ttm_operation_ctx ctx
= { false, true };
986 struct vmw_buffer_object
*buf
;
987 struct ttm_bo_kmap_obj map
;
990 struct vmw_resource
*res
;
992 if (!vmw_shader_id_ok(user_key
, shader_type
))
995 /* Allocate and pin a DMA buffer */
996 buf
= kzalloc(sizeof(*buf
), GFP_KERNEL
);
1000 ret
= vmw_bo_init(dev_priv
, buf
, size
, &vmw_sys_ne_placement
,
1001 true, vmw_bo_bo_free
);
1002 if (unlikely(ret
!= 0))
1005 ret
= ttm_bo_reserve(&buf
->base
, false, true, NULL
);
1006 if (unlikely(ret
!= 0))
1009 /* Map and copy shader bytecode. */
1010 ret
= ttm_bo_kmap(&buf
->base
, 0, PAGE_ALIGN(size
) >> PAGE_SHIFT
,
1012 if (unlikely(ret
!= 0)) {
1013 ttm_bo_unreserve(&buf
->base
);
1017 memcpy(ttm_kmap_obj_virtual(&map
, &is_iomem
), bytecode
, size
);
1020 ttm_bo_kunmap(&map
);
1021 ret
= ttm_bo_validate(&buf
->base
, &vmw_sys_placement
, &ctx
);
1023 ttm_bo_unreserve(&buf
->base
);
1025 res
= vmw_shader_alloc(dev_priv
, buf
, size
, 0, shader_type
);
1026 if (unlikely(ret
!= 0))
1029 ret
= vmw_cmdbuf_res_add(man
, vmw_cmdbuf_res_shader
,
1030 vmw_shader_key(user_key
, shader_type
),
1032 vmw_resource_unreference(&res
);
1034 vmw_bo_unreference(&buf
);
1040 * vmw_shader_lookup - Look up a compat shader
1042 * @man: Pointer to the command buffer managed resource manager identifying
1043 * the shader namespace.
1044 * @user_key: The user space id of the shader.
1045 * @shader_type: The shader type.
1047 * Returns a refcounted pointer to a struct vmw_resource if the shader was
1048 * found. An error pointer otherwise.
1050 struct vmw_resource
*
1051 vmw_shader_lookup(struct vmw_cmdbuf_res_manager
*man
,
1053 SVGA3dShaderType shader_type
)
1055 if (!vmw_shader_id_ok(user_key
, shader_type
))
1056 return ERR_PTR(-EINVAL
);
1058 return vmw_cmdbuf_res_lookup(man
, vmw_cmdbuf_res_shader
,
1059 vmw_shader_key(user_key
, shader_type
));
1062 int vmw_shader_define_ioctl(struct drm_device
*dev
, void *data
,
1063 struct drm_file
*file_priv
)
1065 struct drm_vmw_shader_create_arg
*arg
=
1066 (struct drm_vmw_shader_create_arg
*)data
;
1068 return vmw_shader_define(dev
, file_priv
, arg
->shader_type
,
1070 arg
->size
, arg
->offset
,
1072 &arg
->shader_handle
);