1c74c162fSThomas Hellstrom /************************************************************************** 2c74c162fSThomas Hellstrom * 3c74c162fSThomas Hellstrom * Copyright © 2009-2012 VMware, Inc., Palo Alto, CA., USA 4c74c162fSThomas Hellstrom * All Rights Reserved. 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 28c74c162fSThomas Hellstrom #include "vmwgfx_drv.h" 29c74c162fSThomas Hellstrom #include "vmwgfx_resource_priv.h" 30c74c162fSThomas Hellstrom #include "ttm/ttm_placement.h" 31c74c162fSThomas Hellstrom 32c74c162fSThomas Hellstrom struct vmw_shader { 33c74c162fSThomas Hellstrom struct vmw_resource res; 34c74c162fSThomas Hellstrom SVGA3dShaderType type; 35c74c162fSThomas Hellstrom uint32_t size; 36c74c162fSThomas Hellstrom }; 37c74c162fSThomas Hellstrom 38c74c162fSThomas Hellstrom struct vmw_user_shader { 39c74c162fSThomas Hellstrom struct ttm_base_object base; 40c74c162fSThomas Hellstrom struct vmw_shader shader; 41c74c162fSThomas Hellstrom }; 42c74c162fSThomas Hellstrom 4318e4a466SThomas Hellstrom static uint64_t vmw_user_shader_size; 4418e4a466SThomas Hellstrom static uint64_t vmw_shader_size; 45d5bde956SThomas Hellstrom 46c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res); 47c74c162fSThomas Hellstrom static struct vmw_resource * 48c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base); 49c74c162fSThomas Hellstrom 50c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res); 51c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 52c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 53c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 54c74c162fSThomas Hellstrom bool readback, 55c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 56c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res); 57c74c162fSThomas Hellstrom 58c74c162fSThomas Hellstrom static const struct vmw_user_resource_conv user_shader_conv = { 59c74c162fSThomas Hellstrom .object_type = VMW_RES_SHADER, 60c74c162fSThomas Hellstrom .base_obj_to_res = vmw_user_shader_base_to_res, 61c74c162fSThomas Hellstrom .res_free = vmw_user_shader_free 62c74c162fSThomas Hellstrom }; 63c74c162fSThomas Hellstrom 64c74c162fSThomas Hellstrom const struct vmw_user_resource_conv *user_shader_converter = 65c74c162fSThomas Hellstrom &user_shader_conv; 66c74c162fSThomas Hellstrom 67c74c162fSThomas Hellstrom 68c74c162fSThomas Hellstrom static const struct vmw_res_func vmw_gb_shader_func = { 69c74c162fSThomas Hellstrom .res_type = vmw_res_shader, 70c74c162fSThomas Hellstrom .needs_backup = true, 71c74c162fSThomas Hellstrom .may_evict = true, 72c74c162fSThomas Hellstrom .type_name = "guest backed shaders", 73c74c162fSThomas Hellstrom .backup_placement = &vmw_mob_placement, 74c74c162fSThomas Hellstrom .create = vmw_gb_shader_create, 75c74c162fSThomas Hellstrom .destroy = vmw_gb_shader_destroy, 76c74c162fSThomas Hellstrom .bind = vmw_gb_shader_bind, 77c74c162fSThomas Hellstrom .unbind = vmw_gb_shader_unbind 78c74c162fSThomas Hellstrom }; 79c74c162fSThomas Hellstrom 80c74c162fSThomas Hellstrom /** 81c74c162fSThomas Hellstrom * Shader management: 82c74c162fSThomas Hellstrom */ 83c74c162fSThomas Hellstrom 84c74c162fSThomas Hellstrom static inline struct vmw_shader * 85c74c162fSThomas Hellstrom vmw_res_to_shader(struct vmw_resource *res) 86c74c162fSThomas Hellstrom { 87c74c162fSThomas Hellstrom return container_of(res, struct vmw_shader, res); 88c74c162fSThomas Hellstrom } 89c74c162fSThomas Hellstrom 90c74c162fSThomas Hellstrom static void vmw_hw_shader_destroy(struct vmw_resource *res) 91c74c162fSThomas Hellstrom { 92c74c162fSThomas Hellstrom (void) vmw_gb_shader_destroy(res); 93c74c162fSThomas Hellstrom } 94c74c162fSThomas Hellstrom 95c74c162fSThomas Hellstrom static int vmw_gb_shader_init(struct vmw_private *dev_priv, 96c74c162fSThomas Hellstrom struct vmw_resource *res, 97c74c162fSThomas Hellstrom uint32_t size, 98c74c162fSThomas Hellstrom uint64_t offset, 99c74c162fSThomas Hellstrom SVGA3dShaderType type, 100c74c162fSThomas Hellstrom struct vmw_dma_buffer *byte_code, 101c74c162fSThomas Hellstrom void (*res_free) (struct vmw_resource *res)) 102c74c162fSThomas Hellstrom { 103c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 104c74c162fSThomas Hellstrom int ret; 105c74c162fSThomas Hellstrom 106c74c162fSThomas Hellstrom ret = vmw_resource_init(dev_priv, res, true, 107c74c162fSThomas Hellstrom res_free, &vmw_gb_shader_func); 108c74c162fSThomas Hellstrom 109c74c162fSThomas Hellstrom 110c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 111c74c162fSThomas Hellstrom if (res_free) 112c74c162fSThomas Hellstrom res_free(res); 113c74c162fSThomas Hellstrom else 114c74c162fSThomas Hellstrom kfree(res); 115c74c162fSThomas Hellstrom return ret; 116c74c162fSThomas Hellstrom } 117c74c162fSThomas Hellstrom 118c74c162fSThomas Hellstrom res->backup_size = size; 119c74c162fSThomas Hellstrom if (byte_code) { 120c74c162fSThomas Hellstrom res->backup = vmw_dmabuf_reference(byte_code); 121c74c162fSThomas Hellstrom res->backup_offset = offset; 122c74c162fSThomas Hellstrom } 123c74c162fSThomas Hellstrom shader->size = size; 124c74c162fSThomas Hellstrom shader->type = type; 125c74c162fSThomas Hellstrom 126c74c162fSThomas Hellstrom vmw_resource_activate(res, vmw_hw_shader_destroy); 127c74c162fSThomas Hellstrom return 0; 128c74c162fSThomas Hellstrom } 129c74c162fSThomas Hellstrom 130c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res) 131c74c162fSThomas Hellstrom { 132c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 133c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 134c74c162fSThomas Hellstrom int ret; 135c74c162fSThomas Hellstrom struct { 136c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 137c74c162fSThomas Hellstrom SVGA3dCmdDefineGBShader body; 138c74c162fSThomas Hellstrom } *cmd; 139c74c162fSThomas Hellstrom 140c74c162fSThomas Hellstrom if (likely(res->id != -1)) 141c74c162fSThomas Hellstrom return 0; 142c74c162fSThomas Hellstrom 143c74c162fSThomas Hellstrom ret = vmw_resource_alloc_id(res); 144c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 145c74c162fSThomas Hellstrom DRM_ERROR("Failed to allocate a shader id.\n"); 146c74c162fSThomas Hellstrom goto out_no_id; 147c74c162fSThomas Hellstrom } 148c74c162fSThomas Hellstrom 149c74c162fSThomas Hellstrom if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { 150c74c162fSThomas Hellstrom ret = -EBUSY; 151c74c162fSThomas Hellstrom goto out_no_fifo; 152c74c162fSThomas Hellstrom } 153c74c162fSThomas Hellstrom 154c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 155c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 156c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 157c74c162fSThomas Hellstrom "creation.\n"); 158c74c162fSThomas Hellstrom ret = -ENOMEM; 159c74c162fSThomas Hellstrom goto out_no_fifo; 160c74c162fSThomas Hellstrom } 161c74c162fSThomas Hellstrom 162c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; 163c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 164c74c162fSThomas Hellstrom cmd->body.shid = res->id; 165c74c162fSThomas Hellstrom cmd->body.type = shader->type; 166c74c162fSThomas Hellstrom cmd->body.sizeInBytes = shader->size; 167c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 168153b3d5bSThomas Hellstrom vmw_fifo_resource_inc(dev_priv); 169c74c162fSThomas Hellstrom 170c74c162fSThomas Hellstrom return 0; 171c74c162fSThomas Hellstrom 172c74c162fSThomas Hellstrom out_no_fifo: 173c74c162fSThomas Hellstrom vmw_resource_release_id(res); 174c74c162fSThomas Hellstrom out_no_id: 175c74c162fSThomas Hellstrom return ret; 176c74c162fSThomas Hellstrom } 177c74c162fSThomas Hellstrom 178c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 179c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 180c74c162fSThomas Hellstrom { 181c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 182c74c162fSThomas Hellstrom struct { 183c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 184c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 185c74c162fSThomas Hellstrom } *cmd; 186c74c162fSThomas Hellstrom struct ttm_buffer_object *bo = val_buf->bo; 187c74c162fSThomas Hellstrom 188c74c162fSThomas Hellstrom BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 189c74c162fSThomas Hellstrom 190c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 191c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 192c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 193c74c162fSThomas Hellstrom "binding.\n"); 194c74c162fSThomas Hellstrom return -ENOMEM; 195c74c162fSThomas Hellstrom } 196c74c162fSThomas Hellstrom 197c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 198c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 199c74c162fSThomas Hellstrom cmd->body.shid = res->id; 200c74c162fSThomas Hellstrom cmd->body.mobid = bo->mem.start; 201b8ccd1e4SThomas Hellstrom cmd->body.offsetInBytes = res->backup_offset; 202c74c162fSThomas Hellstrom res->backup_dirty = false; 203c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 204c74c162fSThomas Hellstrom 205c74c162fSThomas Hellstrom return 0; 206c74c162fSThomas Hellstrom } 207c74c162fSThomas Hellstrom 208c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 209c74c162fSThomas Hellstrom bool readback, 210c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 211c74c162fSThomas Hellstrom { 212c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 213c74c162fSThomas Hellstrom struct { 214c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 215c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 216c74c162fSThomas Hellstrom } *cmd; 217c74c162fSThomas Hellstrom struct vmw_fence_obj *fence; 218c74c162fSThomas Hellstrom 219c74c162fSThomas Hellstrom BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB); 220c74c162fSThomas Hellstrom 221c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 222c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 223c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 224c74c162fSThomas Hellstrom "unbinding.\n"); 225c74c162fSThomas Hellstrom return -ENOMEM; 226c74c162fSThomas Hellstrom } 227c74c162fSThomas Hellstrom 228c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 229c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 230c74c162fSThomas Hellstrom cmd->body.shid = res->id; 231c74c162fSThomas Hellstrom cmd->body.mobid = SVGA3D_INVALID_ID; 232c74c162fSThomas Hellstrom cmd->body.offsetInBytes = 0; 233c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 234c74c162fSThomas Hellstrom 235c74c162fSThomas Hellstrom /* 236c74c162fSThomas Hellstrom * Create a fence object and fence the backup buffer. 237c74c162fSThomas Hellstrom */ 238c74c162fSThomas Hellstrom 239c74c162fSThomas Hellstrom (void) vmw_execbuf_fence_commands(NULL, dev_priv, 240c74c162fSThomas Hellstrom &fence, NULL); 241c74c162fSThomas Hellstrom 242c74c162fSThomas Hellstrom vmw_fence_single_bo(val_buf->bo, fence); 243c74c162fSThomas Hellstrom 244c74c162fSThomas Hellstrom if (likely(fence != NULL)) 245c74c162fSThomas Hellstrom vmw_fence_obj_unreference(&fence); 246c74c162fSThomas Hellstrom 247c74c162fSThomas Hellstrom return 0; 248c74c162fSThomas Hellstrom } 249c74c162fSThomas Hellstrom 250c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res) 251c74c162fSThomas Hellstrom { 252c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 253c74c162fSThomas Hellstrom struct { 254c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 255c74c162fSThomas Hellstrom SVGA3dCmdDestroyGBShader body; 256c74c162fSThomas Hellstrom } *cmd; 257c74c162fSThomas Hellstrom 258c74c162fSThomas Hellstrom if (likely(res->id == -1)) 259c74c162fSThomas Hellstrom return 0; 260c74c162fSThomas Hellstrom 261173fb7d4SThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 26230f82d81SThomas Hellstrom vmw_context_binding_res_list_scrub(&res->binding_head); 263173fb7d4SThomas Hellstrom 264c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 265c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 266c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 267c74c162fSThomas Hellstrom "destruction.\n"); 2683e894a62SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 269c74c162fSThomas Hellstrom return -ENOMEM; 270c74c162fSThomas Hellstrom } 271c74c162fSThomas Hellstrom 272c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; 273c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 274c74c162fSThomas Hellstrom cmd->body.shid = res->id; 275c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 276173fb7d4SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 277c74c162fSThomas Hellstrom vmw_resource_release_id(res); 278153b3d5bSThomas Hellstrom vmw_fifo_resource_dec(dev_priv); 279c74c162fSThomas Hellstrom 280c74c162fSThomas Hellstrom return 0; 281c74c162fSThomas Hellstrom } 282c74c162fSThomas Hellstrom 283c74c162fSThomas Hellstrom /** 284c74c162fSThomas Hellstrom * User-space shader management: 285c74c162fSThomas Hellstrom */ 286c74c162fSThomas Hellstrom 287c74c162fSThomas Hellstrom static struct vmw_resource * 288c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base) 289c74c162fSThomas Hellstrom { 290c74c162fSThomas Hellstrom return &(container_of(base, struct vmw_user_shader, base)-> 291c74c162fSThomas Hellstrom shader.res); 292c74c162fSThomas Hellstrom } 293c74c162fSThomas Hellstrom 294c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res) 295c74c162fSThomas Hellstrom { 296c74c162fSThomas Hellstrom struct vmw_user_shader *ushader = 297c74c162fSThomas Hellstrom container_of(res, struct vmw_user_shader, shader.res); 298c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 299c74c162fSThomas Hellstrom 300c74c162fSThomas Hellstrom ttm_base_object_kfree(ushader, base); 301c74c162fSThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 302c74c162fSThomas Hellstrom vmw_user_shader_size); 303c74c162fSThomas Hellstrom } 304c74c162fSThomas Hellstrom 30518e4a466SThomas Hellstrom static void vmw_shader_free(struct vmw_resource *res) 30618e4a466SThomas Hellstrom { 30718e4a466SThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 30818e4a466SThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 30918e4a466SThomas Hellstrom 31018e4a466SThomas Hellstrom kfree(shader); 31118e4a466SThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 31218e4a466SThomas Hellstrom vmw_shader_size); 31318e4a466SThomas Hellstrom } 31418e4a466SThomas Hellstrom 315c74c162fSThomas Hellstrom /** 316c74c162fSThomas Hellstrom * This function is called when user space has no more references on the 317c74c162fSThomas Hellstrom * base object. It releases the base-object's reference on the resource object. 318c74c162fSThomas Hellstrom */ 319c74c162fSThomas Hellstrom 320c74c162fSThomas Hellstrom static void vmw_user_shader_base_release(struct ttm_base_object **p_base) 321c74c162fSThomas Hellstrom { 322c74c162fSThomas Hellstrom struct ttm_base_object *base = *p_base; 323c74c162fSThomas Hellstrom struct vmw_resource *res = vmw_user_shader_base_to_res(base); 324c74c162fSThomas Hellstrom 325c74c162fSThomas Hellstrom *p_base = NULL; 326c74c162fSThomas Hellstrom vmw_resource_unreference(&res); 327c74c162fSThomas Hellstrom } 328c74c162fSThomas Hellstrom 329c74c162fSThomas Hellstrom int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, 330c74c162fSThomas Hellstrom struct drm_file *file_priv) 331c74c162fSThomas Hellstrom { 332c74c162fSThomas Hellstrom struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; 333c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 334c74c162fSThomas Hellstrom 335c74c162fSThomas Hellstrom return ttm_ref_object_base_unref(tfile, arg->handle, 336c74c162fSThomas Hellstrom TTM_REF_USAGE); 337c74c162fSThomas Hellstrom } 338c74c162fSThomas Hellstrom 33918e4a466SThomas Hellstrom static int vmw_user_shader_alloc(struct vmw_private *dev_priv, 340d5bde956SThomas Hellstrom struct vmw_dma_buffer *buffer, 341d5bde956SThomas Hellstrom size_t shader_size, 342d5bde956SThomas Hellstrom size_t offset, 343d5bde956SThomas Hellstrom SVGA3dShaderType shader_type, 344d5bde956SThomas Hellstrom struct ttm_object_file *tfile, 345d5bde956SThomas Hellstrom u32 *handle) 346d5bde956SThomas Hellstrom { 347d5bde956SThomas Hellstrom struct vmw_user_shader *ushader; 348d5bde956SThomas Hellstrom struct vmw_resource *res, *tmp; 349d5bde956SThomas Hellstrom int ret; 350d5bde956SThomas Hellstrom 351d5bde956SThomas Hellstrom /* 352d5bde956SThomas Hellstrom * Approximate idr memory usage with 128 bytes. It will be limited 353d5bde956SThomas Hellstrom * by maximum number_of shaders anyway. 354d5bde956SThomas Hellstrom */ 355d5bde956SThomas Hellstrom if (unlikely(vmw_user_shader_size == 0)) 356d5bde956SThomas Hellstrom vmw_user_shader_size = 357d5bde956SThomas Hellstrom ttm_round_pot(sizeof(struct vmw_user_shader)) + 128; 358d5bde956SThomas Hellstrom 359d5bde956SThomas Hellstrom ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 360d5bde956SThomas Hellstrom vmw_user_shader_size, 361d5bde956SThomas Hellstrom false, true); 362d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 363d5bde956SThomas Hellstrom if (ret != -ERESTARTSYS) 364d5bde956SThomas Hellstrom DRM_ERROR("Out of graphics memory for shader " 365d5bde956SThomas Hellstrom "creation.\n"); 366d5bde956SThomas Hellstrom goto out; 367d5bde956SThomas Hellstrom } 368d5bde956SThomas Hellstrom 369d5bde956SThomas Hellstrom ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); 370d5bde956SThomas Hellstrom if (unlikely(ushader == NULL)) { 371d5bde956SThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 372d5bde956SThomas Hellstrom vmw_user_shader_size); 373d5bde956SThomas Hellstrom ret = -ENOMEM; 374d5bde956SThomas Hellstrom goto out; 375d5bde956SThomas Hellstrom } 376d5bde956SThomas Hellstrom 377d5bde956SThomas Hellstrom res = &ushader->shader.res; 378d5bde956SThomas Hellstrom ushader->base.shareable = false; 379d5bde956SThomas Hellstrom ushader->base.tfile = NULL; 380d5bde956SThomas Hellstrom 381d5bde956SThomas Hellstrom /* 382d5bde956SThomas Hellstrom * From here on, the destructor takes over resource freeing. 383d5bde956SThomas Hellstrom */ 384d5bde956SThomas Hellstrom 385d5bde956SThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, shader_size, 386d5bde956SThomas Hellstrom offset, shader_type, buffer, 387d5bde956SThomas Hellstrom vmw_user_shader_free); 388d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 389d5bde956SThomas Hellstrom goto out; 390d5bde956SThomas Hellstrom 391d5bde956SThomas Hellstrom tmp = vmw_resource_reference(res); 392d5bde956SThomas Hellstrom ret = ttm_base_object_init(tfile, &ushader->base, false, 393d5bde956SThomas Hellstrom VMW_RES_SHADER, 394d5bde956SThomas Hellstrom &vmw_user_shader_base_release, NULL); 395d5bde956SThomas Hellstrom 396d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 397d5bde956SThomas Hellstrom vmw_resource_unreference(&tmp); 398d5bde956SThomas Hellstrom goto out_err; 399d5bde956SThomas Hellstrom } 400d5bde956SThomas Hellstrom 401d5bde956SThomas Hellstrom if (handle) 402d5bde956SThomas Hellstrom *handle = ushader->base.hash.key; 403d5bde956SThomas Hellstrom out_err: 404d5bde956SThomas Hellstrom vmw_resource_unreference(&res); 405d5bde956SThomas Hellstrom out: 406d5bde956SThomas Hellstrom return ret; 407d5bde956SThomas Hellstrom } 408d5bde956SThomas Hellstrom 409d5bde956SThomas Hellstrom 410b9eb1a61SThomas Hellstrom static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, 41118e4a466SThomas Hellstrom struct vmw_dma_buffer *buffer, 41218e4a466SThomas Hellstrom size_t shader_size, 41318e4a466SThomas Hellstrom size_t offset, 41418e4a466SThomas Hellstrom SVGA3dShaderType shader_type) 41518e4a466SThomas Hellstrom { 41618e4a466SThomas Hellstrom struct vmw_shader *shader; 41718e4a466SThomas Hellstrom struct vmw_resource *res; 41818e4a466SThomas Hellstrom int ret; 41918e4a466SThomas Hellstrom 42018e4a466SThomas Hellstrom /* 42118e4a466SThomas Hellstrom * Approximate idr memory usage with 128 bytes. It will be limited 42218e4a466SThomas Hellstrom * by maximum number_of shaders anyway. 42318e4a466SThomas Hellstrom */ 42418e4a466SThomas Hellstrom if (unlikely(vmw_shader_size == 0)) 42518e4a466SThomas Hellstrom vmw_shader_size = 42618e4a466SThomas Hellstrom ttm_round_pot(sizeof(struct vmw_shader)) + 128; 42718e4a466SThomas Hellstrom 42818e4a466SThomas Hellstrom ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 42918e4a466SThomas Hellstrom vmw_shader_size, 43018e4a466SThomas Hellstrom false, true); 43118e4a466SThomas Hellstrom if (unlikely(ret != 0)) { 43218e4a466SThomas Hellstrom if (ret != -ERESTARTSYS) 43318e4a466SThomas Hellstrom DRM_ERROR("Out of graphics memory for shader " 43418e4a466SThomas Hellstrom "creation.\n"); 43518e4a466SThomas Hellstrom goto out_err; 43618e4a466SThomas Hellstrom } 43718e4a466SThomas Hellstrom 43818e4a466SThomas Hellstrom shader = kzalloc(sizeof(*shader), GFP_KERNEL); 43918e4a466SThomas Hellstrom if (unlikely(shader == NULL)) { 44018e4a466SThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 44118e4a466SThomas Hellstrom vmw_shader_size); 44218e4a466SThomas Hellstrom ret = -ENOMEM; 44318e4a466SThomas Hellstrom goto out_err; 44418e4a466SThomas Hellstrom } 44518e4a466SThomas Hellstrom 44618e4a466SThomas Hellstrom res = &shader->res; 44718e4a466SThomas Hellstrom 44818e4a466SThomas Hellstrom /* 44918e4a466SThomas Hellstrom * From here on, the destructor takes over resource freeing. 45018e4a466SThomas Hellstrom */ 45118e4a466SThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, shader_size, 45218e4a466SThomas Hellstrom offset, shader_type, buffer, 45318e4a466SThomas Hellstrom vmw_shader_free); 45418e4a466SThomas Hellstrom 45518e4a466SThomas Hellstrom out_err: 45618e4a466SThomas Hellstrom return ret ? ERR_PTR(ret) : res; 45718e4a466SThomas Hellstrom } 45818e4a466SThomas Hellstrom 45918e4a466SThomas Hellstrom 460c74c162fSThomas Hellstrom int vmw_shader_define_ioctl(struct drm_device *dev, void *data, 461c74c162fSThomas Hellstrom struct drm_file *file_priv) 462c74c162fSThomas Hellstrom { 463c74c162fSThomas Hellstrom struct vmw_private *dev_priv = vmw_priv(dev); 464c74c162fSThomas Hellstrom struct drm_vmw_shader_create_arg *arg = 465c74c162fSThomas Hellstrom (struct drm_vmw_shader_create_arg *)data; 466c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 467c74c162fSThomas Hellstrom struct vmw_dma_buffer *buffer = NULL; 468c74c162fSThomas Hellstrom SVGA3dShaderType shader_type; 469c74c162fSThomas Hellstrom int ret; 470c74c162fSThomas Hellstrom 471c74c162fSThomas Hellstrom if (arg->buffer_handle != SVGA3D_INVALID_ID) { 472c74c162fSThomas Hellstrom ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle, 473c74c162fSThomas Hellstrom &buffer); 474c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 475c74c162fSThomas Hellstrom DRM_ERROR("Could not find buffer for shader " 476c74c162fSThomas Hellstrom "creation.\n"); 477c74c162fSThomas Hellstrom return ret; 478c74c162fSThomas Hellstrom } 479c74c162fSThomas Hellstrom 480c74c162fSThomas Hellstrom if ((u64)buffer->base.num_pages * PAGE_SIZE < 481c74c162fSThomas Hellstrom (u64)arg->size + (u64)arg->offset) { 482c74c162fSThomas Hellstrom DRM_ERROR("Illegal buffer- or shader size.\n"); 483c74c162fSThomas Hellstrom ret = -EINVAL; 484c74c162fSThomas Hellstrom goto out_bad_arg; 485c74c162fSThomas Hellstrom } 486c74c162fSThomas Hellstrom } 487c74c162fSThomas Hellstrom 488c74c162fSThomas Hellstrom switch (arg->shader_type) { 489c74c162fSThomas Hellstrom case drm_vmw_shader_type_vs: 490c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_VS; 491c74c162fSThomas Hellstrom break; 492c74c162fSThomas Hellstrom case drm_vmw_shader_type_ps: 493c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_PS; 494c74c162fSThomas Hellstrom break; 495c74c162fSThomas Hellstrom case drm_vmw_shader_type_gs: 496c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_GS; 497c74c162fSThomas Hellstrom break; 498c74c162fSThomas Hellstrom default: 499c74c162fSThomas Hellstrom DRM_ERROR("Illegal shader type.\n"); 500c74c162fSThomas Hellstrom ret = -EINVAL; 501c74c162fSThomas Hellstrom goto out_bad_arg; 502c74c162fSThomas Hellstrom } 503c74c162fSThomas Hellstrom 504294adf7dSThomas Hellstrom ret = ttm_read_lock(&dev_priv->reservation_sem, true); 505c74c162fSThomas Hellstrom if (unlikely(ret != 0)) 506d5bde956SThomas Hellstrom goto out_bad_arg; 507c74c162fSThomas Hellstrom 50818e4a466SThomas Hellstrom ret = vmw_user_shader_alloc(dev_priv, buffer, arg->size, arg->offset, 509d5bde956SThomas Hellstrom shader_type, tfile, &arg->shader_handle); 510c74c162fSThomas Hellstrom 511294adf7dSThomas Hellstrom ttm_read_unlock(&dev_priv->reservation_sem); 512c74c162fSThomas Hellstrom out_bad_arg: 513c74c162fSThomas Hellstrom vmw_dmabuf_unreference(&buffer); 514d5bde956SThomas Hellstrom return ret; 515d5bde956SThomas Hellstrom } 516c74c162fSThomas Hellstrom 517d5bde956SThomas Hellstrom /** 51818e4a466SThomas Hellstrom * vmw_compat_shader_id_ok - Check whether a compat shader user key and 51918e4a466SThomas Hellstrom * shader type are within valid bounds. 520d5bde956SThomas Hellstrom * 52118e4a466SThomas Hellstrom * @user_key: User space id of the shader. 52218e4a466SThomas Hellstrom * @shader_type: Shader type. 523d5bde956SThomas Hellstrom * 52418e4a466SThomas Hellstrom * Returns true if valid false if not. 525d5bde956SThomas Hellstrom */ 52618e4a466SThomas Hellstrom static bool vmw_compat_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type) 527d5bde956SThomas Hellstrom { 52818e4a466SThomas Hellstrom return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16; 529d5bde956SThomas Hellstrom } 530d5bde956SThomas Hellstrom 531d5bde956SThomas Hellstrom /** 53218e4a466SThomas Hellstrom * vmw_compat_shader_key - Compute a hash key suitable for a compat shader. 533d5bde956SThomas Hellstrom * 53418e4a466SThomas Hellstrom * @user_key: User space id of the shader. 53518e4a466SThomas Hellstrom * @shader_type: Shader type. 536d5bde956SThomas Hellstrom * 53718e4a466SThomas Hellstrom * Returns a hash key suitable for a command buffer managed resource 53818e4a466SThomas Hellstrom * manager hash table. 539d5bde956SThomas Hellstrom */ 54018e4a466SThomas Hellstrom static u32 vmw_compat_shader_key(u32 user_key, SVGA3dShaderType shader_type) 541d5bde956SThomas Hellstrom { 54218e4a466SThomas Hellstrom return user_key | (shader_type << 20); 543d5bde956SThomas Hellstrom } 544d5bde956SThomas Hellstrom 545d5bde956SThomas Hellstrom /** 546d5bde956SThomas Hellstrom * vmw_compat_shader_remove - Stage a compat shader for removal. 547d5bde956SThomas Hellstrom * 54818e4a466SThomas Hellstrom * @man: Pointer to the compat shader manager identifying the shader namespace. 549d5bde956SThomas Hellstrom * @user_key: The key that is used to identify the shader. The key is 550d5bde956SThomas Hellstrom * unique to the shader type. 551d5bde956SThomas Hellstrom * @shader_type: Shader type. 55218e4a466SThomas Hellstrom * @list: Caller's list of staged command buffer resource actions. 553d5bde956SThomas Hellstrom */ 55418e4a466SThomas Hellstrom int vmw_compat_shader_remove(struct vmw_cmdbuf_res_manager *man, 555d5bde956SThomas Hellstrom u32 user_key, SVGA3dShaderType shader_type, 556d5bde956SThomas Hellstrom struct list_head *list) 557d5bde956SThomas Hellstrom { 55818e4a466SThomas Hellstrom if (!vmw_compat_shader_id_ok(user_key, shader_type)) 559d5bde956SThomas Hellstrom return -EINVAL; 560d5bde956SThomas Hellstrom 56118e4a466SThomas Hellstrom return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_compat_shader, 56218e4a466SThomas Hellstrom vmw_compat_shader_key(user_key, 56318e4a466SThomas Hellstrom shader_type), 56418e4a466SThomas Hellstrom list); 565d5bde956SThomas Hellstrom } 566d5bde956SThomas Hellstrom 567d5bde956SThomas Hellstrom /** 56818e4a466SThomas Hellstrom * vmw_compat_shader_add - Create a compat shader and stage it for addition 56918e4a466SThomas Hellstrom * as a command buffer managed resource. 570d5bde956SThomas Hellstrom * 57118e4a466SThomas Hellstrom * @man: Pointer to the compat shader manager identifying the shader namespace. 572d5bde956SThomas Hellstrom * @user_key: The key that is used to identify the shader. The key is 573d5bde956SThomas Hellstrom * unique to the shader type. 574d5bde956SThomas Hellstrom * @bytecode: Pointer to the bytecode of the shader. 575d5bde956SThomas Hellstrom * @shader_type: Shader type. 576d5bde956SThomas Hellstrom * @tfile: Pointer to a struct ttm_object_file that the guest-backed shader is 577d5bde956SThomas Hellstrom * to be created with. 57818e4a466SThomas Hellstrom * @list: Caller's list of staged command buffer resource actions. 579d5bde956SThomas Hellstrom * 580d5bde956SThomas Hellstrom */ 58118e4a466SThomas Hellstrom int vmw_compat_shader_add(struct vmw_private *dev_priv, 58218e4a466SThomas Hellstrom struct vmw_cmdbuf_res_manager *man, 583d5bde956SThomas Hellstrom u32 user_key, const void *bytecode, 584d5bde956SThomas Hellstrom SVGA3dShaderType shader_type, 585d5bde956SThomas Hellstrom size_t size, 586d5bde956SThomas Hellstrom struct list_head *list) 587d5bde956SThomas Hellstrom { 588d5bde956SThomas Hellstrom struct vmw_dma_buffer *buf; 589d5bde956SThomas Hellstrom struct ttm_bo_kmap_obj map; 590d5bde956SThomas Hellstrom bool is_iomem; 591d5bde956SThomas Hellstrom int ret; 59218e4a466SThomas Hellstrom struct vmw_resource *res; 593d5bde956SThomas Hellstrom 59418e4a466SThomas Hellstrom if (!vmw_compat_shader_id_ok(user_key, shader_type)) 595d5bde956SThomas Hellstrom return -EINVAL; 596d5bde956SThomas Hellstrom 597d5bde956SThomas Hellstrom /* Allocate and pin a DMA buffer */ 598d5bde956SThomas Hellstrom buf = kzalloc(sizeof(*buf), GFP_KERNEL); 599d5bde956SThomas Hellstrom if (unlikely(buf == NULL)) 600d5bde956SThomas Hellstrom return -ENOMEM; 601d5bde956SThomas Hellstrom 60218e4a466SThomas Hellstrom ret = vmw_dmabuf_init(dev_priv, buf, size, &vmw_sys_ne_placement, 603d5bde956SThomas Hellstrom true, vmw_dmabuf_bo_free); 604d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 605d5bde956SThomas Hellstrom goto out; 606d5bde956SThomas Hellstrom 607d5bde956SThomas Hellstrom ret = ttm_bo_reserve(&buf->base, false, true, false, NULL); 608d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 609d5bde956SThomas Hellstrom goto no_reserve; 610d5bde956SThomas Hellstrom 611d5bde956SThomas Hellstrom /* Map and copy shader bytecode. */ 612d5bde956SThomas Hellstrom ret = ttm_bo_kmap(&buf->base, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, 613d5bde956SThomas Hellstrom &map); 614d5bde956SThomas Hellstrom if (unlikely(ret != 0)) { 615d5bde956SThomas Hellstrom ttm_bo_unreserve(&buf->base); 616d5bde956SThomas Hellstrom goto no_reserve; 617d5bde956SThomas Hellstrom } 618d5bde956SThomas Hellstrom 619d5bde956SThomas Hellstrom memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size); 620d5bde956SThomas Hellstrom WARN_ON(is_iomem); 621d5bde956SThomas Hellstrom 622d5bde956SThomas Hellstrom ttm_bo_kunmap(&map); 623d5bde956SThomas Hellstrom ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, false, true); 624d5bde956SThomas Hellstrom WARN_ON(ret != 0); 625d5bde956SThomas Hellstrom ttm_bo_unreserve(&buf->base); 626d5bde956SThomas Hellstrom 62718e4a466SThomas Hellstrom res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); 628d5bde956SThomas Hellstrom if (unlikely(ret != 0)) 629d5bde956SThomas Hellstrom goto no_reserve; 630d5bde956SThomas Hellstrom 63118e4a466SThomas Hellstrom ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_compat_shader, 63218e4a466SThomas Hellstrom vmw_compat_shader_key(user_key, shader_type), 63318e4a466SThomas Hellstrom res, list); 63418e4a466SThomas Hellstrom vmw_resource_unreference(&res); 635d5bde956SThomas Hellstrom no_reserve: 63618e4a466SThomas Hellstrom vmw_dmabuf_unreference(&buf); 637d5bde956SThomas Hellstrom out: 638d5bde956SThomas Hellstrom return ret; 639d5bde956SThomas Hellstrom } 640d5bde956SThomas Hellstrom 641d5bde956SThomas Hellstrom /** 64218e4a466SThomas Hellstrom * vmw_compat_shader_lookup - Look up a compat shader 643d5bde956SThomas Hellstrom * 64418e4a466SThomas Hellstrom * @man: Pointer to the command buffer managed resource manager identifying 64518e4a466SThomas Hellstrom * the shader namespace. 64618e4a466SThomas Hellstrom * @user_key: The user space id of the shader. 64718e4a466SThomas Hellstrom * @shader_type: The shader type. 648d5bde956SThomas Hellstrom * 64918e4a466SThomas Hellstrom * Returns a refcounted pointer to a struct vmw_resource if the shader was 65018e4a466SThomas Hellstrom * found. An error pointer otherwise. 651d5bde956SThomas Hellstrom */ 65218e4a466SThomas Hellstrom struct vmw_resource * 65318e4a466SThomas Hellstrom vmw_compat_shader_lookup(struct vmw_cmdbuf_res_manager *man, 65418e4a466SThomas Hellstrom u32 user_key, 65518e4a466SThomas Hellstrom SVGA3dShaderType shader_type) 656d5bde956SThomas Hellstrom { 65718e4a466SThomas Hellstrom if (!vmw_compat_shader_id_ok(user_key, shader_type)) 65818e4a466SThomas Hellstrom return ERR_PTR(-EINVAL); 659d5bde956SThomas Hellstrom 66018e4a466SThomas Hellstrom return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_compat_shader, 66118e4a466SThomas Hellstrom vmw_compat_shader_key(user_key, 66218e4a466SThomas Hellstrom shader_type)); 663c74c162fSThomas Hellstrom } 664