Home | History | Annotate | Line # | Download | only in vmwgfx
vmwgfx_mob.c revision 1.1.1.1
      1 /**************************************************************************
      2  *
      3  * Copyright  2012 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 
     30 /*
     31  * If we set up the screen target otable, screen objects stop working.
     32  */
     33 
     34 #define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) ? 0 : 1)
     35 
     36 #ifdef CONFIG_64BIT
     37 #define VMW_PPN_SIZE 8
     38 #define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH64_0
     39 #define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH64_1
     40 #define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH64_2
     41 #else
     42 #define VMW_PPN_SIZE 4
     43 #define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH_0
     44 #define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH_1
     45 #define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH_2
     46 #endif
     47 
     48 /*
     49  * struct vmw_mob - Structure containing page table and metadata for a
     50  * Guest Memory OBject.
     51  *
     52  * @num_pages       Number of pages that make up the page table.
     53  * @pt_level        The indirection level of the page table. 0-2.
     54  * @pt_root_page    DMA address of the level 0 page of the page table.
     55  */
     56 struct vmw_mob {
     57 	struct ttm_buffer_object *pt_bo;
     58 	unsigned long num_pages;
     59 	unsigned pt_level;
     60 	dma_addr_t pt_root_page;
     61 	uint32_t id;
     62 };
     63 
     64 /*
     65  * struct vmw_otable - Guest Memory OBject table metadata
     66  *
     67  * @size:           Size of the table (page-aligned).
     68  * @page_table:     Pointer to a struct vmw_mob holding the page table.
     69  */
     70 struct vmw_otable {
     71 	unsigned long size;
     72 	struct vmw_mob *page_table;
     73 };
     74 
     75 static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
     76 			       struct vmw_mob *mob);
     77 static void vmw_mob_pt_setup(struct vmw_mob *mob,
     78 			     struct vmw_piter data_iter,
     79 			     unsigned long num_data_pages);
     80 
     81 /*
     82  * vmw_setup_otable_base - Issue an object table base setup command to
     83  * the device
     84  *
     85  * @dev_priv:       Pointer to a device private structure
     86  * @type:           Type of object table base
     87  * @offset          Start of table offset into dev_priv::otable_bo
     88  * @otable          Pointer to otable metadata;
     89  *
     90  * This function returns -ENOMEM if it fails to reserve fifo space,
     91  * and may block waiting for fifo space.
     92  */
     93 static int vmw_setup_otable_base(struct vmw_private *dev_priv,
     94 				 SVGAOTableType type,
     95 				 unsigned long offset,
     96 				 struct vmw_otable *otable)
     97 {
     98 	struct {
     99 		SVGA3dCmdHeader header;
    100 		SVGA3dCmdSetOTableBase64 body;
    101 	} *cmd;
    102 	struct vmw_mob *mob;
    103 	const struct vmw_sg_table *vsgt;
    104 	struct vmw_piter iter;
    105 	int ret;
    106 
    107 	BUG_ON(otable->page_table != NULL);
    108 
    109 	vsgt = vmw_bo_sg_table(dev_priv->otable_bo);
    110 	vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT);
    111 	WARN_ON(!vmw_piter_next(&iter));
    112 
    113 	mob = vmw_mob_create(otable->size >> PAGE_SHIFT);
    114 	if (unlikely(mob == NULL)) {
    115 		DRM_ERROR("Failed creating OTable page table.\n");
    116 		return -ENOMEM;
    117 	}
    118 
    119 	if (otable->size <= PAGE_SIZE) {
    120 		mob->pt_level = VMW_MOBFMT_PTDEPTH_0;
    121 		mob->pt_root_page = vmw_piter_dma_addr(&iter);
    122 	} else if (vsgt->num_regions == 1) {
    123 		mob->pt_level = SVGA3D_MOBFMT_RANGE;
    124 		mob->pt_root_page = vmw_piter_dma_addr(&iter);
    125 	} else {
    126 		ret = vmw_mob_pt_populate(dev_priv, mob);
    127 		if (unlikely(ret != 0))
    128 			goto out_no_populate;
    129 
    130 		vmw_mob_pt_setup(mob, iter, otable->size >> PAGE_SHIFT);
    131 		mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1;
    132 	}
    133 
    134 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    135 	if (unlikely(cmd == NULL)) {
    136 		DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
    137 		ret = -ENOMEM;
    138 		goto out_no_fifo;
    139 	}
    140 
    141 	memset(cmd, 0, sizeof(*cmd));
    142 	cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE64;
    143 	cmd->header.size = sizeof(cmd->body);
    144 	cmd->body.type = type;
    145 	cmd->body.baseAddress = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT);
    146 	cmd->body.sizeInBytes = otable->size;
    147 	cmd->body.validSizeInBytes = 0;
    148 	cmd->body.ptDepth = mob->pt_level;
    149 
    150 	/*
    151 	 * The device doesn't support this, But the otable size is
    152 	 * determined at compile-time, so this BUG shouldn't trigger
    153 	 * randomly.
    154 	 */
    155 	BUG_ON(mob->pt_level == VMW_MOBFMT_PTDEPTH_2);
    156 
    157 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    158 	otable->page_table = mob;
    159 
    160 	return 0;
    161 
    162 out_no_fifo:
    163 out_no_populate:
    164 	vmw_mob_destroy(mob);
    165 	return ret;
    166 }
    167 
    168 /*
    169  * vmw_takedown_otable_base - Issue an object table base takedown command
    170  * to the device
    171  *
    172  * @dev_priv:       Pointer to a device private structure
    173  * @type:           Type of object table base
    174  *
    175  */
    176 static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
    177 				     SVGAOTableType type,
    178 				     struct vmw_otable *otable)
    179 {
    180 	struct {
    181 		SVGA3dCmdHeader header;
    182 		SVGA3dCmdSetOTableBase body;
    183 	} *cmd;
    184 	struct ttm_buffer_object *bo;
    185 
    186 	if (otable->page_table == NULL)
    187 		return;
    188 
    189 	bo = otable->page_table->pt_bo;
    190 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    191 	if (unlikely(cmd == NULL)) {
    192 		DRM_ERROR("Failed reserving FIFO space for OTable "
    193 			  "takedown.\n");
    194 	} else {
    195 		memset(cmd, 0, sizeof(*cmd));
    196 		cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
    197 		cmd->header.size = sizeof(cmd->body);
    198 		cmd->body.type = type;
    199 		cmd->body.baseAddress = 0;
    200 		cmd->body.sizeInBytes = 0;
    201 		cmd->body.validSizeInBytes = 0;
    202 		cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
    203 		vmw_fifo_commit(dev_priv, sizeof(*cmd));
    204 	}
    205 
    206 	if (bo) {
    207 		int ret;
    208 
    209 		ret = ttm_bo_reserve(bo, false, true, false, NULL);
    210 		BUG_ON(ret != 0);
    211 
    212 		vmw_fence_single_bo(bo, NULL);
    213 		ttm_bo_unreserve(bo);
    214 	}
    215 
    216 	vmw_mob_destroy(otable->page_table);
    217 	otable->page_table = NULL;
    218 }
    219 
    220 /*
    221  * vmw_otables_setup - Set up guest backed memory object tables
    222  *
    223  * @dev_priv:       Pointer to a device private structure
    224  *
    225  * Takes care of the device guest backed surface
    226  * initialization, by setting up the guest backed memory object tables.
    227  * Returns 0 on success and various error codes on failure. A succesful return
    228  * means the object tables can be taken down using the vmw_otables_takedown
    229  * function.
    230  */
    231 int vmw_otables_setup(struct vmw_private *dev_priv)
    232 {
    233 	unsigned long offset;
    234 	unsigned long bo_size;
    235 	struct vmw_otable *otables;
    236 	SVGAOTableType i;
    237 	int ret;
    238 
    239 	otables = kzalloc(SVGA_OTABLE_DX9_MAX * sizeof(*otables),
    240 			  GFP_KERNEL);
    241 	if (unlikely(otables == NULL)) {
    242 		DRM_ERROR("Failed to allocate space for otable "
    243 			  "metadata.\n");
    244 		return -ENOMEM;
    245 	}
    246 
    247 	otables[SVGA_OTABLE_MOB].size =
    248 		VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE;
    249 	otables[SVGA_OTABLE_SURFACE].size =
    250 		VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE;
    251 	otables[SVGA_OTABLE_CONTEXT].size =
    252 		VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE;
    253 	otables[SVGA_OTABLE_SHADER].size =
    254 		VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE;
    255 	otables[SVGA_OTABLE_SCREEN_TARGET].size =
    256 		VMWGFX_NUM_GB_SCREEN_TARGET *
    257 		SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE;
    258 
    259 	bo_size = 0;
    260 	for (i = 0; i < SVGA_OTABLE_DX9_MAX; ++i) {
    261 		otables[i].size =
    262 			(otables[i].size + PAGE_SIZE - 1) & PAGE_MASK;
    263 		bo_size += otables[i].size;
    264 	}
    265 
    266 	ret = ttm_bo_create(&dev_priv->bdev, bo_size,
    267 			    ttm_bo_type_device,
    268 			    &vmw_sys_ne_placement,
    269 			    0, false, NULL,
    270 			    &dev_priv->otable_bo);
    271 
    272 	if (unlikely(ret != 0))
    273 		goto out_no_bo;
    274 
    275 	ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, NULL);
    276 	BUG_ON(ret != 0);
    277 	ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm);
    278 	if (unlikely(ret != 0))
    279 		goto out_unreserve;
    280 	ret = vmw_bo_map_dma(dev_priv->otable_bo);
    281 	if (unlikely(ret != 0))
    282 		goto out_unreserve;
    283 
    284 	ttm_bo_unreserve(dev_priv->otable_bo);
    285 
    286 	offset = 0;
    287 	for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) {
    288 		ret = vmw_setup_otable_base(dev_priv, i, offset,
    289 					    &otables[i]);
    290 		if (unlikely(ret != 0))
    291 			goto out_no_setup;
    292 		offset += otables[i].size;
    293 	}
    294 
    295 	dev_priv->otables = otables;
    296 	return 0;
    297 
    298 out_unreserve:
    299 	ttm_bo_unreserve(dev_priv->otable_bo);
    300 out_no_setup:
    301 	for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)
    302 		vmw_takedown_otable_base(dev_priv, i, &otables[i]);
    303 
    304 	ttm_bo_unref(&dev_priv->otable_bo);
    305 out_no_bo:
    306 	kfree(otables);
    307 	return ret;
    308 }
    309 
    310 
    311 /*
    312  * vmw_otables_takedown - Take down guest backed memory object tables
    313  *
    314  * @dev_priv:       Pointer to a device private structure
    315  *
    316  * Take down the Guest Memory Object tables.
    317  */
    318 void vmw_otables_takedown(struct vmw_private *dev_priv)
    319 {
    320 	SVGAOTableType i;
    321 	struct ttm_buffer_object *bo = dev_priv->otable_bo;
    322 	int ret;
    323 
    324 	for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)
    325 		vmw_takedown_otable_base(dev_priv, i,
    326 					 &dev_priv->otables[i]);
    327 
    328 	ret = ttm_bo_reserve(bo, false, true, false, NULL);
    329 	BUG_ON(ret != 0);
    330 
    331 	vmw_fence_single_bo(bo, NULL);
    332 	ttm_bo_unreserve(bo);
    333 
    334 	ttm_bo_unref(&dev_priv->otable_bo);
    335 	kfree(dev_priv->otables);
    336 	dev_priv->otables = NULL;
    337 }
    338 
    339 
    340 /*
    341  * vmw_mob_calculate_pt_pages - Calculate the number of page table pages
    342  * needed for a guest backed memory object.
    343  *
    344  * @data_pages:  Number of data pages in the memory object buffer.
    345  */
    346 static unsigned long vmw_mob_calculate_pt_pages(unsigned long data_pages)
    347 {
    348 	unsigned long data_size = data_pages * PAGE_SIZE;
    349 	unsigned long tot_size = 0;
    350 
    351 	while (likely(data_size > PAGE_SIZE)) {
    352 		data_size = DIV_ROUND_UP(data_size, PAGE_SIZE);
    353 		data_size *= VMW_PPN_SIZE;
    354 		tot_size += (data_size + PAGE_SIZE - 1) & PAGE_MASK;
    355 	}
    356 
    357 	return tot_size >> PAGE_SHIFT;
    358 }
    359 
    360 /*
    361  * vmw_mob_create - Create a mob, but don't populate it.
    362  *
    363  * @data_pages:  Number of data pages of the underlying buffer object.
    364  */
    365 struct vmw_mob *vmw_mob_create(unsigned long data_pages)
    366 {
    367 	struct vmw_mob *mob = kzalloc(sizeof(*mob), GFP_KERNEL);
    368 
    369 	if (unlikely(mob == NULL))
    370 		return NULL;
    371 
    372 	mob->num_pages = vmw_mob_calculate_pt_pages(data_pages);
    373 
    374 	return mob;
    375 }
    376 
    377 /*
    378  * vmw_mob_pt_populate - Populate the mob pagetable
    379  *
    380  * @mob:         Pointer to the mob the pagetable of which we want to
    381  *               populate.
    382  *
    383  * This function allocates memory to be used for the pagetable, and
    384  * adjusts TTM memory accounting accordingly. Returns ENOMEM if
    385  * memory resources aren't sufficient and may cause TTM buffer objects
    386  * to be swapped out by using the TTM memory accounting function.
    387  */
    388 static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
    389 			       struct vmw_mob *mob)
    390 {
    391 	int ret;
    392 	BUG_ON(mob->pt_bo != NULL);
    393 
    394 	ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE,
    395 			    ttm_bo_type_device,
    396 			    &vmw_sys_ne_placement,
    397 			    0, false, NULL, &mob->pt_bo);
    398 	if (unlikely(ret != 0))
    399 		return ret;
    400 
    401 	ret = ttm_bo_reserve(mob->pt_bo, false, true, false, NULL);
    402 
    403 	BUG_ON(ret != 0);
    404 	ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm);
    405 	if (unlikely(ret != 0))
    406 		goto out_unreserve;
    407 	ret = vmw_bo_map_dma(mob->pt_bo);
    408 	if (unlikely(ret != 0))
    409 		goto out_unreserve;
    410 
    411 	ttm_bo_unreserve(mob->pt_bo);
    412 
    413 	return 0;
    414 
    415 out_unreserve:
    416 	ttm_bo_unreserve(mob->pt_bo);
    417 	ttm_bo_unref(&mob->pt_bo);
    418 
    419 	return ret;
    420 }
    421 
    422 /**
    423  * vmw_mob_assign_ppn - Assign a value to a page table entry
    424  *
    425  * @addr: Pointer to pointer to page table entry.
    426  * @val: The page table entry
    427  *
    428  * Assigns a value to a page table entry pointed to by *@addr and increments
    429  * *@addr according to the page table entry size.
    430  */
    431 #if (VMW_PPN_SIZE == 8)
    432 static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val)
    433 {
    434 	*((__le64 *) *addr) = cpu_to_le64(val >> PAGE_SHIFT);
    435 	*addr += 2;
    436 }
    437 #else
    438 static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val)
    439 {
    440 	*(*addr)++ = cpu_to_le32(val >> PAGE_SHIFT);
    441 }
    442 #endif
    443 
    444 /*
    445  * vmw_mob_build_pt - Build a pagetable
    446  *
    447  * @data_addr:      Array of DMA addresses to the underlying buffer
    448  *                  object's data pages.
    449  * @num_data_pages: Number of buffer object data pages.
    450  * @pt_pages:       Array of page pointers to the page table pages.
    451  *
    452  * Returns the number of page table pages actually used.
    453  * Uses atomic kmaps of highmem pages to avoid TLB thrashing.
    454  */
    455 static unsigned long vmw_mob_build_pt(struct vmw_piter *data_iter,
    456 				      unsigned long num_data_pages,
    457 				      struct vmw_piter *pt_iter)
    458 {
    459 	unsigned long pt_size = num_data_pages * VMW_PPN_SIZE;
    460 	unsigned long num_pt_pages = DIV_ROUND_UP(pt_size, PAGE_SIZE);
    461 	unsigned long pt_page;
    462 	__le32 *addr, *save_addr;
    463 	unsigned long i;
    464 	struct page *page;
    465 
    466 	for (pt_page = 0; pt_page < num_pt_pages; ++pt_page) {
    467 		page = vmw_piter_page(pt_iter);
    468 
    469 		save_addr = addr = kmap_atomic(page);
    470 
    471 		for (i = 0; i < PAGE_SIZE / VMW_PPN_SIZE; ++i) {
    472 			vmw_mob_assign_ppn(&addr,
    473 					   vmw_piter_dma_addr(data_iter));
    474 			if (unlikely(--num_data_pages == 0))
    475 				break;
    476 			WARN_ON(!vmw_piter_next(data_iter));
    477 		}
    478 		kunmap_atomic(save_addr);
    479 		vmw_piter_next(pt_iter);
    480 	}
    481 
    482 	return num_pt_pages;
    483 }
    484 
    485 /*
    486  * vmw_mob_build_pt - Set up a multilevel mob pagetable
    487  *
    488  * @mob:            Pointer to a mob whose page table needs setting up.
    489  * @data_addr       Array of DMA addresses to the buffer object's data
    490  *                  pages.
    491  * @num_data_pages: Number of buffer object data pages.
    492  *
    493  * Uses tail recursion to set up a multilevel mob page table.
    494  */
    495 static void vmw_mob_pt_setup(struct vmw_mob *mob,
    496 			     struct vmw_piter data_iter,
    497 			     unsigned long num_data_pages)
    498 {
    499 	unsigned long num_pt_pages = 0;
    500 	struct ttm_buffer_object *bo = mob->pt_bo;
    501 	struct vmw_piter save_pt_iter;
    502 	struct vmw_piter pt_iter;
    503 	const struct vmw_sg_table *vsgt;
    504 	int ret;
    505 
    506 	ret = ttm_bo_reserve(bo, false, true, false, NULL);
    507 	BUG_ON(ret != 0);
    508 
    509 	vsgt = vmw_bo_sg_table(bo);
    510 	vmw_piter_start(&pt_iter, vsgt, 0);
    511 	BUG_ON(!vmw_piter_next(&pt_iter));
    512 	mob->pt_level = 0;
    513 	while (likely(num_data_pages > 1)) {
    514 		++mob->pt_level;
    515 		BUG_ON(mob->pt_level > 2);
    516 		save_pt_iter = pt_iter;
    517 		num_pt_pages = vmw_mob_build_pt(&data_iter, num_data_pages,
    518 						&pt_iter);
    519 		data_iter = save_pt_iter;
    520 		num_data_pages = num_pt_pages;
    521 	}
    522 
    523 	mob->pt_root_page = vmw_piter_dma_addr(&save_pt_iter);
    524 	ttm_bo_unreserve(bo);
    525 }
    526 
    527 /*
    528  * vmw_mob_destroy - Destroy a mob, unpopulating first if necessary.
    529  *
    530  * @mob:            Pointer to a mob to destroy.
    531  */
    532 void vmw_mob_destroy(struct vmw_mob *mob)
    533 {
    534 	if (mob->pt_bo)
    535 		ttm_bo_unref(&mob->pt_bo);
    536 	kfree(mob);
    537 }
    538 
    539 /*
    540  * vmw_mob_unbind - Hide a mob from the device.
    541  *
    542  * @dev_priv:       Pointer to a device private.
    543  * @mob_id:         Device id of the mob to unbind.
    544  */
    545 void vmw_mob_unbind(struct vmw_private *dev_priv,
    546 		    struct vmw_mob *mob)
    547 {
    548 	struct {
    549 		SVGA3dCmdHeader header;
    550 		SVGA3dCmdDestroyGBMob body;
    551 	} *cmd;
    552 	int ret;
    553 	struct ttm_buffer_object *bo = mob->pt_bo;
    554 
    555 	if (bo) {
    556 		ret = ttm_bo_reserve(bo, false, true, false, NULL);
    557 		/*
    558 		 * Noone else should be using this buffer.
    559 		 */
    560 		BUG_ON(ret != 0);
    561 	}
    562 
    563 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    564 	if (unlikely(cmd == NULL)) {
    565 		DRM_ERROR("Failed reserving FIFO space for Memory "
    566 			  "Object unbinding.\n");
    567 	} else {
    568 		cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
    569 		cmd->header.size = sizeof(cmd->body);
    570 		cmd->body.mobid = mob->id;
    571 		vmw_fifo_commit(dev_priv, sizeof(*cmd));
    572 	}
    573 	if (bo) {
    574 		vmw_fence_single_bo(bo, NULL);
    575 		ttm_bo_unreserve(bo);
    576 	}
    577 	vmw_3d_resource_dec(dev_priv, false);
    578 }
    579 
    580 /*
    581  * vmw_mob_bind - Make a mob visible to the device after first
    582  *                populating it if necessary.
    583  *
    584  * @dev_priv:       Pointer to a device private.
    585  * @mob:            Pointer to the mob we're making visible.
    586  * @data_addr:      Array of DMA addresses to the data pages of the underlying
    587  *                  buffer object.
    588  * @num_data_pages: Number of data pages of the underlying buffer
    589  *                  object.
    590  * @mob_id:         Device id of the mob to bind
    591  *
    592  * This function is intended to be interfaced with the ttm_tt backend
    593  * code.
    594  */
    595 int vmw_mob_bind(struct vmw_private *dev_priv,
    596 		 struct vmw_mob *mob,
    597 		 const struct vmw_sg_table *vsgt,
    598 		 unsigned long num_data_pages,
    599 		 int32_t mob_id)
    600 {
    601 	int ret;
    602 	bool pt_set_up = false;
    603 	struct vmw_piter data_iter;
    604 	struct {
    605 		SVGA3dCmdHeader header;
    606 		SVGA3dCmdDefineGBMob64 body;
    607 	} *cmd;
    608 
    609 	mob->id = mob_id;
    610 	vmw_piter_start(&data_iter, vsgt, 0);
    611 	if (unlikely(!vmw_piter_next(&data_iter)))
    612 		return 0;
    613 
    614 	if (likely(num_data_pages == 1)) {
    615 		mob->pt_level = VMW_MOBFMT_PTDEPTH_0;
    616 		mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
    617 	} else if (vsgt->num_regions == 1) {
    618 		mob->pt_level = SVGA3D_MOBFMT_RANGE;
    619 		mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
    620 	} else if (unlikely(mob->pt_bo == NULL)) {
    621 		ret = vmw_mob_pt_populate(dev_priv, mob);
    622 		if (unlikely(ret != 0))
    623 			return ret;
    624 
    625 		vmw_mob_pt_setup(mob, data_iter, num_data_pages);
    626 		pt_set_up = true;
    627 		mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1;
    628 	}
    629 
    630 	(void) vmw_3d_resource_inc(dev_priv, false);
    631 
    632 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
    633 	if (unlikely(cmd == NULL)) {
    634 		DRM_ERROR("Failed reserving FIFO space for Memory "
    635 			  "Object binding.\n");
    636 		goto out_no_cmd_space;
    637 	}
    638 
    639 	cmd->header.id = SVGA_3D_CMD_DEFINE_GB_MOB64;
    640 	cmd->header.size = sizeof(cmd->body);
    641 	cmd->body.mobid = mob_id;
    642 	cmd->body.ptDepth = mob->pt_level;
    643 	cmd->body.base = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT);
    644 	cmd->body.sizeInBytes = num_data_pages * PAGE_SIZE;
    645 
    646 	vmw_fifo_commit(dev_priv, sizeof(*cmd));
    647 
    648 	return 0;
    649 
    650 out_no_cmd_space:
    651 	vmw_3d_resource_dec(dev_priv, false);
    652 	if (pt_set_up)
    653 		ttm_bo_unref(&mob->pt_bo);
    654 
    655 	return -ENOMEM;
    656 }
    657