linux/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/**************************************************************************
   3 *
   4 * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a
   7 * copy of this software and associated documentation files (the
   8 * "Software"), to deal in the Software without restriction, including
   9 * without limitation the rights to use, copy, modify, merge, publish,
  10 * distribute, sub license, and/or sell copies of the Software, and to
  11 * permit persons to whom the Software is furnished to do so, subject to
  12 * the following conditions:
  13 *
  14 * The above copyright notice and this permission notice (including the
  15 * next paragraph) shall be included in all copies or substantial portions
  16 * of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25 *
  26 **************************************************************************/
  27
  28#include <drm/ttm/ttm_placement.h>
  29
  30#include "vmwgfx_drv.h"
  31#include "vmwgfx_resource_priv.h"
  32#include "vmwgfx_binding.h"
  33
  34struct vmw_shader {
  35        struct vmw_resource res;
  36        SVGA3dShaderType type;
  37        uint32_t size;
  38        uint8_t num_input_sig;
  39        uint8_t num_output_sig;
  40};
  41
  42struct vmw_user_shader {
  43        struct ttm_base_object base;
  44        struct vmw_shader shader;
  45};
  46
  47struct vmw_dx_shader {
  48        struct vmw_resource res;
  49        struct vmw_resource *ctx;
  50        struct vmw_resource *cotable;
  51        u32 id;
  52        bool committed;
  53        struct list_head cotable_head;
  54};
  55
  56static void vmw_user_shader_free(struct vmw_resource *res);
  57static struct vmw_resource *
  58vmw_user_shader_base_to_res(struct ttm_base_object *base);
  59
  60static int vmw_gb_shader_create(struct vmw_resource *res);
  61static int vmw_gb_shader_bind(struct vmw_resource *res,
  62                               struct ttm_validate_buffer *val_buf);
  63static int vmw_gb_shader_unbind(struct vmw_resource *res,
  64                                 bool readback,
  65                                 struct ttm_validate_buffer *val_buf);
  66static int vmw_gb_shader_destroy(struct vmw_resource *res);
  67
  68static int vmw_dx_shader_create(struct vmw_resource *res);
  69static int vmw_dx_shader_bind(struct vmw_resource *res,
  70                               struct ttm_validate_buffer *val_buf);
  71static int vmw_dx_shader_unbind(struct vmw_resource *res,
  72                                 bool readback,
  73                                 struct ttm_validate_buffer *val_buf);
  74static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
  75                                        enum vmw_cmdbuf_res_state state);
  76static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type);
  77static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type);
  78
  79static const struct vmw_user_resource_conv user_shader_conv = {
  80        .object_type = VMW_RES_SHADER,
  81        .base_obj_to_res = vmw_user_shader_base_to_res,
  82        .res_free = vmw_user_shader_free
  83};
  84
  85const struct vmw_user_resource_conv *user_shader_converter =
  86        &user_shader_conv;
  87
  88
  89static const struct vmw_res_func vmw_gb_shader_func = {
  90        .res_type = vmw_res_shader,
  91        .needs_backup = true,
  92        .may_evict = true,
  93        .prio = 3,
  94        .dirty_prio = 3,
  95        .type_name = "guest backed shaders",
  96        .backup_placement = &vmw_mob_placement,
  97        .create = vmw_gb_shader_create,
  98        .destroy = vmw_gb_shader_destroy,
  99        .bind = vmw_gb_shader_bind,
 100        .unbind = vmw_gb_shader_unbind
 101};
 102
 103static const struct vmw_res_func vmw_dx_shader_func = {
 104        .res_type = vmw_res_shader,
 105        .needs_backup = true,
 106        .may_evict = true,
 107        .prio = 3,
 108        .dirty_prio = 3,
 109        .type_name = "dx shaders",
 110        .backup_placement = &vmw_mob_placement,
 111        .create = vmw_dx_shader_create,
 112        /*
 113         * The destroy callback is only called with a committed resource on
 114         * context destroy, in which case we destroy the cotable anyway,
 115         * so there's no need to destroy DX shaders separately.
 116         */
 117        .destroy = NULL,
 118        .bind = vmw_dx_shader_bind,
 119        .unbind = vmw_dx_shader_unbind,
 120        .commit_notify = vmw_dx_shader_commit_notify,
 121};
 122
 123/*
 124 * Shader management:
 125 */
 126
 127static inline struct vmw_shader *
 128vmw_res_to_shader(struct vmw_resource *res)
 129{
 130        return container_of(res, struct vmw_shader, res);
 131}
 132
 133/**
 134 * vmw_res_to_dx_shader - typecast a struct vmw_resource to a
 135 * struct vmw_dx_shader
 136 *
 137 * @res: Pointer to the struct vmw_resource.
 138 */
 139static inline struct vmw_dx_shader *
 140vmw_res_to_dx_shader(struct vmw_resource *res)
 141{
 142        return container_of(res, struct vmw_dx_shader, res);
 143}
 144
 145static void vmw_hw_shader_destroy(struct vmw_resource *res)
 146{
 147        if (likely(res->func->destroy))
 148                (void) res->func->destroy(res);
 149        else
 150                res->id = -1;
 151}
 152
 153
 154static int vmw_gb_shader_init(struct vmw_private *dev_priv,
 155                              struct vmw_resource *res,
 156                              uint32_t size,
 157                              uint64_t offset,
 158                              SVGA3dShaderType type,
 159                              uint8_t num_input_sig,
 160                              uint8_t num_output_sig,
 161                              struct vmw_buffer_object *byte_code,
 162                              void (*res_free) (struct vmw_resource *res))
 163{
 164        struct vmw_shader *shader = vmw_res_to_shader(res);
 165        int ret;
 166
 167        ret = vmw_resource_init(dev_priv, res, true, res_free,
 168                                &vmw_gb_shader_func);
 169
 170        if (unlikely(ret != 0)) {
 171                if (res_free)
 172                        res_free(res);
 173                else
 174                        kfree(res);
 175                return ret;
 176        }
 177
 178        res->backup_size = size;
 179        if (byte_code) {
 180                res->backup = vmw_bo_reference(byte_code);
 181                res->backup_offset = offset;
 182        }
 183        shader->size = size;
 184        shader->type = type;
 185        shader->num_input_sig = num_input_sig;
 186        shader->num_output_sig = num_output_sig;
 187
 188        res->hw_destroy = vmw_hw_shader_destroy;
 189        return 0;
 190}
 191
 192/*
 193 * GB shader code:
 194 */
 195
 196static int vmw_gb_shader_create(struct vmw_resource *res)
 197{
 198        struct vmw_private *dev_priv = res->dev_priv;
 199        struct vmw_shader *shader = vmw_res_to_shader(res);
 200        int ret;
 201        struct {
 202                SVGA3dCmdHeader header;
 203                SVGA3dCmdDefineGBShader body;
 204        } *cmd;
 205
 206        if (likely(res->id != -1))
 207                return 0;
 208
 209        ret = vmw_resource_alloc_id(res);
 210        if (unlikely(ret != 0)) {
 211                DRM_ERROR("Failed to allocate a shader id.\n");
 212                goto out_no_id;
 213        }
 214
 215        if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
 216                ret = -EBUSY;
 217                goto out_no_fifo;
 218        }
 219
 220        cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 221        if (unlikely(cmd == NULL)) {
 222                ret = -ENOMEM;
 223                goto out_no_fifo;
 224        }
 225
 226        cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
 227        cmd->header.size = sizeof(cmd->body);
 228        cmd->body.shid = res->id;
 229        cmd->body.type = shader->type;
 230        cmd->body.sizeInBytes = shader->size;
 231        vmw_cmd_commit(dev_priv, sizeof(*cmd));
 232        vmw_fifo_resource_inc(dev_priv);
 233
 234        return 0;
 235
 236out_no_fifo:
 237        vmw_resource_release_id(res);
 238out_no_id:
 239        return ret;
 240}
 241
 242static int vmw_gb_shader_bind(struct vmw_resource *res,
 243                              struct ttm_validate_buffer *val_buf)
 244{
 245        struct vmw_private *dev_priv = res->dev_priv;
 246        struct {
 247                SVGA3dCmdHeader header;
 248                SVGA3dCmdBindGBShader body;
 249        } *cmd;
 250        struct ttm_buffer_object *bo = val_buf->bo;
 251
 252        BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
 253
 254        cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 255        if (unlikely(cmd == NULL))
 256                return -ENOMEM;
 257
 258        cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
 259        cmd->header.size = sizeof(cmd->body);
 260        cmd->body.shid = res->id;
 261        cmd->body.mobid = bo->resource->start;
 262        cmd->body.offsetInBytes = res->backup_offset;
 263        res->backup_dirty = false;
 264        vmw_cmd_commit(dev_priv, sizeof(*cmd));
 265
 266        return 0;
 267}
 268
 269static int vmw_gb_shader_unbind(struct vmw_resource *res,
 270                                bool readback,
 271                                struct ttm_validate_buffer *val_buf)
 272{
 273        struct vmw_private *dev_priv = res->dev_priv;
 274        struct {
 275                SVGA3dCmdHeader header;
 276                SVGA3dCmdBindGBShader body;
 277        } *cmd;
 278        struct vmw_fence_obj *fence;
 279
 280        BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB);
 281
 282        cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 283        if (unlikely(cmd == NULL))
 284                return -ENOMEM;
 285
 286        cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
 287        cmd->header.size = sizeof(cmd->body);
 288        cmd->body.shid = res->id;
 289        cmd->body.mobid = SVGA3D_INVALID_ID;
 290        cmd->body.offsetInBytes = 0;
 291        vmw_cmd_commit(dev_priv, sizeof(*cmd));
 292
 293        /*
 294         * Create a fence object and fence the backup buffer.
 295         */
 296
 297        (void) vmw_execbuf_fence_commands(NULL, dev_priv,
 298                                          &fence, NULL);
 299
 300        vmw_bo_fence_single(val_buf->bo, fence);
 301
 302        if (likely(fence != NULL))
 303                vmw_fence_obj_unreference(&fence);
 304
 305        return 0;
 306}
 307
 308static int vmw_gb_shader_destroy(struct vmw_resource *res)
 309{
 310        struct vmw_private *dev_priv = res->dev_priv;
 311        struct {
 312                SVGA3dCmdHeader header;
 313                SVGA3dCmdDestroyGBShader body;
 314        } *cmd;
 315
 316        if (likely(res->id == -1))
 317                return 0;
 318
 319        mutex_lock(&dev_priv->binding_mutex);
 320        vmw_binding_res_list_scrub(&res->binding_head);
 321
 322        cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 323        if (unlikely(cmd == NULL)) {
 324                mutex_unlock(&dev_priv->binding_mutex);
 325                return -ENOMEM;
 326        }
 327
 328        cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
 329        cmd->header.size = sizeof(cmd->body);
 330        cmd->body.shid = res->id;
 331        vmw_cmd_commit(dev_priv, sizeof(*cmd));
 332        mutex_unlock(&dev_priv->binding_mutex);
 333        vmw_resource_release_id(res);
 334        vmw_fifo_resource_dec(dev_priv);
 335
 336        return 0;
 337}
 338
 339/*
 340 * DX shader code:
 341 */
 342
 343/**
 344 * vmw_dx_shader_commit_notify - Notify that a shader operation has been
 345 * committed to hardware from a user-supplied command stream.
 346 *
 347 * @res: Pointer to the shader resource.
 348 * @state: Indicating whether a creation or removal has been committed.
 349 *
 350 */
 351static void vmw_dx_shader_commit_notify(struct vmw_resource *res,
 352                                        enum vmw_cmdbuf_res_state state)
 353{
 354        struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
 355        struct vmw_private *dev_priv = res->dev_priv;
 356
 357        if (state == VMW_CMDBUF_RES_ADD) {
 358                mutex_lock(&dev_priv->binding_mutex);
 359                vmw_cotable_add_resource(shader->cotable,
 360                                         &shader->cotable_head);
 361                shader->committed = true;
 362                res->id = shader->id;
 363                mutex_unlock(&dev_priv->binding_mutex);
 364        } else {
 365                mutex_lock(&dev_priv->binding_mutex);
 366                list_del_init(&shader->cotable_head);
 367                shader->committed = false;
 368                res->id = -1;
 369                mutex_unlock(&dev_priv->binding_mutex);
 370        }
 371}
 372
 373/**
 374 * vmw_dx_shader_unscrub - Have the device reattach a MOB to a DX shader.
 375 *
 376 * @res: The shader resource
 377 *
 378 * This function reverts a scrub operation.
 379 */
 380static int vmw_dx_shader_unscrub(struct vmw_resource *res)
 381{
 382        struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
 383        struct vmw_private *dev_priv = res->dev_priv;
 384        struct {
 385                SVGA3dCmdHeader header;
 386                SVGA3dCmdDXBindShader body;
 387        } *cmd;
 388
 389        if (!list_empty(&shader->cotable_head) || !shader->committed)
 390                return 0;
 391
 392        cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), shader->ctx->id);
 393        if (unlikely(cmd == NULL))
 394                return -ENOMEM;
 395
 396        cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
 397        cmd->header.size = sizeof(cmd->body);
 398        cmd->body.cid = shader->ctx->id;
 399        cmd->body.shid = shader->id;
 400        cmd->body.mobid = res->backup->base.resource->start;
 401        cmd->body.offsetInBytes = res->backup_offset;
 402        vmw_cmd_commit(dev_priv, sizeof(*cmd));
 403
 404        vmw_cotable_add_resource(shader->cotable, &shader->cotable_head);
 405
 406        return 0;
 407}
 408
 409/**
 410 * vmw_dx_shader_create - The DX shader create callback
 411 *
 412 * @res: The DX shader resource
 413 *
 414 * The create callback is called as part of resource validation and
 415 * makes sure that we unscrub the shader if it's previously been scrubbed.
 416 */
 417static int vmw_dx_shader_create(struct vmw_resource *res)
 418{
 419        struct vmw_private *dev_priv = res->dev_priv;
 420        struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
 421        int ret = 0;
 422
 423        WARN_ON_ONCE(!shader->committed);
 424
 425        if (vmw_resource_mob_attached(res)) {
 426                mutex_lock(&dev_priv->binding_mutex);
 427                ret = vmw_dx_shader_unscrub(res);
 428                mutex_unlock(&dev_priv->binding_mutex);
 429        }
 430
 431        res->id = shader->id;
 432        return ret;
 433}
 434
 435/**
 436 * vmw_dx_shader_bind - The DX shader bind callback
 437 *
 438 * @res: The DX shader resource
 439 * @val_buf: Pointer to the validate buffer.
 440 *
 441 */
 442static int vmw_dx_shader_bind(struct vmw_resource *res,
 443                              struct ttm_validate_buffer *val_buf)
 444{
 445        struct vmw_private *dev_priv = res->dev_priv;
 446        struct ttm_buffer_object *bo = val_buf->bo;
 447
 448        BUG_ON(bo->resource->mem_type != VMW_PL_MOB);
 449        mutex_lock(&dev_priv->binding_mutex);
 450        vmw_dx_shader_unscrub(res);
 451        mutex_unlock(&dev_priv->binding_mutex);
 452
 453        return 0;
 454}
 455
 456/**
 457 * vmw_dx_shader_scrub - Have the device unbind a MOB from a DX shader.
 458 *
 459 * @res: The shader resource
 460 *
 461 * This function unbinds a MOB from the DX shader without requiring the
 462 * MOB dma_buffer to be reserved. The driver still considers the MOB bound.
 463 * However, once the driver eventually decides to unbind the MOB, it doesn't
 464 * need to access the context.
 465 */
 466static int vmw_dx_shader_scrub(struct vmw_resource *res)
 467{
 468        struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
 469        struct vmw_private *dev_priv = res->dev_priv;
 470        struct {
 471                SVGA3dCmdHeader header;
 472                SVGA3dCmdDXBindShader body;
 473        } *cmd;
 474
 475        if (list_empty(&shader->cotable_head))
 476                return 0;
 477
 478        WARN_ON_ONCE(!shader->committed);
 479        cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 480        if (unlikely(cmd == NULL))
 481                return -ENOMEM;
 482
 483        cmd->header.id = SVGA_3D_CMD_DX_BIND_SHADER;
 484        cmd->header.size = sizeof(cmd->body);
 485        cmd->body.cid = shader->ctx->id;
 486        cmd->body.shid = res->id;
 487        cmd->body.mobid = SVGA3D_INVALID_ID;
 488        cmd->body.offsetInBytes = 0;
 489        vmw_cmd_commit(dev_priv, sizeof(*cmd));
 490        res->id = -1;
 491        list_del_init(&shader->cotable_head);
 492
 493        return 0;
 494}
 495
 496/**
 497 * vmw_dx_shader_unbind - The dx shader unbind callback.
 498 *
 499 * @res: The shader resource
 500 * @readback: Whether this is a readback unbind. Currently unused.
 501 * @val_buf: MOB buffer information.
 502 */
 503static int vmw_dx_shader_unbind(struct vmw_resource *res,
 504                                bool readback,
 505                                struct ttm_validate_buffer *val_buf)
 506{
 507        struct vmw_private *dev_priv = res->dev_priv;
 508        struct vmw_fence_obj *fence;
 509        int ret;
 510
 511        BUG_ON(res->backup->base.resource->mem_type != VMW_PL_MOB);
 512
 513        mutex_lock(&dev_priv->binding_mutex);
 514        ret = vmw_dx_shader_scrub(res);
 515        mutex_unlock(&dev_priv->binding_mutex);
 516
 517        if (ret)
 518                return ret;
 519
 520        (void) vmw_execbuf_fence_commands(NULL, dev_priv,
 521                                          &fence, NULL);
 522        vmw_bo_fence_single(val_buf->bo, fence);
 523
 524        if (likely(fence != NULL))
 525                vmw_fence_obj_unreference(&fence);
 526
 527        return 0;
 528}
 529
 530/**
 531 * vmw_dx_shader_cotable_list_scrub - The cotable unbind_func callback for
 532 * DX shaders.
 533 *
 534 * @dev_priv: Pointer to device private structure.
 535 * @list: The list of cotable resources.
 536 * @readback: Whether the call was part of a readback unbind.
 537 *
 538 * Scrubs all shader MOBs so that any subsequent shader unbind or shader
 539 * destroy operation won't need to swap in the context.
 540 */
 541void vmw_dx_shader_cotable_list_scrub(struct vmw_private *dev_priv,
 542                                      struct list_head *list,
 543                                      bool readback)
 544{
 545        struct vmw_dx_shader *entry, *next;
 546
 547        lockdep_assert_held_once(&dev_priv->binding_mutex);
 548
 549        list_for_each_entry_safe(entry, next, list, cotable_head) {
 550                WARN_ON(vmw_dx_shader_scrub(&entry->res));
 551                if (!readback)
 552                        entry->committed = false;
 553        }
 554}
 555
 556/**
 557 * vmw_dx_shader_res_free - The DX shader free callback
 558 *
 559 * @res: The shader resource
 560 *
 561 * Frees the DX shader resource.
 562 */
 563static void vmw_dx_shader_res_free(struct vmw_resource *res)
 564{
 565        struct vmw_dx_shader *shader = vmw_res_to_dx_shader(res);
 566
 567        vmw_resource_unreference(&shader->cotable);
 568        kfree(shader);
 569}
 570
 571/**
 572 * vmw_dx_shader_add - Add a shader resource as a command buffer managed
 573 * resource.
 574 *
 575 * @man: The command buffer resource manager.
 576 * @ctx: Pointer to the context resource.
 577 * @user_key: The id used for this shader.
 578 * @shader_type: The shader type.
 579 * @list: The list of staged command buffer managed resources.
 580 */
 581int vmw_dx_shader_add(struct vmw_cmdbuf_res_manager *man,
 582                      struct vmw_resource *ctx,
 583                      u32 user_key,
 584                      SVGA3dShaderType shader_type,
 585                      struct list_head *list)
 586{
 587        struct vmw_dx_shader *shader;
 588        struct vmw_resource *res;
 589        struct vmw_private *dev_priv = ctx->dev_priv;
 590        int ret;
 591
 592        if (!vmw_shader_id_ok(user_key, shader_type))
 593                return -EINVAL;
 594
 595        shader = kmalloc(sizeof(*shader), GFP_KERNEL);
 596        if (!shader) {
 597                return -ENOMEM;
 598        }
 599
 600        res = &shader->res;
 601        shader->ctx = ctx;
 602        shader->cotable = vmw_resource_reference
 603                (vmw_context_cotable(ctx, SVGA_COTABLE_DXSHADER));
 604        shader->id = user_key;
 605        shader->committed = false;
 606        INIT_LIST_HEAD(&shader->cotable_head);
 607        ret = vmw_resource_init(dev_priv, res, true,
 608                                vmw_dx_shader_res_free, &vmw_dx_shader_func);
 609        if (ret)
 610                goto out_resource_init;
 611
 612        /*
 613         * The user_key name-space is not per shader type for DX shaders,
 614         * so when hashing, use a single zero shader type.
 615         */
 616        ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
 617                                 vmw_shader_key(user_key, 0),
 618                                 res, list);
 619        if (ret)
 620                goto out_resource_init;
 621
 622        res->id = shader->id;
 623        res->hw_destroy = vmw_hw_shader_destroy;
 624
 625out_resource_init:
 626        vmw_resource_unreference(&res);
 627
 628        return ret;
 629}
 630
 631
 632
 633/*
 634 * User-space shader management:
 635 */
 636
 637static struct vmw_resource *
 638vmw_user_shader_base_to_res(struct ttm_base_object *base)
 639{
 640        return &(container_of(base, struct vmw_user_shader, base)->
 641                 shader.res);
 642}
 643
 644static void vmw_user_shader_free(struct vmw_resource *res)
 645{
 646        struct vmw_user_shader *ushader =
 647                container_of(res, struct vmw_user_shader, shader.res);
 648
 649        ttm_base_object_kfree(ushader, base);
 650}
 651
 652static void vmw_shader_free(struct vmw_resource *res)
 653{
 654        struct vmw_shader *shader = vmw_res_to_shader(res);
 655
 656        kfree(shader);
 657}
 658
 659/*
 660 * This function is called when user space has no more references on the
 661 * base object. It releases the base-object's reference on the resource object.
 662 */
 663
 664static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
 665{
 666        struct ttm_base_object *base = *p_base;
 667        struct vmw_resource *res = vmw_user_shader_base_to_res(base);
 668
 669        *p_base = NULL;
 670        vmw_resource_unreference(&res);
 671}
 672
 673int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
 674                              struct drm_file *file_priv)
 675{
 676        struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
 677        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 678
 679        return ttm_ref_object_base_unref(tfile, arg->handle);
 680}
 681
 682static int vmw_user_shader_alloc(struct vmw_private *dev_priv,
 683                                 struct vmw_buffer_object *buffer,
 684                                 size_t shader_size,
 685                                 size_t offset,
 686                                 SVGA3dShaderType shader_type,
 687                                 uint8_t num_input_sig,
 688                                 uint8_t num_output_sig,
 689                                 struct ttm_object_file *tfile,
 690                                 u32 *handle)
 691{
 692        struct vmw_user_shader *ushader;
 693        struct vmw_resource *res, *tmp;
 694        int ret;
 695
 696        ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
 697        if (unlikely(!ushader)) {
 698                ret = -ENOMEM;
 699                goto out;
 700        }
 701
 702        res = &ushader->shader.res;
 703        ushader->base.shareable = false;
 704        ushader->base.tfile = NULL;
 705
 706        /*
 707         * From here on, the destructor takes over resource freeing.
 708         */
 709
 710        ret = vmw_gb_shader_init(dev_priv, res, shader_size,
 711                                 offset, shader_type, num_input_sig,
 712                                 num_output_sig, buffer,
 713                                 vmw_user_shader_free);
 714        if (unlikely(ret != 0))
 715                goto out;
 716
 717        tmp = vmw_resource_reference(res);
 718        ret = ttm_base_object_init(tfile, &ushader->base, false,
 719                                   VMW_RES_SHADER,
 720                                   &vmw_user_shader_base_release);
 721
 722        if (unlikely(ret != 0)) {
 723                vmw_resource_unreference(&tmp);
 724                goto out_err;
 725        }
 726
 727        if (handle)
 728                *handle = ushader->base.handle;
 729out_err:
 730        vmw_resource_unreference(&res);
 731out:
 732        return ret;
 733}
 734
 735
 736static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv,
 737                                             struct vmw_buffer_object *buffer,
 738                                             size_t shader_size,
 739                                             size_t offset,
 740                                             SVGA3dShaderType shader_type)
 741{
 742        struct vmw_shader *shader;
 743        struct vmw_resource *res;
 744        int ret;
 745
 746        shader = kzalloc(sizeof(*shader), GFP_KERNEL);
 747        if (unlikely(!shader)) {
 748                ret = -ENOMEM;
 749                goto out_err;
 750        }
 751
 752        res = &shader->res;
 753
 754        /*
 755         * From here on, the destructor takes over resource freeing.
 756         */
 757        ret = vmw_gb_shader_init(dev_priv, res, shader_size,
 758                                 offset, shader_type, 0, 0, buffer,
 759                                 vmw_shader_free);
 760
 761out_err:
 762        return ret ? ERR_PTR(ret) : res;
 763}
 764
 765
 766static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
 767                             enum drm_vmw_shader_type shader_type_drm,
 768                             u32 buffer_handle, size_t size, size_t offset,
 769                             uint8_t num_input_sig, uint8_t num_output_sig,
 770                             uint32_t *shader_handle)
 771{
 772        struct vmw_private *dev_priv = vmw_priv(dev);
 773        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 774        struct vmw_buffer_object *buffer = NULL;
 775        SVGA3dShaderType shader_type;
 776        int ret;
 777
 778        if (buffer_handle != SVGA3D_INVALID_ID) {
 779                ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer);
 780                if (unlikely(ret != 0)) {
 781                        VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n");
 782                        return ret;
 783                }
 784
 785                if ((u64)buffer->base.base.size < (u64)size + (u64)offset) {
 786                        VMW_DEBUG_USER("Illegal buffer- or shader size.\n");
 787                        ret = -EINVAL;
 788                        goto out_bad_arg;
 789                }
 790        }
 791
 792        switch (shader_type_drm) {
 793        case drm_vmw_shader_type_vs:
 794                shader_type = SVGA3D_SHADERTYPE_VS;
 795                break;
 796        case drm_vmw_shader_type_ps:
 797                shader_type = SVGA3D_SHADERTYPE_PS;
 798                break;
 799        default:
 800                VMW_DEBUG_USER("Illegal shader type.\n");
 801                ret = -EINVAL;
 802                goto out_bad_arg;
 803        }
 804
 805        ret = vmw_user_shader_alloc(dev_priv, buffer, size, offset,
 806                                    shader_type, num_input_sig,
 807                                    num_output_sig, tfile, shader_handle);
 808out_bad_arg:
 809        vmw_bo_unreference(&buffer);
 810        return ret;
 811}
 812
 813/**
 814 * vmw_shader_id_ok - Check whether a compat shader user key and
 815 * shader type are within valid bounds.
 816 *
 817 * @user_key: User space id of the shader.
 818 * @shader_type: Shader type.
 819 *
 820 * Returns true if valid false if not.
 821 */
 822static bool vmw_shader_id_ok(u32 user_key, SVGA3dShaderType shader_type)
 823{
 824        return user_key <= ((1 << 20) - 1) && (unsigned) shader_type < 16;
 825}
 826
 827/**
 828 * vmw_shader_key - Compute a hash key suitable for a compat shader.
 829 *
 830 * @user_key: User space id of the shader.
 831 * @shader_type: Shader type.
 832 *
 833 * Returns a hash key suitable for a command buffer managed resource
 834 * manager hash table.
 835 */
 836static u32 vmw_shader_key(u32 user_key, SVGA3dShaderType shader_type)
 837{
 838        return user_key | (shader_type << 20);
 839}
 840
 841/**
 842 * vmw_shader_remove - Stage a compat shader for removal.
 843 *
 844 * @man: Pointer to the compat shader manager identifying the shader namespace.
 845 * @user_key: The key that is used to identify the shader. The key is
 846 * unique to the shader type.
 847 * @shader_type: Shader type.
 848 * @list: Caller's list of staged command buffer resource actions.
 849 */
 850int vmw_shader_remove(struct vmw_cmdbuf_res_manager *man,
 851                      u32 user_key, SVGA3dShaderType shader_type,
 852                      struct list_head *list)
 853{
 854        struct vmw_resource *dummy;
 855
 856        if (!vmw_shader_id_ok(user_key, shader_type))
 857                return -EINVAL;
 858
 859        return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_shader,
 860                                     vmw_shader_key(user_key, shader_type),
 861                                     list, &dummy);
 862}
 863
 864/**
 865 * vmw_compat_shader_add - Create a compat shader and stage it for addition
 866 * as a command buffer managed resource.
 867 *
 868 * @dev_priv: Pointer to device private structure.
 869 * @man: Pointer to the compat shader manager identifying the shader namespace.
 870 * @user_key: The key that is used to identify the shader. The key is
 871 * unique to the shader type.
 872 * @bytecode: Pointer to the bytecode of the shader.
 873 * @shader_type: Shader type.
 874 * @size: Command size.
 875 * @list: Caller's list of staged command buffer resource actions.
 876 *
 877 */
 878int vmw_compat_shader_add(struct vmw_private *dev_priv,
 879                          struct vmw_cmdbuf_res_manager *man,
 880                          u32 user_key, const void *bytecode,
 881                          SVGA3dShaderType shader_type,
 882                          size_t size,
 883                          struct list_head *list)
 884{
 885        struct ttm_operation_ctx ctx = { false, true };
 886        struct vmw_buffer_object *buf;
 887        struct ttm_bo_kmap_obj map;
 888        bool is_iomem;
 889        int ret;
 890        struct vmw_resource *res;
 891
 892        if (!vmw_shader_id_ok(user_key, shader_type))
 893                return -EINVAL;
 894
 895        ret = vmw_bo_create(dev_priv, size, &vmw_sys_placement,
 896                            true, true, vmw_bo_bo_free, &buf);
 897        if (unlikely(ret != 0))
 898                goto out;
 899
 900        ret = ttm_bo_reserve(&buf->base, false, true, NULL);
 901        if (unlikely(ret != 0))
 902                goto no_reserve;
 903
 904        /* Map and copy shader bytecode. */
 905        ret = ttm_bo_kmap(&buf->base, 0, PFN_UP(size), &map);
 906        if (unlikely(ret != 0)) {
 907                ttm_bo_unreserve(&buf->base);
 908                goto no_reserve;
 909        }
 910
 911        memcpy(ttm_kmap_obj_virtual(&map, &is_iomem), bytecode, size);
 912        WARN_ON(is_iomem);
 913
 914        ttm_bo_kunmap(&map);
 915        ret = ttm_bo_validate(&buf->base, &vmw_sys_placement, &ctx);
 916        WARN_ON(ret != 0);
 917        ttm_bo_unreserve(&buf->base);
 918
 919        res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
 920        if (unlikely(ret != 0))
 921                goto no_reserve;
 922
 923        ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
 924                                 vmw_shader_key(user_key, shader_type),
 925                                 res, list);
 926        vmw_resource_unreference(&res);
 927no_reserve:
 928        vmw_bo_unreference(&buf);
 929out:
 930        return ret;
 931}
 932
 933/**
 934 * vmw_shader_lookup - Look up a compat shader
 935 *
 936 * @man: Pointer to the command buffer managed resource manager identifying
 937 * the shader namespace.
 938 * @user_key: The user space id of the shader.
 939 * @shader_type: The shader type.
 940 *
 941 * Returns a refcounted pointer to a struct vmw_resource if the shader was
 942 * found. An error pointer otherwise.
 943 */
 944struct vmw_resource *
 945vmw_shader_lookup(struct vmw_cmdbuf_res_manager *man,
 946                  u32 user_key,
 947                  SVGA3dShaderType shader_type)
 948{
 949        if (!vmw_shader_id_ok(user_key, shader_type))
 950                return ERR_PTR(-EINVAL);
 951
 952        return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_shader,
 953                                     vmw_shader_key(user_key, shader_type));
 954}
 955
 956int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
 957                             struct drm_file *file_priv)
 958{
 959        struct drm_vmw_shader_create_arg *arg =
 960                (struct drm_vmw_shader_create_arg *)data;
 961
 962        return vmw_shader_define(dev, file_priv, arg->shader_type,
 963                                 arg->buffer_handle,
 964                                 arg->size, arg->offset,
 965                                 0, 0,
 966                                 &arg->shader_handle);
 967}
 968