1 /**************************************************************************
3 * 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 "vmwgfx_drv.h"
29 #include "vmwgfx_resource_priv.h"
30 #include "vmwgfx_binding.h"
31 #include "ttm/ttm_placement.h"
34 struct vmw_resource res
;
35 SVGA3dShaderType type
;
37 uint8_t num_input_sig
;
38 uint8_t num_output_sig
;
41 struct vmw_user_shader
{
42 struct ttm_base_object base
;
43 struct vmw_shader shader
;
46 struct vmw_dx_shader
{
47 struct vmw_resource res
;
48 struct vmw_resource
*ctx
;
49 struct vmw_resource
*cotable
;
52 struct list_head cotable_head
;
55 static uint64_t vmw_user_shader_size
;
56 static uint64_t vmw_shader_size
;
57 static size_t vmw_shader_dx_size
;
59 static void vmw_user_shader_free(struct vmw_resource
*res
);
60 static struct vmw_resource
*
61 vmw_user_shader_base_to_res(struct ttm_base_object
*base
);
63 static int vmw_gb_shader_create(struct vmw_resource
*res
);
64 static int vmw_gb_shader_bind(struct vmw_resource
*res
,
65 struct ttm_validate_buffer
*val_buf
);
66 static int vmw_gb_shader_unbind(struct vmw_resource
*res
,
68 struct ttm_validate_buffer
*val_buf
);
69 static int vmw_gb_shader_destroy(struct vmw_resource
*res
);
71 static int vmw_dx_shader_create(struct vmw_resource
*res
);
72 static int vmw_dx_shader_bind(struct vmw_resource
*res
,
73 struct ttm_validate_buffer
*val_buf
);
74 static int vmw_dx_shader_unbind(struct vmw_resource
*res
,
76 struct ttm_validate_buffer
*val_buf
);
77 static void vmw_dx_shader_commit_notify(struct vmw_resource
*res
,
78 enum vmw_cmdbuf_res_state state
);
79 static bool vmw_shader_id_ok(u32 user_key
, SVGA3dShaderType shader_type
);
80 static u32
vmw_shader_key(u32 user_key
, SVGA3dShaderType shader_type
);
81 static uint64_t vmw_user_shader_size
;
83 static const struct vmw_user_resource_conv user_shader_conv
= {
84 .object_type
= VMW_RES_SHADER
,
85 .base_obj_to_res
= vmw_user_shader_base_to_res
,
86 .res_free
= vmw_user_shader_free
89 const struct vmw_user_resource_conv
*user_shader_converter
=
93 static const struct vmw_res_func vmw_gb_shader_func
= {
94 .res_type
= vmw_res_shader
,
97 .type_name
= "guest backed shaders",
98 .backup_placement
= &vmw_mob_placement
,
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_backup
= true,
109 .type_name
= "dx shaders",
110 .backup_placement
= &vmw_mob_placement
,
111 .create
= vmw_dx_shader_create
,
113 * The destroy callback is only called with a committed resource on
114 * context destroy, in which case we destroy the cotable anyway,
115 * so there's no need to destroy DX shaders separately.
118 .bind
= vmw_dx_shader_bind
,
119 .unbind
= vmw_dx_shader_unbind
,
120 .commit_notify
= vmw_dx_shader_commit_notify
,
127 static inline struct vmw_shader
*
128 vmw_res_to_shader(struct vmw_resource
*res
)
130 return container_of(res
, struct vmw_shader
, res
);
134 * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
135 * struct vmw_dx_shader
137 * @res: Pointer to the struct vmw_resource.
139 static inline struct vmw_dx_shader
*
140 vmw_res_to_dx_shader(struct vmw_resource
*res
)
142 return container_of(res
, struct vmw_dx_shader
, res
);
145 static void vmw_hw_shader_destroy(struct vmw_resource
*res
)
147 if (likely(res
->func
->destroy
))
148 (void) res
->func
->destroy(res
);
154 static int vmw_gb_shader_init(struct vmw_private
*dev_priv
,
155 struct vmw_resource
*res
,
158 SVGA3dShaderType type
,
159 uint8_t num_input_sig
,
160 uint8_t num_output_sig
,
161 struct vmw_dma_buffer
*byte_code
,
162 void (*res_free
) (struct vmw_resource
*res
))
164 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
167 ret
= vmw_resource_init(dev_priv
, res
, true, res_free
,
168 &vmw_gb_shader_func
);
170 if (unlikely(ret
!= 0)) {
178 res
->backup_size
= size
;
180 res
->backup
= vmw_dmabuf_reference(byte_code
);
181 res
->backup_offset
= offset
;
185 shader
->num_input_sig
= num_input_sig
;
186 shader
->num_output_sig
= num_output_sig
;
188 vmw_resource_activate(res
, vmw_hw_shader_destroy
);
196 static int vmw_gb_shader_create(struct vmw_resource
*res
)
198 struct vmw_private
*dev_priv
= res
->dev_priv
;
199 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
202 SVGA3dCmdHeader header
;
203 SVGA3dCmdDefineGBShader body
;
206 if (likely(res
->id
!= -1))
209 ret
= vmw_resource_alloc_id(res
);
210 if (unlikely(ret
!= 0)) {
211 DRM_ERROR("Failed to allocate a shader id.\n");
215 if (unlikely(res
->id
>= VMWGFX_NUM_GB_SHADER
)) {
220 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
221 if (unlikely(cmd
== NULL
)) {
222 DRM_ERROR("Failed reserving FIFO space for shader "
228 cmd
->header
.id
= SVGA_3D_CMD_DEFINE_GB_SHADER
;
229 cmd
->header
.size
= sizeof(cmd
->body
);
230 cmd
->body
.shid
= res
->id
;
231 cmd
->body
.type
= shader
->type
;
232 cmd
->body
.sizeInBytes
= shader
->size
;
233 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
234 vmw_fifo_resource_inc(dev_priv
);
239 vmw_resource_release_id(res
);
244 static int vmw_gb_shader_bind(struct vmw_resource
*res
,
245 struct ttm_validate_buffer
*val_buf
)
247 struct vmw_private
*dev_priv
= res
->dev_priv
;
249 SVGA3dCmdHeader header
;
250 SVGA3dCmdBindGBShader body
;
252 struct ttm_buffer_object
*bo
= val_buf
->bo
;
254 BUG_ON(bo
->mem
.mem_type
!= VMW_PL_MOB
);
256 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
257 if (unlikely(cmd
== NULL
)) {
258 DRM_ERROR("Failed reserving FIFO space for shader "
263 cmd
->header
.id
= SVGA_3D_CMD_BIND_GB_SHADER
;
264 cmd
->header
.size
= sizeof(cmd
->body
);
265 cmd
->body
.shid
= res
->id
;
266 cmd
->body
.mobid
= bo
->mem
.start
;
267 cmd
->body
.offsetInBytes
= res
->backup_offset
;
268 res
->backup_dirty
= false;
269 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
274 static int vmw_gb_shader_unbind(struct vmw_resource
*res
,
276 struct ttm_validate_buffer
*val_buf
)
278 struct vmw_private
*dev_priv
= res
->dev_priv
;
280 SVGA3dCmdHeader header
;
281 SVGA3dCmdBindGBShader body
;
283 struct vmw_fence_obj
*fence
;
285 BUG_ON(res
->backup
->base
.mem
.mem_type
!= VMW_PL_MOB
);
287 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
288 if (unlikely(cmd
== NULL
)) {
289 DRM_ERROR("Failed reserving FIFO space for shader "
294 cmd
->header
.id
= SVGA_3D_CMD_BIND_GB_SHADER
;
295 cmd
->header
.size
= sizeof(cmd
->body
);
296 cmd
->body
.shid
= res
->id
;
297 cmd
->body
.mobid
= SVGA3D_INVALID_ID
;
298 cmd
->body
.offsetInBytes
= 0;
299 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
302 * Create a fence object and fence the backup buffer.
305 (void) vmw_execbuf_fence_commands(NULL
, dev_priv
,
308 vmw_fence_single_bo(val_buf
->bo
, fence
);
310 if (likely(fence
!= NULL
))
311 vmw_fence_obj_unreference(&fence
);
316 static int vmw_gb_shader_destroy(struct vmw_resource
*res
)
318 struct vmw_private
*dev_priv
= res
->dev_priv
;
320 SVGA3dCmdHeader header
;
321 SVGA3dCmdDestroyGBShader body
;
324 if (likely(res
->id
== -1))
327 mutex_lock(&dev_priv
->binding_mutex
);
328 vmw_binding_res_list_scrub(&res
->binding_head
);
330 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
331 if (unlikely(cmd
== NULL
)) {
332 DRM_ERROR("Failed reserving FIFO space for shader "
334 mutex_unlock(&dev_priv
->binding_mutex
);
338 cmd
->header
.id
= SVGA_3D_CMD_DESTROY_GB_SHADER
;
339 cmd
->header
.size
= sizeof(cmd
->body
);
340 cmd
->body
.shid
= res
->id
;
341 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
342 mutex_unlock(&dev_priv
->binding_mutex
);
343 vmw_resource_release_id(res
);
344 vmw_fifo_resource_dec(dev_priv
);
354 * vmw_dx_shader_commit_notify - Notify that a shader operation has been
355 * committed to hardware from a user-supplied command stream.
357 * @res: Pointer to the shader resource.
358 * @state: Indicating whether a creation or removal has been committed.
361 static void vmw_dx_shader_commit_notify(struct vmw_resource
*res
,
362 enum vmw_cmdbuf_res_state state
)
364 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
365 struct vmw_private
*dev_priv
= res
->dev_priv
;
367 if (state
== VMW_CMDBUF_RES_ADD
) {
368 mutex_lock(&dev_priv
->binding_mutex
);
369 vmw_cotable_add_resource(shader
->cotable
,
370 &shader
->cotable_head
);
371 shader
->committed
= true;
372 res
->id
= shader
->id
;
373 mutex_unlock(&dev_priv
->binding_mutex
);
375 mutex_lock(&dev_priv
->binding_mutex
);
376 list_del_init(&shader
->cotable_head
);
377 shader
->committed
= false;
379 mutex_unlock(&dev_priv
->binding_mutex
);
384 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
386 * @res: The shader resource
388 * This function reverts a scrub operation.
390 static int vmw_dx_shader_unscrub(struct vmw_resource
*res
)
392 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
393 struct vmw_private
*dev_priv
= res
->dev_priv
;
395 SVGA3dCmdHeader header
;
396 SVGA3dCmdDXBindShader body
;
399 if (!list_empty(&shader
->cotable_head
) || !shader
->committed
)
402 cmd
= vmw_fifo_reserve_dx(dev_priv
, sizeof(*cmd
),
404 if (unlikely(cmd
== NULL
)) {
405 DRM_ERROR("Failed reserving FIFO space for shader "
410 cmd
->header
.id
= SVGA_3D_CMD_DX_BIND_SHADER
;
411 cmd
->header
.size
= sizeof(cmd
->body
);
412 cmd
->body
.cid
= shader
->ctx
->id
;
413 cmd
->body
.shid
= shader
->id
;
414 cmd
->body
.mobid
= res
->backup
->base
.mem
.start
;
415 cmd
->body
.offsetInBytes
= res
->backup_offset
;
416 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
418 vmw_cotable_add_resource(shader
->cotable
, &shader
->cotable_head
);
424 * vmw_dx_shader_create - The DX shader create callback
426 * @res: The DX shader resource
428 * The create callback is called as part of resource validation and
429 * makes sure that we unscrub the shader if it's previously been scrubbed.
431 static int vmw_dx_shader_create(struct vmw_resource
*res
)
433 struct vmw_private
*dev_priv
= res
->dev_priv
;
434 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
437 WARN_ON_ONCE(!shader
->committed
);
439 if (!list_empty(&res
->mob_head
)) {
440 mutex_lock(&dev_priv
->binding_mutex
);
441 ret
= vmw_dx_shader_unscrub(res
);
442 mutex_unlock(&dev_priv
->binding_mutex
);
445 res
->id
= shader
->id
;
450 * vmw_dx_shader_bind - The DX shader bind callback
452 * @res: The DX shader resource
453 * @val_buf: Pointer to the validate buffer.
456 static int vmw_dx_shader_bind(struct vmw_resource
*res
,
457 struct ttm_validate_buffer
*val_buf
)
459 struct vmw_private
*dev_priv
= res
->dev_priv
;
460 struct ttm_buffer_object
*bo
= val_buf
->bo
;
462 BUG_ON(bo
->mem
.mem_type
!= VMW_PL_MOB
);
463 mutex_lock(&dev_priv
->binding_mutex
);
464 vmw_dx_shader_unscrub(res
);
465 mutex_unlock(&dev_priv
->binding_mutex
);
471 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
473 * @res: The shader resource
475 * This function unbinds a MOB from the DX shader without requiring the
476 * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
477 * However, once the driver eventually decides to unbind the MOB, it doesn't
478 * need to access the context.
480 static int vmw_dx_shader_scrub(struct vmw_resource
*res
)
482 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
483 struct vmw_private
*dev_priv
= res
->dev_priv
;
485 SVGA3dCmdHeader header
;
486 SVGA3dCmdDXBindShader body
;
489 if (list_empty(&shader
->cotable_head
))
492 WARN_ON_ONCE(!shader
->committed
);
493 cmd
= vmw_fifo_reserve(dev_priv
, sizeof(*cmd
));
494 if (unlikely(cmd
== NULL
)) {
495 DRM_ERROR("Failed reserving FIFO space for shader "
500 cmd
->header
.id
= SVGA_3D_CMD_DX_BIND_SHADER
;
501 cmd
->header
.size
= sizeof(cmd
->body
);
502 cmd
->body
.cid
= shader
->ctx
->id
;
503 cmd
->body
.shid
= res
->id
;
504 cmd
->body
.mobid
= SVGA3D_INVALID_ID
;
505 cmd
->body
.offsetInBytes
= 0;
506 vmw_fifo_commit(dev_priv
, sizeof(*cmd
));
508 list_del_init(&shader
->cotable_head
);
514 * vmw_dx_shader_unbind - The dx shader unbind callback.
516 * @res: The shader resource
517 * @readback: Whether this is a readback unbind. Currently unused.
518 * @val_buf: MOB buffer information.
520 static int vmw_dx_shader_unbind(struct vmw_resource
*res
,
522 struct ttm_validate_buffer
*val_buf
)
524 struct vmw_private
*dev_priv
= res
->dev_priv
;
525 struct vmw_fence_obj
*fence
;
528 BUG_ON(res
->backup
->base
.mem
.mem_type
!= VMW_PL_MOB
);
530 mutex_lock(&dev_priv
->binding_mutex
);
531 ret
= vmw_dx_shader_scrub(res
);
532 mutex_unlock(&dev_priv
->binding_mutex
);
537 (void) vmw_execbuf_fence_commands(NULL
, dev_priv
,
539 vmw_fence_single_bo(val_buf
->bo
, fence
);
541 if (likely(fence
!= NULL
))
542 vmw_fence_obj_unreference(&fence
);
548 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
551 * @dev_priv: Pointer to device private structure.
552 * @list: The list of cotable resources.
553 * @readback: Whether the call was part of a readback unbind.
555 * Scrubs all shader MOBs so that any subsequent shader unbind or shader
556 * destroy operation won't need to swap in the context.
558 void vmw_dx_shader_cotable_list_scrub(struct vmw_private
*dev_priv
,
559 struct list_head
*list
,
562 struct vmw_dx_shader
*entry
, *next
;
564 WARN_ON_ONCE(!mutex_is_locked(&dev_priv
->binding_mutex
));
566 list_for_each_entry_safe(entry
, next
, list
, cotable_head
) {
567 WARN_ON(vmw_dx_shader_scrub(&entry
->res
));
569 entry
->committed
= false;
574 * vmw_dx_shader_res_free - The DX shader free callback
576 * @res: The shader resource
578 * Frees the DX shader resource and updates memory accounting.
580 static void vmw_dx_shader_res_free(struct vmw_resource
*res
)
582 struct vmw_private
*dev_priv
= res
->dev_priv
;
583 struct vmw_dx_shader
*shader
= vmw_res_to_dx_shader(res
);
585 vmw_resource_unreference(&shader
->cotable
);
587 ttm_mem_global_free(vmw_mem_glob(dev_priv
), vmw_shader_dx_size
);
591 * vmw_dx_shader_add - Add a shader resource as a command buffer managed
594 * @man: The command buffer resource manager.
595 * @ctx: Pointer to the context resource.
596 * @user_key: The id used for this shader.
597 * @shader_type: The shader type.
598 * @list: The list of staged command buffer managed resources.
600 int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager
*man
,
601 struct vmw_resource
*ctx
,
603 SVGA3dShaderType shader_type
,
604 struct list_head
*list
)
606 struct vmw_dx_shader
*shader
;
607 struct vmw_resource
*res
;
608 struct vmw_private
*dev_priv
= ctx
->dev_priv
;
611 if (!vmw_shader_dx_size
)
612 vmw_shader_dx_size
= ttm_round_pot(sizeof(*shader
));
614 if (!vmw_shader_id_ok(user_key
, shader_type
))
617 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
), vmw_shader_dx_size
,
620 if (ret
!= -ERESTARTSYS
)
621 DRM_ERROR("Out of graphics memory for shader "
626 shader
= kmalloc(sizeof(*shader
), GFP_KERNEL
);
628 ttm_mem_global_free(vmw_mem_glob(dev_priv
), vmw_shader_dx_size
);
634 shader
->cotable
= vmw_context_cotable(ctx
, SVGA_COTABLE_DXSHADER
);
635 shader
->id
= user_key
;
636 shader
->committed
= false;
637 INIT_LIST_HEAD(&shader
->cotable_head
);
638 ret
= vmw_resource_init(dev_priv
, res
, true,
639 vmw_dx_shader_res_free
, &vmw_dx_shader_func
);
641 goto out_resource_init
;
644 * The user_key name-space is not per shader type for DX shaders,
645 * so when hashing, use a single zero shader type.
647 ret
= vmw_cmdbuf_res_add(man
, vmw_cmdbuf_res_shader
,
648 vmw_shader_key(user_key
, 0),
651 goto out_resource_init
;
653 res
->id
= shader
->id
;
654 vmw_resource_activate(res
, vmw_hw_shader_destroy
);
657 vmw_resource_unreference(&res
);
665 * User-space shader management:
668 static struct vmw_resource
*
669 vmw_user_shader_base_to_res(struct ttm_base_object
*base
)
671 return &(container_of(base
, struct vmw_user_shader
, base
)->
675 static void vmw_user_shader_free(struct vmw_resource
*res
)
677 struct vmw_user_shader
*ushader
=
678 container_of(res
, struct vmw_user_shader
, shader
.res
);
679 struct vmw_private
*dev_priv
= res
->dev_priv
;
681 ttm_base_object_kfree(ushader
, base
);
682 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
683 vmw_user_shader_size
);
686 static void vmw_shader_free(struct vmw_resource
*res
)
688 struct vmw_shader
*shader
= vmw_res_to_shader(res
);
689 struct vmw_private
*dev_priv
= res
->dev_priv
;
692 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
697 * This function is called when user space has no more references on the
698 * base object. It releases the base-object's reference on the resource object.
701 static void vmw_user_shader_base_release(struct ttm_base_object
**p_base
)
703 struct ttm_base_object
*base
= *p_base
;
704 struct vmw_resource
*res
= vmw_user_shader_base_to_res(base
);
707 vmw_resource_unreference(&res
);
710 int vmw_shader_destroy_ioctl(struct drm_device
*dev
, void *data
,
711 struct drm_file
*file_priv
)
713 struct drm_vmw_shader_arg
*arg
= (struct drm_vmw_shader_arg
*)data
;
714 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
716 return ttm_ref_object_base_unref(tfile
, arg
->handle
,
720 static int vmw_user_shader_alloc(struct vmw_private
*dev_priv
,
721 struct vmw_dma_buffer
*buffer
,
724 SVGA3dShaderType shader_type
,
725 uint8_t num_input_sig
,
726 uint8_t num_output_sig
,
727 struct ttm_object_file
*tfile
,
730 struct vmw_user_shader
*ushader
;
731 struct vmw_resource
*res
, *tmp
;
735 * Approximate idr memory usage with 128 bytes. It will be limited
736 * by maximum number_of shaders anyway.
738 if (unlikely(vmw_user_shader_size
== 0))
739 vmw_user_shader_size
=
740 ttm_round_pot(sizeof(struct vmw_user_shader
)) + 128;
742 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
),
743 vmw_user_shader_size
,
745 if (unlikely(ret
!= 0)) {
746 if (ret
!= -ERESTARTSYS
)
747 DRM_ERROR("Out of graphics memory for shader "
752 ushader
= kzalloc(sizeof(*ushader
), GFP_KERNEL
);
753 if (unlikely(ushader
== NULL
)) {
754 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
755 vmw_user_shader_size
);
760 res
= &ushader
->shader
.res
;
761 ushader
->base
.shareable
= false;
762 ushader
->base
.tfile
= NULL
;
765 * From here on, the destructor takes over resource freeing.
768 ret
= vmw_gb_shader_init(dev_priv
, res
, shader_size
,
769 offset
, shader_type
, num_input_sig
,
770 num_output_sig
, buffer
,
771 vmw_user_shader_free
);
772 if (unlikely(ret
!= 0))
775 tmp
= vmw_resource_reference(res
);
776 ret
= ttm_base_object_init(tfile
, &ushader
->base
, false,
778 &vmw_user_shader_base_release
, NULL
);
780 if (unlikely(ret
!= 0)) {
781 vmw_resource_unreference(&tmp
);
786 *handle
= ushader
->base
.hash
.key
;
788 vmw_resource_unreference(&res
);
794 static struct vmw_resource
*vmw_shader_alloc(struct vmw_private
*dev_priv
,
795 struct vmw_dma_buffer
*buffer
,
798 SVGA3dShaderType shader_type
)
800 struct vmw_shader
*shader
;
801 struct vmw_resource
*res
;
805 * Approximate idr memory usage with 128 bytes. It will be limited
806 * by maximum number_of shaders anyway.
808 if (unlikely(vmw_shader_size
== 0))
810 ttm_round_pot(sizeof(struct vmw_shader
)) + 128;
812 ret
= ttm_mem_global_alloc(vmw_mem_glob(dev_priv
),
815 if (unlikely(ret
!= 0)) {
816 if (ret
!= -ERESTARTSYS
)
817 DRM_ERROR("Out of graphics memory for shader "
822 shader
= kzalloc(sizeof(*shader
), GFP_KERNEL
);
823 if (unlikely(shader
== NULL
)) {
824 ttm_mem_global_free(vmw_mem_glob(dev_priv
),
833 * From here on, the destructor takes over resource freeing.
835 ret
= vmw_gb_shader_init(dev_priv
, res
, shader_size
,
836 offset
, shader_type
, 0, 0, buffer
,
840 return ret
? ERR_PTR(ret
) : res
;
844 static int vmw_shader_define(struct drm_device
*dev
, struct drm_file
*file_priv
,
845 enum drm_vmw_shader_type shader_type_drm
,
846 u32 buffer_handle
, size_t size
, size_t offset
,
847 uint8_t num_input_sig
, uint8_t num_output_sig
,
848 uint32_t *shader_handle
)
850 struct vmw_private
*dev_priv
= vmw_priv(dev
);
851 struct ttm_object_file
*tfile
= vmw_fpriv(file_priv
)->tfile
;
852 struct vmw_dma_buffer
*buffer
= NULL
;
853 SVGA3dShaderType shader_type
;
856 if (buffer_handle
!= SVGA3D_INVALID_ID
) {
857 ret
= vmw_user_dmabuf_lookup(tfile
, buffer_handle
,
859 if (unlikely(ret
!= 0)) {
860 DRM_ERROR("Could not find buffer for shader "
865 if ((u64
)buffer
->base
.num_pages
* PAGE_SIZE
<
866 (u64
)size
+ (u64
)offset
) {
867 DRM_ERROR("Illegal buffer- or shader size.\n");
873 switch (shader_type_drm
) {
874 case drm_vmw_shader_type_vs
:
875 shader_type
= SVGA3D_SHADERTYPE_VS
;
877 case drm_vmw_shader_type_ps
:
878 shader_type
= SVGA3D_SHADERTYPE_PS
;
881 DRM_ERROR("Illegal shader type.\n");
886 ret
= ttm_read_lock(&dev_priv
->reservation_sem
, true);
887 if (unlikely(ret
!= 0))
890 ret
= vmw_user_shader_alloc(dev_priv
, buffer
, size
, offset
,
891 shader_type
, num_input_sig
,
892 num_output_sig
, tfile
, shader_handle
);
894 ttm_read_unlock(&dev_priv
->reservation_sem
);
896 vmw_dmabuf_unreference(&buffer
);
901 * vmw_shader_id_ok - Check whether a compat shader user key and
902 * shader type are within valid bounds.
904 * @user_key: User space id of the shader.
905 * @shader_type: Shader type.
907 * Returns true if valid false if not.
909 static bool vmw_shader_id_ok(u32 user_key
, SVGA3dShaderType shader_type
)
911 return user_key
<= ((1 << 20) - 1) && (unsigned) shader_type
< 16;
915 * vmw_shader_key - Compute a hash key suitable for a compat shader.
917 * @user_key: User space id of the shader.
918 * @shader_type: Shader type.
920 * Returns a hash key suitable for a command buffer managed resource
921 * manager hash table.
923 static u32
vmw_shader_key(u32 user_key
, SVGA3dShaderType shader_type
)
925 return user_key
| (shader_type
<< 20);
929 * vmw_shader_remove - Stage a compat shader for removal.
931 * @man: Pointer to the compat shader manager identifying the shader namespace.
932 * @user_key: The key that is used to identify the shader. The key is
933 * unique to the shader type.
934 * @shader_type: Shader type.
935 * @list: Caller's list of staged command buffer resource actions.
937 int vmw_shader_remove(struct vmw_cmdbuf_res_manager
*man
,
938 u32 user_key
, SVGA3dShaderType shader_type
,
939 struct list_head
*list
)
941 struct vmw_resource
*dummy
;
943 if (!vmw_shader_id_ok(user_key
, shader_type
))
946 return vmw_cmdbuf_res_remove(man
, vmw_cmdbuf_res_shader
,
947 vmw_shader_key(user_key
, shader_type
),
952 * vmw_compat_shader_add - Create a compat shader and stage it for addition
953 * as a command buffer managed resource.
955 * @man: Pointer to the compat shader manager identifying the shader namespace.
956 * @user_key: The key that is used to identify the shader. The key is
957 * unique to the shader type.
958 * @bytecode: Pointer to the bytecode of the shader.
959 * @shader_type: Shader type.
960 * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is
961 * to be created with.
962 * @list: Caller's list of staged command buffer resource actions.
965 int vmw_compat_shader_add(struct vmw_private
*dev_priv
,
966 struct vmw_cmdbuf_res_manager
*man
,
967 u32 user_key
, const void *bytecode
,
968 SVGA3dShaderType shader_type
,
970 struct list_head
*list
)
972 struct vmw_dma_buffer
*buf
;
973 struct ttm_bo_kmap_obj map
;
976 struct vmw_resource
*res
;
978 if (!vmw_shader_id_ok(user_key
, shader_type
))
981 /* Allocate and pin a DMA buffer */
982 buf
= kzalloc(sizeof(*buf
), GFP_KERNEL
);
983 if (unlikely(buf
== NULL
))
986 ret
= vmw_dmabuf_init(dev_priv
, buf
, size
, &vmw_sys_ne_placement
,
987 true, vmw_dmabuf_bo_free
);
988 if (unlikely(ret
!= 0))
991 ret
= ttm_bo_reserve(&buf
->base
, false, true, false, NULL
);
992 if (unlikely(ret
!= 0))
995 /* Map and copy shader bytecode. */
996 ret
= ttm_bo_kmap(&buf
->base
, 0, PAGE_ALIGN(size
) >> PAGE_SHIFT
,
998 if (unlikely(ret
!= 0)) {
999 ttm_bo_unreserve(&buf
->base
);
1003 memcpy(ttm_kmap_obj_virtual(&map
, &is_iomem
), bytecode
, size
);
1006 ttm_bo_kunmap(&map
);
1007 ret
= ttm_bo_validate(&buf
->base
, &vmw_sys_placement
, false, true);
1009 ttm_bo_unreserve(&buf
->base
);
1011 res
= vmw_shader_alloc(dev_priv
, buf
, size
, 0, shader_type
);
1012 if (unlikely(ret
!= 0))
1015 ret
= vmw_cmdbuf_res_add(man
, vmw_cmdbuf_res_shader
,
1016 vmw_shader_key(user_key
, shader_type
),
1018 vmw_resource_unreference(&res
);
1020 vmw_dmabuf_unreference(&buf
);
1026 * vmw_shader_lookup - Look up a compat shader
1028 * @man: Pointer to the command buffer managed resource manager identifying
1029 * the shader namespace.
1030 * @user_key: The user space id of the shader.
1031 * @shader_type: The shader type.
1033 * Returns a refcounted pointer to a struct vmw_resource if the shader was
1034 * found. An error pointer otherwise.
1036 struct vmw_resource
*
1037 vmw_shader_lookup(struct vmw_cmdbuf_res_manager
*man
,
1039 SVGA3dShaderType shader_type
)
1041 if (!vmw_shader_id_ok(user_key
, shader_type
))
1042 return ERR_PTR(-EINVAL
);
1044 return vmw_cmdbuf_res_lookup(man
, vmw_cmdbuf_res_shader
,
1045 vmw_shader_key(user_key
, shader_type
));
1048 int vmw_shader_define_ioctl(struct drm_device
*dev
, void *data
,
1049 struct drm_file
*file_priv
)
1051 struct drm_vmw_shader_create_arg
*arg
=
1052 (struct drm_vmw_shader_create_arg
*)data
;
1054 return vmw_shader_define(dev
, file_priv
, arg
->shader_type
,
1056 arg
->size
, arg
->offset
,
1058 &arg
->shader_handle
);