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 res->hw_destroy = 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)) {
227 cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
228 cmd->header.size = sizeof(cmd->body);
229 cmd->body.shid = res->id;
230 cmd->body.type = shader->type;
231 cmd->body.sizeInBytes = shader->size;
232 vmw_fifo_commit(dev_priv, sizeof(*cmd));
233 vmw_fifo_resource_inc(dev_priv);
238 vmw_resource_release_id(res);
243 static int vmw_gb_shader_bind(struct vmw_resource *res,
244 struct ttm_validate_buffer *val_buf)
246 struct vmw_private *dev_priv = res->dev_priv;
248 SVGA3dCmdHeader header;
249 SVGA3dCmdBindGBShader body;
251 struct ttm_buffer_object *bo = val_buf->bo;
253 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
255 cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
256 if (unlikely(cmd == NULL))
259 cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
260 cmd->header.size = sizeof(cmd->body);
261 cmd->body.shid = res->id;
262 cmd->body.mobid = bo->mem.start;
263 cmd->body.offsetInBytes = res->backup_offset;
264 res->backup_dirty = false;
265 vmw_fifo_commit(dev_priv, sizeof(*cmd));
270 static int vmw_gb_shader_unbind(struct vmw_resource *res,
272 struct ttm_validate_buffer *val_buf)
274 struct vmw_private *dev_priv = res->dev_priv;
276 SVGA3dCmdHeader header;
277 SVGA3dCmdBindGBShader body;
279 struct vmw_fence_obj *fence;
281 BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
283 cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
284 if (unlikely(cmd == NULL))
287 cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
288 cmd->header.size = sizeof(cmd->body);
289 cmd->body.shid = res->id;
290 cmd->body.mobid = SVGA3D_INVALID_ID;
291 cmd->body.offsetInBytes = 0;
292 vmw_fifo_commit(dev_priv, sizeof(*cmd));
295 * Create a fence object and fence the backup buffer.
298 (void) vmw_execbuf_fence_commands(NULL, dev_priv,
301 vmw_bo_fence_single(val_buf->bo, fence);
303 if (likely(fence != NULL))
304 vmw_fence_obj_unreference(&fence);
309 static int vmw_gb_shader_destroy(struct vmw_resource *res)
311 struct vmw_private *dev_priv = res->dev_priv;
313 SVGA3dCmdHeader header;
314 SVGA3dCmdDestroyGBShader body;
317 if (likely(res->id == -1))
320 mutex_lock(&dev_priv->binding_mutex);
321 vmw_binding_res_list_scrub(&res->binding_head);
323 cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
324 if (unlikely(cmd == NULL)) {
325 mutex_unlock(&dev_priv->binding_mutex);
329 cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
330 cmd->header.size = sizeof(cmd->body);
331 cmd->body.shid = res->id;
332 vmw_fifo_commit(dev_priv, sizeof(*cmd));
333 mutex_unlock(&dev_priv->binding_mutex);
334 vmw_resource_release_id(res);
335 vmw_fifo_resource_dec(dev_priv);
345 * vmw_dx_shader_commit_notify - Notify that a shader operation has been
346 * committed to hardware from a user-supplied command stream.
348 * @res: Pointer to the shader resource.
349 * @state: Indicating whether a creation or removal has been committed.
352 static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
353 enum vmw_cmdbuf_res_state state)
355 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
356 struct vmw_private *dev_priv = res->dev_priv;
358 if (state == VMW_CMDBUF_RES_ADD) {
359 mutex_lock(&dev_priv->binding_mutex);
360 vmw_cotable_add_resource(shader->cotable,
361 &shader->cotable_head);
362 shader->committed = true;
363 res->id = shader->id;
364 mutex_unlock(&dev_priv->binding_mutex);
366 mutex_lock(&dev_priv->binding_mutex);
367 list_del_init(&shader->cotable_head);
368 shader->committed = false;
370 mutex_unlock(&dev_priv->binding_mutex);
375 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
377 * @res: The shader resource
379 * This function reverts a scrub operation.
381 static int vmw_dx_shader_unscrub(struct vmw_resource *res)
383 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
384 struct vmw_private *dev_priv = res->dev_priv;
386 SVGA3dCmdHeader header;
387 SVGA3dCmdDXBindShader body;
390 if (!list_empty(&shader->cotable_head) || !shader->committed)
393 cmd = VMW_FIFO_RESERVE_DX(dev_priv, sizeof(*cmd), shader->ctx->id);
394 if (unlikely(cmd == NULL))
397 cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
398 cmd->header.size = sizeof(cmd->body);
399 cmd->body.cid = shader->ctx->id;
400 cmd->body.shid = shader->id;
401 cmd->body.mobid = res->backup->base.mem.start;
402 cmd->body.offsetInBytes = res->backup_offset;
403 vmw_fifo_commit(dev_priv, sizeof(*cmd));
405 vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
411 * vmw_dx_shader_create - The DX shader create callback
413 * @res: The DX shader resource
415 * The create callback is called as part of resource validation and
416 * makes sure that we unscrub the shader if it's previously been scrubbed.
418 static int vmw_dx_shader_create(struct vmw_resource *res)
420 struct vmw_private *dev_priv = res->dev_priv;
421 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
424 WARN_ON_ONCE(!shader->committed);
426 if (!list_empty(&res->mob_head)) {
427 mutex_lock(&dev_priv->binding_mutex);
428 ret = vmw_dx_shader_unscrub(res);
429 mutex_unlock(&dev_priv->binding_mutex);
432 res->id = shader->id;
437 * vmw_dx_shader_bind - The DX shader bind callback
439 * @res: The DX shader resource
440 * @val_buf: Pointer to the validate buffer.
443 static int vmw_dx_shader_bind(struct vmw_resource *res,
444 struct ttm_validate_buffer *val_buf)
446 struct vmw_private *dev_priv = res->dev_priv;
447 struct ttm_buffer_object *bo = val_buf->bo;
449 BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
450 mutex_lock(&dev_priv->binding_mutex);
451 vmw_dx_shader_unscrub(res);
452 mutex_unlock(&dev_priv->binding_mutex);
458 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
460 * @res: The shader resource
462 * This function unbinds a MOB from the DX shader without requiring the
463 * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
464 * However, once the driver eventually decides to unbind the MOB, it doesn't
465 * need to access the context.
467 static int vmw_dx_shader_scrub(struct vmw_resource *res)
469 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
470 struct vmw_private *dev_priv = res->dev_priv;
472 SVGA3dCmdHeader header;
473 SVGA3dCmdDXBindShader body;
476 if (list_empty(&shader->cotable_head))
479 WARN_ON_ONCE(!shader->committed);
480 cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd));
481 if (unlikely(cmd == NULL))
484 cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
485 cmd->header.size = sizeof(cmd->body);
486 cmd->body.cid = shader->ctx->id;
487 cmd->body.shid = res->id;
488 cmd->body.mobid = SVGA3D_INVALID_ID;
489 cmd->body.offsetInBytes = 0;
490 vmw_fifo_commit(dev_priv, sizeof(*cmd));
492 list_del_init(&shader->cotable_head);
498 * vmw_dx_shader_unbind - The dx shader unbind callback.
500 * @res: The shader resource
501 * @readback: Whether this is a readback unbind. Currently unused.
502 * @val_buf: MOB buffer information.
504 static int vmw_dx_shader_unbind(struct vmw_resource *res,
506 struct ttm_validate_buffer *val_buf)
508 struct vmw_private *dev_priv = res->dev_priv;
509 struct vmw_fence_obj *fence;
512 BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
514 mutex_lock(&dev_priv->binding_mutex);
515 ret = vmw_dx_shader_scrub(res);
516 mutex_unlock(&dev_priv->binding_mutex);
521 (void) vmw_execbuf_fence_commands(NULL, dev_priv,
523 vmw_bo_fence_single(val_buf->bo, fence);
525 if (likely(fence != NULL))
526 vmw_fence_obj_unreference(&fence);
532 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
535 * @dev_priv: Pointer to device private structure.
536 * @list: The list of cotable resources.
537 * @readback: Whether the call was part of a readback unbind.
539 * Scrubs all shader MOBs so that any subsequent shader unbind or shader
540 * destroy operation won't need to swap in the context.
542 void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
543 struct list_head *list,
546 struct vmw_dx_shader *entry, *next;
548 lockdep_assert_held_once(&dev_priv->binding_mutex);
550 list_for_each_entry_safe(entry, next, list, cotable_head) {
551 WARN_ON(vmw_dx_shader_scrub(&entry->res));
553 entry->committed = false;
558 * vmw_dx_shader_res_free - The DX shader free callback
560 * @res: The shader resource
562 * Frees the DX shader resource and updates memory accounting.
564 static void vmw_dx_shader_res_free(struct vmw_resource *res)
566 struct vmw_private *dev_priv = res->dev_priv;
567 struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
569 vmw_resource_unreference(&shader->cotable);
571 ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
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;
593 struct ttm_operation_ctx ttm_opt_ctx = {
594 .interruptible = true,
599 if (!vmw_shader_dx_size)
600 vmw_shader_dx_size = ttm_round_pot(sizeof(*shader));
602 if (!vmw_shader_id_ok(user_key, shader_type))
605 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_shader_dx_size,
608 if (ret != -ERESTARTSYS)
609 DRM_ERROR("Out of graphics memory for shader "
614 shader = kmalloc(sizeof(*shader), GFP_KERNEL);
616 ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size);
622 shader->cotable = vmw_resource_reference
623 (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
624 shader->id = user_key;
625 shader->committed = false;
626 INIT_LIST_HEAD(&shader->cotable_head);
627 ret = vmw_resource_init(dev_priv, res, true,
628 vmw_dx_shader_res_free, &vmw_dx_shader_func);
630 goto out_resource_init;
633 * The user_key name-space is not per shader type for DX shaders,
634 * so when hashing, use a single zero shader type.
636 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
637 vmw_shader_key(user_key, 0),
640 goto out_resource_init;
642 res->id = shader->id;
643 res->hw_destroy = vmw_hw_shader_destroy;
646 vmw_resource_unreference(&res);
654 * User-space shader management:
657 static struct vmw_resource *
658 vmw_user_shader_base_to_res(struct ttm_base_object *base)
660 return &(container_of(base, struct vmw_user_shader, base)->
664 static void vmw_user_shader_free(struct vmw_resource *res)
666 struct vmw_user_shader *ushader =
667 container_of(res, struct vmw_user_shader, shader.res);
668 struct vmw_private *dev_priv = res->dev_priv;
670 ttm_base_object_kfree(ushader, base);
671 ttm_mem_global_free(vmw_mem_glob(dev_priv),
672 vmw_user_shader_size);
675 static void vmw_shader_free(struct vmw_resource *res)
677 struct vmw_shader *shader = vmw_res_to_shader(res);
678 struct vmw_private *dev_priv = res->dev_priv;
681 ttm_mem_global_free(vmw_mem_glob(dev_priv),
686 * This function is called when user space has no more references on the
687 * base object. It releases the base-object's reference on the resource object.
690 static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
692 struct ttm_base_object *base = *p_base;
693 struct vmw_resource *res = vmw_user_shader_base_to_res(base);
696 vmw_resource_unreference(&res);
699 int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
700 struct drm_file *file_priv)
702 struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
703 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
705 return ttm_ref_object_base_unref(tfile, arg->handle,
709 static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
710 struct vmw_buffer_object *buffer,
713 SVGA3dShaderType shader_type,
714 uint8_t num_input_sig,
715 uint8_t num_output_sig,
716 struct ttm_object_file *tfile,
719 struct vmw_user_shader *ushader;
720 struct vmw_resource *res, *tmp;
721 struct ttm_operation_ctx ctx = {
722 .interruptible = true,
727 if (unlikely(vmw_user_shader_size == 0))
728 vmw_user_shader_size =
729 ttm_round_pot(sizeof(struct vmw_user_shader)) +
730 VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE;
732 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
733 vmw_user_shader_size,
735 if (unlikely(ret != 0)) {
736 if (ret != -ERESTARTSYS)
737 DRM_ERROR("Out of graphics memory for shader "
742 ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
743 if (unlikely(!ushader)) {
744 ttm_mem_global_free(vmw_mem_glob(dev_priv),
745 vmw_user_shader_size);
750 res = &ushader->shader.res;
751 ushader->base.shareable = false;
752 ushader->base.tfile = NULL;
755 * From here on, the destructor takes over resource freeing.
758 ret = vmw_gb_shader_init(dev_priv, res, shader_size,
759 offset, shader_type, num_input_sig,
760 num_output_sig, buffer,
761 vmw_user_shader_free);
762 if (unlikely(ret != 0))
765 tmp = vmw_resource_reference(res);
766 ret = ttm_base_object_init(tfile, &ushader->base, false,
768 &vmw_user_shader_base_release, NULL);
770 if (unlikely(ret != 0)) {
771 vmw_resource_unreference(&tmp);
776 *handle = ushader->base.handle;
778 vmw_resource_unreference(&res);
784 static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
785 struct vmw_buffer_object *buffer,
788 SVGA3dShaderType shader_type)
790 struct vmw_shader *shader;
791 struct vmw_resource *res;
792 struct ttm_operation_ctx ctx = {
793 .interruptible = true,
798 if (unlikely(vmw_shader_size == 0))
800 ttm_round_pot(sizeof(struct vmw_shader)) +
803 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
806 if (unlikely(ret != 0)) {
807 if (ret != -ERESTARTSYS)
808 DRM_ERROR("Out of graphics memory for shader "
813 shader = kzalloc(sizeof(*shader), GFP_KERNEL);
814 if (unlikely(!shader)) {
815 ttm_mem_global_free(vmw_mem_glob(dev_priv),
824 * From here on, the destructor takes over resource freeing.
826 ret = vmw_gb_shader_init(dev_priv, res, shader_size,
827 offset, shader_type, 0, 0, buffer,
831 return ret ? ERR_PTR(ret) : res;
835 static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
836 enum drm_vmw_shader_type shader_type_drm,
837 u32 buffer_handle, size_t size, size_t offset,
838 uint8_t num_input_sig, uint8_t num_output_sig,
839 uint32_t *shader_handle)
841 struct vmw_private *dev_priv = vmw_priv(dev);
842 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
843 struct vmw_buffer_object *buffer = NULL;
844 SVGA3dShaderType shader_type;
847 if (buffer_handle != SVGA3D_INVALID_ID) {
848 ret = vmw_user_bo_lookup(tfile, buffer_handle,
850 if (unlikely(ret != 0)) {
851 VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
855 if ((u64)buffer->base.num_pages * PAGE_SIZE <
856 (u64)size + (u64)offset) {
857 VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
863 switch (shader_type_drm) {
864 case drm_vmw_shader_type_vs:
865 shader_type = SVGA3D_SHADERTYPE_VS;
867 case drm_vmw_shader_type_ps:
868 shader_type = SVGA3D_SHADERTYPE_PS;
871 VMW_DEBUG_USER("Illegal shader type.\n");
876 ret = ttm_read_lock(&dev_priv->reservation_sem, true);
877 if (unlikely(ret != 0))
880 ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
881 shader_type, num_input_sig,
882 num_output_sig, tfile, shader_handle);
884 ttm_read_unlock(&dev_priv->reservation_sem);
886 vmw_bo_unreference(&buffer);
891 * vmw_shader_id_ok - Check whether a compat shader user key and
892 * shader type are within valid bounds.
894 * @user_key: User space id of the shader.
895 * @shader_type: Shader type.
897 * Returns true if valid false if not.
899 static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
901 return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
905 * vmw_shader_key - Compute a hash key suitable for a compat shader.
907 * @user_key: User space id of the shader.
908 * @shader_type: Shader type.
910 * Returns a hash key suitable for a command buffer managed resource
911 * manager hash table.
913 static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
915 return user_key | (shader_type << 20);
919 * vmw_shader_remove - Stage a compat shader for removal.
921 * @man: Pointer to the compat shader manager identifying the shader namespace.
922 * @user_key: The key that is used to identify the shader. The key is
923 * unique to the shader type.
924 * @shader_type: Shader type.
925 * @list: Caller's list of staged command buffer resource actions.
927 int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
928 u32 user_key, SVGA3dShaderType shader_type,
929 struct list_head *list)
931 struct vmw_resource *dummy;
933 if (!vmw_shader_id_ok(user_key, shader_type))
936 return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
937 vmw_shader_key(user_key, shader_type),
942 * vmw_compat_shader_add - Create a compat shader and stage it for addition
943 * as a command buffer managed resource.
945 * @man: Pointer to the compat shader manager identifying the shader namespace.
946 * @user_key: The key that is used to identify the shader. The key is
947 * unique to the shader type.
948 * @bytecode: Pointer to the bytecode of the shader.
949 * @shader_type: Shader type.
950 * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is
951 * to be created with.
952 * @list: Caller's list of staged command buffer resource actions.
955 int vmw_compat_shader_add(struct vmw_private *dev_priv,
956 struct vmw_cmdbuf_res_manager *man,
957 u32 user_key, const void *bytecode,
958 SVGA3dShaderType shader_type,
960 struct list_head *list)
962 struct ttm_operation_ctx ctx = { false, true };
963 struct vmw_buffer_object *buf;
964 struct ttm_bo_kmap_obj map;
967 struct vmw_resource *res;
969 if (!vmw_shader_id_ok(user_key, shader_type))
972 /* Allocate and pin a DMA buffer */
973 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
977 ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_ne_placement,
978 true, vmw_bo_bo_free);
979 if (unlikely(ret != 0))
982 ret = ttm_bo_reserve(&buf->base, false, true, NULL);
983 if (unlikely(ret != 0))
986 /* Map and copy shader bytecode. */
987 ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT,
989 if (unlikely(ret != 0)) {
990 ttm_bo_unreserve(&buf->base);
994 memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
998 ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx);
1000 ttm_bo_unreserve(&buf->base);
1002 res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
1003 if (unlikely(ret != 0))
1006 ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
1007 vmw_shader_key(user_key, shader_type),
1009 vmw_resource_unreference(&res);
1011 vmw_bo_unreference(&buf);
1017 * vmw_shader_lookup - Look up a compat shader
1019 * @man: Pointer to the command buffer managed resource manager identifying
1020 * the shader namespace.
1021 * @user_key: The user space id of the shader.
1022 * @shader_type: The shader type.
1024 * Returns a refcounted pointer to a struct vmw_resource if the shader was
1025 * found. An error pointer otherwise.
1027 struct vmw_resource *
1028 vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
1030 SVGA3dShaderType shader_type)
1032 if (!vmw_shader_id_ok(user_key, shader_type))
1033 return ERR_PTR(-EINVAL);
1035 return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
1036 vmw_shader_key(user_key, shader_type));
1039 int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
1040 struct drm_file *file_priv)
1042 struct drm_vmw_shader_create_arg *arg =
1043 (struct drm_vmw_shader_create_arg *)data;
1045 return vmw_shader_define(dev, file_priv, arg->shader_type,
1047 arg->size, arg->offset,
1049 &arg->shader_handle);