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 43c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res); 44c74c162fSThomas Hellstrom static struct vmw_resource * 45c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base); 46c74c162fSThomas Hellstrom 47c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res); 48c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 49c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 50c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 51c74c162fSThomas Hellstrom bool readback, 52c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf); 53c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res); 54c74c162fSThomas Hellstrom 55c74c162fSThomas Hellstrom static uint64_t vmw_user_shader_size; 56c74c162fSThomas Hellstrom 57c74c162fSThomas Hellstrom static const struct vmw_user_resource_conv user_shader_conv = { 58c74c162fSThomas Hellstrom .object_type = VMW_RES_SHADER, 59c74c162fSThomas Hellstrom .base_obj_to_res = vmw_user_shader_base_to_res, 60c74c162fSThomas Hellstrom .res_free = vmw_user_shader_free 61c74c162fSThomas Hellstrom }; 62c74c162fSThomas Hellstrom 63c74c162fSThomas Hellstrom const struct vmw_user_resource_conv *user_shader_converter = 64c74c162fSThomas Hellstrom &user_shader_conv; 65c74c162fSThomas Hellstrom 66c74c162fSThomas Hellstrom 67c74c162fSThomas Hellstrom static const struct vmw_res_func vmw_gb_shader_func = { 68c74c162fSThomas Hellstrom .res_type = vmw_res_shader, 69c74c162fSThomas Hellstrom .needs_backup = true, 70c74c162fSThomas Hellstrom .may_evict = true, 71c74c162fSThomas Hellstrom .type_name = "guest backed shaders", 72c74c162fSThomas Hellstrom .backup_placement = &vmw_mob_placement, 73c74c162fSThomas Hellstrom .create = vmw_gb_shader_create, 74c74c162fSThomas Hellstrom .destroy = vmw_gb_shader_destroy, 75c74c162fSThomas Hellstrom .bind = vmw_gb_shader_bind, 76c74c162fSThomas Hellstrom .unbind = vmw_gb_shader_unbind 77c74c162fSThomas Hellstrom }; 78c74c162fSThomas Hellstrom 79c74c162fSThomas Hellstrom /** 80c74c162fSThomas Hellstrom * Shader management: 81c74c162fSThomas Hellstrom */ 82c74c162fSThomas Hellstrom 83c74c162fSThomas Hellstrom static inline struct vmw_shader * 84c74c162fSThomas Hellstrom vmw_res_to_shader(struct vmw_resource *res) 85c74c162fSThomas Hellstrom { 86c74c162fSThomas Hellstrom return container_of(res, struct vmw_shader, res); 87c74c162fSThomas Hellstrom } 88c74c162fSThomas Hellstrom 89c74c162fSThomas Hellstrom static void vmw_hw_shader_destroy(struct vmw_resource *res) 90c74c162fSThomas Hellstrom { 91c74c162fSThomas Hellstrom (void) vmw_gb_shader_destroy(res); 92c74c162fSThomas Hellstrom } 93c74c162fSThomas Hellstrom 94c74c162fSThomas Hellstrom static int vmw_gb_shader_init(struct vmw_private *dev_priv, 95c74c162fSThomas Hellstrom struct vmw_resource *res, 96c74c162fSThomas Hellstrom uint32_t size, 97c74c162fSThomas Hellstrom uint64_t offset, 98c74c162fSThomas Hellstrom SVGA3dShaderType type, 99c74c162fSThomas Hellstrom struct vmw_dma_buffer *byte_code, 100c74c162fSThomas Hellstrom void (*res_free) (struct vmw_resource *res)) 101c74c162fSThomas Hellstrom { 102c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 103c74c162fSThomas Hellstrom int ret; 104c74c162fSThomas Hellstrom 105c74c162fSThomas Hellstrom ret = vmw_resource_init(dev_priv, res, true, 106c74c162fSThomas Hellstrom res_free, &vmw_gb_shader_func); 107c74c162fSThomas Hellstrom 108c74c162fSThomas Hellstrom 109c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 110c74c162fSThomas Hellstrom if (res_free) 111c74c162fSThomas Hellstrom res_free(res); 112c74c162fSThomas Hellstrom else 113c74c162fSThomas Hellstrom kfree(res); 114c74c162fSThomas Hellstrom return ret; 115c74c162fSThomas Hellstrom } 116c74c162fSThomas Hellstrom 117c74c162fSThomas Hellstrom res->backup_size = size; 118c74c162fSThomas Hellstrom if (byte_code) { 119c74c162fSThomas Hellstrom res->backup = vmw_dmabuf_reference(byte_code); 120c74c162fSThomas Hellstrom res->backup_offset = offset; 121c74c162fSThomas Hellstrom } 122c74c162fSThomas Hellstrom shader->size = size; 123c74c162fSThomas Hellstrom shader->type = type; 124c74c162fSThomas Hellstrom 125c74c162fSThomas Hellstrom vmw_resource_activate(res, vmw_hw_shader_destroy); 126c74c162fSThomas Hellstrom return 0; 127c74c162fSThomas Hellstrom } 128c74c162fSThomas Hellstrom 129c74c162fSThomas Hellstrom static int vmw_gb_shader_create(struct vmw_resource *res) 130c74c162fSThomas Hellstrom { 131c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 132c74c162fSThomas Hellstrom struct vmw_shader *shader = vmw_res_to_shader(res); 133c74c162fSThomas Hellstrom int ret; 134c74c162fSThomas Hellstrom struct { 135c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 136c74c162fSThomas Hellstrom SVGA3dCmdDefineGBShader body; 137c74c162fSThomas Hellstrom } *cmd; 138c74c162fSThomas Hellstrom 139c74c162fSThomas Hellstrom if (likely(res->id != -1)) 140c74c162fSThomas Hellstrom return 0; 141c74c162fSThomas Hellstrom 142c74c162fSThomas Hellstrom ret = vmw_resource_alloc_id(res); 143c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 144c74c162fSThomas Hellstrom DRM_ERROR("Failed to allocate a shader id.\n"); 145c74c162fSThomas Hellstrom goto out_no_id; 146c74c162fSThomas Hellstrom } 147c74c162fSThomas Hellstrom 148c74c162fSThomas Hellstrom if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) { 149c74c162fSThomas Hellstrom ret = -EBUSY; 150c74c162fSThomas Hellstrom goto out_no_fifo; 151c74c162fSThomas Hellstrom } 152c74c162fSThomas Hellstrom 153c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 154c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 155c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 156c74c162fSThomas Hellstrom "creation.\n"); 157c74c162fSThomas Hellstrom ret = -ENOMEM; 158c74c162fSThomas Hellstrom goto out_no_fifo; 159c74c162fSThomas Hellstrom } 160c74c162fSThomas Hellstrom 161c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER; 162c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 163c74c162fSThomas Hellstrom cmd->body.shid = res->id; 164c74c162fSThomas Hellstrom cmd->body.type = shader->type; 165c74c162fSThomas Hellstrom cmd->body.sizeInBytes = shader->size; 166c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 167c74c162fSThomas Hellstrom (void) vmw_3d_resource_inc(dev_priv, false); 168c74c162fSThomas Hellstrom 169c74c162fSThomas Hellstrom return 0; 170c74c162fSThomas Hellstrom 171c74c162fSThomas Hellstrom out_no_fifo: 172c74c162fSThomas Hellstrom vmw_resource_release_id(res); 173c74c162fSThomas Hellstrom out_no_id: 174c74c162fSThomas Hellstrom return ret; 175c74c162fSThomas Hellstrom } 176c74c162fSThomas Hellstrom 177c74c162fSThomas Hellstrom static int vmw_gb_shader_bind(struct vmw_resource *res, 178c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 179c74c162fSThomas Hellstrom { 180c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 181c74c162fSThomas Hellstrom struct { 182c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 183c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 184c74c162fSThomas Hellstrom } *cmd; 185c74c162fSThomas Hellstrom struct ttm_buffer_object *bo = val_buf->bo; 186c74c162fSThomas Hellstrom 187c74c162fSThomas Hellstrom BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 188c74c162fSThomas Hellstrom 189c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 190c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 191c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 192c74c162fSThomas Hellstrom "binding.\n"); 193c74c162fSThomas Hellstrom return -ENOMEM; 194c74c162fSThomas Hellstrom } 195c74c162fSThomas Hellstrom 196c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 197c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 198c74c162fSThomas Hellstrom cmd->body.shid = res->id; 199c74c162fSThomas Hellstrom cmd->body.mobid = bo->mem.start; 200c74c162fSThomas Hellstrom cmd->body.offsetInBytes = 0; 201c74c162fSThomas Hellstrom res->backup_dirty = false; 202c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 203c74c162fSThomas Hellstrom 204c74c162fSThomas Hellstrom return 0; 205c74c162fSThomas Hellstrom } 206c74c162fSThomas Hellstrom 207c74c162fSThomas Hellstrom static int vmw_gb_shader_unbind(struct vmw_resource *res, 208c74c162fSThomas Hellstrom bool readback, 209c74c162fSThomas Hellstrom struct ttm_validate_buffer *val_buf) 210c74c162fSThomas Hellstrom { 211c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 212c74c162fSThomas Hellstrom struct { 213c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 214c74c162fSThomas Hellstrom SVGA3dCmdBindGBShader body; 215c74c162fSThomas Hellstrom } *cmd; 216c74c162fSThomas Hellstrom struct vmw_fence_obj *fence; 217c74c162fSThomas Hellstrom 218c74c162fSThomas Hellstrom BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB); 219c74c162fSThomas Hellstrom 220c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 221c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 222c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 223c74c162fSThomas Hellstrom "unbinding.\n"); 224c74c162fSThomas Hellstrom return -ENOMEM; 225c74c162fSThomas Hellstrom } 226c74c162fSThomas Hellstrom 227c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER; 228c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 229c74c162fSThomas Hellstrom cmd->body.shid = res->id; 230c74c162fSThomas Hellstrom cmd->body.mobid = SVGA3D_INVALID_ID; 231c74c162fSThomas Hellstrom cmd->body.offsetInBytes = 0; 232c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 233c74c162fSThomas Hellstrom 234c74c162fSThomas Hellstrom /* 235c74c162fSThomas Hellstrom * Create a fence object and fence the backup buffer. 236c74c162fSThomas Hellstrom */ 237c74c162fSThomas Hellstrom 238c74c162fSThomas Hellstrom (void) vmw_execbuf_fence_commands(NULL, dev_priv, 239c74c162fSThomas Hellstrom &fence, NULL); 240c74c162fSThomas Hellstrom 241c74c162fSThomas Hellstrom vmw_fence_single_bo(val_buf->bo, fence); 242c74c162fSThomas Hellstrom 243c74c162fSThomas Hellstrom if (likely(fence != NULL)) 244c74c162fSThomas Hellstrom vmw_fence_obj_unreference(&fence); 245c74c162fSThomas Hellstrom 246c74c162fSThomas Hellstrom return 0; 247c74c162fSThomas Hellstrom } 248c74c162fSThomas Hellstrom 249c74c162fSThomas Hellstrom static int vmw_gb_shader_destroy(struct vmw_resource *res) 250c74c162fSThomas Hellstrom { 251c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 252c74c162fSThomas Hellstrom struct { 253c74c162fSThomas Hellstrom SVGA3dCmdHeader header; 254c74c162fSThomas Hellstrom SVGA3dCmdDestroyGBShader body; 255c74c162fSThomas Hellstrom } *cmd; 256c74c162fSThomas Hellstrom 257c74c162fSThomas Hellstrom if (likely(res->id == -1)) 258c74c162fSThomas Hellstrom return 0; 259c74c162fSThomas Hellstrom 260173fb7d4SThomas Hellstrom mutex_lock(&dev_priv->binding_mutex); 261173fb7d4SThomas Hellstrom vmw_context_binding_res_list_kill(&res->binding_head); 262173fb7d4SThomas Hellstrom 263c74c162fSThomas Hellstrom cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); 264c74c162fSThomas Hellstrom if (unlikely(cmd == NULL)) { 265c74c162fSThomas Hellstrom DRM_ERROR("Failed reserving FIFO space for shader " 266c74c162fSThomas Hellstrom "destruction.\n"); 2673e894a62SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 268c74c162fSThomas Hellstrom return -ENOMEM; 269c74c162fSThomas Hellstrom } 270c74c162fSThomas Hellstrom 271c74c162fSThomas Hellstrom cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER; 272c74c162fSThomas Hellstrom cmd->header.size = sizeof(cmd->body); 273c74c162fSThomas Hellstrom cmd->body.shid = res->id; 274c74c162fSThomas Hellstrom vmw_fifo_commit(dev_priv, sizeof(*cmd)); 275173fb7d4SThomas Hellstrom mutex_unlock(&dev_priv->binding_mutex); 276c74c162fSThomas Hellstrom vmw_resource_release_id(res); 277c74c162fSThomas Hellstrom vmw_3d_resource_dec(dev_priv, false); 278c74c162fSThomas Hellstrom 279c74c162fSThomas Hellstrom return 0; 280c74c162fSThomas Hellstrom } 281c74c162fSThomas Hellstrom 282c74c162fSThomas Hellstrom /** 283c74c162fSThomas Hellstrom * User-space shader management: 284c74c162fSThomas Hellstrom */ 285c74c162fSThomas Hellstrom 286c74c162fSThomas Hellstrom static struct vmw_resource * 287c74c162fSThomas Hellstrom vmw_user_shader_base_to_res(struct ttm_base_object *base) 288c74c162fSThomas Hellstrom { 289c74c162fSThomas Hellstrom return &(container_of(base, struct vmw_user_shader, base)-> 290c74c162fSThomas Hellstrom shader.res); 291c74c162fSThomas Hellstrom } 292c74c162fSThomas Hellstrom 293c74c162fSThomas Hellstrom static void vmw_user_shader_free(struct vmw_resource *res) 294c74c162fSThomas Hellstrom { 295c74c162fSThomas Hellstrom struct vmw_user_shader *ushader = 296c74c162fSThomas Hellstrom container_of(res, struct vmw_user_shader, shader.res); 297c74c162fSThomas Hellstrom struct vmw_private *dev_priv = res->dev_priv; 298c74c162fSThomas Hellstrom 299c74c162fSThomas Hellstrom ttm_base_object_kfree(ushader, base); 300c74c162fSThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 301c74c162fSThomas Hellstrom vmw_user_shader_size); 302c74c162fSThomas Hellstrom } 303c74c162fSThomas Hellstrom 304c74c162fSThomas Hellstrom /** 305c74c162fSThomas Hellstrom * This function is called when user space has no more references on the 306c74c162fSThomas Hellstrom * base object. It releases the base-object's reference on the resource object. 307c74c162fSThomas Hellstrom */ 308c74c162fSThomas Hellstrom 309c74c162fSThomas Hellstrom static void vmw_user_shader_base_release(struct ttm_base_object **p_base) 310c74c162fSThomas Hellstrom { 311c74c162fSThomas Hellstrom struct ttm_base_object *base = *p_base; 312c74c162fSThomas Hellstrom struct vmw_resource *res = vmw_user_shader_base_to_res(base); 313c74c162fSThomas Hellstrom 314c74c162fSThomas Hellstrom *p_base = NULL; 315c74c162fSThomas Hellstrom vmw_resource_unreference(&res); 316c74c162fSThomas Hellstrom } 317c74c162fSThomas Hellstrom 318c74c162fSThomas Hellstrom int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, 319c74c162fSThomas Hellstrom struct drm_file *file_priv) 320c74c162fSThomas Hellstrom { 321c74c162fSThomas Hellstrom struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; 322c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 323c74c162fSThomas Hellstrom 324c74c162fSThomas Hellstrom return ttm_ref_object_base_unref(tfile, arg->handle, 325c74c162fSThomas Hellstrom TTM_REF_USAGE); 326c74c162fSThomas Hellstrom } 327c74c162fSThomas Hellstrom 328c74c162fSThomas Hellstrom int vmw_shader_define_ioctl(struct drm_device *dev, void *data, 329c74c162fSThomas Hellstrom struct drm_file *file_priv) 330c74c162fSThomas Hellstrom { 331c74c162fSThomas Hellstrom struct vmw_private *dev_priv = vmw_priv(dev); 332c74c162fSThomas Hellstrom struct vmw_user_shader *ushader; 333c74c162fSThomas Hellstrom struct vmw_resource *res; 334c74c162fSThomas Hellstrom struct vmw_resource *tmp; 335c74c162fSThomas Hellstrom struct drm_vmw_shader_create_arg *arg = 336c74c162fSThomas Hellstrom (struct drm_vmw_shader_create_arg *)data; 337c74c162fSThomas Hellstrom struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 338c74c162fSThomas Hellstrom struct vmw_master *vmaster = vmw_master(file_priv->master); 339c74c162fSThomas Hellstrom struct vmw_dma_buffer *buffer = NULL; 340c74c162fSThomas Hellstrom SVGA3dShaderType shader_type; 341c74c162fSThomas Hellstrom int ret; 342c74c162fSThomas Hellstrom 343c74c162fSThomas Hellstrom if (arg->buffer_handle != SVGA3D_INVALID_ID) { 344c74c162fSThomas Hellstrom ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle, 345c74c162fSThomas Hellstrom &buffer); 346c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 347c74c162fSThomas Hellstrom DRM_ERROR("Could not find buffer for shader " 348c74c162fSThomas Hellstrom "creation.\n"); 349c74c162fSThomas Hellstrom return ret; 350c74c162fSThomas Hellstrom } 351c74c162fSThomas Hellstrom 352c74c162fSThomas Hellstrom if ((u64)buffer->base.num_pages * PAGE_SIZE < 353c74c162fSThomas Hellstrom (u64)arg->size + (u64)arg->offset) { 354c74c162fSThomas Hellstrom DRM_ERROR("Illegal buffer- or shader size.\n"); 355c74c162fSThomas Hellstrom ret = -EINVAL; 356c74c162fSThomas Hellstrom goto out_bad_arg; 357c74c162fSThomas Hellstrom } 358c74c162fSThomas Hellstrom } 359c74c162fSThomas Hellstrom 360c74c162fSThomas Hellstrom switch (arg->shader_type) { 361c74c162fSThomas Hellstrom case drm_vmw_shader_type_vs: 362c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_VS; 363c74c162fSThomas Hellstrom break; 364c74c162fSThomas Hellstrom case drm_vmw_shader_type_ps: 365c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_PS; 366c74c162fSThomas Hellstrom break; 367c74c162fSThomas Hellstrom case drm_vmw_shader_type_gs: 368c74c162fSThomas Hellstrom shader_type = SVGA3D_SHADERTYPE_GS; 369c74c162fSThomas Hellstrom break; 370c74c162fSThomas Hellstrom default: 371c74c162fSThomas Hellstrom DRM_ERROR("Illegal shader type.\n"); 372c74c162fSThomas Hellstrom ret = -EINVAL; 373c74c162fSThomas Hellstrom goto out_bad_arg; 374c74c162fSThomas Hellstrom } 375c74c162fSThomas Hellstrom 376c74c162fSThomas Hellstrom /* 377c74c162fSThomas Hellstrom * Approximate idr memory usage with 128 bytes. It will be limited 378c74c162fSThomas Hellstrom * by maximum number_of shaders anyway. 379c74c162fSThomas Hellstrom */ 380c74c162fSThomas Hellstrom 381c74c162fSThomas Hellstrom if (unlikely(vmw_user_shader_size == 0)) 382c74c162fSThomas Hellstrom vmw_user_shader_size = ttm_round_pot(sizeof(*ushader)) 383c74c162fSThomas Hellstrom + 128; 384c74c162fSThomas Hellstrom 385c74c162fSThomas Hellstrom ret = ttm_read_lock(&vmaster->lock, true); 386c74c162fSThomas Hellstrom if (unlikely(ret != 0)) 387c74c162fSThomas Hellstrom return ret; 388c74c162fSThomas Hellstrom 389c74c162fSThomas Hellstrom ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 390c74c162fSThomas Hellstrom vmw_user_shader_size, 391c74c162fSThomas Hellstrom false, true); 392c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 393c74c162fSThomas Hellstrom if (ret != -ERESTARTSYS) 394c74c162fSThomas Hellstrom DRM_ERROR("Out of graphics memory for shader" 395c74c162fSThomas Hellstrom " creation.\n"); 396c74c162fSThomas Hellstrom goto out_unlock; 397c74c162fSThomas Hellstrom } 398c74c162fSThomas Hellstrom 399c74c162fSThomas Hellstrom ushader = kzalloc(sizeof(*ushader), GFP_KERNEL); 400c74c162fSThomas Hellstrom if (unlikely(ushader == NULL)) { 401c74c162fSThomas Hellstrom ttm_mem_global_free(vmw_mem_glob(dev_priv), 402c74c162fSThomas Hellstrom vmw_user_shader_size); 403c74c162fSThomas Hellstrom ret = -ENOMEM; 404c74c162fSThomas Hellstrom goto out_unlock; 405c74c162fSThomas Hellstrom } 406c74c162fSThomas Hellstrom 407c74c162fSThomas Hellstrom res = &ushader->shader.res; 408c74c162fSThomas Hellstrom ushader->base.shareable = false; 409c74c162fSThomas Hellstrom ushader->base.tfile = NULL; 410c74c162fSThomas Hellstrom 411c74c162fSThomas Hellstrom /* 412c74c162fSThomas Hellstrom * From here on, the destructor takes over resource freeing. 413c74c162fSThomas Hellstrom */ 414c74c162fSThomas Hellstrom 415c74c162fSThomas Hellstrom ret = vmw_gb_shader_init(dev_priv, res, arg->size, 416c74c162fSThomas Hellstrom arg->offset, shader_type, buffer, 417c74c162fSThomas Hellstrom vmw_user_shader_free); 418c74c162fSThomas Hellstrom if (unlikely(ret != 0)) 419c74c162fSThomas Hellstrom goto out_unlock; 420c74c162fSThomas Hellstrom 421c74c162fSThomas Hellstrom tmp = vmw_resource_reference(res); 422c74c162fSThomas Hellstrom ret = ttm_base_object_init(tfile, &ushader->base, false, 423c74c162fSThomas Hellstrom VMW_RES_SHADER, 424c74c162fSThomas Hellstrom &vmw_user_shader_base_release, NULL); 425c74c162fSThomas Hellstrom 426c74c162fSThomas Hellstrom if (unlikely(ret != 0)) { 427c74c162fSThomas Hellstrom vmw_resource_unreference(&tmp); 428c74c162fSThomas Hellstrom goto out_err; 429c74c162fSThomas Hellstrom } 430c74c162fSThomas Hellstrom 431c74c162fSThomas Hellstrom arg->shader_handle = ushader->base.hash.key; 432c74c162fSThomas Hellstrom out_err: 433c74c162fSThomas Hellstrom vmw_resource_unreference(&res); 434c74c162fSThomas Hellstrom out_unlock: 435c74c162fSThomas Hellstrom ttm_read_unlock(&vmaster->lock); 436c74c162fSThomas Hellstrom out_bad_arg: 437c74c162fSThomas Hellstrom vmw_dmabuf_unreference(&buffer); 438c74c162fSThomas Hellstrom 439c74c162fSThomas Hellstrom return ret; 440c74c162fSThomas Hellstrom 441c74c162fSThomas Hellstrom } 442