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