xref: /linux/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c (revision 4b660dbd9ee2059850fd30e0df420ca7a38a1856)
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
3  *
4  * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include "vmwgfx_bo.h"
29 #include "vmwgfx_drv.h"
30 #include <drm/ttm/ttm_placement.h>
31 
32 static const struct ttm_place vram_placement_flags = {
33 	.fpfn = 0,
34 	.lpfn = 0,
35 	.mem_type = TTM_PL_VRAM,
36 	.flags = 0
37 };
38 
39 static const struct ttm_place sys_placement_flags = {
40 	.fpfn = 0,
41 	.lpfn = 0,
42 	.mem_type = TTM_PL_SYSTEM,
43 	.flags = 0
44 };
45 
46 struct ttm_placement vmw_vram_placement = {
47 	.num_placement = 1,
48 	.placement = &vram_placement_flags,
49 };
50 
51 struct ttm_placement vmw_sys_placement = {
52 	.num_placement = 1,
53 	.placement = &sys_placement_flags,
54 };
55 
56 const size_t vmw_tt_size = sizeof(struct vmw_ttm_tt);
57 
58 /**
59  * __vmw_piter_non_sg_next: Helper functions to advance
60  * a struct vmw_piter iterator.
61  *
62  * @viter: Pointer to the iterator.
63  *
64  * These functions return false if past the end of the list,
65  * true otherwise. Functions are selected depending on the current
66  * DMA mapping mode.
67  */
68 static bool __vmw_piter_non_sg_next(struct vmw_piter *viter)
69 {
70 	return ++(viter->i) < viter->num_pages;
71 }
72 
73 static bool __vmw_piter_sg_next(struct vmw_piter *viter)
74 {
75 	bool ret = __vmw_piter_non_sg_next(viter);
76 
77 	return __sg_page_iter_dma_next(&viter->iter) && ret;
78 }
79 
80 
81 static dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter)
82 {
83 	return viter->addrs[viter->i];
84 }
85 
86 static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter)
87 {
88 	return sg_page_iter_dma_address(&viter->iter);
89 }
90 
91 
92 /**
93  * vmw_piter_start - Initialize a struct vmw_piter.
94  *
95  * @viter: Pointer to the iterator to initialize
96  * @vsgt: Pointer to a struct vmw_sg_table to initialize from
97  * @p_offset: Pointer offset used to update current array position
98  *
99  * Note that we're following the convention of __sg_page_iter_start, so that
100  * the iterator doesn't point to a valid page after initialization; it has
101  * to be advanced one step first.
102  */
103 void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt,
104 		     unsigned long p_offset)
105 {
106 	viter->i = p_offset - 1;
107 	viter->num_pages = vsgt->num_pages;
108 	viter->pages = vsgt->pages;
109 	switch (vsgt->mode) {
110 	case vmw_dma_alloc_coherent:
111 		viter->next = &__vmw_piter_non_sg_next;
112 		viter->dma_address = &__vmw_piter_dma_addr;
113 		viter->addrs = vsgt->addrs;
114 		break;
115 	case vmw_dma_map_populate:
116 	case vmw_dma_map_bind:
117 		viter->next = &__vmw_piter_sg_next;
118 		viter->dma_address = &__vmw_piter_sg_addr;
119 		__sg_page_iter_start(&viter->iter.base, vsgt->sgt->sgl,
120 				     vsgt->sgt->orig_nents, p_offset);
121 		break;
122 	default:
123 		BUG();
124 	}
125 }
126 
127 /**
128  * vmw_ttm_unmap_from_dma - unmap  device addresses previsouly mapped for
129  * TTM pages
130  *
131  * @vmw_tt: Pointer to a struct vmw_ttm_backend
132  *
133  * Used to free dma mappings previously mapped by vmw_ttm_map_for_dma.
134  */
135 static void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt *vmw_tt)
136 {
137 	struct device *dev = vmw_tt->dev_priv->drm.dev;
138 
139 	dma_unmap_sgtable(dev, &vmw_tt->sgt, DMA_BIDIRECTIONAL, 0);
140 	vmw_tt->sgt.nents = vmw_tt->sgt.orig_nents;
141 }
142 
143 /**
144  * vmw_ttm_map_for_dma - map TTM pages to get device addresses
145  *
146  * @vmw_tt: Pointer to a struct vmw_ttm_backend
147  *
148  * This function is used to get device addresses from the kernel DMA layer.
149  * However, it's violating the DMA API in that when this operation has been
150  * performed, it's illegal for the CPU to write to the pages without first
151  * unmapping the DMA mappings, or calling dma_sync_sg_for_cpu(). It is
152  * therefore only legal to call this function if we know that the function
153  * dma_sync_sg_for_cpu() is a NOP, and dma_sync_sg_for_device() is at most
154  * a CPU write buffer flush.
155  */
156 static int vmw_ttm_map_for_dma(struct vmw_ttm_tt *vmw_tt)
157 {
158 	struct device *dev = vmw_tt->dev_priv->drm.dev;
159 
160 	return dma_map_sgtable(dev, &vmw_tt->sgt, DMA_BIDIRECTIONAL, 0);
161 }
162 
163 /**
164  * vmw_ttm_map_dma - Make sure TTM pages are visible to the device
165  *
166  * @vmw_tt: Pointer to a struct vmw_ttm_tt
167  *
168  * Select the correct function for and make sure the TTM pages are
169  * visible to the device. Allocate storage for the device mappings.
170  * If a mapping has already been performed, indicated by the storage
171  * pointer being non NULL, the function returns success.
172  */
173 static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
174 {
175 	struct vmw_private *dev_priv = vmw_tt->dev_priv;
176 	struct vmw_sg_table *vsgt = &vmw_tt->vsgt;
177 	int ret = 0;
178 
179 	if (vmw_tt->mapped)
180 		return 0;
181 
182 	vsgt->mode = dev_priv->map_mode;
183 	vsgt->pages = vmw_tt->dma_ttm.pages;
184 	vsgt->num_pages = vmw_tt->dma_ttm.num_pages;
185 	vsgt->addrs = vmw_tt->dma_ttm.dma_address;
186 	vsgt->sgt = NULL;
187 
188 	switch (dev_priv->map_mode) {
189 	case vmw_dma_map_bind:
190 	case vmw_dma_map_populate:
191 		vsgt->sgt = &vmw_tt->sgt;
192 		ret = sg_alloc_table_from_pages_segment(
193 			&vmw_tt->sgt, vsgt->pages, vsgt->num_pages, 0,
194 			(unsigned long)vsgt->num_pages << PAGE_SHIFT,
195 			dma_get_max_seg_size(dev_priv->drm.dev), GFP_KERNEL);
196 		if (ret)
197 			goto out_sg_alloc_fail;
198 
199 		ret = vmw_ttm_map_for_dma(vmw_tt);
200 		if (unlikely(ret != 0))
201 			goto out_map_fail;
202 
203 		break;
204 	default:
205 		break;
206 	}
207 
208 	vmw_tt->mapped = true;
209 	return 0;
210 
211 out_map_fail:
212 	sg_free_table(vmw_tt->vsgt.sgt);
213 	vmw_tt->vsgt.sgt = NULL;
214 out_sg_alloc_fail:
215 	return ret;
216 }
217 
218 /**
219  * vmw_ttm_unmap_dma - Tear down any TTM page device mappings
220  *
221  * @vmw_tt: Pointer to a struct vmw_ttm_tt
222  *
223  * Tear down any previously set up device DMA mappings and free
224  * any storage space allocated for them. If there are no mappings set up,
225  * this function is a NOP.
226  */
227 static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
228 {
229 	struct vmw_private *dev_priv = vmw_tt->dev_priv;
230 
231 	if (!vmw_tt->vsgt.sgt)
232 		return;
233 
234 	switch (dev_priv->map_mode) {
235 	case vmw_dma_map_bind:
236 	case vmw_dma_map_populate:
237 		vmw_ttm_unmap_from_dma(vmw_tt);
238 		sg_free_table(vmw_tt->vsgt.sgt);
239 		vmw_tt->vsgt.sgt = NULL;
240 		break;
241 	default:
242 		break;
243 	}
244 	vmw_tt->mapped = false;
245 }
246 
247 /**
248  * vmw_bo_sg_table - Return a struct vmw_sg_table object for a
249  * TTM buffer object
250  *
251  * @bo: Pointer to a struct ttm_buffer_object
252  *
253  * Returns a pointer to a struct vmw_sg_table object. The object should
254  * not be freed after use.
255  * Note that for the device addresses to be valid, the buffer object must
256  * either be reserved or pinned.
257  */
258 const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo)
259 {
260 	struct vmw_ttm_tt *vmw_tt =
261 		container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm);
262 
263 	return &vmw_tt->vsgt;
264 }
265 
266 
267 static int vmw_ttm_bind(struct ttm_device *bdev,
268 			struct ttm_tt *ttm, struct ttm_resource *bo_mem)
269 {
270 	struct vmw_ttm_tt *vmw_be =
271 		container_of(ttm, struct vmw_ttm_tt, dma_ttm);
272 	int ret = 0;
273 
274 	if (!bo_mem)
275 		return -EINVAL;
276 
277 	if (vmw_be->bound)
278 		return 0;
279 
280 	ret = vmw_ttm_map_dma(vmw_be);
281 	if (unlikely(ret != 0))
282 		return ret;
283 
284 	vmw_be->gmr_id = bo_mem->start;
285 	vmw_be->mem_type = bo_mem->mem_type;
286 
287 	switch (bo_mem->mem_type) {
288 	case VMW_PL_GMR:
289 		ret = vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
290 				    ttm->num_pages, vmw_be->gmr_id);
291 		break;
292 	case VMW_PL_MOB:
293 		if (unlikely(vmw_be->mob == NULL)) {
294 			vmw_be->mob =
295 				vmw_mob_create(ttm->num_pages);
296 			if (unlikely(vmw_be->mob == NULL))
297 				return -ENOMEM;
298 		}
299 
300 		ret = vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob,
301 				    &vmw_be->vsgt, ttm->num_pages,
302 				    vmw_be->gmr_id);
303 		break;
304 	case VMW_PL_SYSTEM:
305 		/* Nothing to be done for a system bind */
306 		break;
307 	default:
308 		BUG();
309 	}
310 	vmw_be->bound = true;
311 	return ret;
312 }
313 
314 static void vmw_ttm_unbind(struct ttm_device *bdev,
315 			   struct ttm_tt *ttm)
316 {
317 	struct vmw_ttm_tt *vmw_be =
318 		container_of(ttm, struct vmw_ttm_tt, dma_ttm);
319 
320 	if (!vmw_be->bound)
321 		return;
322 
323 	switch (vmw_be->mem_type) {
324 	case VMW_PL_GMR:
325 		vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
326 		break;
327 	case VMW_PL_MOB:
328 		vmw_mob_unbind(vmw_be->dev_priv, vmw_be->mob);
329 		break;
330 	case VMW_PL_SYSTEM:
331 		break;
332 	default:
333 		BUG();
334 	}
335 
336 	if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind)
337 		vmw_ttm_unmap_dma(vmw_be);
338 	vmw_be->bound = false;
339 }
340 
341 
342 static void vmw_ttm_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
343 {
344 	struct vmw_ttm_tt *vmw_be =
345 		container_of(ttm, struct vmw_ttm_tt, dma_ttm);
346 
347 	vmw_ttm_unmap_dma(vmw_be);
348 	ttm_tt_fini(ttm);
349 	if (vmw_be->mob)
350 		vmw_mob_destroy(vmw_be->mob);
351 
352 	kfree(vmw_be);
353 }
354 
355 
356 static int vmw_ttm_populate(struct ttm_device *bdev,
357 			    struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
358 {
359 	int ret;
360 
361 	/* TODO: maybe completely drop this ? */
362 	if (ttm_tt_is_populated(ttm))
363 		return 0;
364 
365 	ret = ttm_pool_alloc(&bdev->pool, ttm, ctx);
366 
367 	return ret;
368 }
369 
370 static void vmw_ttm_unpopulate(struct ttm_device *bdev,
371 			       struct ttm_tt *ttm)
372 {
373 	struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
374 						 dma_ttm);
375 
376 	vmw_ttm_unbind(bdev, ttm);
377 
378 	if (vmw_tt->mob) {
379 		vmw_mob_destroy(vmw_tt->mob);
380 		vmw_tt->mob = NULL;
381 	}
382 
383 	vmw_ttm_unmap_dma(vmw_tt);
384 
385 	ttm_pool_free(&bdev->pool, ttm);
386 }
387 
388 static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
389 					uint32_t page_flags)
390 {
391 	struct vmw_ttm_tt *vmw_be;
392 	int ret;
393 
394 	vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL);
395 	if (!vmw_be)
396 		return NULL;
397 
398 	vmw_be->dev_priv = vmw_priv_from_ttm(bo->bdev);
399 	vmw_be->mob = NULL;
400 
401 	if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
402 		ret = ttm_sg_tt_init(&vmw_be->dma_ttm, bo, page_flags,
403 				     ttm_cached);
404 	else
405 		ret = ttm_tt_init(&vmw_be->dma_ttm, bo, page_flags,
406 				  ttm_cached, 0);
407 	if (unlikely(ret != 0))
408 		goto out_no_init;
409 
410 	return &vmw_be->dma_ttm;
411 out_no_init:
412 	kfree(vmw_be);
413 	return NULL;
414 }
415 
416 static void vmw_evict_flags(struct ttm_buffer_object *bo,
417 		     struct ttm_placement *placement)
418 {
419 	*placement = vmw_sys_placement;
420 }
421 
422 static int vmw_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem)
423 {
424 	struct vmw_private *dev_priv = vmw_priv_from_ttm(bdev);
425 
426 	switch (mem->mem_type) {
427 	case TTM_PL_SYSTEM:
428 	case VMW_PL_SYSTEM:
429 	case VMW_PL_GMR:
430 	case VMW_PL_MOB:
431 		return 0;
432 	case TTM_PL_VRAM:
433 		mem->bus.offset = (mem->start << PAGE_SHIFT) +
434 			dev_priv->vram_start;
435 		mem->bus.is_iomem = true;
436 		mem->bus.caching = ttm_cached;
437 		break;
438 	default:
439 		return -EINVAL;
440 	}
441 	return 0;
442 }
443 
444 /**
445  * vmw_move_notify - TTM move_notify_callback
446  *
447  * @bo: The TTM buffer object about to move.
448  * @old_mem: The old memory where we move from
449  * @new_mem: The struct ttm_resource indicating to what memory
450  *       region the move is taking place.
451  *
452  * Calls move_notify for all subsystems needing it.
453  * (currently only resources).
454  */
455 static void vmw_move_notify(struct ttm_buffer_object *bo,
456 			    struct ttm_resource *old_mem,
457 			    struct ttm_resource *new_mem)
458 {
459 	vmw_bo_move_notify(bo, new_mem);
460 	vmw_query_move_notify(bo, old_mem, new_mem);
461 }
462 
463 
464 /**
465  * vmw_swap_notify - TTM move_notify_callback
466  *
467  * @bo: The TTM buffer object about to be swapped out.
468  */
469 static void vmw_swap_notify(struct ttm_buffer_object *bo)
470 {
471 	vmw_bo_swap_notify(bo);
472 	(void) ttm_bo_wait(bo, false, false);
473 }
474 
475 static bool vmw_memtype_is_system(uint32_t mem_type)
476 {
477 	return mem_type == TTM_PL_SYSTEM || mem_type == VMW_PL_SYSTEM;
478 }
479 
480 static int vmw_move(struct ttm_buffer_object *bo,
481 		    bool evict,
482 		    struct ttm_operation_ctx *ctx,
483 		    struct ttm_resource *new_mem,
484 		    struct ttm_place *hop)
485 {
486 	struct ttm_resource_manager *new_man;
487 	struct ttm_resource_manager *old_man = NULL;
488 	int ret = 0;
489 
490 	new_man = ttm_manager_type(bo->bdev, new_mem->mem_type);
491 	if (bo->resource)
492 		old_man = ttm_manager_type(bo->bdev, bo->resource->mem_type);
493 
494 	if (new_man->use_tt && !vmw_memtype_is_system(new_mem->mem_type)) {
495 		ret = vmw_ttm_bind(bo->bdev, bo->ttm, new_mem);
496 		if (ret)
497 			return ret;
498 	}
499 
500 	if (!bo->resource || (bo->resource->mem_type == TTM_PL_SYSTEM &&
501 			      bo->ttm == NULL)) {
502 		ttm_bo_move_null(bo, new_mem);
503 		return 0;
504 	}
505 
506 	vmw_move_notify(bo, bo->resource, new_mem);
507 
508 	if (old_man && old_man->use_tt && new_man->use_tt) {
509 		if (vmw_memtype_is_system(bo->resource->mem_type)) {
510 			ttm_bo_move_null(bo, new_mem);
511 			return 0;
512 		}
513 		ret = ttm_bo_wait_ctx(bo, ctx);
514 		if (ret)
515 			goto fail;
516 
517 		vmw_ttm_unbind(bo->bdev, bo->ttm);
518 		ttm_resource_free(bo, &bo->resource);
519 		ttm_bo_assign_mem(bo, new_mem);
520 		return 0;
521 	} else {
522 		ret = ttm_bo_move_memcpy(bo, ctx, new_mem);
523 		if (ret)
524 			goto fail;
525 	}
526 	return 0;
527 fail:
528 	vmw_move_notify(bo, new_mem, bo->resource);
529 	return ret;
530 }
531 
532 struct ttm_device_funcs vmw_bo_driver = {
533 	.ttm_tt_create = &vmw_ttm_tt_create,
534 	.ttm_tt_populate = &vmw_ttm_populate,
535 	.ttm_tt_unpopulate = &vmw_ttm_unpopulate,
536 	.ttm_tt_destroy = &vmw_ttm_destroy,
537 	.eviction_valuable = ttm_bo_eviction_valuable,
538 	.evict_flags = vmw_evict_flags,
539 	.move = vmw_move,
540 	.swap_notify = vmw_swap_notify,
541 	.io_mem_reserve = &vmw_ttm_io_mem_reserve,
542 };
543 
544 int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
545 			       size_t bo_size, u32 domain,
546 			       struct vmw_bo **bo_p)
547 {
548 	struct ttm_operation_ctx ctx = {
549 		.interruptible = false,
550 		.no_wait_gpu = false
551 	};
552 	struct vmw_bo *vbo;
553 	int ret;
554 	struct vmw_bo_params bo_params = {
555 		.domain = domain,
556 		.busy_domain = domain,
557 		.bo_type = ttm_bo_type_kernel,
558 		.size = bo_size,
559 		.pin = true
560 	};
561 
562 	ret = vmw_bo_create(dev_priv, &bo_params, &vbo);
563 	if (unlikely(ret != 0))
564 		return ret;
565 
566 	ret = ttm_bo_reserve(&vbo->tbo, false, true, NULL);
567 	BUG_ON(ret != 0);
568 	ret = vmw_ttm_populate(vbo->tbo.bdev, vbo->tbo.ttm, &ctx);
569 	if (likely(ret == 0)) {
570 		struct vmw_ttm_tt *vmw_tt =
571 			container_of(vbo->tbo.ttm, struct vmw_ttm_tt, dma_ttm);
572 		ret = vmw_ttm_map_dma(vmw_tt);
573 	}
574 
575 	ttm_bo_unreserve(&vbo->tbo);
576 
577 	if (likely(ret == 0))
578 		*bo_p = vbo;
579 	return ret;
580 }
581