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