1dff96888SDirk Hohndel (VMware) // SPDX-License-Identifier: GPL-2.0 OR MIT 2c74c162fSThomas Hellstrom /************************************************************************** 3c74c162fSThomas Hellstrom * 4dff96888SDirk Hohndel (VMware) * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 5c74c162fSThomas Hellstrom * 6c74c162fSThomas Hellstrom * Permission is hereby granted, free of charge, to any person obtaining a 7c74c162fSThomas Hellstrom * copy of this software and associated documentation files (the 8c74c162fSThomas Hellstrom * "Software"), to deal in the Software without restriction, including 9c74c162fSThomas Hellstrom * without limitation the rights to use, copy, modify, merge, publish, 10c74c162fSThomas Hellstrom * distribute, sub license, and/or sell copies of the Software, and to 11c74c162fSThomas Hellstrom * permit persons to whom the Software is furnished to do so, subject to 12c74c162fSThomas Hellstrom * the following conditions: 13c74c162fSThomas Hellstrom * 14c74c162fSThomas Hellstrom * The above copyright notice and this permission notice (including the 15c74c162fSThomas Hellstrom * next paragraph) shall be included in all copies or substantial portions 16c74c162fSThomas Hellstrom * of the Software. 17c74c162fSThomas Hellstrom * 18c74c162fSThomas Hellstrom * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19c74c162fSThomas Hellstrom * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20c74c162fSThomas Hellstrom * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21c74c162fSThomas Hellstrom * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22c74c162fSThomas Hellstrom * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23c74c162fSThomas Hellstrom * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24c74c162fSThomas Hellstrom * USE OR OTHER DEALINGS IN THE SOFTWARE. 25c74c162fSThomas Hellstrom * 26c74c162fSThomas Hellstrom **************************************************************************/ 27c74c162fSThomas Hellstrom 28008be682SMasahiro Yamada #include <drm/ttm/ttm_placement.h> 29008be682SMasahiro Yamada 30c74c162fSThomas Hellstrom #include "vmwgfx_drv.h" 31c74c162fSThomas Hellstrom #include "vmwgfx_resource_priv.h" 32d80efd5cSThomas Hellstrom #include "vmwgfx_binding.h" 33c74c162fSThomas Hellstrom 34c74c162fSThomas Hellstrom struct vmw_shader { 35c74c162fSThomas Hellstrom struct vmw_resource res; 36c74c162fSThomas Hellstrom SVGA3dShaderType type; 37c74c162fSThomas Hellstrom uint32_t size; 38d80efd5cSThomas Hellstrom uint8_t num_input_sig; 39d80efd5cSThomas Hellstrom uint8_t num_output_sig; 40c74c162fSThomas Hellstrom }; 41c74c162fSThomas Hellstrom 42c74c162fSThomas Hellstrom struct vmw_user_shader { 43c74c162fSThomas Hellstrom struct ttm_base_object base; 44c74c162fSThomas Hellstrom struct vmw_shader shader; 45c74c162fSThomas Hellstrom }; 46c74c162fSThomas Hellstrom 47d80efd5cSThomas Hellstrom struct vmw_dx_shader { 48d80efd5cSThomas Hellstrom struct vmw_resource res; 49d80efd5cSThomas Hellstrom struct vmw_resource *ctx; 50d80efd5cSThomas Hellstrom struct vmw_resource *cotable; 51d80efd5cSThomas Hellstrom u32 id; 52d80efd5cSThomas Hellstrom bool committed; 53d80efd5cSThomas Hellstrom struct list_head cotable_head; 54d80efd5cSThomas Hellstrom }; 55d80efd5cSThomas Hellstrom 5618e4a466SThomas Hellstrom static uint64_t vmw_user_shader_size; 5718e4a466SThomas Hellstrom static uint64_t vmw_shader_size; 58d80efd5cSThomas Hellstrom static size_t vmw_shader_dx_size; 59d5bde956SThomas Hellstrom 60c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res); 61c74c162fSThomas Hellstrom static struct vmw_resource * 62c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base); 63c74c162fSThomas Hellstrom 64c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res); 65c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 66c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 67c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 68c74c162fSThomas Hellstrom bool readback, 69c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 70c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res); 71c74c162fSThomas Hellstrom 72d80efd5cSThomas Hellstrom static int vmw_dx_shader_create(struct vmw_resource *res); 73d80efd5cSThomas Hellstrom static int vmw_dx_shader_bind(struct vmw_resource *res, 74d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf); 75d80efd5cSThomas Hellstrom static int vmw_dx_shader_unbind(struct vmw_resource *res, 76d80efd5cSThomas Hellstrom bool readback, 77d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf); 78d80efd5cSThomas Hellstrom static void vmw_dx_shader_commit_notify(struct vmw_resource *res, 79d80efd5cSThomas Hellstrom enum vmw_cmdbuf_res_state state); 80d80efd5cSThomas Hellstrom static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type); 81d80efd5cSThomas Hellstrom static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type); 82d80efd5cSThomas Hellstrom static uint64_t vmw_user_shader_size; 83d80efd5cSThomas Hellstrom 84c74c162fSThomas Hellstrom static const struct vmw_user_resource_conv user_shader_conv = { 85c74c162fSThomas Hellstrom .object_type = VMW_RES_SHADER, 86c74c162fSThomas Hellstrom .base_obj_to_res = vmw_user_shader_base_to_res, 87c74c162fSThomas Hellstrom .res_free = vmw_user_shader_free 88c74c162fSThomas Hellstrom }; 89c74c162fSThomas Hellstrom 90c74c162fSThomas Hellstrom const struct vmw_user_resource_conv *user_shader_converter = 91c74c162fSThomas Hellstrom &user_shader_conv; 92c74c162fSThomas Hellstrom 93c74c162fSThomas Hellstrom 94c74c162fSThomas Hellstrom static const struct vmw_res_func vmw_gb_shader_func = { 95c74c162fSThomas Hellstrom .res_type = vmw_res_shader, 96c74c162fSThomas Hellstrom .needs_backup = true, 97c74c162fSThomas Hellstrom .may_evict = true, 98a0a63940SThomas Hellstrom .prio = 3, 99a0a63940SThomas Hellstrom .dirty_prio = 3, 100c74c162fSThomas Hellstrom .type_name = "guest backed shaders", 101c74c162fSThomas Hellstrom .backup_placement = &vmw_mob_placement, 102c74c162fSThomas Hellstrom .create = vmw_gb_shader_create, 103c74c162fSThomas Hellstrom .destroy = vmw_gb_shader_destroy, 104c74c162fSThomas Hellstrom .bind = vmw_gb_shader_bind, 105c74c162fSThomas Hellstrom .unbind = vmw_gb_shader_unbind 106c74c162fSThomas Hellstrom }; 107c74c162fSThomas Hellstrom 108d80efd5cSThomas Hellstrom static const struct vmw_res_func vmw_dx_shader_func = { 109d80efd5cSThomas Hellstrom .res_type = vmw_res_shader, 110d80efd5cSThomas Hellstrom .needs_backup = true, 111a0a63940SThomas Hellstrom .may_evict = true, 112a0a63940SThomas Hellstrom .prio = 3, 113a0a63940SThomas Hellstrom .dirty_prio = 3, 114d80efd5cSThomas Hellstrom .type_name = "dx shaders", 115d80efd5cSThomas Hellstrom .backup_placement = &vmw_mob_placement, 116d80efd5cSThomas Hellstrom .create = vmw_dx_shader_create, 117d80efd5cSThomas Hellstrom /* 118d80efd5cSThomas Hellstrom * The destroy callback is only called with a committed resource on 119d80efd5cSThomas Hellstrom * context destroy, in which case we destroy the cotable anyway, 120d80efd5cSThomas Hellstrom * so there's no need to destroy DX shaders separately. 121d80efd5cSThomas Hellstrom */ 122d80efd5cSThomas Hellstrom .destroy = NULL, 123d80efd5cSThomas Hellstrom .bind = vmw_dx_shader_bind, 124d80efd5cSThomas Hellstrom .unbind = vmw_dx_shader_unbind, 125d80efd5cSThomas Hellstrom .commit_notify = vmw_dx_shader_commit_notify, 126d80efd5cSThomas Hellstrom }; 127d80efd5cSThomas Hellstrom 128ad2ae415SLee Jones /* 129c74c162fSThomas Hellstrom * Shader management: 130c74c162fSThomas Hellstrom */ 131c74c162fSThomas Hellstrom 132c74c162fSThomas Hellstrom static inline struct vmw_shader * 133c74c162fSThomas Hellstrom vmw_res_to_shader(struct vmw_resource *res) 134c74c162fSThomas Hellstrom { 135c74c162fSThomas Hellstrom return container_of(res, struct vmw_shader, res); 136c74c162fSThomas Hellstrom } 137c74c162fSThomas Hellstrom 138d80efd5cSThomas Hellstrom /** 139d80efd5cSThomas Hellstrom * vmw_res_to_dx_shader - typecast a struct vmw_resource to a 140d80efd5cSThomas Hellstrom * struct vmw_dx_shader 141d80efd5cSThomas Hellstrom * 142d80efd5cSThomas Hellstrom * @res: Pointer to the struct vmw_resource. 143d80efd5cSThomas Hellstrom */ 144d80efd5cSThomas Hellstrom static inline struct vmw_dx_shader * 145d80efd5cSThomas Hellstrom vmw_res_to_dx_shader(struct vmw_resource *res) 146d80efd5cSThomas Hellstrom { 147d80efd5cSThomas Hellstrom return container_of(res, struct vmw_dx_shader, res); 148d80efd5cSThomas Hellstrom } 149d80efd5cSThomas Hellstrom 150c74c162fSThomas Hellstrom static void vmw_hw_shader_destroy(struct vmw_resource *res) 151c74c162fSThomas Hellstrom { 152d80efd5cSThomas Hellstrom if (likely(res->func->destroy)) 153d80efd5cSThomas Hellstrom (void) res->func->destroy(res); 154d80efd5cSThomas Hellstrom else 155d80efd5cSThomas Hellstrom res->id = -1; 156c74c162fSThomas Hellstrom } 157c74c162fSThomas Hellstrom 158d80efd5cSThomas Hellstrom 159c74c162fSThomas Hellstrom static int vmw_gb_shader_init(struct vmw_private *dev_priv, 160c74c162fSThomas Hellstrom struct vmw_resource *res, 161c74c162fSThomas Hellstrom uint32_t size, 162c74c162fSThomas Hellstrom uint64_t offset, 163c74c162fSThomas Hellstrom SVGA3dShaderType type, 164d80efd5cSThomas Hellstrom uint8_t num_input_sig, 165d80efd5cSThomas Hellstrom uint8_t num_output_sig, 166f1d34bfdSThomas Hellstrom struct vmw_buffer_object *byte_code, 167c74c162fSThomas Hellstrom void (*res_free) (struct vmw_resource *res)) 168c74c162fSThomas Hellstrom { 169c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 170c74c162fSThomas Hellstrom int ret; 171c74c162fSThomas Hellstrom 172d80efd5cSThomas Hellstrom ret = vmw_resource_init(dev_priv, res, true, res_free, 173d80efd5cSThomas Hellstrom &vmw_gb_shader_func); 174c74c162fSThomas Hellstrom 175c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 176c74c162fSThomas Hellstrom if (res_free) 177c74c162fSThomas Hellstrom res_free(res); 178c74c162fSThomas Hellstrom else 179c74c162fSThomas Hellstrom kfree(res); 180c74c162fSThomas Hellstrom return ret; 181c74c162fSThomas Hellstrom } 182c74c162fSThomas Hellstrom 183c74c162fSThomas Hellstrom res->backup_size = size; 184c74c162fSThomas Hellstrom if (byte_code) { 185f1d34bfdSThomas Hellstrom res->backup = vmw_bo_reference(byte_code); 186c74c162fSThomas Hellstrom res->backup_offset = offset; 187c74c162fSThomas Hellstrom } 188c74c162fSThomas Hellstrom shader->size = size; 189c74c162fSThomas Hellstrom shader->type = type; 190d80efd5cSThomas Hellstrom shader->num_input_sig = num_input_sig; 191d80efd5cSThomas Hellstrom shader->num_output_sig = num_output_sig; 192c74c162fSThomas Hellstrom 19313289241SThomas Hellstrom res->hw_destroy = vmw_hw_shader_destroy; 194c74c162fSThomas Hellstrom return 0; 195c74c162fSThomas Hellstrom } 196c74c162fSThomas Hellstrom 197d80efd5cSThomas Hellstrom /* 198d80efd5cSThomas Hellstrom * GB shader code: 199d80efd5cSThomas Hellstrom */ 200d80efd5cSThomas Hellstrom 201c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res) 202c74c162fSThomas Hellstrom { 203c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 204c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 205c74c162fSThomas Hellstrom int ret; 206c74c162fSThomas Hellstrom struct { 207c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 208c74c162fSThomas Hellstrom SVGA3dCmdDefineGBShader body; 209c74c162fSThomas Hellstrom } *cmd; 210c74c162fSThomas Hellstrom 211c74c162fSThomas Hellstrom if (likely(res->id != -1)) 212c74c162fSThomas Hellstrom return 0; 213c74c162fSThomas Hellstrom 214c74c162fSThomas Hellstrom ret = vmw_resource_alloc_id(res); 215c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 216c74c162fSThomas Hellstrom DRM_ERROR("Failed to allocate a shader id.\n"); 217c74c162fSThomas Hellstrom goto out_no_id; 218c74c162fSThomas Hellstrom } 219c74c162fSThomas Hellstrom 220c74c162fSThomas Hellstrom if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { 221c74c162fSThomas Hellstrom ret = -EBUSY; 222c74c162fSThomas Hellstrom goto out_no_fifo; 223c74c162fSThomas Hellstrom } 224c74c162fSThomas Hellstrom 2258426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 226c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 227c74c162fSThomas Hellstrom ret = -ENOMEM; 228c74c162fSThomas Hellstrom goto out_no_fifo; 229c74c162fSThomas Hellstrom } 230c74c162fSThomas Hellstrom 231c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; 232c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 233c74c162fSThomas Hellstrom cmd->body.shid = res->id; 234c74c162fSThomas Hellstrom cmd->body.type = shader->type; 235c74c162fSThomas Hellstrom cmd->body.sizeInBytes = shader->size; 2368426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 237153b3d5bSThomas Hellstrom vmw_fifo_resource_inc(dev_priv); 238c74c162fSThomas Hellstrom 239c74c162fSThomas Hellstrom return 0; 240c74c162fSThomas Hellstrom 241c74c162fSThomas Hellstrom out_no_fifo: 242c74c162fSThomas Hellstrom vmw_resource_release_id(res); 243c74c162fSThomas Hellstrom out_no_id: 244c74c162fSThomas Hellstrom return ret; 245c74c162fSThomas Hellstrom } 246c74c162fSThomas Hellstrom 247c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 248c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 249c74c162fSThomas Hellstrom { 250c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 251c74c162fSThomas Hellstrom struct { 252c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 253c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 254c74c162fSThomas Hellstrom } *cmd; 255c74c162fSThomas Hellstrom struct ttm_buffer_object *bo = val_buf->bo; 256c74c162fSThomas Hellstrom 257d3116756SChristian König BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 258c74c162fSThomas Hellstrom 2598426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 26011c45419SDeepak Rawat if (unlikely(cmd == NULL)) 261c74c162fSThomas Hellstrom return -ENOMEM; 262c74c162fSThomas Hellstrom 263c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 264c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 265c74c162fSThomas Hellstrom cmd->body.shid = res->id; 266d3116756SChristian König cmd->body.mobid = bo->resource->start; 267b8ccd1e4SThomas Hellstrom cmd->body.offsetInBytes = res->backup_offset; 268c74c162fSThomas Hellstrom res->backup_dirty = false; 2698426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 270c74c162fSThomas Hellstrom 271c74c162fSThomas Hellstrom return 0; 272c74c162fSThomas Hellstrom } 273c74c162fSThomas Hellstrom 274c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 275c74c162fSThomas Hellstrom bool readback, 276c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 277c74c162fSThomas Hellstrom { 278c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 279c74c162fSThomas Hellstrom struct { 280c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 281c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 282c74c162fSThomas Hellstrom } *cmd; 283c74c162fSThomas Hellstrom struct vmw_fence_obj *fence; 284c74c162fSThomas Hellstrom 285d3116756SChristian König BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB); 286c74c162fSThomas Hellstrom 2878426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 28811c45419SDeepak Rawat if (unlikely(cmd == NULL)) 289c74c162fSThomas Hellstrom return -ENOMEM; 290c74c162fSThomas Hellstrom 291c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 292c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 293c74c162fSThomas Hellstrom cmd->body.shid = res->id; 294c74c162fSThomas Hellstrom cmd->body.mobid = SVGA3D_INVALID_ID; 295c74c162fSThomas Hellstrom cmd->body.offsetInBytes = 0; 2968426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 297c74c162fSThomas Hellstrom 298c74c162fSThomas Hellstrom /* 299c74c162fSThomas Hellstrom * Create a fence object and fence the backup buffer. 300c74c162fSThomas Hellstrom */ 301c74c162fSThomas Hellstrom 302c74c162fSThomas Hellstrom (void) vmw_execbuf_fence_commands(NULL, dev_priv, 303c74c162fSThomas Hellstrom &fence, NULL); 304c74c162fSThomas Hellstrom 305e9431ea5SThomas Hellstrom vmw_bo_fence_single(val_buf->bo, fence); 306c74c162fSThomas Hellstrom 307c74c162fSThomas Hellstrom if (likely(fence != NULL)) 308c74c162fSThomas Hellstrom vmw_fence_obj_unreference(&fence); 309c74c162fSThomas Hellstrom 310c74c162fSThomas Hellstrom return 0; 311c74c162fSThomas Hellstrom } 312c74c162fSThomas Hellstrom 313c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res) 314c74c162fSThomas Hellstrom { 315c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 316c74c162fSThomas Hellstrom struct { 317c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 318c74c162fSThomas Hellstrom SVGA3dCmdDestroyGBShader body; 319c74c162fSThomas Hellstrom } *cmd; 320c74c162fSThomas Hellstrom 321c74c162fSThomas Hellstrom if (likely(res->id == -1)) 322c74c162fSThomas Hellstrom return 0; 323c74c162fSThomas Hellstrom 324173fb7d4SThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 325d80efd5cSThomas Hellstrom vmw_binding_res_list_scrub(&res->binding_head); 326173fb7d4SThomas Hellstrom 3278426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 328c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 3293e894a62SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 330c74c162fSThomas Hellstrom return -ENOMEM; 331c74c162fSThomas Hellstrom } 332c74c162fSThomas Hellstrom 333c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; 334c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 335c74c162fSThomas Hellstrom cmd->body.shid = res->id; 3368426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 337173fb7d4SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 338c74c162fSThomas Hellstrom vmw_resource_release_id(res); 339153b3d5bSThomas Hellstrom vmw_fifo_resource_dec(dev_priv); 340c74c162fSThomas Hellstrom 341c74c162fSThomas Hellstrom return 0; 342c74c162fSThomas Hellstrom } 343c74c162fSThomas Hellstrom 344d80efd5cSThomas Hellstrom /* 345d80efd5cSThomas Hellstrom * DX shader code: 346d80efd5cSThomas Hellstrom */ 347d80efd5cSThomas Hellstrom 348d80efd5cSThomas Hellstrom /** 349d80efd5cSThomas Hellstrom * vmw_dx_shader_commit_notify - Notify that a shader operation has been 350d80efd5cSThomas Hellstrom * committed to hardware from a user-supplied command stream. 351d80efd5cSThomas Hellstrom * 352d80efd5cSThomas Hellstrom * @res: Pointer to the shader resource. 353d80efd5cSThomas Hellstrom * @state: Indicating whether a creation or removal has been committed. 354d80efd5cSThomas Hellstrom * 355d80efd5cSThomas Hellstrom */ 356d80efd5cSThomas Hellstrom static void vmw_dx_shader_commit_notify(struct vmw_resource *res, 357d80efd5cSThomas Hellstrom enum vmw_cmdbuf_res_state state) 358d80efd5cSThomas Hellstrom { 359d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 360d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 361d80efd5cSThomas Hellstrom 362d80efd5cSThomas Hellstrom if (state == VMW_CMDBUF_RES_ADD) { 363d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 364d80efd5cSThomas Hellstrom vmw_cotable_add_resource(shader->cotable, 365d80efd5cSThomas Hellstrom &shader->cotable_head); 366d80efd5cSThomas Hellstrom shader->committed = true; 367d80efd5cSThomas Hellstrom res->id = shader->id; 368d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 369d80efd5cSThomas Hellstrom } else { 370d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 371d80efd5cSThomas Hellstrom list_del_init(&shader->cotable_head); 372d80efd5cSThomas Hellstrom shader->committed = false; 373d80efd5cSThomas Hellstrom res->id = -1; 374d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 375d80efd5cSThomas Hellstrom } 376d80efd5cSThomas Hellstrom } 377d80efd5cSThomas Hellstrom 378d80efd5cSThomas Hellstrom /** 379d80efd5cSThomas Hellstrom * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader. 380d80efd5cSThomas Hellstrom * 381d80efd5cSThomas Hellstrom * @res: The shader resource 382d80efd5cSThomas Hellstrom * 383d80efd5cSThomas Hellstrom * This function reverts a scrub operation. 384d80efd5cSThomas Hellstrom */ 385d80efd5cSThomas Hellstrom static int vmw_dx_shader_unscrub(struct vmw_resource *res) 386d80efd5cSThomas Hellstrom { 387d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 388d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 389d80efd5cSThomas Hellstrom struct { 390d80efd5cSThomas Hellstrom SVGA3dCmdHeader header; 391d80efd5cSThomas Hellstrom SVGA3dCmdDXBindShader body; 392d80efd5cSThomas Hellstrom } *cmd; 393d80efd5cSThomas Hellstrom 394d80efd5cSThomas Hellstrom if (!list_empty(&shader->cotable_head) || !shader->committed) 395d80efd5cSThomas Hellstrom return 0; 396d80efd5cSThomas Hellstrom 3978426ed9cSZack Rusin cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id); 39811c45419SDeepak Rawat if (unlikely(cmd == NULL)) 399d80efd5cSThomas Hellstrom return -ENOMEM; 400d80efd5cSThomas Hellstrom 401d80efd5cSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER; 402d80efd5cSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 403d80efd5cSThomas Hellstrom cmd->body.cid = shader->ctx->id; 404d80efd5cSThomas Hellstrom cmd->body.shid = shader->id; 405d3116756SChristian König cmd->body.mobid = res->backup->base.resource->start; 406d80efd5cSThomas Hellstrom cmd->body.offsetInBytes = res->backup_offset; 4078426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 408d80efd5cSThomas Hellstrom 409d80efd5cSThomas Hellstrom vmw_cotable_add_resource(shader->cotable, &shader->cotable_head); 410d80efd5cSThomas Hellstrom 411d80efd5cSThomas Hellstrom return 0; 412d80efd5cSThomas Hellstrom } 413d80efd5cSThomas Hellstrom 414d80efd5cSThomas Hellstrom /** 415d80efd5cSThomas Hellstrom * vmw_dx_shader_create - The DX shader create callback 416d80efd5cSThomas Hellstrom * 417d80efd5cSThomas Hellstrom * @res: The DX shader resource 418d80efd5cSThomas Hellstrom * 419d80efd5cSThomas Hellstrom * The create callback is called as part of resource validation and 420d80efd5cSThomas Hellstrom * makes sure that we unscrub the shader if it's previously been scrubbed. 421d80efd5cSThomas Hellstrom */ 422d80efd5cSThomas Hellstrom static int vmw_dx_shader_create(struct vmw_resource *res) 423d80efd5cSThomas Hellstrom { 424d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 425d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 426d80efd5cSThomas Hellstrom int ret = 0; 427d80efd5cSThomas Hellstrom 428d80efd5cSThomas Hellstrom WARN_ON_ONCE(!shader->committed); 429d80efd5cSThomas Hellstrom 430a0a63940SThomas Hellstrom if (vmw_resource_mob_attached(res)) { 431d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 432d80efd5cSThomas Hellstrom ret = vmw_dx_shader_unscrub(res); 433d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 434d80efd5cSThomas Hellstrom } 435d80efd5cSThomas Hellstrom 436d80efd5cSThomas Hellstrom res->id = shader->id; 437d80efd5cSThomas Hellstrom return ret; 438d80efd5cSThomas Hellstrom } 439d80efd5cSThomas Hellstrom 440d80efd5cSThomas Hellstrom /** 441d80efd5cSThomas Hellstrom * vmw_dx_shader_bind - The DX shader bind callback 442d80efd5cSThomas Hellstrom * 443d80efd5cSThomas Hellstrom * @res: The DX shader resource 444d80efd5cSThomas Hellstrom * @val_buf: Pointer to the validate buffer. 445d80efd5cSThomas Hellstrom * 446d80efd5cSThomas Hellstrom */ 447d80efd5cSThomas Hellstrom static int vmw_dx_shader_bind(struct vmw_resource *res, 448d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf) 449d80efd5cSThomas Hellstrom { 450d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 451d80efd5cSThomas Hellstrom struct ttm_buffer_object *bo = val_buf->bo; 452d80efd5cSThomas Hellstrom 453d3116756SChristian König BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 454d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 455d80efd5cSThomas Hellstrom vmw_dx_shader_unscrub(res); 456d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 457d80efd5cSThomas Hellstrom 458d80efd5cSThomas Hellstrom return 0; 459d80efd5cSThomas Hellstrom } 460d80efd5cSThomas Hellstrom 461d80efd5cSThomas Hellstrom /** 462d80efd5cSThomas Hellstrom * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader. 463d80efd5cSThomas Hellstrom * 464d80efd5cSThomas Hellstrom * @res: The shader resource 465d80efd5cSThomas Hellstrom * 466d80efd5cSThomas Hellstrom * This function unbinds a MOB from the DX shader without requiring the 467d80efd5cSThomas Hellstrom * MOB dma_buffer to be reserved. The driver still considers the MOB bound. 468d80efd5cSThomas Hellstrom * However, once the driver eventually decides to unbind the MOB, it doesn't 469d80efd5cSThomas Hellstrom * need to access the context. 470d80efd5cSThomas Hellstrom */ 471d80efd5cSThomas Hellstrom static int vmw_dx_shader_scrub(struct vmw_resource *res) 472d80efd5cSThomas Hellstrom { 473d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 474d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 475d80efd5cSThomas Hellstrom struct { 476d80efd5cSThomas Hellstrom SVGA3dCmdHeader header; 477d80efd5cSThomas Hellstrom SVGA3dCmdDXBindShader body; 478d80efd5cSThomas Hellstrom } *cmd; 479d80efd5cSThomas Hellstrom 480d80efd5cSThomas Hellstrom if (list_empty(&shader->cotable_head)) 481d80efd5cSThomas Hellstrom return 0; 482d80efd5cSThomas Hellstrom 483d80efd5cSThomas Hellstrom WARN_ON_ONCE(!shader->committed); 4848426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 48511c45419SDeepak Rawat if (unlikely(cmd == NULL)) 486d80efd5cSThomas Hellstrom return -ENOMEM; 487d80efd5cSThomas Hellstrom 488d80efd5cSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER; 489d80efd5cSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 490d80efd5cSThomas Hellstrom cmd->body.cid = shader->ctx->id; 491d80efd5cSThomas Hellstrom cmd->body.shid = res->id; 492d80efd5cSThomas Hellstrom cmd->body.mobid = SVGA3D_INVALID_ID; 493d80efd5cSThomas Hellstrom cmd->body.offsetInBytes = 0; 4948426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 495d80efd5cSThomas Hellstrom res->id = -1; 496d80efd5cSThomas Hellstrom list_del_init(&shader->cotable_head); 497d80efd5cSThomas Hellstrom 498d80efd5cSThomas Hellstrom return 0; 499d80efd5cSThomas Hellstrom } 500d80efd5cSThomas Hellstrom 501d80efd5cSThomas Hellstrom /** 502d80efd5cSThomas Hellstrom * vmw_dx_shader_unbind - The dx shader unbind callback. 503d80efd5cSThomas Hellstrom * 504d80efd5cSThomas Hellstrom * @res: The shader resource 505d80efd5cSThomas Hellstrom * @readback: Whether this is a readback unbind. Currently unused. 506d80efd5cSThomas Hellstrom * @val_buf: MOB buffer information. 507d80efd5cSThomas Hellstrom */ 508d80efd5cSThomas Hellstrom static int vmw_dx_shader_unbind(struct vmw_resource *res, 509d80efd5cSThomas Hellstrom bool readback, 510d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf) 511d80efd5cSThomas Hellstrom { 512d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 513d80efd5cSThomas Hellstrom struct vmw_fence_obj *fence; 514d80efd5cSThomas Hellstrom int ret; 515d80efd5cSThomas Hellstrom 516d3116756SChristian König BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB); 517d80efd5cSThomas Hellstrom 518d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 519d80efd5cSThomas Hellstrom ret = vmw_dx_shader_scrub(res); 520d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 521d80efd5cSThomas Hellstrom 522d80efd5cSThomas Hellstrom if (ret) 523d80efd5cSThomas Hellstrom return ret; 524d80efd5cSThomas Hellstrom 525d80efd5cSThomas Hellstrom (void) vmw_execbuf_fence_commands(NULL, dev_priv, 526d80efd5cSThomas Hellstrom &fence, NULL); 527e9431ea5SThomas Hellstrom vmw_bo_fence_single(val_buf->bo, fence); 528d80efd5cSThomas Hellstrom 529d80efd5cSThomas Hellstrom if (likely(fence != NULL)) 530d80efd5cSThomas Hellstrom vmw_fence_obj_unreference(&fence); 531d80efd5cSThomas Hellstrom 532d80efd5cSThomas Hellstrom return 0; 533d80efd5cSThomas Hellstrom } 534d80efd5cSThomas Hellstrom 535d80efd5cSThomas Hellstrom /** 536d80efd5cSThomas Hellstrom * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for 537d80efd5cSThomas Hellstrom * DX shaders. 538d80efd5cSThomas Hellstrom * 539d80efd5cSThomas Hellstrom * @dev_priv: Pointer to device private structure. 540d80efd5cSThomas Hellstrom * @list: The list of cotable resources. 541d80efd5cSThomas Hellstrom * @readback: Whether the call was part of a readback unbind. 542d80efd5cSThomas Hellstrom * 543d80efd5cSThomas Hellstrom * Scrubs all shader MOBs so that any subsequent shader unbind or shader 544d80efd5cSThomas Hellstrom * destroy operation won't need to swap in the context. 545d80efd5cSThomas Hellstrom */ 546d80efd5cSThomas Hellstrom void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv, 547d80efd5cSThomas Hellstrom struct list_head *list, 548d80efd5cSThomas Hellstrom bool readback) 549d80efd5cSThomas Hellstrom { 550d80efd5cSThomas Hellstrom struct vmw_dx_shader *entry, *next; 551d80efd5cSThomas Hellstrom 552d76ce03eSThomas Hellstrom lockdep_assert_held_once(&dev_priv->binding_mutex); 553d80efd5cSThomas Hellstrom 554d80efd5cSThomas Hellstrom list_for_each_entry_safe(entry, next, list, cotable_head) { 555d80efd5cSThomas Hellstrom WARN_ON(vmw_dx_shader_scrub(&entry->res)); 556d80efd5cSThomas Hellstrom if (!readback) 557d80efd5cSThomas Hellstrom entry->committed = false; 558d80efd5cSThomas Hellstrom } 559d80efd5cSThomas Hellstrom } 560d80efd5cSThomas Hellstrom 561d80efd5cSThomas Hellstrom /** 562d80efd5cSThomas Hellstrom * vmw_dx_shader_res_free - The DX shader free callback 563d80efd5cSThomas Hellstrom * 564d80efd5cSThomas Hellstrom * @res: The shader resource 565d80efd5cSThomas Hellstrom * 566d80efd5cSThomas Hellstrom * Frees the DX shader resource and updates memory accounting. 567d80efd5cSThomas Hellstrom */ 568d80efd5cSThomas Hellstrom static void vmw_dx_shader_res_free(struct vmw_resource *res) 569d80efd5cSThomas Hellstrom { 570d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 571d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 572d80efd5cSThomas Hellstrom 573d80efd5cSThomas Hellstrom vmw_resource_unreference(&shader->cotable); 574d80efd5cSThomas Hellstrom kfree(shader); 575d80efd5cSThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size); 576d80efd5cSThomas Hellstrom } 577d80efd5cSThomas Hellstrom 578d80efd5cSThomas Hellstrom /** 579d80efd5cSThomas Hellstrom * vmw_dx_shader_add - Add a shader resource as a command buffer managed 580d80efd5cSThomas Hellstrom * resource. 581d80efd5cSThomas Hellstrom * 582d80efd5cSThomas Hellstrom * @man: The command buffer resource manager. 583d80efd5cSThomas Hellstrom * @ctx: Pointer to the context resource. 584d80efd5cSThomas Hellstrom * @user_key: The id used for this shader. 585d80efd5cSThomas Hellstrom * @shader_type: The shader type. 586d80efd5cSThomas Hellstrom * @list: The list of staged command buffer managed resources. 587d80efd5cSThomas Hellstrom */ 588d80efd5cSThomas Hellstrom int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man, 589d80efd5cSThomas Hellstrom struct vmw_resource *ctx, 590d80efd5cSThomas Hellstrom u32 user_key, 591d80efd5cSThomas Hellstrom SVGA3dShaderType shader_type, 592d80efd5cSThomas Hellstrom struct list_head *list) 593d80efd5cSThomas Hellstrom { 594d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader; 595d80efd5cSThomas Hellstrom struct vmw_resource *res; 596d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = ctx->dev_priv; 597279c01f6SRoger He struct ttm_operation_ctx ttm_opt_ctx = { 598279c01f6SRoger He .interruptible = true, 599279c01f6SRoger He .no_wait_gpu = false 600279c01f6SRoger He }; 601d80efd5cSThomas Hellstrom int ret; 602d80efd5cSThomas Hellstrom 603d80efd5cSThomas Hellstrom if (!vmw_shader_dx_size) 604d80efd5cSThomas Hellstrom vmw_shader_dx_size = ttm_round_pot(sizeof(*shader)); 605d80efd5cSThomas Hellstrom 606d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 607d80efd5cSThomas Hellstrom return -EINVAL; 608d80efd5cSThomas Hellstrom 609d80efd5cSThomas Hellstrom ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_shader_dx_size, 610279c01f6SRoger He &ttm_opt_ctx); 611d80efd5cSThomas Hellstrom if (ret) { 612d80efd5cSThomas Hellstrom if (ret != -ERESTARTSYS) 613d80efd5cSThomas Hellstrom DRM_ERROR("Out of graphics memory for shader " 614d80efd5cSThomas Hellstrom "creation.\n"); 615d80efd5cSThomas Hellstrom return ret; 616d80efd5cSThomas Hellstrom } 617d80efd5cSThomas Hellstrom 618d80efd5cSThomas Hellstrom shader = kmalloc(sizeof(*shader), GFP_KERNEL); 619d80efd5cSThomas Hellstrom if (!shader) { 620d80efd5cSThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_shader_dx_size); 621d80efd5cSThomas Hellstrom return -ENOMEM; 622d80efd5cSThomas Hellstrom } 623d80efd5cSThomas Hellstrom 624d80efd5cSThomas Hellstrom res = &shader->res; 625d80efd5cSThomas Hellstrom shader->ctx = ctx; 6261b9a01d6SThomas Hellstrom shader->cotable = vmw_resource_reference 6271b9a01d6SThomas Hellstrom (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER)); 628d80efd5cSThomas Hellstrom shader->id = user_key; 629d80efd5cSThomas Hellstrom shader->committed = false; 630d80efd5cSThomas Hellstrom INIT_LIST_HEAD(&shader->cotable_head); 631d80efd5cSThomas Hellstrom ret = vmw_resource_init(dev_priv, res, true, 632d80efd5cSThomas Hellstrom vmw_dx_shader_res_free, &vmw_dx_shader_func); 633d80efd5cSThomas Hellstrom if (ret) 634d80efd5cSThomas Hellstrom goto out_resource_init; 635d80efd5cSThomas Hellstrom 636d80efd5cSThomas Hellstrom /* 637d80efd5cSThomas Hellstrom * The user_key name-space is not per shader type for DX shaders, 638d80efd5cSThomas Hellstrom * so when hashing, use a single zero shader type. 639d80efd5cSThomas Hellstrom */ 640d80efd5cSThomas Hellstrom ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, 641d80efd5cSThomas Hellstrom vmw_shader_key(user_key, 0), 642d80efd5cSThomas Hellstrom res, list); 643d80efd5cSThomas Hellstrom if (ret) 644d80efd5cSThomas Hellstrom goto out_resource_init; 645d80efd5cSThomas Hellstrom 646d80efd5cSThomas Hellstrom res->id = shader->id; 64713289241SThomas Hellstrom res->hw_destroy = vmw_hw_shader_destroy; 648d80efd5cSThomas Hellstrom 649d80efd5cSThomas Hellstrom out_resource_init: 650d80efd5cSThomas Hellstrom vmw_resource_unreference(&res); 651d80efd5cSThomas Hellstrom 652d80efd5cSThomas Hellstrom return ret; 653d80efd5cSThomas Hellstrom } 654d80efd5cSThomas Hellstrom 655d80efd5cSThomas Hellstrom 656d80efd5cSThomas Hellstrom 657ad2ae415SLee Jones /* 658c74c162fSThomas Hellstrom * User-space shader management: 659c74c162fSThomas Hellstrom */ 660c74c162fSThomas Hellstrom 661c74c162fSThomas Hellstrom static struct vmw_resource * 662c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base) 663c74c162fSThomas Hellstrom { 664c74c162fSThomas Hellstrom return &(container_of(base, struct vmw_user_shader, base)-> 665c74c162fSThomas Hellstrom shader.res); 666c74c162fSThomas Hellstrom } 667c74c162fSThomas Hellstrom 668c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res) 669c74c162fSThomas Hellstrom { 670c74c162fSThomas Hellstrom struct vmw_user_shader *ushader = 671c74c162fSThomas Hellstrom container_of(res, struct vmw_user_shader, shader.res); 672c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 673c74c162fSThomas Hellstrom 674c74c162fSThomas Hellstrom ttm_base_object_kfree(ushader, base); 675c74c162fSThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 676c74c162fSThomas Hellstrom vmw_user_shader_size); 677c74c162fSThomas Hellstrom } 678c74c162fSThomas Hellstrom 67918e4a466SThomas Hellstrom static void vmw_shader_free(struct vmw_resource *res) 68018e4a466SThomas Hellstrom { 68118e4a466SThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 68218e4a466SThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 68318e4a466SThomas Hellstrom 68418e4a466SThomas Hellstrom kfree(shader); 68518e4a466SThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 68618e4a466SThomas Hellstrom vmw_shader_size); 68718e4a466SThomas Hellstrom } 68818e4a466SThomas Hellstrom 689ad2ae415SLee Jones /* 690c74c162fSThomas Hellstrom * This function is called when user space has no more references on the 691c74c162fSThomas Hellstrom * base object. It releases the base-object's reference on the resource object. 692c74c162fSThomas Hellstrom */ 693c74c162fSThomas Hellstrom 694c74c162fSThomas Hellstrom static void vmw_user_shader_base_release(struct ttm_base_object **p_base) 695c74c162fSThomas Hellstrom { 696c74c162fSThomas Hellstrom struct ttm_base_object *base = *p_base; 697c74c162fSThomas Hellstrom struct vmw_resource *res = vmw_user_shader_base_to_res(base); 698c74c162fSThomas Hellstrom 699c74c162fSThomas Hellstrom *p_base = NULL; 700c74c162fSThomas Hellstrom vmw_resource_unreference(&res); 701c74c162fSThomas Hellstrom } 702c74c162fSThomas Hellstrom 703c74c162fSThomas Hellstrom int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, 704c74c162fSThomas Hellstrom struct drm_file *file_priv) 705c74c162fSThomas Hellstrom { 706c74c162fSThomas Hellstrom struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; 707c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 708c74c162fSThomas Hellstrom 709c74c162fSThomas Hellstrom return ttm_ref_object_base_unref(tfile, arg->handle, 710c74c162fSThomas Hellstrom TTM_REF_USAGE); 711c74c162fSThomas Hellstrom } 712c74c162fSThomas Hellstrom 71318e4a466SThomas Hellstrom static int vmw_user_shader_alloc(struct vmw_private *dev_priv, 714f1d34bfdSThomas Hellstrom struct vmw_buffer_object *buffer, 715d5bde956SThomas Hellstrom size_t shader_size, 716d5bde956SThomas Hellstrom size_t offset, 717d5bde956SThomas Hellstrom SVGA3dShaderType shader_type, 718d80efd5cSThomas Hellstrom uint8_t num_input_sig, 719d80efd5cSThomas Hellstrom uint8_t num_output_sig, 720d5bde956SThomas Hellstrom struct ttm_object_file *tfile, 721d5bde956SThomas Hellstrom u32 *handle) 722d5bde956SThomas Hellstrom { 723d5bde956SThomas Hellstrom struct vmw_user_shader *ushader; 724d5bde956SThomas Hellstrom struct vmw_resource *res, *tmp; 725279c01f6SRoger He struct ttm_operation_ctx ctx = { 726279c01f6SRoger He .interruptible = true, 727279c01f6SRoger He .no_wait_gpu = false 728279c01f6SRoger He }; 729d5bde956SThomas Hellstrom int ret; 730d5bde956SThomas Hellstrom 731d5bde956SThomas Hellstrom if (unlikely(vmw_user_shader_size == 0)) 732d5bde956SThomas Hellstrom vmw_user_shader_size = 733c7eae626SThomas Hellstrom ttm_round_pot(sizeof(struct vmw_user_shader)) + 734c7eae626SThomas Hellstrom VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; 735d5bde956SThomas Hellstrom 736d5bde956SThomas Hellstrom ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 737d5bde956SThomas Hellstrom vmw_user_shader_size, 738279c01f6SRoger He &ctx); 739d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 740d5bde956SThomas Hellstrom if (ret != -ERESTARTSYS) 741d5bde956SThomas Hellstrom DRM_ERROR("Out of graphics memory for shader " 742d5bde956SThomas Hellstrom "creation.\n"); 743d5bde956SThomas Hellstrom goto out; 744d5bde956SThomas Hellstrom } 745d5bde956SThomas Hellstrom 746d5bde956SThomas Hellstrom ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); 7471a4adb05SRavikant B Sharma if (unlikely(!ushader)) { 748d5bde956SThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 749d5bde956SThomas Hellstrom vmw_user_shader_size); 750d5bde956SThomas Hellstrom ret = -ENOMEM; 751d5bde956SThomas Hellstrom goto out; 752d5bde956SThomas Hellstrom } 753d5bde956SThomas Hellstrom 754d5bde956SThomas Hellstrom res = &ushader->shader.res; 755d5bde956SThomas Hellstrom ushader->base.shareable = false; 756d5bde956SThomas Hellstrom ushader->base.tfile = NULL; 757d5bde956SThomas Hellstrom 758d5bde956SThomas Hellstrom /* 759d5bde956SThomas Hellstrom * From here on, the destructor takes over resource freeing. 760d5bde956SThomas Hellstrom */ 761d5bde956SThomas Hellstrom 762d5bde956SThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, shader_size, 763d80efd5cSThomas Hellstrom offset, shader_type, num_input_sig, 764d80efd5cSThomas Hellstrom num_output_sig, buffer, 765d5bde956SThomas Hellstrom vmw_user_shader_free); 766d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 767d5bde956SThomas Hellstrom goto out; 768d5bde956SThomas Hellstrom 769d5bde956SThomas Hellstrom tmp = vmw_resource_reference(res); 770d5bde956SThomas Hellstrom ret = ttm_base_object_init(tfile, &ushader->base, false, 771d5bde956SThomas Hellstrom VMW_RES_SHADER, 772d5bde956SThomas Hellstrom &vmw_user_shader_base_release, NULL); 773d5bde956SThomas Hellstrom 774d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 775d5bde956SThomas Hellstrom vmw_resource_unreference(&tmp); 776d5bde956SThomas Hellstrom goto out_err; 777d5bde956SThomas Hellstrom } 778d5bde956SThomas Hellstrom 779d5bde956SThomas Hellstrom if (handle) 780c7eae626SThomas Hellstrom *handle = ushader->base.handle; 781d5bde956SThomas Hellstrom out_err: 782d5bde956SThomas Hellstrom vmw_resource_unreference(&res); 783d5bde956SThomas Hellstrom out: 784d5bde956SThomas Hellstrom return ret; 785d5bde956SThomas Hellstrom } 786d5bde956SThomas Hellstrom 787d5bde956SThomas Hellstrom 788b9eb1a61SThomas Hellstrom static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, 789f1d34bfdSThomas Hellstrom struct vmw_buffer_object *buffer, 79018e4a466SThomas Hellstrom size_t shader_size, 79118e4a466SThomas Hellstrom size_t offset, 79218e4a466SThomas Hellstrom SVGA3dShaderType shader_type) 79318e4a466SThomas Hellstrom { 79418e4a466SThomas Hellstrom struct vmw_shader *shader; 79518e4a466SThomas Hellstrom struct vmw_resource *res; 796279c01f6SRoger He struct ttm_operation_ctx ctx = { 797279c01f6SRoger He .interruptible = true, 798279c01f6SRoger He .no_wait_gpu = false 799279c01f6SRoger He }; 80018e4a466SThomas Hellstrom int ret; 80118e4a466SThomas Hellstrom 80218e4a466SThomas Hellstrom if (unlikely(vmw_shader_size == 0)) 80318e4a466SThomas Hellstrom vmw_shader_size = 804c7eae626SThomas Hellstrom ttm_round_pot(sizeof(struct vmw_shader)) + 805c7eae626SThomas Hellstrom VMW_IDA_ACC_SIZE; 80618e4a466SThomas Hellstrom 80718e4a466SThomas Hellstrom ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 80818e4a466SThomas Hellstrom vmw_shader_size, 809279c01f6SRoger He &ctx); 81018e4a466SThomas Hellstrom if (unlikely(ret != 0)) { 81118e4a466SThomas Hellstrom if (ret != -ERESTARTSYS) 81218e4a466SThomas Hellstrom DRM_ERROR("Out of graphics memory for shader " 81318e4a466SThomas Hellstrom "creation.\n"); 81418e4a466SThomas Hellstrom goto out_err; 81518e4a466SThomas Hellstrom } 81618e4a466SThomas Hellstrom 81718e4a466SThomas Hellstrom shader = kzalloc(sizeof(*shader), GFP_KERNEL); 8181a4adb05SRavikant B Sharma if (unlikely(!shader)) { 81918e4a466SThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 82018e4a466SThomas Hellstrom vmw_shader_size); 82118e4a466SThomas Hellstrom ret = -ENOMEM; 82218e4a466SThomas Hellstrom goto out_err; 82318e4a466SThomas Hellstrom } 82418e4a466SThomas Hellstrom 82518e4a466SThomas Hellstrom res = &shader->res; 82618e4a466SThomas Hellstrom 82718e4a466SThomas Hellstrom /* 82818e4a466SThomas Hellstrom * From here on, the destructor takes over resource freeing. 82918e4a466SThomas Hellstrom */ 83018e4a466SThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, shader_size, 831d80efd5cSThomas Hellstrom offset, shader_type, 0, 0, buffer, 83218e4a466SThomas Hellstrom vmw_shader_free); 83318e4a466SThomas Hellstrom 83418e4a466SThomas Hellstrom out_err: 83518e4a466SThomas Hellstrom return ret ? ERR_PTR(ret) : res; 83618e4a466SThomas Hellstrom } 83718e4a466SThomas Hellstrom 83818e4a466SThomas Hellstrom 839d80efd5cSThomas Hellstrom static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, 840d80efd5cSThomas Hellstrom enum drm_vmw_shader_type shader_type_drm, 841d80efd5cSThomas Hellstrom u32 buffer_handle, size_t size, size_t offset, 842d80efd5cSThomas Hellstrom uint8_t num_input_sig, uint8_t num_output_sig, 843d80efd5cSThomas Hellstrom uint32_t *shader_handle) 844c74c162fSThomas Hellstrom { 845c74c162fSThomas Hellstrom struct vmw_private *dev_priv = vmw_priv(dev); 846c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 847f1d34bfdSThomas Hellstrom struct vmw_buffer_object *buffer = NULL; 848c74c162fSThomas Hellstrom SVGA3dShaderType shader_type; 849c74c162fSThomas Hellstrom int ret; 850c74c162fSThomas Hellstrom 851d80efd5cSThomas Hellstrom if (buffer_handle != SVGA3D_INVALID_ID) { 852f1d34bfdSThomas Hellstrom ret = vmw_user_bo_lookup(tfile, buffer_handle, 85354c12bc3SThomas Hellstrom &buffer, NULL); 854c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 8555724f899SDeepak Rawat VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n"); 856c74c162fSThomas Hellstrom return ret; 857c74c162fSThomas Hellstrom } 858c74c162fSThomas Hellstrom 859e11bfb99SChristian König if ((u64)buffer->base.base.size < (u64)size + (u64)offset) { 8605724f899SDeepak Rawat VMW_DEBUG_USER("Illegal buffer- or shader size.\n"); 861c74c162fSThomas Hellstrom ret = -EINVAL; 862c74c162fSThomas Hellstrom goto out_bad_arg; 863c74c162fSThomas Hellstrom } 864c74c162fSThomas Hellstrom } 865c74c162fSThomas Hellstrom 866d80efd5cSThomas Hellstrom switch (shader_type_drm) { 867c74c162fSThomas Hellstrom case drm_vmw_shader_type_vs: 868c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_VS; 869c74c162fSThomas Hellstrom break; 870c74c162fSThomas Hellstrom case drm_vmw_shader_type_ps: 871c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_PS; 872c74c162fSThomas Hellstrom break; 873c74c162fSThomas Hellstrom default: 8745724f899SDeepak Rawat VMW_DEBUG_USER("Illegal shader type.\n"); 875c74c162fSThomas Hellstrom ret = -EINVAL; 876c74c162fSThomas Hellstrom goto out_bad_arg; 877c74c162fSThomas Hellstrom } 878c74c162fSThomas Hellstrom 879d80efd5cSThomas Hellstrom ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset, 880d80efd5cSThomas Hellstrom shader_type, num_input_sig, 881d80efd5cSThomas Hellstrom num_output_sig, tfile, shader_handle); 882c74c162fSThomas Hellstrom out_bad_arg: 883f1d34bfdSThomas Hellstrom vmw_bo_unreference(&buffer); 884d5bde956SThomas Hellstrom return ret; 885d5bde956SThomas Hellstrom } 886c74c162fSThomas Hellstrom 887d5bde956SThomas Hellstrom /** 888d80efd5cSThomas Hellstrom * vmw_shader_id_ok - Check whether a compat shader user key and 88918e4a466SThomas Hellstrom * shader type are within valid bounds. 890d5bde956SThomas Hellstrom * 89118e4a466SThomas Hellstrom * @user_key: User space id of the shader. 89218e4a466SThomas Hellstrom * @shader_type: Shader type. 893d5bde956SThomas Hellstrom * 89418e4a466SThomas Hellstrom * Returns true if valid false if not. 895d5bde956SThomas Hellstrom */ 896d80efd5cSThomas Hellstrom static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) 897d5bde956SThomas Hellstrom { 89818e4a466SThomas Hellstrom return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16; 899d5bde956SThomas Hellstrom } 900d5bde956SThomas Hellstrom 901d5bde956SThomas Hellstrom /** 902d80efd5cSThomas Hellstrom * vmw_shader_key - Compute a hash key suitable for a compat shader. 903d5bde956SThomas Hellstrom * 90418e4a466SThomas Hellstrom * @user_key: User space id of the shader. 90518e4a466SThomas Hellstrom * @shader_type: Shader type. 906d5bde956SThomas Hellstrom * 90718e4a466SThomas Hellstrom * Returns a hash key suitable for a command buffer managed resource 90818e4a466SThomas Hellstrom * manager hash table. 909d5bde956SThomas Hellstrom */ 910d80efd5cSThomas Hellstrom static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type) 911d5bde956SThomas Hellstrom { 91218e4a466SThomas Hellstrom return user_key | (shader_type << 20); 913d5bde956SThomas Hellstrom } 914d5bde956SThomas Hellstrom 915d5bde956SThomas Hellstrom /** 916d80efd5cSThomas Hellstrom * vmw_shader_remove - Stage a compat shader for removal. 917d5bde956SThomas Hellstrom * 91818e4a466SThomas Hellstrom * @man: Pointer to the compat shader manager identifying the shader namespace. 919d5bde956SThomas Hellstrom * @user_key: The key that is used to identify the shader. The key is 920d5bde956SThomas Hellstrom * unique to the shader type. 921d5bde956SThomas Hellstrom * @shader_type: Shader type. 92218e4a466SThomas Hellstrom * @list: Caller's list of staged command buffer resource actions. 923d5bde956SThomas Hellstrom */ 924d80efd5cSThomas Hellstrom int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man, 925d5bde956SThomas Hellstrom u32 user_key, SVGA3dShaderType shader_type, 926d5bde956SThomas Hellstrom struct list_head *list) 927d5bde956SThomas Hellstrom { 928d80efd5cSThomas Hellstrom struct vmw_resource *dummy; 929d80efd5cSThomas Hellstrom 930d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 931d5bde956SThomas Hellstrom return -EINVAL; 932d5bde956SThomas Hellstrom 933d80efd5cSThomas Hellstrom return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader, 934d80efd5cSThomas Hellstrom vmw_shader_key(user_key, shader_type), 935d80efd5cSThomas Hellstrom list, &dummy); 936d5bde956SThomas Hellstrom } 937d5bde956SThomas Hellstrom 938d5bde956SThomas Hellstrom /** 93918e4a466SThomas Hellstrom * vmw_compat_shader_add - Create a compat shader and stage it for addition 94018e4a466SThomas Hellstrom * as a command buffer managed resource. 941d5bde956SThomas Hellstrom * 942ad2ae415SLee Jones * @dev_priv: Pointer to device private structure. 94318e4a466SThomas Hellstrom * @man: Pointer to the compat shader manager identifying the shader namespace. 944d5bde956SThomas Hellstrom * @user_key: The key that is used to identify the shader. The key is 945d5bde956SThomas Hellstrom * unique to the shader type. 946d5bde956SThomas Hellstrom * @bytecode: Pointer to the bytecode of the shader. 947d5bde956SThomas Hellstrom * @shader_type: Shader type. 948ad2ae415SLee Jones * @size: Command size. 94918e4a466SThomas Hellstrom * @list: Caller's list of staged command buffer resource actions. 950d5bde956SThomas Hellstrom * 951d5bde956SThomas Hellstrom */ 95218e4a466SThomas Hellstrom int vmw_compat_shader_add(struct vmw_private *dev_priv, 95318e4a466SThomas Hellstrom struct vmw_cmdbuf_res_manager *man, 954d5bde956SThomas Hellstrom u32 user_key, const void *bytecode, 955d5bde956SThomas Hellstrom SVGA3dShaderType shader_type, 956d5bde956SThomas Hellstrom size_t size, 957d5bde956SThomas Hellstrom struct list_head *list) 958d5bde956SThomas Hellstrom { 95919be5570SChristian König struct ttm_operation_ctx ctx = { false, true }; 960f1d34bfdSThomas Hellstrom struct vmw_buffer_object *buf; 961d5bde956SThomas Hellstrom struct ttm_bo_kmap_obj map; 962d5bde956SThomas Hellstrom bool is_iomem; 963d5bde956SThomas Hellstrom int ret; 96418e4a466SThomas Hellstrom struct vmw_resource *res; 965d5bde956SThomas Hellstrom 966d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 967d5bde956SThomas Hellstrom return -EINVAL; 968d5bde956SThomas Hellstrom 969d5bde956SThomas Hellstrom /* Allocate and pin a DMA buffer */ 970d5bde956SThomas Hellstrom buf = kzalloc(sizeof(*buf), GFP_KERNEL); 9711a4adb05SRavikant B Sharma if (unlikely(!buf)) 972d5bde956SThomas Hellstrom return -ENOMEM; 973d5bde956SThomas Hellstrom 974fbe86ca5SChristian König ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_placement, 975fbe86ca5SChristian König true, true, vmw_bo_bo_free); 976d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 977d5bde956SThomas Hellstrom goto out; 978d5bde956SThomas Hellstrom 979dfd5e50eSChristian König ret = ttm_bo_reserve(&buf->base, false, true, NULL); 980d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 981d5bde956SThomas Hellstrom goto no_reserve; 982d5bde956SThomas Hellstrom 983d5bde956SThomas Hellstrom /* Map and copy shader bytecode. */ 984*bc65754cSCai Huoqing ret = ttm_bo_kmap(&buf->base, 0, PFN_UP(size), &map); 985d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 986d5bde956SThomas Hellstrom ttm_bo_unreserve(&buf->base); 987d5bde956SThomas Hellstrom goto no_reserve; 988d5bde956SThomas Hellstrom } 989d5bde956SThomas Hellstrom 990d5bde956SThomas Hellstrom memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); 991d5bde956SThomas Hellstrom WARN_ON(is_iomem); 992d5bde956SThomas Hellstrom 993d5bde956SThomas Hellstrom ttm_bo_kunmap(&map); 99419be5570SChristian König ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx); 995d5bde956SThomas Hellstrom WARN_ON(ret != 0); 996d5bde956SThomas Hellstrom ttm_bo_unreserve(&buf->base); 997d5bde956SThomas Hellstrom 99818e4a466SThomas Hellstrom res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); 999d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 1000d5bde956SThomas Hellstrom goto no_reserve; 1001d5bde956SThomas Hellstrom 1002d80efd5cSThomas Hellstrom ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, 1003d80efd5cSThomas Hellstrom vmw_shader_key(user_key, shader_type), 100418e4a466SThomas Hellstrom res, list); 100518e4a466SThomas Hellstrom vmw_resource_unreference(&res); 1006d5bde956SThomas Hellstrom no_reserve: 1007f1d34bfdSThomas Hellstrom vmw_bo_unreference(&buf); 1008d5bde956SThomas Hellstrom out: 1009d5bde956SThomas Hellstrom return ret; 1010d5bde956SThomas Hellstrom } 1011d5bde956SThomas Hellstrom 1012d5bde956SThomas Hellstrom /** 1013d80efd5cSThomas Hellstrom * vmw_shader_lookup - Look up a compat shader 1014d5bde956SThomas Hellstrom * 101518e4a466SThomas Hellstrom * @man: Pointer to the command buffer managed resource manager identifying 101618e4a466SThomas Hellstrom * the shader namespace. 101718e4a466SThomas Hellstrom * @user_key: The user space id of the shader. 101818e4a466SThomas Hellstrom * @shader_type: The shader type. 1019d5bde956SThomas Hellstrom * 102018e4a466SThomas Hellstrom * Returns a refcounted pointer to a struct vmw_resource if the shader was 102118e4a466SThomas Hellstrom * found. An error pointer otherwise. 1022d5bde956SThomas Hellstrom */ 102318e4a466SThomas Hellstrom struct vmw_resource * 1024d80efd5cSThomas Hellstrom vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man, 102518e4a466SThomas Hellstrom u32 user_key, 102618e4a466SThomas Hellstrom SVGA3dShaderType shader_type) 1027d5bde956SThomas Hellstrom { 1028d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 102918e4a466SThomas Hellstrom return ERR_PTR(-EINVAL); 1030d5bde956SThomas Hellstrom 1031d80efd5cSThomas Hellstrom return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader, 1032d80efd5cSThomas Hellstrom vmw_shader_key(user_key, shader_type)); 1033d80efd5cSThomas Hellstrom } 1034d80efd5cSThomas Hellstrom 1035d80efd5cSThomas Hellstrom int vmw_shader_define_ioctl(struct drm_device *dev, void *data, 1036d80efd5cSThomas Hellstrom struct drm_file *file_priv) 1037d80efd5cSThomas Hellstrom { 1038d80efd5cSThomas Hellstrom struct drm_vmw_shader_create_arg *arg = 1039d80efd5cSThomas Hellstrom (struct drm_vmw_shader_create_arg *)data; 1040d80efd5cSThomas Hellstrom 1041d80efd5cSThomas Hellstrom return vmw_shader_define(dev, file_priv, arg->shader_type, 1042d80efd5cSThomas Hellstrom arg->buffer_handle, 1043d80efd5cSThomas Hellstrom arg->size, arg->offset, 1044d80efd5cSThomas Hellstrom 0, 0, 1045d80efd5cSThomas Hellstrom &arg->shader_handle); 1046c74c162fSThomas Hellstrom } 1047