1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /************************************************************************** 3 * 4 * Copyright 2014-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 * Treat context OTables as resources to make use of the resource 29 * backing MOB eviction mechanism, that is used to read back the COTable 30 * whenever the backing MOB is evicted. 31 */ 32 33 #include <drm/ttm/ttm_placement.h> 34 35 #include "vmwgfx_drv.h" 36 #include "vmwgfx_resource_priv.h" 37 #include "vmwgfx_so.h" 38 39 /** 40 * struct vmw_cotable - Context Object Table resource 41 * 42 * @res: struct vmw_resource we are deriving from. 43 * @ctx: non-refcounted pointer to the owning context. 44 * @size_read_back: Size of data read back during eviction. 45 * @seen_entries: Seen entries in command stream for this cotable. 46 * @type: The cotable type. 47 * @scrubbed: Whether the cotable has been scrubbed. 48 * @resource_list: List of resources in the cotable. 49 */ 50 struct vmw_cotable { 51 struct vmw_resource res; 52 struct vmw_resource *ctx; 53 size_t size_read_back; 54 int seen_entries; 55 u32 type; 56 bool scrubbed; 57 struct list_head resource_list; 58 }; 59 60 /** 61 * struct vmw_cotable_info - Static info about cotable types 62 * 63 * @min_initial_entries: Min number of initial intries at cotable allocation 64 * for this cotable type. 65 * @size: Size of each entry. 66 */ 67 struct vmw_cotable_info { 68 u32 min_initial_entries; 69 u32 size; 70 void (*unbind_func)(struct vmw_private *, struct list_head *, 71 bool); 72 }; 73 74 static const struct vmw_cotable_info co_info[] = { 75 {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy}, 76 {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy}, 77 {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy}, 78 {1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, 79 {1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, 80 {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL}, 81 {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL}, 82 {1, sizeof(SVGACOTableDXSamplerEntry), NULL}, 83 {1, sizeof(SVGACOTableDXStreamOutputEntry), &vmw_dx_streamoutput_cotable_list_scrub}, 84 {1, sizeof(SVGACOTableDXQueryEntry), NULL}, 85 {1, sizeof(SVGACOTableDXShaderEntry), &vmw_dx_shader_cotable_list_scrub}, 86 {1, sizeof(SVGACOTableDXUAViewEntry), &vmw_view_cotable_list_destroy} 87 }; 88 89 /* 90 * Cotables with bindings that we remove must be scrubbed first, 91 * otherwise, the device will swap in an invalid context when we remove 92 * bindings before scrubbing a cotable... 93 */ 94 const SVGACOTableType vmw_cotable_scrub_order[] = { 95 SVGA_COTABLE_RTVIEW, 96 SVGA_COTABLE_DSVIEW, 97 SVGA_COTABLE_SRVIEW, 98 SVGA_COTABLE_DXSHADER, 99 SVGA_COTABLE_ELEMENTLAYOUT, 100 SVGA_COTABLE_BLENDSTATE, 101 SVGA_COTABLE_DEPTHSTENCIL, 102 SVGA_COTABLE_RASTERIZERSTATE, 103 SVGA_COTABLE_SAMPLER, 104 SVGA_COTABLE_STREAMOUTPUT, 105 SVGA_COTABLE_DXQUERY, 106 SVGA_COTABLE_UAVIEW, 107 }; 108 109 static int vmw_cotable_bind(struct vmw_resource *res, 110 struct ttm_validate_buffer *val_buf); 111 static int vmw_cotable_unbind(struct vmw_resource *res, 112 bool readback, 113 struct ttm_validate_buffer *val_buf); 114 static int vmw_cotable_create(struct vmw_resource *res); 115 static int vmw_cotable_destroy(struct vmw_resource *res); 116 117 static const struct vmw_res_func vmw_cotable_func = { 118 .res_type = vmw_res_cotable, 119 .needs_backup = true, 120 .may_evict = true, 121 .prio = 3, 122 .dirty_prio = 3, 123 .type_name = "context guest backed object tables", 124 .backup_placement = &vmw_mob_placement, 125 .create = vmw_cotable_create, 126 .destroy = vmw_cotable_destroy, 127 .bind = vmw_cotable_bind, 128 .unbind = vmw_cotable_unbind, 129 }; 130 131 /** 132 * vmw_cotable - Convert a struct vmw_resource pointer to a struct 133 * vmw_cotable pointer 134 * 135 * @res: Pointer to the resource. 136 */ 137 static struct vmw_cotable *vmw_cotable(struct vmw_resource *res) 138 { 139 return container_of(res, struct vmw_cotable, res); 140 } 141 142 /** 143 * vmw_cotable_destroy - Cotable resource destroy callback 144 * 145 * @res: Pointer to the cotable resource. 146 * 147 * There is no device cotable destroy command, so this function only 148 * makes sure that the resource id is set to invalid. 149 */ 150 static int vmw_cotable_destroy(struct vmw_resource *res) 151 { 152 res->id = -1; 153 return 0; 154 } 155 156 /** 157 * vmw_cotable_unscrub - Undo a cotable unscrub operation 158 * 159 * @res: Pointer to the cotable resource 160 * 161 * This function issues commands to (re)bind the cotable to 162 * its backing mob, which needs to be validated and reserved at this point. 163 * This is identical to bind() except the function interface looks different. 164 */ 165 static int vmw_cotable_unscrub(struct vmw_resource *res) 166 { 167 struct vmw_cotable *vcotbl = vmw_cotable(res); 168 struct vmw_private *dev_priv = res->dev_priv; 169 struct ttm_buffer_object *bo = &res->backup->base; 170 struct { 171 SVGA3dCmdHeader header; 172 SVGA3dCmdDXSetCOTable body; 173 } *cmd; 174 175 WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB); 176 dma_resv_assert_held(bo->base.resv); 177 178 cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 179 if (!cmd) 180 return -ENOMEM; 181 182 WARN_ON(vcotbl->ctx->id == SVGA3D_INVALID_ID); 183 WARN_ON(bo->mem.mem_type != VMW_PL_MOB); 184 cmd->header.id = SVGA_3D_CMD_DX_SET_COTABLE; 185 cmd->header.size = sizeof(cmd->body); 186 cmd->body.cid = vcotbl->ctx->id; 187 cmd->body.type = vcotbl->type; 188 cmd->body.mobid = bo->mem.start; 189 cmd->body.validSizeInBytes = vcotbl->size_read_back; 190 191 vmw_fifo_commit_flush(dev_priv, sizeof(*cmd)); 192 vcotbl->scrubbed = false; 193 194 return 0; 195 } 196 197 /** 198 * vmw_cotable_bind - Undo a cotable unscrub operation 199 * 200 * @res: Pointer to the cotable resource 201 * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller 202 * for convenience / fencing. 203 * 204 * This function issues commands to (re)bind the cotable to 205 * its backing mob, which needs to be validated and reserved at this point. 206 */ 207 static int vmw_cotable_bind(struct vmw_resource *res, 208 struct ttm_validate_buffer *val_buf) 209 { 210 /* 211 * The create() callback may have changed @res->backup without 212 * the caller noticing, and with val_buf->bo still pointing to 213 * the old backup buffer. Although hackish, and not used currently, 214 * take the opportunity to correct the value here so that it's not 215 * misused in the future. 216 */ 217 val_buf->bo = &res->backup->base; 218 219 return vmw_cotable_unscrub(res); 220 } 221 222 /** 223 * vmw_cotable_scrub - Scrub the cotable from the device. 224 * 225 * @res: Pointer to the cotable resource. 226 * @readback: Whether initiate a readback of the cotable data to the backup 227 * buffer. 228 * 229 * In some situations (context swapouts) it might be desirable to make the 230 * device forget about the cotable without performing a full unbind. A full 231 * unbind requires reserved backup buffers and it might not be possible to 232 * reserve them due to locking order violation issues. The vmw_cotable_scrub 233 * function implements a partial unbind() without that requirement but with the 234 * following restrictions. 235 * 1) Before the cotable is again used by the GPU, vmw_cotable_unscrub() must 236 * be called. 237 * 2) Before the cotable backing buffer is used by the CPU, or during the 238 * resource destruction, vmw_cotable_unbind() must be called. 239 */ 240 int vmw_cotable_scrub(struct vmw_resource *res, bool readback) 241 { 242 struct vmw_cotable *vcotbl = vmw_cotable(res); 243 struct vmw_private *dev_priv = res->dev_priv; 244 size_t submit_size; 245 246 struct { 247 SVGA3dCmdHeader header; 248 SVGA3dCmdDXReadbackCOTable body; 249 } *cmd0; 250 struct { 251 SVGA3dCmdHeader header; 252 SVGA3dCmdDXSetCOTable body; 253 } *cmd1; 254 255 if (vcotbl->scrubbed) 256 return 0; 257 258 if (co_info[vcotbl->type].unbind_func) 259 co_info[vcotbl->type].unbind_func(dev_priv, 260 &vcotbl->resource_list, 261 readback); 262 submit_size = sizeof(*cmd1); 263 if (readback) 264 submit_size += sizeof(*cmd0); 265 266 cmd1 = VMW_FIFO_RESERVE(dev_priv, submit_size); 267 if (!cmd1) 268 return -ENOMEM; 269 270 vcotbl->size_read_back = 0; 271 if (readback) { 272 cmd0 = (void *) cmd1; 273 cmd0->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE; 274 cmd0->header.size = sizeof(cmd0->body); 275 cmd0->body.cid = vcotbl->ctx->id; 276 cmd0->body.type = vcotbl->type; 277 cmd1 = (void *) &cmd0[1]; 278 vcotbl->size_read_back = res->backup_size; 279 } 280 cmd1->header.id = SVGA_3D_CMD_DX_SET_COTABLE; 281 cmd1->header.size = sizeof(cmd1->body); 282 cmd1->body.cid = vcotbl->ctx->id; 283 cmd1->body.type = vcotbl->type; 284 cmd1->body.mobid = SVGA3D_INVALID_ID; 285 cmd1->body.validSizeInBytes = 0; 286 vmw_fifo_commit_flush(dev_priv, submit_size); 287 vcotbl->scrubbed = true; 288 289 /* Trigger a create() on next validate. */ 290 res->id = -1; 291 292 return 0; 293 } 294 295 /** 296 * vmw_cotable_unbind - Cotable resource unbind callback 297 * 298 * @res: Pointer to the cotable resource. 299 * @readback: Whether to read back cotable data to the backup buffer. 300 * val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller 301 * for convenience / fencing. 302 * 303 * Unbinds the cotable from the device and fences the backup buffer. 304 */ 305 static int vmw_cotable_unbind(struct vmw_resource *res, 306 bool readback, 307 struct ttm_validate_buffer *val_buf) 308 { 309 struct vmw_cotable *vcotbl = vmw_cotable(res); 310 struct vmw_private *dev_priv = res->dev_priv; 311 struct ttm_buffer_object *bo = val_buf->bo; 312 struct vmw_fence_obj *fence; 313 314 if (!vmw_resource_mob_attached(res)) 315 return 0; 316 317 WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB); 318 dma_resv_assert_held(bo->base.resv); 319 320 mutex_lock(&dev_priv->binding_mutex); 321 if (!vcotbl->scrubbed) 322 vmw_dx_context_scrub_cotables(vcotbl->ctx, readback); 323 mutex_unlock(&dev_priv->binding_mutex); 324 (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 325 vmw_bo_fence_single(bo, fence); 326 if (likely(fence != NULL)) 327 vmw_fence_obj_unreference(&fence); 328 329 return 0; 330 } 331 332 /** 333 * vmw_cotable_readback - Read back a cotable without unbinding. 334 * 335 * @res: The cotable resource. 336 * 337 * Reads back a cotable to its backing mob without scrubbing the MOB from 338 * the cotable. The MOB is fenced for subsequent CPU access. 339 */ 340 static int vmw_cotable_readback(struct vmw_resource *res) 341 { 342 struct vmw_cotable *vcotbl = vmw_cotable(res); 343 struct vmw_private *dev_priv = res->dev_priv; 344 345 struct { 346 SVGA3dCmdHeader header; 347 SVGA3dCmdDXReadbackCOTable body; 348 } *cmd; 349 struct vmw_fence_obj *fence; 350 351 if (!vcotbl->scrubbed) { 352 cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 353 if (!cmd) 354 return -ENOMEM; 355 356 cmd->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE; 357 cmd->header.size = sizeof(cmd->body); 358 cmd->body.cid = vcotbl->ctx->id; 359 cmd->body.type = vcotbl->type; 360 vcotbl->size_read_back = res->backup_size; 361 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 362 } 363 364 (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 365 vmw_bo_fence_single(&res->backup->base, fence); 366 vmw_fence_obj_unreference(&fence); 367 368 return 0; 369 } 370 371 /** 372 * vmw_cotable_resize - Resize a cotable. 373 * 374 * @res: The cotable resource. 375 * @new_size: The new size. 376 * 377 * Resizes a cotable and binds the new backup buffer. 378 * On failure the cotable is left intact. 379 * Important! This function may not fail once the MOB switch has been 380 * committed to hardware. That would put the device context in an 381 * invalid state which we can't currently recover from. 382 */ 383 static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) 384 { 385 struct ttm_operation_ctx ctx = { false, false }; 386 struct vmw_private *dev_priv = res->dev_priv; 387 struct vmw_cotable *vcotbl = vmw_cotable(res); 388 struct vmw_buffer_object *buf, *old_buf = res->backup; 389 struct ttm_buffer_object *bo, *old_bo = &res->backup->base; 390 size_t old_size = res->backup_size; 391 size_t old_size_read_back = vcotbl->size_read_back; 392 size_t cur_size_read_back; 393 struct ttm_bo_kmap_obj old_map, new_map; 394 int ret; 395 size_t i; 396 397 ret = vmw_cotable_readback(res); 398 if (ret) 399 return ret; 400 401 cur_size_read_back = vcotbl->size_read_back; 402 vcotbl->size_read_back = old_size_read_back; 403 404 /* 405 * While device is processing, Allocate and reserve a buffer object 406 * for the new COTable. Initially pin the buffer object to make sure 407 * we can use tryreserve without failure. 408 */ 409 buf = kzalloc(sizeof(*buf), GFP_KERNEL); 410 if (!buf) 411 return -ENOMEM; 412 413 ret = vmw_bo_init(dev_priv, buf, new_size, &vmw_mob_ne_placement, 414 true, vmw_bo_bo_free); 415 if (ret) { 416 DRM_ERROR("Failed initializing new cotable MOB.\n"); 417 return ret; 418 } 419 420 bo = &buf->base; 421 WARN_ON_ONCE(ttm_bo_reserve(bo, false, true, NULL)); 422 423 ret = ttm_bo_wait(old_bo, false, false); 424 if (unlikely(ret != 0)) { 425 DRM_ERROR("Failed waiting for cotable unbind.\n"); 426 goto out_wait; 427 } 428 429 /* 430 * Do a page by page copy of COTables. This eliminates slow vmap()s. 431 * This should really be a TTM utility. 432 */ 433 for (i = 0; i < old_bo->num_pages; ++i) { 434 bool dummy; 435 436 ret = ttm_bo_kmap(old_bo, i, 1, &old_map); 437 if (unlikely(ret != 0)) { 438 DRM_ERROR("Failed mapping old COTable on resize.\n"); 439 goto out_wait; 440 } 441 ret = ttm_bo_kmap(bo, i, 1, &new_map); 442 if (unlikely(ret != 0)) { 443 DRM_ERROR("Failed mapping new COTable on resize.\n"); 444 goto out_map_new; 445 } 446 memcpy(ttm_kmap_obj_virtual(&new_map, &dummy), 447 ttm_kmap_obj_virtual(&old_map, &dummy), 448 PAGE_SIZE); 449 ttm_bo_kunmap(&new_map); 450 ttm_bo_kunmap(&old_map); 451 } 452 453 /* Unpin new buffer, and switch backup buffers. */ 454 ret = ttm_bo_validate(bo, &vmw_mob_placement, &ctx); 455 if (unlikely(ret != 0)) { 456 DRM_ERROR("Failed validating new COTable backup buffer.\n"); 457 goto out_wait; 458 } 459 460 vmw_resource_mob_detach(res); 461 res->backup = buf; 462 res->backup_size = new_size; 463 vcotbl->size_read_back = cur_size_read_back; 464 465 /* 466 * Now tell the device to switch. If this fails, then we need to 467 * revert the full resize. 468 */ 469 ret = vmw_cotable_unscrub(res); 470 if (ret) { 471 DRM_ERROR("Failed switching COTable backup buffer.\n"); 472 res->backup = old_buf; 473 res->backup_size = old_size; 474 vcotbl->size_read_back = old_size_read_back; 475 vmw_resource_mob_attach(res); 476 goto out_wait; 477 } 478 479 vmw_resource_mob_attach(res); 480 /* Let go of the old mob. */ 481 vmw_bo_unreference(&old_buf); 482 res->id = vcotbl->type; 483 484 return 0; 485 486 out_map_new: 487 ttm_bo_kunmap(&old_map); 488 out_wait: 489 ttm_bo_unreserve(bo); 490 vmw_bo_unreference(&buf); 491 492 return ret; 493 } 494 495 /** 496 * vmw_cotable_create - Cotable resource create callback 497 * 498 * @res: Pointer to a cotable resource. 499 * 500 * There is no separate create command for cotables, so this callback, which 501 * is called before bind() in the validation sequence is instead used for two 502 * things. 503 * 1) Unscrub the cotable if it is scrubbed and still attached to a backup 504 * buffer. 505 * 2) Resize the cotable if needed. 506 */ 507 static int vmw_cotable_create(struct vmw_resource *res) 508 { 509 struct vmw_cotable *vcotbl = vmw_cotable(res); 510 size_t new_size = res->backup_size; 511 size_t needed_size; 512 int ret; 513 514 /* Check whether we need to resize the cotable */ 515 needed_size = (vcotbl->seen_entries + 1) * co_info[vcotbl->type].size; 516 while (needed_size > new_size) 517 new_size *= 2; 518 519 if (likely(new_size <= res->backup_size)) { 520 if (vcotbl->scrubbed && vmw_resource_mob_attached(res)) { 521 ret = vmw_cotable_unscrub(res); 522 if (ret) 523 return ret; 524 } 525 res->id = vcotbl->type; 526 return 0; 527 } 528 529 return vmw_cotable_resize(res, new_size); 530 } 531 532 /** 533 * vmw_hw_cotable_destroy - Cotable hw_destroy callback 534 * 535 * @res: Pointer to a cotable resource. 536 * 537 * The final (part of resource destruction) destroy callback. 538 */ 539 static void vmw_hw_cotable_destroy(struct vmw_resource *res) 540 { 541 (void) vmw_cotable_destroy(res); 542 } 543 544 static size_t cotable_acc_size; 545 546 /** 547 * vmw_cotable_free - Cotable resource destructor 548 * 549 * @res: Pointer to a cotable resource. 550 */ 551 static void vmw_cotable_free(struct vmw_resource *res) 552 { 553 struct vmw_private *dev_priv = res->dev_priv; 554 555 kfree(res); 556 ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size); 557 } 558 559 /** 560 * vmw_cotable_alloc - Create a cotable resource 561 * 562 * @dev_priv: Pointer to a device private struct. 563 * @ctx: Pointer to the context resource. 564 * The cotable resource will not add a refcount. 565 * @type: The cotable type. 566 */ 567 struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv, 568 struct vmw_resource *ctx, 569 u32 type) 570 { 571 struct vmw_cotable *vcotbl; 572 struct ttm_operation_ctx ttm_opt_ctx = { 573 .interruptible = true, 574 .no_wait_gpu = false 575 }; 576 int ret; 577 u32 num_entries; 578 579 if (unlikely(cotable_acc_size == 0)) 580 cotable_acc_size = ttm_round_pot(sizeof(struct vmw_cotable)); 581 582 ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), 583 cotable_acc_size, &ttm_opt_ctx); 584 if (unlikely(ret)) 585 return ERR_PTR(ret); 586 587 vcotbl = kzalloc(sizeof(*vcotbl), GFP_KERNEL); 588 if (unlikely(!vcotbl)) { 589 ret = -ENOMEM; 590 goto out_no_alloc; 591 } 592 593 ret = vmw_resource_init(dev_priv, &vcotbl->res, true, 594 vmw_cotable_free, &vmw_cotable_func); 595 if (unlikely(ret != 0)) 596 goto out_no_init; 597 598 INIT_LIST_HEAD(&vcotbl->resource_list); 599 vcotbl->res.id = type; 600 vcotbl->res.backup_size = PAGE_SIZE; 601 num_entries = PAGE_SIZE / co_info[type].size; 602 if (num_entries < co_info[type].min_initial_entries) { 603 vcotbl->res.backup_size = co_info[type].min_initial_entries * 604 co_info[type].size; 605 vcotbl->res.backup_size = 606 (vcotbl->res.backup_size + PAGE_SIZE - 1) & PAGE_MASK; 607 } 608 609 vcotbl->scrubbed = true; 610 vcotbl->seen_entries = -1; 611 vcotbl->type = type; 612 vcotbl->ctx = ctx; 613 614 vcotbl->res.hw_destroy = vmw_hw_cotable_destroy; 615 616 return &vcotbl->res; 617 618 out_no_init: 619 kfree(vcotbl); 620 out_no_alloc: 621 ttm_mem_global_free(vmw_mem_glob(dev_priv), cotable_acc_size); 622 return ERR_PTR(ret); 623 } 624 625 /** 626 * vmw_cotable_notify - Notify the cotable about an item creation 627 * 628 * @res: Pointer to a cotable resource. 629 * @id: Item id. 630 */ 631 int vmw_cotable_notify(struct vmw_resource *res, int id) 632 { 633 struct vmw_cotable *vcotbl = vmw_cotable(res); 634 635 if (id < 0 || id >= SVGA_COTABLE_MAX_IDS) { 636 DRM_ERROR("Illegal COTable id. Type is %u. Id is %d\n", 637 (unsigned) vcotbl->type, id); 638 return -EINVAL; 639 } 640 641 if (vcotbl->seen_entries < id) { 642 /* Trigger a call to create() on next validate */ 643 res->id = -1; 644 vcotbl->seen_entries = id; 645 } 646 647 return 0; 648 } 649 650 /** 651 * vmw_cotable_add_view - add a view to the cotable's list of active views. 652 * 653 * @res: pointer struct vmw_resource representing the cotable. 654 * @head: pointer to the struct list_head member of the resource, dedicated 655 * to the cotable active resource list. 656 */ 657 void vmw_cotable_add_resource(struct vmw_resource *res, struct list_head *head) 658 { 659 struct vmw_cotable *vcotbl = 660 container_of(res, struct vmw_cotable, res); 661 662 list_add_tail(head, &vcotbl->resource_list); 663 } 664