Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR MIT
0002 /**************************************************************************
0003  *
0004  * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
0005  *
0006  * Permission is hereby granted, free of charge, to any person obtaining a
0007  * copy of this software and associated documentation files (the
0008  * "Software"), to deal in the Software without restriction, including
0009  * without limitation the rights to use, copy, modify, merge, publish,
0010  * distribute, sub license, and/or sell copies of the Software, and to
0011  * permit persons to whom the Software is furnished to do so, subject to
0012  * the following conditions:
0013  *
0014  * The above copyright notice and this permission notice (including the
0015  * next paragraph) shall be included in all copies or substantial portions
0016  * of the Software.
0017  *
0018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0019  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0020  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
0021  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
0022  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
0023  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
0024  * USE OR OTHER DEALINGS IN THE SOFTWARE.
0025  *
0026  **************************************************************************/
0027 
0028 #include <drm/ttm/ttm_placement.h>
0029 
0030 #include "vmwgfx_drv.h"
0031 #include "vmwgfx_resource_priv.h"
0032 #include "vmwgfx_binding.h"
0033 
0034 struct vmw_shader {
0035     struct vmw_resource res;
0036     SVGA3dShaderType type;
0037     uint32_t size;
0038     uint8_t num_input_sig;
0039     uint8_t num_output_sig;
0040 };
0041 
0042 struct vmw_user_shader {
0043     struct ttm_base_object base;
0044     struct vmw_shader shader;
0045 };
0046 
0047 struct vmw_dx_shader {
0048     struct vmw_resource res;
0049     struct vmw_resource *ctx;
0050     struct vmw_resource *cotable;
0051     u32 id;
0052     bool committed;
0053     struct list_head cotable_head;
0054 };
0055 
0056 static void vmw_user_shader_free(struct vmw_resource *res);
0057 static struct vmw_resource *
0058 vmw_user_shader_base_to_res(struct ttm_base_object *base);
0059 
0060 static int vmw_gb_shader_create(struct vmw_resource *res);
0061 static int vmw_gb_shader_bind(struct vmw_resource *res,
0062                    struct ttm_validate_buffer *val_buf);
0063 static int vmw_gb_shader_unbind(struct vmw_resource *res,
0064                  bool readback,
0065                  struct ttm_validate_buffer *val_buf);
0066 static int vmw_gb_shader_destroy(struct vmw_resource *res);
0067 
0068 static int vmw_dx_shader_create(struct vmw_resource *res);
0069 static int vmw_dx_shader_bind(struct vmw_resource *res,
0070                    struct ttm_validate_buffer *val_buf);
0071 static int vmw_dx_shader_unbind(struct vmw_resource *res,
0072                  bool readback,
0073                  struct ttm_validate_buffer *val_buf);
0074 static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
0075                     enum vmw_cmdbuf_res_state state);
0076 static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
0077 static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
0078 
0079 static const struct vmw_user_resource_conv user_shader_conv = {
0080     .object_type = VMW_RES_SHADER,
0081     .base_obj_to_res = vmw_user_shader_base_to_res,
0082     .res_free = vmw_user_shader_free
0083 };
0084 
0085 const struct vmw_user_resource_conv *user_shader_converter =
0086     &user_shader_conv;
0087 
0088 
0089 static const struct vmw_res_func vmw_gb_shader_func = {
0090     .res_type = vmw_res_shader,
0091     .needs_backup = true,
0092     .may_evict = true,
0093     .prio = 3,
0094     .dirty_prio = 3,
0095     .type_name = "guest backed shaders",
0096     .backup_placement = &vmw_mob_placement,
0097     .create = vmw_gb_shader_create,
0098     .destroy = vmw_gb_shader_destroy,
0099     .bind = vmw_gb_shader_bind,
0100     .unbind = vmw_gb_shader_unbind
0101 };
0102 
0103 static const struct vmw_res_func vmw_dx_shader_func = {
0104     .res_type = vmw_res_shader,
0105     .needs_backup = true,
0106     .may_evict = true,
0107     .prio = 3,
0108     .dirty_prio = 3,
0109     .type_name = "dx shaders",
0110     .backup_placement = &vmw_mob_placement,
0111     .create = vmw_dx_shader_create,
0112     /*
0113      * The destroy callback is only called with a committed resource on
0114      * context destroy, in which case we destroy the cotable anyway,
0115      * so there's no need to destroy DX shaders separately.
0116      */
0117     .destroy = NULL,
0118     .bind = vmw_dx_shader_bind,
0119     .unbind = vmw_dx_shader_unbind,
0120     .commit_notify = vmw_dx_shader_commit_notify,
0121 };
0122 
0123 /*
0124  * Shader management:
0125  */
0126 
0127 static inline struct vmw_shader *
0128 vmw_res_to_shader(struct vmw_resource *res)
0129 {
0130     return container_of(res, struct vmw_shader, res);
0131 }
0132 
0133 /**
0134  * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
0135  * struct vmw_dx_shader
0136  *
0137  * @res: Pointer to the struct vmw_resource.
0138  */
0139 static inline struct vmw_dx_shader *
0140 vmw_res_to_dx_shader(struct vmw_resource *res)
0141 {
0142     return container_of(res, struct vmw_dx_shader, res);
0143 }
0144 
0145 static void vmw_hw_shader_destroy(struct vmw_resource *res)
0146 {
0147     if (likely(res->func->destroy))
0148         (void) res->func->destroy(res);
0149     else
0150         res->id = -1;
0151 }
0152 
0153 
0154 static int vmw_gb_shader_init(struct vmw_private *dev_priv,
0155                   struct vmw_resource *res,
0156                   uint32_t size,
0157                   uint64_t offset,
0158                   SVGA3dShaderType type,
0159                   uint8_t num_input_sig,
0160                   uint8_t num_output_sig,
0161                   struct vmw_buffer_object *byte_code,
0162                   void (*res_free) (struct vmw_resource *res))
0163 {
0164     struct vmw_shader *shader = vmw_res_to_shader(res);
0165     int ret;
0166 
0167     ret = vmw_resource_init(dev_priv, res, true, res_free,
0168                 &vmw_gb_shader_func);
0169 
0170     if (unlikely(ret != 0)) {
0171         if (res_free)
0172             res_free(res);
0173         else
0174             kfree(res);
0175         return ret;
0176     }
0177 
0178     res->backup_size = size;
0179     if (byte_code) {
0180         res->backup = vmw_bo_reference(byte_code);
0181         res->backup_offset = offset;
0182     }
0183     shader->size = size;
0184     shader->type = type;
0185     shader->num_input_sig = num_input_sig;
0186     shader->num_output_sig = num_output_sig;
0187 
0188     res->hw_destroy = vmw_hw_shader_destroy;
0189     return 0;
0190 }
0191 
0192 /*
0193  * GB shader code:
0194  */
0195 
0196 static int vmw_gb_shader_create(struct vmw_resource *res)
0197 {
0198     struct vmw_private *dev_priv = res->dev_priv;
0199     struct vmw_shader *shader = vmw_res_to_shader(res);
0200     int ret;
0201     struct {
0202         SVGA3dCmdHeader header;
0203         SVGA3dCmdDefineGBShader body;
0204     } *cmd;
0205 
0206     if (likely(res->id != -1))
0207         return 0;
0208 
0209     ret = vmw_resource_alloc_id(res);
0210     if (unlikely(ret != 0)) {
0211         DRM_ERROR("Failed to allocate a shader id.\n");
0212         goto out_no_id;
0213     }
0214 
0215     if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
0216         ret = -EBUSY;
0217         goto out_no_fifo;
0218     }
0219 
0220     cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
0221     if (unlikely(cmd == NULL)) {
0222         ret = -ENOMEM;
0223         goto out_no_fifo;
0224     }
0225 
0226     cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
0227     cmd->header.size = sizeof(cmd->body);
0228     cmd->body.shid = res->id;
0229     cmd->body.type = shader->type;
0230     cmd->body.sizeInBytes = shader->size;
0231     vmw_cmd_commit(dev_priv, sizeof(*cmd));
0232     vmw_fifo_resource_inc(dev_priv);
0233 
0234     return 0;
0235 
0236 out_no_fifo:
0237     vmw_resource_release_id(res);
0238 out_no_id:
0239     return ret;
0240 }
0241 
0242 static int vmw_gb_shader_bind(struct vmw_resource *res,
0243                   struct ttm_validate_buffer *val_buf)
0244 {
0245     struct vmw_private *dev_priv = res->dev_priv;
0246     struct {
0247         SVGA3dCmdHeader header;
0248         SVGA3dCmdBindGBShader body;
0249     } *cmd;
0250     struct ttm_buffer_object *bo = val_buf->bo;
0251 
0252     BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
0253 
0254     cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
0255     if (unlikely(cmd == NULL))
0256         return -ENOMEM;
0257 
0258     cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
0259     cmd->header.size = sizeof(cmd->body);
0260     cmd->body.shid = res->id;
0261     cmd->body.mobid = bo->resource->start;
0262     cmd->body.offsetInBytes = res->backup_offset;
0263     res->backup_dirty = false;
0264     vmw_cmd_commit(dev_priv, sizeof(*cmd));
0265 
0266     return 0;
0267 }
0268 
0269 static int vmw_gb_shader_unbind(struct vmw_resource *res,
0270                 bool readback,
0271                 struct ttm_validate_buffer *val_buf)
0272 {
0273     struct vmw_private *dev_priv = res->dev_priv;
0274     struct {
0275         SVGA3dCmdHeader header;
0276         SVGA3dCmdBindGBShader body;
0277     } *cmd;
0278     struct vmw_fence_obj *fence;
0279 
0280     BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB);
0281 
0282     cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
0283     if (unlikely(cmd == NULL))
0284         return -ENOMEM;
0285 
0286     cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
0287     cmd->header.size = sizeof(cmd->body);
0288     cmd->body.shid = res->id;
0289     cmd->body.mobid = SVGA3D_INVALID_ID;
0290     cmd->body.offsetInBytes = 0;
0291     vmw_cmd_commit(dev_priv, sizeof(*cmd));
0292 
0293     /*
0294      * Create a fence object and fence the backup buffer.
0295      */
0296 
0297     (void) vmw_execbuf_fence_commands(NULL, dev_priv,
0298                       &fence, NULL);
0299 
0300     vmw_bo_fence_single(val_buf->bo, fence);
0301 
0302     if (likely(fence != NULL))
0303         vmw_fence_obj_unreference(&fence);
0304 
0305     return 0;
0306 }
0307 
0308 static int vmw_gb_shader_destroy(struct vmw_resource *res)
0309 {
0310     struct vmw_private *dev_priv = res->dev_priv;
0311     struct {
0312         SVGA3dCmdHeader header;
0313         SVGA3dCmdDestroyGBShader body;
0314     } *cmd;
0315 
0316     if (likely(res->id == -1))
0317         return 0;
0318 
0319     mutex_lock(&dev_priv->binding_mutex);
0320     vmw_binding_res_list_scrub(&res->binding_head);
0321 
0322     cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
0323     if (unlikely(cmd == NULL)) {
0324         mutex_unlock(&dev_priv->binding_mutex);
0325         return -ENOMEM;
0326     }
0327 
0328     cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
0329     cmd->header.size = sizeof(cmd->body);
0330     cmd->body.shid = res->id;
0331     vmw_cmd_commit(dev_priv, sizeof(*cmd));
0332     mutex_unlock(&dev_priv->binding_mutex);
0333     vmw_resource_release_id(res);
0334     vmw_fifo_resource_dec(dev_priv);
0335 
0336     return 0;
0337 }
0338 
0339 /*
0340  * DX shader code:
0341  */
0342 
0343 /**
0344  * vmw_dx_shader_commit_notify - Notify that a shader operation has been
0345  * committed to hardware from a user-supplied command stream.
0346  *
0347  * @res: Pointer to the shader resource.
0348  * @state: Indicating whether a creation or removal has been committed.
0349  *
0350  */
0351 static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
0352                     enum vmw_cmdbuf_res_state state)
0353 {
0354     struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
0355     struct vmw_private *dev_priv = res->dev_priv;
0356 
0357     if (state == VMW_CMDBUF_RES_ADD) {
0358         mutex_lock(&dev_priv->binding_mutex);
0359         vmw_cotable_add_resource(shader->cotable,
0360                      &shader->cotable_head);
0361         shader->committed = true;
0362         res->id = shader->id;
0363         mutex_unlock(&dev_priv->binding_mutex);
0364     } else {
0365         mutex_lock(&dev_priv->binding_mutex);
0366         list_del_init(&shader->cotable_head);
0367         shader->committed = false;
0368         res->id = -1;
0369         mutex_unlock(&dev_priv->binding_mutex);
0370     }
0371 }
0372 
0373 /**
0374  * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
0375  *
0376  * @res: The shader resource
0377  *
0378  * This function reverts a scrub operation.
0379  */
0380 static int vmw_dx_shader_unscrub(struct vmw_resource *res)
0381 {
0382     struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
0383     struct vmw_private *dev_priv = res->dev_priv;
0384     struct {
0385         SVGA3dCmdHeader header;
0386         SVGA3dCmdDXBindShader body;
0387     } *cmd;
0388 
0389     if (!list_empty(&shader->cotable_head) || !shader->committed)
0390         return 0;
0391 
0392     cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id);
0393     if (unlikely(cmd == NULL))
0394         return -ENOMEM;
0395 
0396     cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
0397     cmd->header.size = sizeof(cmd->body);
0398     cmd->body.cid = shader->ctx->id;
0399     cmd->body.shid = shader->id;
0400     cmd->body.mobid = res->backup->base.resource->start;
0401     cmd->body.offsetInBytes = res->backup_offset;
0402     vmw_cmd_commit(dev_priv, sizeof(*cmd));
0403 
0404     vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
0405 
0406     return 0;
0407 }
0408 
0409 /**
0410  * vmw_dx_shader_create - The DX shader create callback
0411  *
0412  * @res: The DX shader resource
0413  *
0414  * The create callback is called as part of resource validation and
0415  * makes sure that we unscrub the shader if it's previously been scrubbed.
0416  */
0417 static int vmw_dx_shader_create(struct vmw_resource *res)
0418 {
0419     struct vmw_private *dev_priv = res->dev_priv;
0420     struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
0421     int ret = 0;
0422 
0423     WARN_ON_ONCE(!shader->committed);
0424 
0425     if (vmw_resource_mob_attached(res)) {
0426         mutex_lock(&dev_priv->binding_mutex);
0427         ret = vmw_dx_shader_unscrub(res);
0428         mutex_unlock(&dev_priv->binding_mutex);
0429     }
0430 
0431     res->id = shader->id;
0432     return ret;
0433 }
0434 
0435 /**
0436  * vmw_dx_shader_bind - The DX shader bind callback
0437  *
0438  * @res: The DX shader resource
0439  * @val_buf: Pointer to the validate buffer.
0440  *
0441  */
0442 static int vmw_dx_shader_bind(struct vmw_resource *res,
0443                   struct ttm_validate_buffer *val_buf)
0444 {
0445     struct vmw_private *dev_priv = res->dev_priv;
0446     struct ttm_buffer_object *bo = val_buf->bo;
0447 
0448     BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
0449     mutex_lock(&dev_priv->binding_mutex);
0450     vmw_dx_shader_unscrub(res);
0451     mutex_unlock(&dev_priv->binding_mutex);
0452 
0453     return 0;
0454 }
0455 
0456 /**
0457  * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
0458  *
0459  * @res: The shader resource
0460  *
0461  * This function unbinds a MOB from the DX shader without requiring the
0462  * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
0463  * However, once the driver eventually decides to unbind the MOB, it doesn't
0464  * need to access the context.
0465  */
0466 static int vmw_dx_shader_scrub(struct vmw_resource *res)
0467 {
0468     struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
0469     struct vmw_private *dev_priv = res->dev_priv;
0470     struct {
0471         SVGA3dCmdHeader header;
0472         SVGA3dCmdDXBindShader body;
0473     } *cmd;
0474 
0475     if (list_empty(&shader->cotable_head))
0476         return 0;
0477 
0478     WARN_ON_ONCE(!shader->committed);
0479     cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
0480     if (unlikely(cmd == NULL))
0481         return -ENOMEM;
0482 
0483     cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
0484     cmd->header.size = sizeof(cmd->body);
0485     cmd->body.cid = shader->ctx->id;
0486     cmd->body.shid = res->id;
0487     cmd->body.mobid = SVGA3D_INVALID_ID;
0488     cmd->body.offsetInBytes = 0;
0489     vmw_cmd_commit(dev_priv, sizeof(*cmd));
0490     res->id = -1;
0491     list_del_init(&shader->cotable_head);
0492 
0493     return 0;
0494 }
0495 
0496 /**
0497  * vmw_dx_shader_unbind - The dx shader unbind callback.
0498  *
0499  * @res: The shader resource
0500  * @readback: Whether this is a readback unbind. Currently unused.
0501  * @val_buf: MOB buffer information.
0502  */
0503 static int vmw_dx_shader_unbind(struct vmw_resource *res,
0504                 bool readback,
0505                 struct ttm_validate_buffer *val_buf)
0506 {
0507     struct vmw_private *dev_priv = res->dev_priv;
0508     struct vmw_fence_obj *fence;
0509     int ret;
0510 
0511     BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB);
0512 
0513     mutex_lock(&dev_priv->binding_mutex);
0514     ret = vmw_dx_shader_scrub(res);
0515     mutex_unlock(&dev_priv->binding_mutex);
0516 
0517     if (ret)
0518         return ret;
0519 
0520     (void) vmw_execbuf_fence_commands(NULL, dev_priv,
0521                       &fence, NULL);
0522     vmw_bo_fence_single(val_buf->bo, fence);
0523 
0524     if (likely(fence != NULL))
0525         vmw_fence_obj_unreference(&fence);
0526 
0527     return 0;
0528 }
0529 
0530 /**
0531  * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
0532  * DX shaders.
0533  *
0534  * @dev_priv: Pointer to device private structure.
0535  * @list: The list of cotable resources.
0536  * @readback: Whether the call was part of a readback unbind.
0537  *
0538  * Scrubs all shader MOBs so that any subsequent shader unbind or shader
0539  * destroy operation won't need to swap in the context.
0540  */
0541 void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
0542                       struct list_head *list,
0543                       bool readback)
0544 {
0545     struct vmw_dx_shader *entry, *next;
0546 
0547     lockdep_assert_held_once(&dev_priv->binding_mutex);
0548 
0549     list_for_each_entry_safe(entry, next, list, cotable_head) {
0550         WARN_ON(vmw_dx_shader_scrub(&entry->res));
0551         if (!readback)
0552             entry->committed = false;
0553     }
0554 }
0555 
0556 /**
0557  * vmw_dx_shader_res_free - The DX shader free callback
0558  *
0559  * @res: The shader resource
0560  *
0561  * Frees the DX shader resource.
0562  */
0563 static void vmw_dx_shader_res_free(struct vmw_resource *res)
0564 {
0565     struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
0566 
0567     vmw_resource_unreference(&shader->cotable);
0568     kfree(shader);
0569 }
0570 
0571 /**
0572  * vmw_dx_shader_add - Add a shader resource as a command buffer managed
0573  * resource.
0574  *
0575  * @man: The command buffer resource manager.
0576  * @ctx: Pointer to the context resource.
0577  * @user_key: The id used for this shader.
0578  * @shader_type: The shader type.
0579  * @list: The list of staged command buffer managed resources.
0580  */
0581 int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
0582               struct vmw_resource *ctx,
0583               u32 user_key,
0584               SVGA3dShaderType shader_type,
0585               struct list_head *list)
0586 {
0587     struct vmw_dx_shader *shader;
0588     struct vmw_resource *res;
0589     struct vmw_private *dev_priv = ctx->dev_priv;
0590     int ret;
0591 
0592     if (!vmw_shader_id_ok(user_key, shader_type))
0593         return -EINVAL;
0594 
0595     shader = kmalloc(sizeof(*shader), GFP_KERNEL);
0596     if (!shader) {
0597         return -ENOMEM;
0598     }
0599 
0600     res = &shader->res;
0601     shader->ctx = ctx;
0602     shader->cotable = vmw_resource_reference
0603         (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
0604     shader->id = user_key;
0605     shader->committed = false;
0606     INIT_LIST_HEAD(&shader->cotable_head);
0607     ret = vmw_resource_init(dev_priv, res, true,
0608                 vmw_dx_shader_res_free, &vmw_dx_shader_func);
0609     if (ret)
0610         goto out_resource_init;
0611 
0612     /*
0613      * The user_key name-space is not per shader type for DX shaders,
0614      * so when hashing, use a single zero shader type.
0615      */
0616     ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
0617                  vmw_shader_key(user_key, 0),
0618                  res, list);
0619     if (ret)
0620         goto out_resource_init;
0621 
0622     res->id = shader->id;
0623     res->hw_destroy = vmw_hw_shader_destroy;
0624 
0625 out_resource_init:
0626     vmw_resource_unreference(&res);
0627 
0628     return ret;
0629 }
0630 
0631 
0632 
0633 /*
0634  * User-space shader management:
0635  */
0636 
0637 static struct vmw_resource *
0638 vmw_user_shader_base_to_res(struct ttm_base_object *base)
0639 {
0640     return &(container_of(base, struct vmw_user_shader, base)->
0641          shader.res);
0642 }
0643 
0644 static void vmw_user_shader_free(struct vmw_resource *res)
0645 {
0646     struct vmw_user_shader *ushader =
0647         container_of(res, struct vmw_user_shader, shader.res);
0648 
0649     ttm_base_object_kfree(ushader, base);
0650 }
0651 
0652 static void vmw_shader_free(struct vmw_resource *res)
0653 {
0654     struct vmw_shader *shader = vmw_res_to_shader(res);
0655 
0656     kfree(shader);
0657 }
0658 
0659 /*
0660  * This function is called when user space has no more references on the
0661  * base object. It releases the base-object's reference on the resource object.
0662  */
0663 
0664 static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
0665 {
0666     struct ttm_base_object *base = *p_base;
0667     struct vmw_resource *res = vmw_user_shader_base_to_res(base);
0668 
0669     *p_base = NULL;
0670     vmw_resource_unreference(&res);
0671 }
0672 
0673 int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
0674                   struct drm_file *file_priv)
0675 {
0676     struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
0677     struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
0678 
0679     return ttm_ref_object_base_unref(tfile, arg->handle);
0680 }
0681 
0682 static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
0683                  struct vmw_buffer_object *buffer,
0684                  size_t shader_size,
0685                  size_t offset,
0686                  SVGA3dShaderType shader_type,
0687                  uint8_t num_input_sig,
0688                  uint8_t num_output_sig,
0689                  struct ttm_object_file *tfile,
0690                  u32 *handle)
0691 {
0692     struct vmw_user_shader *ushader;
0693     struct vmw_resource *res, *tmp;
0694     int ret;
0695 
0696     ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
0697     if (unlikely(!ushader)) {
0698         ret = -ENOMEM;
0699         goto out;
0700     }
0701 
0702     res = &ushader->shader.res;
0703     ushader->base.shareable = false;
0704     ushader->base.tfile = NULL;
0705 
0706     /*
0707      * From here on, the destructor takes over resource freeing.
0708      */
0709 
0710     ret = vmw_gb_shader_init(dev_priv, res, shader_size,
0711                  offset, shader_type, num_input_sig,
0712                  num_output_sig, buffer,
0713                  vmw_user_shader_free);
0714     if (unlikely(ret != 0))
0715         goto out;
0716 
0717     tmp = vmw_resource_reference(res);
0718     ret = ttm_base_object_init(tfile, &ushader->base, false,
0719                    VMW_RES_SHADER,
0720                    &vmw_user_shader_base_release);
0721 
0722     if (unlikely(ret != 0)) {
0723         vmw_resource_unreference(&tmp);
0724         goto out_err;
0725     }
0726 
0727     if (handle)
0728         *handle = ushader->base.handle;
0729 out_err:
0730     vmw_resource_unreference(&res);
0731 out:
0732     return ret;
0733 }
0734 
0735 
0736 static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
0737                          struct vmw_buffer_object *buffer,
0738                          size_t shader_size,
0739                          size_t offset,
0740                          SVGA3dShaderType shader_type)
0741 {
0742     struct vmw_shader *shader;
0743     struct vmw_resource *res;
0744     int ret;
0745 
0746     shader = kzalloc(sizeof(*shader), GFP_KERNEL);
0747     if (unlikely(!shader)) {
0748         ret = -ENOMEM;
0749         goto out_err;
0750     }
0751 
0752     res = &shader->res;
0753 
0754     /*
0755      * From here on, the destructor takes over resource freeing.
0756      */
0757     ret = vmw_gb_shader_init(dev_priv, res, shader_size,
0758                  offset, shader_type, 0, 0, buffer,
0759                  vmw_shader_free);
0760 
0761 out_err:
0762     return ret ? ERR_PTR(ret) : res;
0763 }
0764 
0765 
0766 static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
0767                  enum drm_vmw_shader_type shader_type_drm,
0768                  u32 buffer_handle, size_t size, size_t offset,
0769                  uint8_t num_input_sig, uint8_t num_output_sig,
0770                  uint32_t *shader_handle)
0771 {
0772     struct vmw_private *dev_priv = vmw_priv(dev);
0773     struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
0774     struct vmw_buffer_object *buffer = NULL;
0775     SVGA3dShaderType shader_type;
0776     int ret;
0777 
0778     if (buffer_handle != SVGA3D_INVALID_ID) {
0779         ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);
0780         if (unlikely(ret != 0)) {
0781             VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
0782             return ret;
0783         }
0784 
0785         if ((u64)buffer->base.base.size < (u64)size + (u64)offset) {
0786             VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
0787             ret = -EINVAL;
0788             goto out_bad_arg;
0789         }
0790     }
0791 
0792     switch (shader_type_drm) {
0793     case drm_vmw_shader_type_vs:
0794         shader_type = SVGA3D_SHADERTYPE_VS;
0795         break;
0796     case drm_vmw_shader_type_ps:
0797         shader_type = SVGA3D_SHADERTYPE_PS;
0798         break;
0799     default:
0800         VMW_DEBUG_USER("Illegal shader type.\n");
0801         ret = -EINVAL;
0802         goto out_bad_arg;
0803     }
0804 
0805     ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
0806                     shader_type, num_input_sig,
0807                     num_output_sig, tfile, shader_handle);
0808 out_bad_arg:
0809     vmw_bo_unreference(&buffer);
0810     return ret;
0811 }
0812 
0813 /**
0814  * vmw_shader_id_ok - Check whether a compat shader user key and
0815  * shader type are within valid bounds.
0816  *
0817  * @user_key: User space id of the shader.
0818  * @shader_type: Shader type.
0819  *
0820  * Returns true if valid false if not.
0821  */
0822 static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
0823 {
0824     return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
0825 }
0826 
0827 /**
0828  * vmw_shader_key - Compute a hash key suitable for a compat shader.
0829  *
0830  * @user_key: User space id of the shader.
0831  * @shader_type: Shader type.
0832  *
0833  * Returns a hash key suitable for a command buffer managed resource
0834  * manager hash table.
0835  */
0836 static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
0837 {
0838     return user_key | (shader_type << 20);
0839 }
0840 
0841 /**
0842  * vmw_shader_remove - Stage a compat shader for removal.
0843  *
0844  * @man: Pointer to the compat shader manager identifying the shader namespace.
0845  * @user_key: The key that is used to identify the shader. The key is
0846  * unique to the shader type.
0847  * @shader_type: Shader type.
0848  * @list: Caller's list of staged command buffer resource actions.
0849  */
0850 int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
0851               u32 user_key, SVGA3dShaderType shader_type,
0852               struct list_head *list)
0853 {
0854     struct vmw_resource *dummy;
0855 
0856     if (!vmw_shader_id_ok(user_key, shader_type))
0857         return -EINVAL;
0858 
0859     return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
0860                      vmw_shader_key(user_key, shader_type),
0861                      list, &dummy);
0862 }
0863 
0864 /**
0865  * vmw_compat_shader_add - Create a compat shader and stage it for addition
0866  * as a command buffer managed resource.
0867  *
0868  * @dev_priv: Pointer to device private structure.
0869  * @man: Pointer to the compat shader manager identifying the shader namespace.
0870  * @user_key: The key that is used to identify the shader. The key is
0871  * unique to the shader type.
0872  * @bytecode: Pointer to the bytecode of the shader.
0873  * @shader_type: Shader type.
0874  * @size: Command size.
0875  * @list: Caller's list of staged command buffer resource actions.
0876  *
0877  */
0878 int vmw_compat_shader_add(struct vmw_private *dev_priv,
0879               struct vmw_cmdbuf_res_manager *man,
0880               u32 user_key, const void *bytecode,
0881               SVGA3dShaderType shader_type,
0882               size_t size,
0883               struct list_head *list)
0884 {
0885     struct ttm_operation_ctx ctx = { false, true };
0886     struct vmw_buffer_object *buf;
0887     struct ttm_bo_kmap_obj map;
0888     bool is_iomem;
0889     int ret;
0890     struct vmw_resource *res;
0891 
0892     if (!vmw_shader_id_ok(user_key, shader_type))
0893         return -EINVAL;
0894 
0895     ret = vmw_bo_create(dev_priv, size, &vmw_sys_placement,
0896                 true, true, vmw_bo_bo_free, &buf);
0897     if (unlikely(ret != 0))
0898         goto out;
0899 
0900     ret = ttm_bo_reserve(&buf->base, false, true, NULL);
0901     if (unlikely(ret != 0))
0902         goto no_reserve;
0903 
0904     /* Map and copy shader bytecode. */
0905     ret = ttm_bo_kmap(&buf->base, 0, PFN_UP(size), &map);
0906     if (unlikely(ret != 0)) {
0907         ttm_bo_unreserve(&buf->base);
0908         goto no_reserve;
0909     }
0910 
0911     memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
0912     WARN_ON(is_iomem);
0913 
0914     ttm_bo_kunmap(&map);
0915     ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx);
0916     WARN_ON(ret != 0);
0917     ttm_bo_unreserve(&buf->base);
0918 
0919     res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
0920     if (unlikely(ret != 0))
0921         goto no_reserve;
0922 
0923     ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
0924                  vmw_shader_key(user_key, shader_type),
0925                  res, list);
0926     vmw_resource_unreference(&res);
0927 no_reserve:
0928     vmw_bo_unreference(&buf);
0929 out:
0930     return ret;
0931 }
0932 
0933 /**
0934  * vmw_shader_lookup - Look up a compat shader
0935  *
0936  * @man: Pointer to the command buffer managed resource manager identifying
0937  * the shader namespace.
0938  * @user_key: The user space id of the shader.
0939  * @shader_type: The shader type.
0940  *
0941  * Returns a refcounted pointer to a struct vmw_resource if the shader was
0942  * found. An error pointer otherwise.
0943  */
0944 struct vmw_resource *
0945 vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
0946           u32 user_key,
0947           SVGA3dShaderType shader_type)
0948 {
0949     if (!vmw_shader_id_ok(user_key, shader_type))
0950         return ERR_PTR(-EINVAL);
0951 
0952     return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
0953                      vmw_shader_key(user_key, shader_type));
0954 }
0955 
0956 int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
0957                  struct drm_file *file_priv)
0958 {
0959     struct drm_vmw_shader_create_arg *arg =
0960         (struct drm_vmw_shader_create_arg *)data;
0961 
0962     return vmw_shader_define(dev, file_priv, arg->shader_type,
0963                  arg->buffer_handle,
0964                  arg->size, arg->offset,
0965                  0, 0,
0966                  &arg->shader_handle);
0967 }