1dff96888SDirk Hohndel (VMware) // SPDX-License-Identifier: GPL-2.0 OR MIT 2c74c162fSThomas Hellstrom /************************************************************************** 3c74c162fSThomas Hellstrom * 409881d29SZack Rusin * Copyright 2009-2023 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 3009881d29SZack Rusin #include "vmwgfx_binding.h" 3109881d29SZack Rusin #include "vmwgfx_bo.h" 32c74c162fSThomas Hellstrom #include "vmwgfx_drv.h" 33c74c162fSThomas Hellstrom #include "vmwgfx_resource_priv.h" 34c74c162fSThomas Hellstrom 35c74c162fSThomas Hellstrom struct vmw_shader { 36c74c162fSThomas Hellstrom struct vmw_resource res; 37c74c162fSThomas Hellstrom SVGA3dShaderType type; 38c74c162fSThomas Hellstrom uint32_t size; 39d80efd5cSThomas Hellstrom uint8_t num_input_sig; 40d80efd5cSThomas Hellstrom uint8_t num_output_sig; 41c74c162fSThomas Hellstrom }; 42c74c162fSThomas Hellstrom 43c74c162fSThomas Hellstrom struct vmw_user_shader { 44c74c162fSThomas Hellstrom struct ttm_base_object base; 45c74c162fSThomas Hellstrom struct vmw_shader shader; 46c74c162fSThomas Hellstrom }; 47c74c162fSThomas Hellstrom 48d80efd5cSThomas Hellstrom struct vmw_dx_shader { 49d80efd5cSThomas Hellstrom struct vmw_resource res; 50d80efd5cSThomas Hellstrom struct vmw_resource *ctx; 51d80efd5cSThomas Hellstrom struct vmw_resource *cotable; 52d80efd5cSThomas Hellstrom u32 id; 53d80efd5cSThomas Hellstrom bool committed; 54d80efd5cSThomas Hellstrom struct list_head cotable_head; 55d80efd5cSThomas Hellstrom }; 56d80efd5cSThomas Hellstrom 57c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res); 58c74c162fSThomas Hellstrom static struct vmw_resource * 59c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base); 60c74c162fSThomas Hellstrom 61c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res); 62c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 63c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 64c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 65c74c162fSThomas Hellstrom bool readback, 66c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 67c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res); 68c74c162fSThomas Hellstrom 69d80efd5cSThomas Hellstrom static int vmw_dx_shader_create(struct vmw_resource *res); 70d80efd5cSThomas Hellstrom static int vmw_dx_shader_bind(struct vmw_resource *res, 71d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf); 72d80efd5cSThomas Hellstrom static int vmw_dx_shader_unbind(struct vmw_resource *res, 73d80efd5cSThomas Hellstrom bool readback, 74d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf); 75d80efd5cSThomas Hellstrom static void vmw_dx_shader_commit_notify(struct vmw_resource *res, 76d80efd5cSThomas Hellstrom enum vmw_cmdbuf_res_state state); 77d80efd5cSThomas Hellstrom static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type); 78d80efd5cSThomas Hellstrom static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type); 79d80efd5cSThomas Hellstrom 80c74c162fSThomas Hellstrom static const struct vmw_user_resource_conv user_shader_conv = { 81c74c162fSThomas Hellstrom .object_type = VMW_RES_SHADER, 82c74c162fSThomas Hellstrom .base_obj_to_res = vmw_user_shader_base_to_res, 83c74c162fSThomas Hellstrom .res_free = vmw_user_shader_free 84c74c162fSThomas Hellstrom }; 85c74c162fSThomas Hellstrom 86c74c162fSThomas Hellstrom const struct vmw_user_resource_conv *user_shader_converter = 87c74c162fSThomas Hellstrom &user_shader_conv; 88c74c162fSThomas Hellstrom 89c74c162fSThomas Hellstrom 90c74c162fSThomas Hellstrom static const struct vmw_res_func vmw_gb_shader_func = { 91c74c162fSThomas Hellstrom .res_type = vmw_res_shader, 92*668b2066SZack Rusin .needs_guest_memory = true, 93c74c162fSThomas Hellstrom .may_evict = true, 94a0a63940SThomas Hellstrom .prio = 3, 95a0a63940SThomas Hellstrom .dirty_prio = 3, 96c74c162fSThomas Hellstrom .type_name = "guest backed shaders", 9739985eeaSZack Rusin .domain = VMW_BO_DOMAIN_MOB, 9839985eeaSZack Rusin .busy_domain = VMW_BO_DOMAIN_MOB, 99c74c162fSThomas Hellstrom .create = vmw_gb_shader_create, 100c74c162fSThomas Hellstrom .destroy = vmw_gb_shader_destroy, 101c74c162fSThomas Hellstrom .bind = vmw_gb_shader_bind, 102c74c162fSThomas Hellstrom .unbind = vmw_gb_shader_unbind 103c74c162fSThomas Hellstrom }; 104c74c162fSThomas Hellstrom 105d80efd5cSThomas Hellstrom static const struct vmw_res_func vmw_dx_shader_func = { 106d80efd5cSThomas Hellstrom .res_type = vmw_res_shader, 107*668b2066SZack Rusin .needs_guest_memory = true, 108a0a63940SThomas Hellstrom .may_evict = true, 109a0a63940SThomas Hellstrom .prio = 3, 110a0a63940SThomas Hellstrom .dirty_prio = 3, 111d80efd5cSThomas Hellstrom .type_name = "dx shaders", 11239985eeaSZack Rusin .domain = VMW_BO_DOMAIN_MOB, 11339985eeaSZack Rusin .busy_domain = VMW_BO_DOMAIN_MOB, 114d80efd5cSThomas Hellstrom .create = vmw_dx_shader_create, 115d80efd5cSThomas Hellstrom /* 116d80efd5cSThomas Hellstrom * The destroy callback is only called with a committed resource on 117d80efd5cSThomas Hellstrom * context destroy, in which case we destroy the cotable anyway, 118d80efd5cSThomas Hellstrom * so there's no need to destroy DX shaders separately. 119d80efd5cSThomas Hellstrom */ 120d80efd5cSThomas Hellstrom .destroy = NULL, 121d80efd5cSThomas Hellstrom .bind = vmw_dx_shader_bind, 122d80efd5cSThomas Hellstrom .unbind = vmw_dx_shader_unbind, 123d80efd5cSThomas Hellstrom .commit_notify = vmw_dx_shader_commit_notify, 124d80efd5cSThomas Hellstrom }; 125d80efd5cSThomas Hellstrom 126ad2ae415SLee Jones /* 127c74c162fSThomas Hellstrom * Shader management: 128c74c162fSThomas Hellstrom */ 129c74c162fSThomas Hellstrom 130c74c162fSThomas Hellstrom static inline struct vmw_shader * 131c74c162fSThomas Hellstrom vmw_res_to_shader(struct vmw_resource *res) 132c74c162fSThomas Hellstrom { 133c74c162fSThomas Hellstrom return container_of(res, struct vmw_shader, res); 134c74c162fSThomas Hellstrom } 135c74c162fSThomas Hellstrom 136d80efd5cSThomas Hellstrom /** 137d80efd5cSThomas Hellstrom * vmw_res_to_dx_shader - typecast a struct vmw_resource to a 138d80efd5cSThomas Hellstrom * struct vmw_dx_shader 139d80efd5cSThomas Hellstrom * 140d80efd5cSThomas Hellstrom * @res: Pointer to the struct vmw_resource. 141d80efd5cSThomas Hellstrom */ 142d80efd5cSThomas Hellstrom static inline struct vmw_dx_shader * 143d80efd5cSThomas Hellstrom vmw_res_to_dx_shader(struct vmw_resource *res) 144d80efd5cSThomas Hellstrom { 145d80efd5cSThomas Hellstrom return container_of(res, struct vmw_dx_shader, res); 146d80efd5cSThomas Hellstrom } 147d80efd5cSThomas Hellstrom 148c74c162fSThomas Hellstrom static void vmw_hw_shader_destroy(struct vmw_resource *res) 149c74c162fSThomas Hellstrom { 150d80efd5cSThomas Hellstrom if (likely(res->func->destroy)) 151d80efd5cSThomas Hellstrom (void) res->func->destroy(res); 152d80efd5cSThomas Hellstrom else 153d80efd5cSThomas Hellstrom res->id = -1; 154c74c162fSThomas Hellstrom } 155c74c162fSThomas Hellstrom 156d80efd5cSThomas Hellstrom 157c74c162fSThomas Hellstrom static int vmw_gb_shader_init(struct vmw_private *dev_priv, 158c74c162fSThomas Hellstrom struct vmw_resource *res, 159c74c162fSThomas Hellstrom uint32_t size, 160c74c162fSThomas Hellstrom uint64_t offset, 161c74c162fSThomas Hellstrom SVGA3dShaderType type, 162d80efd5cSThomas Hellstrom uint8_t num_input_sig, 163d80efd5cSThomas Hellstrom uint8_t num_output_sig, 16409881d29SZack Rusin struct vmw_bo *byte_code, 165c74c162fSThomas Hellstrom void (*res_free) (struct vmw_resource *res)) 166c74c162fSThomas Hellstrom { 167c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 168c74c162fSThomas Hellstrom int ret; 169c74c162fSThomas Hellstrom 170d80efd5cSThomas Hellstrom ret = vmw_resource_init(dev_priv, res, true, res_free, 171d80efd5cSThomas Hellstrom &vmw_gb_shader_func); 172c74c162fSThomas Hellstrom 173c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 174c74c162fSThomas Hellstrom if (res_free) 175c74c162fSThomas Hellstrom res_free(res); 176c74c162fSThomas Hellstrom else 177c74c162fSThomas Hellstrom kfree(res); 178c74c162fSThomas Hellstrom return ret; 179c74c162fSThomas Hellstrom } 180c74c162fSThomas Hellstrom 181*668b2066SZack Rusin res->guest_memory_size = size; 182c74c162fSThomas Hellstrom if (byte_code) { 183*668b2066SZack Rusin res->guest_memory_bo = vmw_bo_reference(byte_code); 184*668b2066SZack Rusin res->guest_memory_offset = offset; 185c74c162fSThomas Hellstrom } 186c74c162fSThomas Hellstrom shader->size = size; 187c74c162fSThomas Hellstrom shader->type = type; 188d80efd5cSThomas Hellstrom shader->num_input_sig = num_input_sig; 189d80efd5cSThomas Hellstrom shader->num_output_sig = num_output_sig; 190c74c162fSThomas Hellstrom 19113289241SThomas Hellstrom res->hw_destroy = vmw_hw_shader_destroy; 192c74c162fSThomas Hellstrom return 0; 193c74c162fSThomas Hellstrom } 194c74c162fSThomas Hellstrom 195d80efd5cSThomas Hellstrom /* 196d80efd5cSThomas Hellstrom * GB shader code: 197d80efd5cSThomas Hellstrom */ 198d80efd5cSThomas Hellstrom 199c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res) 200c74c162fSThomas Hellstrom { 201c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 202c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 203c74c162fSThomas Hellstrom int ret; 204c74c162fSThomas Hellstrom struct { 205c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 206c74c162fSThomas Hellstrom SVGA3dCmdDefineGBShader body; 207c74c162fSThomas Hellstrom } *cmd; 208c74c162fSThomas Hellstrom 209c74c162fSThomas Hellstrom if (likely(res->id != -1)) 210c74c162fSThomas Hellstrom return 0; 211c74c162fSThomas Hellstrom 212c74c162fSThomas Hellstrom ret = vmw_resource_alloc_id(res); 213c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 214c74c162fSThomas Hellstrom DRM_ERROR("Failed to allocate a shader id.\n"); 215c74c162fSThomas Hellstrom goto out_no_id; 216c74c162fSThomas Hellstrom } 217c74c162fSThomas Hellstrom 218c74c162fSThomas Hellstrom if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { 219c74c162fSThomas Hellstrom ret = -EBUSY; 220c74c162fSThomas Hellstrom goto out_no_fifo; 221c74c162fSThomas Hellstrom } 222c74c162fSThomas Hellstrom 2238426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 224c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 225c74c162fSThomas Hellstrom ret = -ENOMEM; 226c74c162fSThomas Hellstrom goto out_no_fifo; 227c74c162fSThomas Hellstrom } 228c74c162fSThomas Hellstrom 229c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; 230c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 231c74c162fSThomas Hellstrom cmd->body.shid = res->id; 232c74c162fSThomas Hellstrom cmd->body.type = shader->type; 233c74c162fSThomas Hellstrom cmd->body.sizeInBytes = shader->size; 2348426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 235153b3d5bSThomas Hellstrom vmw_fifo_resource_inc(dev_priv); 236c74c162fSThomas Hellstrom 237c74c162fSThomas Hellstrom return 0; 238c74c162fSThomas Hellstrom 239c74c162fSThomas Hellstrom out_no_fifo: 240c74c162fSThomas Hellstrom vmw_resource_release_id(res); 241c74c162fSThomas Hellstrom out_no_id: 242c74c162fSThomas Hellstrom return ret; 243c74c162fSThomas Hellstrom } 244c74c162fSThomas Hellstrom 245c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 246c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 247c74c162fSThomas Hellstrom { 248c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 249c74c162fSThomas Hellstrom struct { 250c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 251c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 252c74c162fSThomas Hellstrom } *cmd; 253c74c162fSThomas Hellstrom struct ttm_buffer_object *bo = val_buf->bo; 254c74c162fSThomas Hellstrom 255d3116756SChristian König BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 256c74c162fSThomas Hellstrom 2578426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 25811c45419SDeepak Rawat if (unlikely(cmd == NULL)) 259c74c162fSThomas Hellstrom return -ENOMEM; 260c74c162fSThomas Hellstrom 261c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 262c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 263c74c162fSThomas Hellstrom cmd->body.shid = res->id; 264d3116756SChristian König cmd->body.mobid = bo->resource->start; 265*668b2066SZack Rusin cmd->body.offsetInBytes = res->guest_memory_offset; 266*668b2066SZack Rusin res->guest_memory_dirty = false; 2678426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 268c74c162fSThomas Hellstrom 269c74c162fSThomas Hellstrom return 0; 270c74c162fSThomas Hellstrom } 271c74c162fSThomas Hellstrom 272c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 273c74c162fSThomas Hellstrom bool readback, 274c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 275c74c162fSThomas Hellstrom { 276c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 277c74c162fSThomas Hellstrom struct { 278c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 279c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 280c74c162fSThomas Hellstrom } *cmd; 281c74c162fSThomas Hellstrom struct vmw_fence_obj *fence; 282c74c162fSThomas Hellstrom 283*668b2066SZack Rusin BUG_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB); 284c74c162fSThomas Hellstrom 2858426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 28611c45419SDeepak Rawat if (unlikely(cmd == NULL)) 287c74c162fSThomas Hellstrom return -ENOMEM; 288c74c162fSThomas Hellstrom 289c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 290c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 291c74c162fSThomas Hellstrom cmd->body.shid = res->id; 292c74c162fSThomas Hellstrom cmd->body.mobid = SVGA3D_INVALID_ID; 293c74c162fSThomas Hellstrom cmd->body.offsetInBytes = 0; 2948426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 295c74c162fSThomas Hellstrom 296c74c162fSThomas Hellstrom /* 297c74c162fSThomas Hellstrom * Create a fence object and fence the backup buffer. 298c74c162fSThomas Hellstrom */ 299c74c162fSThomas Hellstrom 300c74c162fSThomas Hellstrom (void) vmw_execbuf_fence_commands(NULL, dev_priv, 301c74c162fSThomas Hellstrom &fence, NULL); 302c74c162fSThomas Hellstrom 303e9431ea5SThomas Hellstrom vmw_bo_fence_single(val_buf->bo, fence); 304c74c162fSThomas Hellstrom 305c74c162fSThomas Hellstrom if (likely(fence != NULL)) 306c74c162fSThomas Hellstrom vmw_fence_obj_unreference(&fence); 307c74c162fSThomas Hellstrom 308c74c162fSThomas Hellstrom return 0; 309c74c162fSThomas Hellstrom } 310c74c162fSThomas Hellstrom 311c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res) 312c74c162fSThomas Hellstrom { 313c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 314c74c162fSThomas Hellstrom struct { 315c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 316c74c162fSThomas Hellstrom SVGA3dCmdDestroyGBShader body; 317c74c162fSThomas Hellstrom } *cmd; 318c74c162fSThomas Hellstrom 319c74c162fSThomas Hellstrom if (likely(res->id == -1)) 320c74c162fSThomas Hellstrom return 0; 321c74c162fSThomas Hellstrom 322173fb7d4SThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 323d80efd5cSThomas Hellstrom vmw_binding_res_list_scrub(&res->binding_head); 324173fb7d4SThomas Hellstrom 3258426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 326c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 3273e894a62SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 328c74c162fSThomas Hellstrom return -ENOMEM; 329c74c162fSThomas Hellstrom } 330c74c162fSThomas Hellstrom 331c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; 332c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 333c74c162fSThomas Hellstrom cmd->body.shid = res->id; 3348426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 335173fb7d4SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 336c74c162fSThomas Hellstrom vmw_resource_release_id(res); 337153b3d5bSThomas Hellstrom vmw_fifo_resource_dec(dev_priv); 338c74c162fSThomas Hellstrom 339c74c162fSThomas Hellstrom return 0; 340c74c162fSThomas Hellstrom } 341c74c162fSThomas Hellstrom 342d80efd5cSThomas Hellstrom /* 343d80efd5cSThomas Hellstrom * DX shader code: 344d80efd5cSThomas Hellstrom */ 345d80efd5cSThomas Hellstrom 346d80efd5cSThomas Hellstrom /** 347d80efd5cSThomas Hellstrom * vmw_dx_shader_commit_notify - Notify that a shader operation has been 348d80efd5cSThomas Hellstrom * committed to hardware from a user-supplied command stream. 349d80efd5cSThomas Hellstrom * 350d80efd5cSThomas Hellstrom * @res: Pointer to the shader resource. 351d80efd5cSThomas Hellstrom * @state: Indicating whether a creation or removal has been committed. 352d80efd5cSThomas Hellstrom * 353d80efd5cSThomas Hellstrom */ 354d80efd5cSThomas Hellstrom static void vmw_dx_shader_commit_notify(struct vmw_resource *res, 355d80efd5cSThomas Hellstrom enum vmw_cmdbuf_res_state state) 356d80efd5cSThomas Hellstrom { 357d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 358d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 359d80efd5cSThomas Hellstrom 360d80efd5cSThomas Hellstrom if (state == VMW_CMDBUF_RES_ADD) { 361d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 362d80efd5cSThomas Hellstrom vmw_cotable_add_resource(shader->cotable, 363d80efd5cSThomas Hellstrom &shader->cotable_head); 364d80efd5cSThomas Hellstrom shader->committed = true; 365d80efd5cSThomas Hellstrom res->id = shader->id; 366d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 367d80efd5cSThomas Hellstrom } else { 368d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 369d80efd5cSThomas Hellstrom list_del_init(&shader->cotable_head); 370d80efd5cSThomas Hellstrom shader->committed = false; 371d80efd5cSThomas Hellstrom res->id = -1; 372d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 373d80efd5cSThomas Hellstrom } 374d80efd5cSThomas Hellstrom } 375d80efd5cSThomas Hellstrom 376d80efd5cSThomas Hellstrom /** 377d80efd5cSThomas Hellstrom * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader. 378d80efd5cSThomas Hellstrom * 379d80efd5cSThomas Hellstrom * @res: The shader resource 380d80efd5cSThomas Hellstrom * 381d80efd5cSThomas Hellstrom * This function reverts a scrub operation. 382d80efd5cSThomas Hellstrom */ 383d80efd5cSThomas Hellstrom static int vmw_dx_shader_unscrub(struct vmw_resource *res) 384d80efd5cSThomas Hellstrom { 385d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 386d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 387d80efd5cSThomas Hellstrom struct { 388d80efd5cSThomas Hellstrom SVGA3dCmdHeader header; 389d80efd5cSThomas Hellstrom SVGA3dCmdDXBindShader body; 390d80efd5cSThomas Hellstrom } *cmd; 391d80efd5cSThomas Hellstrom 392d80efd5cSThomas Hellstrom if (!list_empty(&shader->cotable_head) || !shader->committed) 393d80efd5cSThomas Hellstrom return 0; 394d80efd5cSThomas Hellstrom 3958426ed9cSZack Rusin cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id); 39611c45419SDeepak Rawat if (unlikely(cmd == NULL)) 397d80efd5cSThomas Hellstrom return -ENOMEM; 398d80efd5cSThomas Hellstrom 399d80efd5cSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER; 400d80efd5cSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 401d80efd5cSThomas Hellstrom cmd->body.cid = shader->ctx->id; 402d80efd5cSThomas Hellstrom cmd->body.shid = shader->id; 403*668b2066SZack Rusin cmd->body.mobid = res->guest_memory_bo->tbo.resource->start; 404*668b2066SZack Rusin cmd->body.offsetInBytes = res->guest_memory_offset; 4058426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 406d80efd5cSThomas Hellstrom 407d80efd5cSThomas Hellstrom vmw_cotable_add_resource(shader->cotable, &shader->cotable_head); 408d80efd5cSThomas Hellstrom 409d80efd5cSThomas Hellstrom return 0; 410d80efd5cSThomas Hellstrom } 411d80efd5cSThomas Hellstrom 412d80efd5cSThomas Hellstrom /** 413d80efd5cSThomas Hellstrom * vmw_dx_shader_create - The DX shader create callback 414d80efd5cSThomas Hellstrom * 415d80efd5cSThomas Hellstrom * @res: The DX shader resource 416d80efd5cSThomas Hellstrom * 417d80efd5cSThomas Hellstrom * The create callback is called as part of resource validation and 418d80efd5cSThomas Hellstrom * makes sure that we unscrub the shader if it's previously been scrubbed. 419d80efd5cSThomas Hellstrom */ 420d80efd5cSThomas Hellstrom static int vmw_dx_shader_create(struct vmw_resource *res) 421d80efd5cSThomas Hellstrom { 422d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 423d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 424d80efd5cSThomas Hellstrom int ret = 0; 425d80efd5cSThomas Hellstrom 426d80efd5cSThomas Hellstrom WARN_ON_ONCE(!shader->committed); 427d80efd5cSThomas Hellstrom 428a0a63940SThomas Hellstrom if (vmw_resource_mob_attached(res)) { 429d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 430d80efd5cSThomas Hellstrom ret = vmw_dx_shader_unscrub(res); 431d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 432d80efd5cSThomas Hellstrom } 433d80efd5cSThomas Hellstrom 434d80efd5cSThomas Hellstrom res->id = shader->id; 435d80efd5cSThomas Hellstrom return ret; 436d80efd5cSThomas Hellstrom } 437d80efd5cSThomas Hellstrom 438d80efd5cSThomas Hellstrom /** 439d80efd5cSThomas Hellstrom * vmw_dx_shader_bind - The DX shader bind callback 440d80efd5cSThomas Hellstrom * 441d80efd5cSThomas Hellstrom * @res: The DX shader resource 442d80efd5cSThomas Hellstrom * @val_buf: Pointer to the validate buffer. 443d80efd5cSThomas Hellstrom * 444d80efd5cSThomas Hellstrom */ 445d80efd5cSThomas Hellstrom static int vmw_dx_shader_bind(struct vmw_resource *res, 446d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf) 447d80efd5cSThomas Hellstrom { 448d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 449d80efd5cSThomas Hellstrom struct ttm_buffer_object *bo = val_buf->bo; 450d80efd5cSThomas Hellstrom 451d3116756SChristian König BUG_ON(bo->resource->mem_type != VMW_PL_MOB); 452d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 453d80efd5cSThomas Hellstrom vmw_dx_shader_unscrub(res); 454d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 455d80efd5cSThomas Hellstrom 456d80efd5cSThomas Hellstrom return 0; 457d80efd5cSThomas Hellstrom } 458d80efd5cSThomas Hellstrom 459d80efd5cSThomas Hellstrom /** 460d80efd5cSThomas Hellstrom * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader. 461d80efd5cSThomas Hellstrom * 462d80efd5cSThomas Hellstrom * @res: The shader resource 463d80efd5cSThomas Hellstrom * 464d80efd5cSThomas Hellstrom * This function unbinds a MOB from the DX shader without requiring the 465d80efd5cSThomas Hellstrom * MOB dma_buffer to be reserved. The driver still considers the MOB bound. 466d80efd5cSThomas Hellstrom * However, once the driver eventually decides to unbind the MOB, it doesn't 467d80efd5cSThomas Hellstrom * need to access the context. 468d80efd5cSThomas Hellstrom */ 469d80efd5cSThomas Hellstrom static int vmw_dx_shader_scrub(struct vmw_resource *res) 470d80efd5cSThomas Hellstrom { 471d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 472d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 473d80efd5cSThomas Hellstrom struct { 474d80efd5cSThomas Hellstrom SVGA3dCmdHeader header; 475d80efd5cSThomas Hellstrom SVGA3dCmdDXBindShader body; 476d80efd5cSThomas Hellstrom } *cmd; 477d80efd5cSThomas Hellstrom 478d80efd5cSThomas Hellstrom if (list_empty(&shader->cotable_head)) 479d80efd5cSThomas Hellstrom return 0; 480d80efd5cSThomas Hellstrom 481d80efd5cSThomas Hellstrom WARN_ON_ONCE(!shader->committed); 4828426ed9cSZack Rusin cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 48311c45419SDeepak Rawat if (unlikely(cmd == NULL)) 484d80efd5cSThomas Hellstrom return -ENOMEM; 485d80efd5cSThomas Hellstrom 486d80efd5cSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER; 487d80efd5cSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 488d80efd5cSThomas Hellstrom cmd->body.cid = shader->ctx->id; 489d80efd5cSThomas Hellstrom cmd->body.shid = res->id; 490d80efd5cSThomas Hellstrom cmd->body.mobid = SVGA3D_INVALID_ID; 491d80efd5cSThomas Hellstrom cmd->body.offsetInBytes = 0; 4928426ed9cSZack Rusin vmw_cmd_commit(dev_priv, sizeof(*cmd)); 493d80efd5cSThomas Hellstrom res->id = -1; 494d80efd5cSThomas Hellstrom list_del_init(&shader->cotable_head); 495d80efd5cSThomas Hellstrom 496d80efd5cSThomas Hellstrom return 0; 497d80efd5cSThomas Hellstrom } 498d80efd5cSThomas Hellstrom 499d80efd5cSThomas Hellstrom /** 500d80efd5cSThomas Hellstrom * vmw_dx_shader_unbind - The dx shader unbind callback. 501d80efd5cSThomas Hellstrom * 502d80efd5cSThomas Hellstrom * @res: The shader resource 503d80efd5cSThomas Hellstrom * @readback: Whether this is a readback unbind. Currently unused. 504d80efd5cSThomas Hellstrom * @val_buf: MOB buffer information. 505d80efd5cSThomas Hellstrom */ 506d80efd5cSThomas Hellstrom static int vmw_dx_shader_unbind(struct vmw_resource *res, 507d80efd5cSThomas Hellstrom bool readback, 508d80efd5cSThomas Hellstrom struct ttm_validate_buffer *val_buf) 509d80efd5cSThomas Hellstrom { 510d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 511d80efd5cSThomas Hellstrom struct vmw_fence_obj *fence; 512d80efd5cSThomas Hellstrom int ret; 513d80efd5cSThomas Hellstrom 514*668b2066SZack Rusin BUG_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB); 515d80efd5cSThomas Hellstrom 516d80efd5cSThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 517d80efd5cSThomas Hellstrom ret = vmw_dx_shader_scrub(res); 518d80efd5cSThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 519d80efd5cSThomas Hellstrom 520d80efd5cSThomas Hellstrom if (ret) 521d80efd5cSThomas Hellstrom return ret; 522d80efd5cSThomas Hellstrom 523d80efd5cSThomas Hellstrom (void) vmw_execbuf_fence_commands(NULL, dev_priv, 524d80efd5cSThomas Hellstrom &fence, NULL); 525e9431ea5SThomas Hellstrom vmw_bo_fence_single(val_buf->bo, fence); 526d80efd5cSThomas Hellstrom 527d80efd5cSThomas Hellstrom if (likely(fence != NULL)) 528d80efd5cSThomas Hellstrom vmw_fence_obj_unreference(&fence); 529d80efd5cSThomas Hellstrom 530d80efd5cSThomas Hellstrom return 0; 531d80efd5cSThomas Hellstrom } 532d80efd5cSThomas Hellstrom 533d80efd5cSThomas Hellstrom /** 534d80efd5cSThomas Hellstrom * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for 535d80efd5cSThomas Hellstrom * DX shaders. 536d80efd5cSThomas Hellstrom * 537d80efd5cSThomas Hellstrom * @dev_priv: Pointer to device private structure. 538d80efd5cSThomas Hellstrom * @list: The list of cotable resources. 539d80efd5cSThomas Hellstrom * @readback: Whether the call was part of a readback unbind. 540d80efd5cSThomas Hellstrom * 541d80efd5cSThomas Hellstrom * Scrubs all shader MOBs so that any subsequent shader unbind or shader 542d80efd5cSThomas Hellstrom * destroy operation won't need to swap in the context. 543d80efd5cSThomas Hellstrom */ 544d80efd5cSThomas Hellstrom void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv, 545d80efd5cSThomas Hellstrom struct list_head *list, 546d80efd5cSThomas Hellstrom bool readback) 547d80efd5cSThomas Hellstrom { 548d80efd5cSThomas Hellstrom struct vmw_dx_shader *entry, *next; 549d80efd5cSThomas Hellstrom 550d76ce03eSThomas Hellstrom lockdep_assert_held_once(&dev_priv->binding_mutex); 551d80efd5cSThomas Hellstrom 552d80efd5cSThomas Hellstrom list_for_each_entry_safe(entry, next, list, cotable_head) { 553d80efd5cSThomas Hellstrom WARN_ON(vmw_dx_shader_scrub(&entry->res)); 554d80efd5cSThomas Hellstrom if (!readback) 555d80efd5cSThomas Hellstrom entry->committed = false; 556d80efd5cSThomas Hellstrom } 557d80efd5cSThomas Hellstrom } 558d80efd5cSThomas Hellstrom 559d80efd5cSThomas Hellstrom /** 560d80efd5cSThomas Hellstrom * vmw_dx_shader_res_free - The DX shader free callback 561d80efd5cSThomas Hellstrom * 562d80efd5cSThomas Hellstrom * @res: The shader resource 563d80efd5cSThomas Hellstrom * 5648aadeb8aSZack Rusin * Frees the DX shader resource. 565d80efd5cSThomas Hellstrom */ 566d80efd5cSThomas Hellstrom static void vmw_dx_shader_res_free(struct vmw_resource *res) 567d80efd5cSThomas Hellstrom { 568d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res); 569d80efd5cSThomas Hellstrom 570d80efd5cSThomas Hellstrom vmw_resource_unreference(&shader->cotable); 571d80efd5cSThomas Hellstrom kfree(shader); 572d80efd5cSThomas Hellstrom } 573d80efd5cSThomas Hellstrom 574d80efd5cSThomas Hellstrom /** 575d80efd5cSThomas Hellstrom * vmw_dx_shader_add - Add a shader resource as a command buffer managed 576d80efd5cSThomas Hellstrom * resource. 577d80efd5cSThomas Hellstrom * 578d80efd5cSThomas Hellstrom * @man: The command buffer resource manager. 579d80efd5cSThomas Hellstrom * @ctx: Pointer to the context resource. 580d80efd5cSThomas Hellstrom * @user_key: The id used for this shader. 581d80efd5cSThomas Hellstrom * @shader_type: The shader type. 582d80efd5cSThomas Hellstrom * @list: The list of staged command buffer managed resources. 583d80efd5cSThomas Hellstrom */ 584d80efd5cSThomas Hellstrom int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man, 585d80efd5cSThomas Hellstrom struct vmw_resource *ctx, 586d80efd5cSThomas Hellstrom u32 user_key, 587d80efd5cSThomas Hellstrom SVGA3dShaderType shader_type, 588d80efd5cSThomas Hellstrom struct list_head *list) 589d80efd5cSThomas Hellstrom { 590d80efd5cSThomas Hellstrom struct vmw_dx_shader *shader; 591d80efd5cSThomas Hellstrom struct vmw_resource *res; 592d80efd5cSThomas Hellstrom struct vmw_private *dev_priv = ctx->dev_priv; 593d80efd5cSThomas Hellstrom int ret; 594d80efd5cSThomas Hellstrom 595d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 596d80efd5cSThomas Hellstrom return -EINVAL; 597d80efd5cSThomas Hellstrom 598d80efd5cSThomas Hellstrom shader = kmalloc(sizeof(*shader), GFP_KERNEL); 599d80efd5cSThomas Hellstrom if (!shader) { 600d80efd5cSThomas Hellstrom return -ENOMEM; 601d80efd5cSThomas Hellstrom } 602d80efd5cSThomas Hellstrom 603d80efd5cSThomas Hellstrom res = &shader->res; 604d80efd5cSThomas Hellstrom shader->ctx = ctx; 6051b9a01d6SThomas Hellstrom shader->cotable = vmw_resource_reference 6061b9a01d6SThomas Hellstrom (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER)); 607d80efd5cSThomas Hellstrom shader->id = user_key; 608d80efd5cSThomas Hellstrom shader->committed = false; 609d80efd5cSThomas Hellstrom INIT_LIST_HEAD(&shader->cotable_head); 610d80efd5cSThomas Hellstrom ret = vmw_resource_init(dev_priv, res, true, 611d80efd5cSThomas Hellstrom vmw_dx_shader_res_free, &vmw_dx_shader_func); 612d80efd5cSThomas Hellstrom if (ret) 613d80efd5cSThomas Hellstrom goto out_resource_init; 614d80efd5cSThomas Hellstrom 615d80efd5cSThomas Hellstrom /* 616d80efd5cSThomas Hellstrom * The user_key name-space is not per shader type for DX shaders, 617d80efd5cSThomas Hellstrom * so when hashing, use a single zero shader type. 618d80efd5cSThomas Hellstrom */ 619d80efd5cSThomas Hellstrom ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, 620d80efd5cSThomas Hellstrom vmw_shader_key(user_key, 0), 621d80efd5cSThomas Hellstrom res, list); 622d80efd5cSThomas Hellstrom if (ret) 623d80efd5cSThomas Hellstrom goto out_resource_init; 624d80efd5cSThomas Hellstrom 625d80efd5cSThomas Hellstrom res->id = shader->id; 62613289241SThomas Hellstrom res->hw_destroy = vmw_hw_shader_destroy; 627d80efd5cSThomas Hellstrom 628d80efd5cSThomas Hellstrom out_resource_init: 629d80efd5cSThomas Hellstrom vmw_resource_unreference(&res); 630d80efd5cSThomas Hellstrom 631d80efd5cSThomas Hellstrom return ret; 632d80efd5cSThomas Hellstrom } 633d80efd5cSThomas Hellstrom 634d80efd5cSThomas Hellstrom 635d80efd5cSThomas Hellstrom 636ad2ae415SLee Jones /* 637c74c162fSThomas Hellstrom * User-space shader management: 638c74c162fSThomas Hellstrom */ 639c74c162fSThomas Hellstrom 640c74c162fSThomas Hellstrom static struct vmw_resource * 641c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base) 642c74c162fSThomas Hellstrom { 643c74c162fSThomas Hellstrom return &(container_of(base, struct vmw_user_shader, base)-> 644c74c162fSThomas Hellstrom shader.res); 645c74c162fSThomas Hellstrom } 646c74c162fSThomas Hellstrom 647c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res) 648c74c162fSThomas Hellstrom { 649c74c162fSThomas Hellstrom struct vmw_user_shader *ushader = 650c74c162fSThomas Hellstrom container_of(res, struct vmw_user_shader, shader.res); 651c74c162fSThomas Hellstrom 652c74c162fSThomas Hellstrom ttm_base_object_kfree(ushader, base); 653c74c162fSThomas Hellstrom } 654c74c162fSThomas Hellstrom 65518e4a466SThomas Hellstrom static void vmw_shader_free(struct vmw_resource *res) 65618e4a466SThomas Hellstrom { 65718e4a466SThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 65818e4a466SThomas Hellstrom 65918e4a466SThomas Hellstrom kfree(shader); 66018e4a466SThomas Hellstrom } 66118e4a466SThomas Hellstrom 662ad2ae415SLee Jones /* 663c74c162fSThomas Hellstrom * This function is called when user space has no more references on the 664c74c162fSThomas Hellstrom * base object. It releases the base-object's reference on the resource object. 665c74c162fSThomas Hellstrom */ 666c74c162fSThomas Hellstrom 667c74c162fSThomas Hellstrom static void vmw_user_shader_base_release(struct ttm_base_object **p_base) 668c74c162fSThomas Hellstrom { 669c74c162fSThomas Hellstrom struct ttm_base_object *base = *p_base; 670c74c162fSThomas Hellstrom struct vmw_resource *res = vmw_user_shader_base_to_res(base); 671c74c162fSThomas Hellstrom 672c74c162fSThomas Hellstrom *p_base = NULL; 673c74c162fSThomas Hellstrom vmw_resource_unreference(&res); 674c74c162fSThomas Hellstrom } 675c74c162fSThomas Hellstrom 676c74c162fSThomas Hellstrom int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, 677c74c162fSThomas Hellstrom struct drm_file *file_priv) 678c74c162fSThomas Hellstrom { 679c74c162fSThomas Hellstrom struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; 680c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 681c74c162fSThomas Hellstrom 6828afa13a0SZack Rusin return ttm_ref_object_base_unref(tfile, arg->handle); 683c74c162fSThomas Hellstrom } 684c74c162fSThomas Hellstrom 68518e4a466SThomas Hellstrom static int vmw_user_shader_alloc(struct vmw_private *dev_priv, 68609881d29SZack Rusin struct vmw_bo *buffer, 687d5bde956SThomas Hellstrom size_t shader_size, 688d5bde956SThomas Hellstrom size_t offset, 689d5bde956SThomas Hellstrom SVGA3dShaderType shader_type, 690d80efd5cSThomas Hellstrom uint8_t num_input_sig, 691d80efd5cSThomas Hellstrom uint8_t num_output_sig, 692d5bde956SThomas Hellstrom struct ttm_object_file *tfile, 693d5bde956SThomas Hellstrom u32 *handle) 694d5bde956SThomas Hellstrom { 695d5bde956SThomas Hellstrom struct vmw_user_shader *ushader; 696d5bde956SThomas Hellstrom struct vmw_resource *res, *tmp; 697d5bde956SThomas Hellstrom int ret; 698d5bde956SThomas Hellstrom 699d5bde956SThomas Hellstrom ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); 7001a4adb05SRavikant B Sharma if (unlikely(!ushader)) { 701d5bde956SThomas Hellstrom ret = -ENOMEM; 702d5bde956SThomas Hellstrom goto out; 703d5bde956SThomas Hellstrom } 704d5bde956SThomas Hellstrom 705d5bde956SThomas Hellstrom res = &ushader->shader.res; 706d5bde956SThomas Hellstrom ushader->base.shareable = false; 707d5bde956SThomas Hellstrom ushader->base.tfile = NULL; 708d5bde956SThomas Hellstrom 709d5bde956SThomas Hellstrom /* 710d5bde956SThomas Hellstrom * From here on, the destructor takes over resource freeing. 711d5bde956SThomas Hellstrom */ 712d5bde956SThomas Hellstrom 713d5bde956SThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, shader_size, 714d80efd5cSThomas Hellstrom offset, shader_type, num_input_sig, 715d80efd5cSThomas Hellstrom num_output_sig, buffer, 716d5bde956SThomas Hellstrom vmw_user_shader_free); 717d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 718d5bde956SThomas Hellstrom goto out; 719d5bde956SThomas Hellstrom 720d5bde956SThomas Hellstrom tmp = vmw_resource_reference(res); 721d5bde956SThomas Hellstrom ret = ttm_base_object_init(tfile, &ushader->base, false, 722d5bde956SThomas Hellstrom VMW_RES_SHADER, 7238afa13a0SZack Rusin &vmw_user_shader_base_release); 724d5bde956SThomas Hellstrom 725d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 726d5bde956SThomas Hellstrom vmw_resource_unreference(&tmp); 727d5bde956SThomas Hellstrom goto out_err; 728d5bde956SThomas Hellstrom } 729d5bde956SThomas Hellstrom 730d5bde956SThomas Hellstrom if (handle) 731c7eae626SThomas Hellstrom *handle = ushader->base.handle; 732d5bde956SThomas Hellstrom out_err: 733d5bde956SThomas Hellstrom vmw_resource_unreference(&res); 734d5bde956SThomas Hellstrom out: 735d5bde956SThomas Hellstrom return ret; 736d5bde956SThomas Hellstrom } 737d5bde956SThomas Hellstrom 738d5bde956SThomas Hellstrom 739b9eb1a61SThomas Hellstrom static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, 74009881d29SZack Rusin struct vmw_bo *buffer, 74118e4a466SThomas Hellstrom size_t shader_size, 74218e4a466SThomas Hellstrom size_t offset, 74318e4a466SThomas Hellstrom SVGA3dShaderType shader_type) 74418e4a466SThomas Hellstrom { 74518e4a466SThomas Hellstrom struct vmw_shader *shader; 74618e4a466SThomas Hellstrom struct vmw_resource *res; 74718e4a466SThomas Hellstrom int ret; 74818e4a466SThomas Hellstrom 74918e4a466SThomas Hellstrom shader = kzalloc(sizeof(*shader), GFP_KERNEL); 7501a4adb05SRavikant B Sharma if (unlikely(!shader)) { 75118e4a466SThomas Hellstrom ret = -ENOMEM; 75218e4a466SThomas Hellstrom goto out_err; 75318e4a466SThomas Hellstrom } 75418e4a466SThomas Hellstrom 75518e4a466SThomas Hellstrom res = &shader->res; 75618e4a466SThomas Hellstrom 75718e4a466SThomas Hellstrom /* 75818e4a466SThomas Hellstrom * From here on, the destructor takes over resource freeing. 75918e4a466SThomas Hellstrom */ 76018e4a466SThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, shader_size, 761d80efd5cSThomas Hellstrom offset, shader_type, 0, 0, buffer, 76218e4a466SThomas Hellstrom vmw_shader_free); 76318e4a466SThomas Hellstrom 76418e4a466SThomas Hellstrom out_err: 76518e4a466SThomas Hellstrom return ret ? ERR_PTR(ret) : res; 76618e4a466SThomas Hellstrom } 76718e4a466SThomas Hellstrom 76818e4a466SThomas Hellstrom 769d80efd5cSThomas Hellstrom static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, 770d80efd5cSThomas Hellstrom enum drm_vmw_shader_type shader_type_drm, 771d80efd5cSThomas Hellstrom u32 buffer_handle, size_t size, size_t offset, 772d80efd5cSThomas Hellstrom uint8_t num_input_sig, uint8_t num_output_sig, 773d80efd5cSThomas Hellstrom uint32_t *shader_handle) 774c74c162fSThomas Hellstrom { 775c74c162fSThomas Hellstrom struct vmw_private *dev_priv = vmw_priv(dev); 776c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 77709881d29SZack Rusin struct vmw_bo *buffer = NULL; 778c74c162fSThomas Hellstrom SVGA3dShaderType shader_type; 779c74c162fSThomas Hellstrom int ret; 780c74c162fSThomas Hellstrom 781d80efd5cSThomas Hellstrom if (buffer_handle != SVGA3D_INVALID_ID) { 7828afa13a0SZack Rusin ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer); 783c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 7845724f899SDeepak Rawat VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n"); 785c74c162fSThomas Hellstrom return ret; 786c74c162fSThomas Hellstrom } 787c74c162fSThomas Hellstrom 788*668b2066SZack Rusin if ((u64)buffer->tbo.base.size < (u64)size + (u64)offset) { 7895724f899SDeepak Rawat VMW_DEBUG_USER("Illegal buffer- or shader size.\n"); 790c74c162fSThomas Hellstrom ret = -EINVAL; 791c74c162fSThomas Hellstrom goto out_bad_arg; 792c74c162fSThomas Hellstrom } 793c74c162fSThomas Hellstrom } 794c74c162fSThomas Hellstrom 795d80efd5cSThomas Hellstrom switch (shader_type_drm) { 796c74c162fSThomas Hellstrom case drm_vmw_shader_type_vs: 797c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_VS; 798c74c162fSThomas Hellstrom break; 799c74c162fSThomas Hellstrom case drm_vmw_shader_type_ps: 800c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_PS; 801c74c162fSThomas Hellstrom break; 802c74c162fSThomas Hellstrom default: 8035724f899SDeepak Rawat VMW_DEBUG_USER("Illegal shader type.\n"); 804c74c162fSThomas Hellstrom ret = -EINVAL; 805c74c162fSThomas Hellstrom goto out_bad_arg; 806c74c162fSThomas Hellstrom } 807c74c162fSThomas Hellstrom 808d80efd5cSThomas Hellstrom ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset, 809d80efd5cSThomas Hellstrom shader_type, num_input_sig, 810d80efd5cSThomas Hellstrom num_output_sig, tfile, shader_handle); 811c74c162fSThomas Hellstrom out_bad_arg: 812f1d34bfdSThomas Hellstrom vmw_bo_unreference(&buffer); 813d5bde956SThomas Hellstrom return ret; 814d5bde956SThomas Hellstrom } 815c74c162fSThomas Hellstrom 816d5bde956SThomas Hellstrom /** 817d80efd5cSThomas Hellstrom * vmw_shader_id_ok - Check whether a compat shader user key and 81818e4a466SThomas Hellstrom * shader type are within valid bounds. 819d5bde956SThomas Hellstrom * 82018e4a466SThomas Hellstrom * @user_key: User space id of the shader. 82118e4a466SThomas Hellstrom * @shader_type: Shader type. 822d5bde956SThomas Hellstrom * 82318e4a466SThomas Hellstrom * Returns true if valid false if not. 824d5bde956SThomas Hellstrom */ 825d80efd5cSThomas Hellstrom static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) 826d5bde956SThomas Hellstrom { 82718e4a466SThomas Hellstrom return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16; 828d5bde956SThomas Hellstrom } 829d5bde956SThomas Hellstrom 830d5bde956SThomas Hellstrom /** 831d80efd5cSThomas Hellstrom * vmw_shader_key - Compute a hash key suitable for a compat shader. 832d5bde956SThomas Hellstrom * 83318e4a466SThomas Hellstrom * @user_key: User space id of the shader. 83418e4a466SThomas Hellstrom * @shader_type: Shader type. 835d5bde956SThomas Hellstrom * 83618e4a466SThomas Hellstrom * Returns a hash key suitable for a command buffer managed resource 83718e4a466SThomas Hellstrom * manager hash table. 838d5bde956SThomas Hellstrom */ 839d80efd5cSThomas Hellstrom static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type) 840d5bde956SThomas Hellstrom { 84118e4a466SThomas Hellstrom return user_key | (shader_type << 20); 842d5bde956SThomas Hellstrom } 843d5bde956SThomas Hellstrom 844d5bde956SThomas Hellstrom /** 845d80efd5cSThomas Hellstrom * vmw_shader_remove - Stage a compat shader for removal. 846d5bde956SThomas Hellstrom * 84718e4a466SThomas Hellstrom * @man: Pointer to the compat shader manager identifying the shader namespace. 848d5bde956SThomas Hellstrom * @user_key: The key that is used to identify the shader. The key is 849d5bde956SThomas Hellstrom * unique to the shader type. 850d5bde956SThomas Hellstrom * @shader_type: Shader type. 85118e4a466SThomas Hellstrom * @list: Caller's list of staged command buffer resource actions. 852d5bde956SThomas Hellstrom */ 853d80efd5cSThomas Hellstrom int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man, 854d5bde956SThomas Hellstrom u32 user_key, SVGA3dShaderType shader_type, 855d5bde956SThomas Hellstrom struct list_head *list) 856d5bde956SThomas Hellstrom { 857d80efd5cSThomas Hellstrom struct vmw_resource *dummy; 858d80efd5cSThomas Hellstrom 859d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 860d5bde956SThomas Hellstrom return -EINVAL; 861d5bde956SThomas Hellstrom 862d80efd5cSThomas Hellstrom return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader, 863d80efd5cSThomas Hellstrom vmw_shader_key(user_key, shader_type), 864d80efd5cSThomas Hellstrom list, &dummy); 865d5bde956SThomas Hellstrom } 866d5bde956SThomas Hellstrom 867d5bde956SThomas Hellstrom /** 86818e4a466SThomas Hellstrom * vmw_compat_shader_add - Create a compat shader and stage it for addition 86918e4a466SThomas Hellstrom * as a command buffer managed resource. 870d5bde956SThomas Hellstrom * 871ad2ae415SLee Jones * @dev_priv: Pointer to device private structure. 87218e4a466SThomas Hellstrom * @man: Pointer to the compat shader manager identifying the shader namespace. 873d5bde956SThomas Hellstrom * @user_key: The key that is used to identify the shader. The key is 874d5bde956SThomas Hellstrom * unique to the shader type. 875d5bde956SThomas Hellstrom * @bytecode: Pointer to the bytecode of the shader. 876d5bde956SThomas Hellstrom * @shader_type: Shader type. 877ad2ae415SLee Jones * @size: Command size. 87818e4a466SThomas Hellstrom * @list: Caller's list of staged command buffer resource actions. 879d5bde956SThomas Hellstrom * 880d5bde956SThomas Hellstrom */ 88118e4a466SThomas Hellstrom int vmw_compat_shader_add(struct vmw_private *dev_priv, 88218e4a466SThomas Hellstrom struct vmw_cmdbuf_res_manager *man, 883d5bde956SThomas Hellstrom u32 user_key, const void *bytecode, 884d5bde956SThomas Hellstrom SVGA3dShaderType shader_type, 885d5bde956SThomas Hellstrom size_t size, 886d5bde956SThomas Hellstrom struct list_head *list) 887d5bde956SThomas Hellstrom { 88819be5570SChristian König struct ttm_operation_ctx ctx = { false, true }; 88909881d29SZack Rusin struct vmw_bo *buf; 890d5bde956SThomas Hellstrom struct ttm_bo_kmap_obj map; 891d5bde956SThomas Hellstrom bool is_iomem; 892d5bde956SThomas Hellstrom int ret; 89318e4a466SThomas Hellstrom struct vmw_resource *res; 894*668b2066SZack Rusin struct vmw_bo_params bo_params = { 895*668b2066SZack Rusin .domain = VMW_BO_DOMAIN_SYS, 896*668b2066SZack Rusin .busy_domain = VMW_BO_DOMAIN_SYS, 897*668b2066SZack Rusin .bo_type = ttm_bo_type_device, 898*668b2066SZack Rusin .size = size, 899*668b2066SZack Rusin .pin = true 900*668b2066SZack Rusin }; 901d5bde956SThomas Hellstrom 902d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 903d5bde956SThomas Hellstrom return -EINVAL; 904d5bde956SThomas Hellstrom 905*668b2066SZack Rusin ret = vmw_bo_create(dev_priv, &bo_params, &buf); 906d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 907d5bde956SThomas Hellstrom goto out; 908d5bde956SThomas Hellstrom 909*668b2066SZack Rusin ret = ttm_bo_reserve(&buf->tbo, false, true, NULL); 910d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 911d5bde956SThomas Hellstrom goto no_reserve; 912d5bde956SThomas Hellstrom 913d5bde956SThomas Hellstrom /* Map and copy shader bytecode. */ 914*668b2066SZack Rusin ret = ttm_bo_kmap(&buf->tbo, 0, PFN_UP(size), &map); 915d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 916*668b2066SZack Rusin ttm_bo_unreserve(&buf->tbo); 917d5bde956SThomas Hellstrom goto no_reserve; 918d5bde956SThomas Hellstrom } 919d5bde956SThomas Hellstrom 920d5bde956SThomas Hellstrom memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); 921d5bde956SThomas Hellstrom WARN_ON(is_iomem); 922d5bde956SThomas Hellstrom 923d5bde956SThomas Hellstrom ttm_bo_kunmap(&map); 924*668b2066SZack Rusin ret = ttm_bo_validate(&buf->tbo, &buf->placement, &ctx); 925d5bde956SThomas Hellstrom WARN_ON(ret != 0); 926*668b2066SZack Rusin ttm_bo_unreserve(&buf->tbo); 927d5bde956SThomas Hellstrom 92818e4a466SThomas Hellstrom res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); 929d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 930d5bde956SThomas Hellstrom goto no_reserve; 931d5bde956SThomas Hellstrom 932d80efd5cSThomas Hellstrom ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, 933d80efd5cSThomas Hellstrom vmw_shader_key(user_key, shader_type), 93418e4a466SThomas Hellstrom res, list); 93518e4a466SThomas Hellstrom vmw_resource_unreference(&res); 936d5bde956SThomas Hellstrom no_reserve: 937f1d34bfdSThomas Hellstrom vmw_bo_unreference(&buf); 938d5bde956SThomas Hellstrom out: 939d5bde956SThomas Hellstrom return ret; 940d5bde956SThomas Hellstrom } 941d5bde956SThomas Hellstrom 942d5bde956SThomas Hellstrom /** 943d80efd5cSThomas Hellstrom * vmw_shader_lookup - Look up a compat shader 944d5bde956SThomas Hellstrom * 94518e4a466SThomas Hellstrom * @man: Pointer to the command buffer managed resource manager identifying 94618e4a466SThomas Hellstrom * the shader namespace. 94718e4a466SThomas Hellstrom * @user_key: The user space id of the shader. 94818e4a466SThomas Hellstrom * @shader_type: The shader type. 949d5bde956SThomas Hellstrom * 95018e4a466SThomas Hellstrom * Returns a refcounted pointer to a struct vmw_resource if the shader was 95118e4a466SThomas Hellstrom * found. An error pointer otherwise. 952d5bde956SThomas Hellstrom */ 95318e4a466SThomas Hellstrom struct vmw_resource * 954d80efd5cSThomas Hellstrom vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man, 95518e4a466SThomas Hellstrom u32 user_key, 95618e4a466SThomas Hellstrom SVGA3dShaderType shader_type) 957d5bde956SThomas Hellstrom { 958d80efd5cSThomas Hellstrom if (!vmw_shader_id_ok(user_key, shader_type)) 95918e4a466SThomas Hellstrom return ERR_PTR(-EINVAL); 960d5bde956SThomas Hellstrom 961d80efd5cSThomas Hellstrom return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader, 962d80efd5cSThomas Hellstrom vmw_shader_key(user_key, shader_type)); 963d80efd5cSThomas Hellstrom } 964d80efd5cSThomas Hellstrom 965d80efd5cSThomas Hellstrom int vmw_shader_define_ioctl(struct drm_device *dev, void *data, 966d80efd5cSThomas Hellstrom struct drm_file *file_priv) 967d80efd5cSThomas Hellstrom { 968d80efd5cSThomas Hellstrom struct drm_vmw_shader_create_arg *arg = 969d80efd5cSThomas Hellstrom (struct drm_vmw_shader_create_arg *)data; 970d80efd5cSThomas Hellstrom 971d80efd5cSThomas Hellstrom return vmw_shader_define(dev, file_priv, arg->shader_type, 972d80efd5cSThomas Hellstrom arg->buffer_handle, 973d80efd5cSThomas Hellstrom arg->size, arg->offset, 974d80efd5cSThomas Hellstrom 0, 0, 975d80efd5cSThomas Hellstrom &arg->shader_handle); 976c74c162fSThomas Hellstrom } 977