linux/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
<<
>>
Prefs
   1/**************************************************************************
   2 *
   3 * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
   4 * All Rights Reserved.
   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 "vmwgfx_drv.h"
  29#include "vmwgfx_resource_priv.h"
  30#include "vmwgfx_binding.h"
  31#include "ttm/ttm_placement.h"
  32
  33struct vmw_user_context {
  34        struct ttm_base_object base;
  35        struct vmw_resource res;
  36        struct vmw_ctx_binding_state *cbs;
  37        struct vmw_cmdbuf_res_manager *man;
  38        struct vmw_resource *cotables[SVGA_COTABLE_DX10_MAX];
  39        spinlock_t cotable_lock;
  40        struct vmw_dma_buffer *dx_query_mob;
  41};
  42
  43static void vmw_user_context_free(struct vmw_resource *res);
  44static struct vmw_resource *
  45vmw_user_context_base_to_res(struct ttm_base_object *base);
  46
  47static int vmw_gb_context_create(struct vmw_resource *res);
  48static int vmw_gb_context_bind(struct vmw_resource *res,
  49                               struct ttm_validate_buffer *val_buf);
  50static int vmw_gb_context_unbind(struct vmw_resource *res,
  51                                 bool readback,
  52                                 struct ttm_validate_buffer *val_buf);
  53static int vmw_gb_context_destroy(struct vmw_resource *res);
  54static int vmw_dx_context_create(struct vmw_resource *res);
  55static int vmw_dx_context_bind(struct vmw_resource *res,
  56                               struct ttm_validate_buffer *val_buf);
  57static int vmw_dx_context_unbind(struct vmw_resource *res,
  58                                 bool readback,
  59                                 struct ttm_validate_buffer *val_buf);
  60static int vmw_dx_context_destroy(struct vmw_resource *res);
  61
  62static uint64_t vmw_user_context_size;
  63
  64static const struct vmw_user_resource_conv user_context_conv = {
  65        .object_type = VMW_RES_CONTEXT,
  66        .base_obj_to_res = vmw_user_context_base_to_res,
  67        .res_free = vmw_user_context_free
  68};
  69
  70const struct vmw_user_resource_conv *user_context_converter =
  71        &user_context_conv;
  72
  73
  74static const struct vmw_res_func vmw_legacy_context_func = {
  75        .res_type = vmw_res_context,
  76        .needs_backup = false,
  77        .may_evict = false,
  78        .type_name = "legacy contexts",
  79        .backup_placement = NULL,
  80        .create = NULL,
  81        .destroy = NULL,
  82        .bind = NULL,
  83        .unbind = NULL
  84};
  85
  86static const struct vmw_res_func vmw_gb_context_func = {
  87        .res_type = vmw_res_context,
  88        .needs_backup = true,
  89        .may_evict = true,
  90        .type_name = "guest backed contexts",
  91        .backup_placement = &vmw_mob_placement,
  92        .create = vmw_gb_context_create,
  93        .destroy = vmw_gb_context_destroy,
  94        .bind = vmw_gb_context_bind,
  95        .unbind = vmw_gb_context_unbind
  96};
  97
  98static const struct vmw_res_func vmw_dx_context_func = {
  99        .res_type = vmw_res_dx_context,
 100        .needs_backup = true,
 101        .may_evict = true,
 102        .type_name = "dx contexts",
 103        .backup_placement = &vmw_mob_placement,
 104        .create = vmw_dx_context_create,
 105        .destroy = vmw_dx_context_destroy,
 106        .bind = vmw_dx_context_bind,
 107        .unbind = vmw_dx_context_unbind
 108};
 109
 110/**
 111 * Context management:
 112 */
 113
 114static void vmw_context_cotables_unref(struct vmw_user_context *uctx)
 115{
 116        struct vmw_resource *res;
 117        int i;
 118
 119        for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
 120                spin_lock(&uctx->cotable_lock);
 121                res = uctx->cotables[i];
 122                uctx->cotables[i] = NULL;
 123                spin_unlock(&uctx->cotable_lock);
 124
 125                if (res)
 126                        vmw_resource_unreference(&res);
 127        }
 128}
 129
 130static void vmw_hw_context_destroy(struct vmw_resource *res)
 131{
 132        struct vmw_user_context *uctx =
 133                container_of(res, struct vmw_user_context, res);
 134        struct vmw_private *dev_priv = res->dev_priv;
 135        struct {
 136                SVGA3dCmdHeader header;
 137                SVGA3dCmdDestroyContext body;
 138        } *cmd;
 139
 140
 141        if (res->func->destroy == vmw_gb_context_destroy ||
 142            res->func->destroy == vmw_dx_context_destroy) {
 143                mutex_lock(&dev_priv->cmdbuf_mutex);
 144                vmw_cmdbuf_res_man_destroy(uctx->man);
 145                mutex_lock(&dev_priv->binding_mutex);
 146                vmw_binding_state_kill(uctx->cbs);
 147                (void) res->func->destroy(res);
 148                mutex_unlock(&dev_priv->binding_mutex);
 149                if (dev_priv->pinned_bo != NULL &&
 150                    !dev_priv->query_cid_valid)
 151                        __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
 152                mutex_unlock(&dev_priv->cmdbuf_mutex);
 153                vmw_context_cotables_unref(uctx);
 154                return;
 155        }
 156
 157        vmw_execbuf_release_pinned_bo(dev_priv);
 158        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 159        if (unlikely(cmd == NULL)) {
 160                DRM_ERROR("Failed reserving FIFO space for surface "
 161                          "destruction.\n");
 162                return;
 163        }
 164
 165        cmd->header.id = SVGA_3D_CMD_CONTEXT_DESTROY;
 166        cmd->header.size = sizeof(cmd->body);
 167        cmd->body.cid = res->id;
 168
 169        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 170        vmw_fifo_resource_dec(dev_priv);
 171}
 172
 173static int vmw_gb_context_init(struct vmw_private *dev_priv,
 174                               bool dx,
 175                               struct vmw_resource *res,
 176                               void (*res_free)(struct vmw_resource *res))
 177{
 178        int ret, i;
 179        struct vmw_user_context *uctx =
 180                container_of(res, struct vmw_user_context, res);
 181
 182        res->backup_size = (dx ? sizeof(SVGADXContextMobFormat) :
 183                            SVGA3D_CONTEXT_DATA_SIZE);
 184        ret = vmw_resource_init(dev_priv, res, true,
 185                                res_free,
 186                                dx ? &vmw_dx_context_func :
 187                                &vmw_gb_context_func);
 188        if (unlikely(ret != 0))
 189                goto out_err;
 190
 191        if (dev_priv->has_mob) {
 192                uctx->man = vmw_cmdbuf_res_man_create(dev_priv);
 193                if (IS_ERR(uctx->man)) {
 194                        ret = PTR_ERR(uctx->man);
 195                        uctx->man = NULL;
 196                        goto out_err;
 197                }
 198        }
 199
 200        uctx->cbs = vmw_binding_state_alloc(dev_priv);
 201        if (IS_ERR(uctx->cbs)) {
 202                ret = PTR_ERR(uctx->cbs);
 203                goto out_err;
 204        }
 205
 206        spin_lock_init(&uctx->cotable_lock);
 207
 208        if (dx) {
 209                for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
 210                        uctx->cotables[i] = vmw_cotable_alloc(dev_priv,
 211                                                              &uctx->res, i);
 212                        if (unlikely(uctx->cotables[i] == NULL)) {
 213                                ret = -ENOMEM;
 214                                goto out_cotables;
 215                        }
 216                }
 217        }
 218
 219
 220
 221        vmw_resource_activate(res, vmw_hw_context_destroy);
 222        return 0;
 223
 224out_cotables:
 225        vmw_context_cotables_unref(uctx);
 226out_err:
 227        if (res_free)
 228                res_free(res);
 229        else
 230                kfree(res);
 231        return ret;
 232}
 233
 234static int vmw_context_init(struct vmw_private *dev_priv,
 235                            struct vmw_resource *res,
 236                            void (*res_free)(struct vmw_resource *res),
 237                            bool dx)
 238{
 239        int ret;
 240
 241        struct {
 242                SVGA3dCmdHeader header;
 243                SVGA3dCmdDefineContext body;
 244        } *cmd;
 245
 246        if (dev_priv->has_mob)
 247                return vmw_gb_context_init(dev_priv, dx, res, res_free);
 248
 249        ret = vmw_resource_init(dev_priv, res, false,
 250                                res_free, &vmw_legacy_context_func);
 251
 252        if (unlikely(ret != 0)) {
 253                DRM_ERROR("Failed to allocate a resource id.\n");
 254                goto out_early;
 255        }
 256
 257        if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
 258                DRM_ERROR("Out of hw context ids.\n");
 259                vmw_resource_unreference(&res);
 260                return -ENOMEM;
 261        }
 262
 263        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 264        if (unlikely(cmd == NULL)) {
 265                DRM_ERROR("Fifo reserve failed.\n");
 266                vmw_resource_unreference(&res);
 267                return -ENOMEM;
 268        }
 269
 270        cmd->header.id = SVGA_3D_CMD_CONTEXT_DEFINE;
 271        cmd->header.size = sizeof(cmd->body);
 272        cmd->body.cid = res->id;
 273
 274        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 275        vmw_fifo_resource_inc(dev_priv);
 276        vmw_resource_activate(res, vmw_hw_context_destroy);
 277        return 0;
 278
 279out_early:
 280        if (res_free == NULL)
 281                kfree(res);
 282        else
 283                res_free(res);
 284        return ret;
 285}
 286
 287
 288/*
 289 * GB context.
 290 */
 291
 292static int vmw_gb_context_create(struct vmw_resource *res)
 293{
 294        struct vmw_private *dev_priv = res->dev_priv;
 295        int ret;
 296        struct {
 297                SVGA3dCmdHeader header;
 298                SVGA3dCmdDefineGBContext body;
 299        } *cmd;
 300
 301        if (likely(res->id != -1))
 302                return 0;
 303
 304        ret = vmw_resource_alloc_id(res);
 305        if (unlikely(ret != 0)) {
 306                DRM_ERROR("Failed to allocate a context id.\n");
 307                goto out_no_id;
 308        }
 309
 310        if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) {
 311                ret = -EBUSY;
 312                goto out_no_fifo;
 313        }
 314
 315        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 316        if (unlikely(cmd == NULL)) {
 317                DRM_ERROR("Failed reserving FIFO space for context "
 318                          "creation.\n");
 319                ret = -ENOMEM;
 320                goto out_no_fifo;
 321        }
 322
 323        cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT;
 324        cmd->header.size = sizeof(cmd->body);
 325        cmd->body.cid = res->id;
 326        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 327        vmw_fifo_resource_inc(dev_priv);
 328
 329        return 0;
 330
 331out_no_fifo:
 332        vmw_resource_release_id(res);
 333out_no_id:
 334        return ret;
 335}
 336
 337static int vmw_gb_context_bind(struct vmw_resource *res,
 338                               struct ttm_validate_buffer *val_buf)
 339{
 340        struct vmw_private *dev_priv = res->dev_priv;
 341        struct {
 342                SVGA3dCmdHeader header;
 343                SVGA3dCmdBindGBContext body;
 344        } *cmd;
 345        struct ttm_buffer_object *bo = val_buf->bo;
 346
 347        BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
 348
 349        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 350        if (unlikely(cmd == NULL)) {
 351                DRM_ERROR("Failed reserving FIFO space for context "
 352                          "binding.\n");
 353                return -ENOMEM;
 354        }
 355        cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
 356        cmd->header.size = sizeof(cmd->body);
 357        cmd->body.cid = res->id;
 358        cmd->body.mobid = bo->mem.start;
 359        cmd->body.validContents = res->backup_dirty;
 360        res->backup_dirty = false;
 361        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 362
 363        return 0;
 364}
 365
 366static int vmw_gb_context_unbind(struct vmw_resource *res,
 367                                 bool readback,
 368                                 struct ttm_validate_buffer *val_buf)
 369{
 370        struct vmw_private *dev_priv = res->dev_priv;
 371        struct ttm_buffer_object *bo = val_buf->bo;
 372        struct vmw_fence_obj *fence;
 373        struct vmw_user_context *uctx =
 374                container_of(res, struct vmw_user_context, res);
 375
 376        struct {
 377                SVGA3dCmdHeader header;
 378                SVGA3dCmdReadbackGBContext body;
 379        } *cmd1;
 380        struct {
 381                SVGA3dCmdHeader header;
 382                SVGA3dCmdBindGBContext body;
 383        } *cmd2;
 384        uint32_t submit_size;
 385        uint8_t *cmd;
 386
 387
 388        BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
 389
 390        mutex_lock(&dev_priv->binding_mutex);
 391        vmw_binding_state_scrub(uctx->cbs);
 392
 393        submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
 394
 395        cmd = vmw_fifo_reserve(dev_priv, submit_size);
 396        if (unlikely(cmd == NULL)) {
 397                DRM_ERROR("Failed reserving FIFO space for context "
 398                          "unbinding.\n");
 399                mutex_unlock(&dev_priv->binding_mutex);
 400                return -ENOMEM;
 401        }
 402
 403        cmd2 = (void *) cmd;
 404        if (readback) {
 405                cmd1 = (void *) cmd;
 406                cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT;
 407                cmd1->header.size = sizeof(cmd1->body);
 408                cmd1->body.cid = res->id;
 409                cmd2 = (void *) (&cmd1[1]);
 410        }
 411        cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
 412        cmd2->header.size = sizeof(cmd2->body);
 413        cmd2->body.cid = res->id;
 414        cmd2->body.mobid = SVGA3D_INVALID_ID;
 415
 416        vmw_fifo_commit(dev_priv, submit_size);
 417        mutex_unlock(&dev_priv->binding_mutex);
 418
 419        /*
 420         * Create a fence object and fence the backup buffer.
 421         */
 422
 423        (void) vmw_execbuf_fence_commands(NULL, dev_priv,
 424                                          &fence, NULL);
 425
 426        vmw_fence_single_bo(bo, fence);
 427
 428        if (likely(fence != NULL))
 429                vmw_fence_obj_unreference(&fence);
 430
 431        return 0;
 432}
 433
 434static int vmw_gb_context_destroy(struct vmw_resource *res)
 435{
 436        struct vmw_private *dev_priv = res->dev_priv;
 437        struct {
 438                SVGA3dCmdHeader header;
 439                SVGA3dCmdDestroyGBContext body;
 440        } *cmd;
 441
 442        if (likely(res->id == -1))
 443                return 0;
 444
 445        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 446        if (unlikely(cmd == NULL)) {
 447                DRM_ERROR("Failed reserving FIFO space for context "
 448                          "destruction.\n");
 449                return -ENOMEM;
 450        }
 451
 452        cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT;
 453        cmd->header.size = sizeof(cmd->body);
 454        cmd->body.cid = res->id;
 455        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 456        if (dev_priv->query_cid == res->id)
 457                dev_priv->query_cid_valid = false;
 458        vmw_resource_release_id(res);
 459        vmw_fifo_resource_dec(dev_priv);
 460
 461        return 0;
 462}
 463
 464/*
 465 * DX context.
 466 */
 467
 468static int vmw_dx_context_create(struct vmw_resource *res)
 469{
 470        struct vmw_private *dev_priv = res->dev_priv;
 471        int ret;
 472        struct {
 473                SVGA3dCmdHeader header;
 474                SVGA3dCmdDXDefineContext body;
 475        } *cmd;
 476
 477        if (likely(res->id != -1))
 478                return 0;
 479
 480        ret = vmw_resource_alloc_id(res);
 481        if (unlikely(ret != 0)) {
 482                DRM_ERROR("Failed to allocate a context id.\n");
 483                goto out_no_id;
 484        }
 485
 486        if (unlikely(res->id >= VMWGFX_NUM_DXCONTEXT)) {
 487                ret = -EBUSY;
 488                goto out_no_fifo;
 489        }
 490
 491        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 492        if (unlikely(cmd == NULL)) {
 493                DRM_ERROR("Failed reserving FIFO space for context "
 494                          "creation.\n");
 495                ret = -ENOMEM;
 496                goto out_no_fifo;
 497        }
 498
 499        cmd->header.id = SVGA_3D_CMD_DX_DEFINE_CONTEXT;
 500        cmd->header.size = sizeof(cmd->body);
 501        cmd->body.cid = res->id;
 502        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 503        vmw_fifo_resource_inc(dev_priv);
 504
 505        return 0;
 506
 507out_no_fifo:
 508        vmw_resource_release_id(res);
 509out_no_id:
 510        return ret;
 511}
 512
 513static int vmw_dx_context_bind(struct vmw_resource *res,
 514                               struct ttm_validate_buffer *val_buf)
 515{
 516        struct vmw_private *dev_priv = res->dev_priv;
 517        struct {
 518                SVGA3dCmdHeader header;
 519                SVGA3dCmdDXBindContext body;
 520        } *cmd;
 521        struct ttm_buffer_object *bo = val_buf->bo;
 522
 523        BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
 524
 525        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 526        if (unlikely(cmd == NULL)) {
 527                DRM_ERROR("Failed reserving FIFO space for context "
 528                          "binding.\n");
 529                return -ENOMEM;
 530        }
 531
 532        cmd->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
 533        cmd->header.size = sizeof(cmd->body);
 534        cmd->body.cid = res->id;
 535        cmd->body.mobid = bo->mem.start;
 536        cmd->body.validContents = res->backup_dirty;
 537        res->backup_dirty = false;
 538        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 539
 540
 541        return 0;
 542}
 543
 544/**
 545 * vmw_dx_context_scrub_cotables - Scrub all bindings and
 546 * cotables from a context
 547 *
 548 * @ctx: Pointer to the context resource
 549 * @readback: Whether to save the otable contents on scrubbing.
 550 *
 551 * COtables must be unbound before their context, but unbinding requires
 552 * the backup buffer being reserved, whereas scrubbing does not.
 553 * This function scrubs all cotables of a context, potentially reading back
 554 * the contents into their backup buffers. However, scrubbing cotables
 555 * also makes the device context invalid, so scrub all bindings first so
 556 * that doesn't have to be done later with an invalid context.
 557 */
 558void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx,
 559                                   bool readback)
 560{
 561        struct vmw_user_context *uctx =
 562                container_of(ctx, struct vmw_user_context, res);
 563        int i;
 564
 565        vmw_binding_state_scrub(uctx->cbs);
 566        for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
 567                struct vmw_resource *res;
 568
 569                /* Avoid racing with ongoing cotable destruction. */
 570                spin_lock(&uctx->cotable_lock);
 571                res = uctx->cotables[vmw_cotable_scrub_order[i]];
 572                if (res)
 573                        res = vmw_resource_reference_unless_doomed(res);
 574                spin_unlock(&uctx->cotable_lock);
 575                if (!res)
 576                        continue;
 577
 578                WARN_ON(vmw_cotable_scrub(res, readback));
 579                vmw_resource_unreference(&res);
 580        }
 581}
 582
 583static int vmw_dx_context_unbind(struct vmw_resource *res,
 584                                 bool readback,
 585                                 struct ttm_validate_buffer *val_buf)
 586{
 587        struct vmw_private *dev_priv = res->dev_priv;
 588        struct ttm_buffer_object *bo = val_buf->bo;
 589        struct vmw_fence_obj *fence;
 590        struct vmw_user_context *uctx =
 591                container_of(res, struct vmw_user_context, res);
 592
 593        struct {
 594                SVGA3dCmdHeader header;
 595                SVGA3dCmdDXReadbackContext body;
 596        } *cmd1;
 597        struct {
 598                SVGA3dCmdHeader header;
 599                SVGA3dCmdDXBindContext body;
 600        } *cmd2;
 601        uint32_t submit_size;
 602        uint8_t *cmd;
 603
 604
 605        BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
 606
 607        mutex_lock(&dev_priv->binding_mutex);
 608        vmw_dx_context_scrub_cotables(res, readback);
 609
 610        if (uctx->dx_query_mob && uctx->dx_query_mob->dx_query_ctx &&
 611            readback) {
 612                WARN_ON(uctx->dx_query_mob->dx_query_ctx != res);
 613                if (vmw_query_readback_all(uctx->dx_query_mob))
 614                        DRM_ERROR("Failed to read back query states\n");
 615        }
 616
 617        submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
 618
 619        cmd = vmw_fifo_reserve(dev_priv, submit_size);
 620        if (unlikely(cmd == NULL)) {
 621                DRM_ERROR("Failed reserving FIFO space for context "
 622                          "unbinding.\n");
 623                mutex_unlock(&dev_priv->binding_mutex);
 624                return -ENOMEM;
 625        }
 626
 627        cmd2 = (void *) cmd;
 628        if (readback) {
 629                cmd1 = (void *) cmd;
 630                cmd1->header.id = SVGA_3D_CMD_DX_READBACK_CONTEXT;
 631                cmd1->header.size = sizeof(cmd1->body);
 632                cmd1->body.cid = res->id;
 633                cmd2 = (void *) (&cmd1[1]);
 634        }
 635        cmd2->header.id = SVGA_3D_CMD_DX_BIND_CONTEXT;
 636        cmd2->header.size = sizeof(cmd2->body);
 637        cmd2->body.cid = res->id;
 638        cmd2->body.mobid = SVGA3D_INVALID_ID;
 639
 640        vmw_fifo_commit(dev_priv, submit_size);
 641        mutex_unlock(&dev_priv->binding_mutex);
 642
 643        /*
 644         * Create a fence object and fence the backup buffer.
 645         */
 646
 647        (void) vmw_execbuf_fence_commands(NULL, dev_priv,
 648                                          &fence, NULL);
 649
 650        vmw_fence_single_bo(bo, fence);
 651
 652        if (likely(fence != NULL))
 653                vmw_fence_obj_unreference(&fence);
 654
 655        return 0;
 656}
 657
 658static int vmw_dx_context_destroy(struct vmw_resource *res)
 659{
 660        struct vmw_private *dev_priv = res->dev_priv;
 661        struct {
 662                SVGA3dCmdHeader header;
 663                SVGA3dCmdDXDestroyContext body;
 664        } *cmd;
 665
 666        if (likely(res->id == -1))
 667                return 0;
 668
 669        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
 670        if (unlikely(cmd == NULL)) {
 671                DRM_ERROR("Failed reserving FIFO space for context "
 672                          "destruction.\n");
 673                return -ENOMEM;
 674        }
 675
 676        cmd->header.id = SVGA_3D_CMD_DX_DESTROY_CONTEXT;
 677        cmd->header.size = sizeof(cmd->body);
 678        cmd->body.cid = res->id;
 679        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 680        if (dev_priv->query_cid == res->id)
 681                dev_priv->query_cid_valid = false;
 682        vmw_resource_release_id(res);
 683        vmw_fifo_resource_dec(dev_priv);
 684
 685        return 0;
 686}
 687
 688/**
 689 * User-space context management:
 690 */
 691
 692static struct vmw_resource *
 693vmw_user_context_base_to_res(struct ttm_base_object *base)
 694{
 695        return &(container_of(base, struct vmw_user_context, base)->res);
 696}
 697
 698static void vmw_user_context_free(struct vmw_resource *res)
 699{
 700        struct vmw_user_context *ctx =
 701            container_of(res, struct vmw_user_context, res);
 702        struct vmw_private *dev_priv = res->dev_priv;
 703
 704        if (ctx->cbs)
 705                vmw_binding_state_free(ctx->cbs);
 706
 707        (void) vmw_context_bind_dx_query(res, NULL);
 708
 709        ttm_base_object_kfree(ctx, base);
 710        ttm_mem_global_free(vmw_mem_glob(dev_priv),
 711                            vmw_user_context_size);
 712}
 713
 714/**
 715 * This function is called when user space has no more references on the
 716 * base object. It releases the base-object's reference on the resource object.
 717 */
 718
 719static void vmw_user_context_base_release(struct ttm_base_object **p_base)
 720{
 721        struct ttm_base_object *base = *p_base;
 722        struct vmw_user_context *ctx =
 723            container_of(base, struct vmw_user_context, base);
 724        struct vmw_resource *res = &ctx->res;
 725
 726        *p_base = NULL;
 727        vmw_resource_unreference(&res);
 728}
 729
 730int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
 731                              struct drm_file *file_priv)
 732{
 733        struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
 734        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 735
 736        return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE);
 737}
 738
 739static int vmw_context_define(struct drm_device *dev, void *data,
 740                              struct drm_file *file_priv, bool dx)
 741{
 742        struct vmw_private *dev_priv = vmw_priv(dev);
 743        struct vmw_user_context *ctx;
 744        struct vmw_resource *res;
 745        struct vmw_resource *tmp;
 746        struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
 747        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 748        int ret;
 749
 750        if (!dev_priv->has_dx && dx) {
 751                DRM_ERROR("DX contexts not supported by device.\n");
 752                return -EINVAL;
 753        }
 754
 755        /*
 756         * Approximate idr memory usage with 128 bytes. It will be limited
 757         * by maximum number_of contexts anyway.
 758         */
 759
 760        if (unlikely(vmw_user_context_size == 0))
 761                vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128 +
 762                  ((dev_priv->has_mob) ? vmw_cmdbuf_res_man_size() : 0);
 763
 764        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
 765        if (unlikely(ret != 0))
 766                return ret;
 767
 768        ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
 769                                   vmw_user_context_size,
 770                                   false, true);
 771        if (unlikely(ret != 0)) {
 772                if (ret != -ERESTARTSYS)
 773                        DRM_ERROR("Out of graphics memory for context"
 774                                  " creation.\n");
 775                goto out_unlock;
 776        }
 777
 778        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 779        if (unlikely(ctx == NULL)) {
 780                ttm_mem_global_free(vmw_mem_glob(dev_priv),
 781                                    vmw_user_context_size);
 782                ret = -ENOMEM;
 783                goto out_unlock;
 784        }
 785
 786        res = &ctx->res;
 787        ctx->base.shareable = false;
 788        ctx->base.tfile = NULL;
 789
 790        /*
 791         * From here on, the destructor takes over resource freeing.
 792         */
 793
 794        ret = vmw_context_init(dev_priv, res, vmw_user_context_free, dx);
 795        if (unlikely(ret != 0))
 796                goto out_unlock;
 797
 798        tmp = vmw_resource_reference(&ctx->res);
 799        ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
 800                                   &vmw_user_context_base_release, NULL);
 801
 802        if (unlikely(ret != 0)) {
 803                vmw_resource_unreference(&tmp);
 804                goto out_err;
 805        }
 806
 807        arg->cid = ctx->base.hash.key;
 808out_err:
 809        vmw_resource_unreference(&res);
 810out_unlock:
 811        ttm_read_unlock(&dev_priv->reservation_sem);
 812        return ret;
 813}
 814
 815int vmw_context_define_ioctl(struct drm_device *dev, void *data,
 816                             struct drm_file *file_priv)
 817{
 818        return vmw_context_define(dev, data, file_priv, false);
 819}
 820
 821int vmw_extended_context_define_ioctl(struct drm_device *dev, void *data,
 822                                      struct drm_file *file_priv)
 823{
 824        union drm_vmw_extended_context_arg *arg = (typeof(arg)) data;
 825        struct drm_vmw_context_arg *rep = &arg->rep;
 826
 827        switch (arg->req) {
 828        case drm_vmw_context_legacy:
 829                return vmw_context_define(dev, rep, file_priv, false);
 830        case drm_vmw_context_dx:
 831                return vmw_context_define(dev, rep, file_priv, true);
 832        default:
 833                break;
 834        }
 835        return -EINVAL;
 836}
 837
 838/**
 839 * vmw_context_binding_list - Return a list of context bindings
 840 *
 841 * @ctx: The context resource
 842 *
 843 * Returns the current list of bindings of the given context. Note that
 844 * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
 845 */
 846struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
 847{
 848        struct vmw_user_context *uctx =
 849                container_of(ctx, struct vmw_user_context, res);
 850
 851        return vmw_binding_state_list(uctx->cbs);
 852}
 853
 854struct vmw_cmdbuf_res_manager *vmw_context_res_man(struct vmw_resource *ctx)
 855{
 856        return container_of(ctx, struct vmw_user_context, res)->man;
 857}
 858
 859struct vmw_resource *vmw_context_cotable(struct vmw_resource *ctx,
 860                                         SVGACOTableType cotable_type)
 861{
 862        if (cotable_type >= SVGA_COTABLE_DX10_MAX)
 863                return ERR_PTR(-EINVAL);
 864
 865        return vmw_resource_reference
 866                (container_of(ctx, struct vmw_user_context, res)->
 867                 cotables[cotable_type]);
 868}
 869
 870/**
 871 * vmw_context_binding_state -
 872 * Return a pointer to a context binding state structure
 873 *
 874 * @ctx: The context resource
 875 *
 876 * Returns the current state of bindings of the given context. Note that
 877 * this state becomes stale as soon as the dev_priv::binding_mutex is unlocked.
 878 */
 879struct vmw_ctx_binding_state *
 880vmw_context_binding_state(struct vmw_resource *ctx)
 881{
 882        return container_of(ctx, struct vmw_user_context, res)->cbs;
 883}
 884
 885/**
 886 * vmw_context_bind_dx_query -
 887 * Sets query MOB for the context.  If @mob is NULL, then this function will
 888 * remove the association between the MOB and the context.  This function
 889 * assumes the binding_mutex is held.
 890 *
 891 * @ctx_res: The context resource
 892 * @mob: a reference to the query MOB
 893 *
 894 * Returns -EINVAL if a MOB has already been set and does not match the one
 895 * specified in the parameter.  0 otherwise.
 896 */
 897int vmw_context_bind_dx_query(struct vmw_resource *ctx_res,
 898                              struct vmw_dma_buffer *mob)
 899{
 900        struct vmw_user_context *uctx =
 901                container_of(ctx_res, struct vmw_user_context, res);
 902
 903        if (mob == NULL) {
 904                if (uctx->dx_query_mob) {
 905                        uctx->dx_query_mob->dx_query_ctx = NULL;
 906                        vmw_dmabuf_unreference(&uctx->dx_query_mob);
 907                        uctx->dx_query_mob = NULL;
 908                }
 909
 910                return 0;
 911        }
 912
 913        /* Can only have one MOB per context for queries */
 914        if (uctx->dx_query_mob && uctx->dx_query_mob != mob)
 915                return -EINVAL;
 916
 917        mob->dx_query_ctx  = ctx_res;
 918
 919        if (!uctx->dx_query_mob)
 920                uctx->dx_query_mob = vmw_dmabuf_reference(mob);
 921
 922        return 0;
 923}
 924
 925/**
 926 * vmw_context_get_dx_query_mob - Returns non-counted reference to DX query mob
 927 *
 928 * @ctx_res: The context resource
 929 */
 930struct vmw_dma_buffer *
 931vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res)
 932{
 933        struct vmw_user_context *uctx =
 934                container_of(ctx_res, struct vmw_user_context, res);
 935
 936        return uctx->dx_query_mob;
 937}
 938