]> Git Repo - linux.git/blob - drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / vmwgfx / vmwgfx_bo.c
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /**************************************************************************
3  *
4  * Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term
5  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25  * USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28
29 #include "vmwgfx_bo.h"
30 #include "vmwgfx_drv.h"
31 #include "vmwgfx_resource_priv.h"
32
33 #include <drm/ttm/ttm_placement.h>
34
35 static void vmw_bo_release(struct vmw_bo *vbo)
36 {
37         struct vmw_resource *res;
38
39         WARN_ON(vbo->tbo.base.funcs &&
40                 kref_read(&vbo->tbo.base.refcount) != 0);
41         vmw_bo_unmap(vbo);
42
43         xa_destroy(&vbo->detached_resources);
44         WARN_ON(vbo->is_dumb && !vbo->dumb_surface);
45         if (vbo->is_dumb && vbo->dumb_surface) {
46                 res = &vbo->dumb_surface->res;
47                 WARN_ON(vbo != res->guest_memory_bo);
48                 WARN_ON(!res->guest_memory_bo);
49                 if (res->guest_memory_bo) {
50                         /* Reserve and switch the backing mob. */
51                         mutex_lock(&res->dev_priv->cmdbuf_mutex);
52                         (void)vmw_resource_reserve(res, false, true);
53                         vmw_resource_mob_detach(res);
54                         if (res->coherent)
55                                 vmw_bo_dirty_release(res->guest_memory_bo);
56                         res->guest_memory_bo = NULL;
57                         res->guest_memory_offset = 0;
58                         vmw_resource_unreserve(res, false, false, false, NULL,
59                                                0);
60                         mutex_unlock(&res->dev_priv->cmdbuf_mutex);
61                 }
62                 vmw_surface_unreference(&vbo->dumb_surface);
63         }
64         drm_gem_object_release(&vbo->tbo.base);
65 }
66
67 /**
68  * vmw_bo_free - vmw_bo destructor
69  *
70  * @bo: Pointer to the embedded struct ttm_buffer_object
71  */
72 static void vmw_bo_free(struct ttm_buffer_object *bo)
73 {
74         struct vmw_bo *vbo = to_vmw_bo(&bo->base);
75
76         WARN_ON(vbo->dirty);
77         WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree));
78         vmw_bo_release(vbo);
79         kfree(vbo);
80 }
81
82 /**
83  * vmw_bo_pin_in_placement - Validate a buffer to placement.
84  *
85  * @dev_priv:  Driver private.
86  * @buf:  DMA buffer to move.
87  * @placement:  The placement to pin it.
88  * @interruptible:  Use interruptible wait.
89  * Return: Zero on success, Negative error code on failure. In particular
90  * -ERESTARTSYS if interrupted by a signal
91  */
92 static int vmw_bo_pin_in_placement(struct vmw_private *dev_priv,
93                                    struct vmw_bo *buf,
94                                    struct ttm_placement *placement,
95                                    bool interruptible)
96 {
97         struct ttm_operation_ctx ctx = {interruptible, false };
98         struct ttm_buffer_object *bo = &buf->tbo;
99         int ret;
100
101         vmw_execbuf_release_pinned_bo(dev_priv);
102
103         ret = ttm_bo_reserve(bo, interruptible, false, NULL);
104         if (unlikely(ret != 0))
105                 goto err;
106
107         ret = ttm_bo_validate(bo, placement, &ctx);
108         if (!ret)
109                 vmw_bo_pin_reserved(buf, true);
110
111         ttm_bo_unreserve(bo);
112 err:
113         return ret;
114 }
115
116
117 /**
118  * vmw_bo_pin_in_vram_or_gmr - Move a buffer to vram or gmr.
119  *
120  * This function takes the reservation_sem in write mode.
121  * Flushes and unpins the query bo to avoid failures.
122  *
123  * @dev_priv:  Driver private.
124  * @buf:  DMA buffer to move.
125  * @interruptible:  Use interruptible wait.
126  * Return: Zero on success, Negative error code on failure. In particular
127  * -ERESTARTSYS if interrupted by a signal
128  */
129 int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv,
130                               struct vmw_bo *buf,
131                               bool interruptible)
132 {
133         struct ttm_operation_ctx ctx = {interruptible, false };
134         struct ttm_buffer_object *bo = &buf->tbo;
135         int ret;
136
137         vmw_execbuf_release_pinned_bo(dev_priv);
138
139         ret = ttm_bo_reserve(bo, interruptible, false, NULL);
140         if (unlikely(ret != 0))
141                 goto err;
142
143         vmw_bo_placement_set(buf,
144                              VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
145                              VMW_BO_DOMAIN_GMR);
146         ret = ttm_bo_validate(bo, &buf->placement, &ctx);
147         if (likely(ret == 0) || ret == -ERESTARTSYS)
148                 goto out_unreserve;
149
150         vmw_bo_placement_set(buf,
151                              VMW_BO_DOMAIN_VRAM,
152                              VMW_BO_DOMAIN_VRAM);
153         ret = ttm_bo_validate(bo, &buf->placement, &ctx);
154
155 out_unreserve:
156         if (!ret)
157                 vmw_bo_pin_reserved(buf, true);
158
159         ttm_bo_unreserve(bo);
160 err:
161         return ret;
162 }
163
164
165 /**
166  * vmw_bo_pin_in_vram - Move a buffer to vram.
167  *
168  * This function takes the reservation_sem in write mode.
169  * Flushes and unpins the query bo to avoid failures.
170  *
171  * @dev_priv:  Driver private.
172  * @buf:  DMA buffer to move.
173  * @interruptible:  Use interruptible wait.
174  * Return: Zero on success, Negative error code on failure. In particular
175  * -ERESTARTSYS if interrupted by a signal
176  */
177 int vmw_bo_pin_in_vram(struct vmw_private *dev_priv,
178                        struct vmw_bo *buf,
179                        bool interruptible)
180 {
181         return vmw_bo_pin_in_placement(dev_priv, buf, &vmw_vram_placement,
182                                        interruptible);
183 }
184
185
186 /**
187  * vmw_bo_pin_in_start_of_vram - Move a buffer to start of vram.
188  *
189  * This function takes the reservation_sem in write mode.
190  * Flushes and unpins the query bo to avoid failures.
191  *
192  * @dev_priv:  Driver private.
193  * @buf:  DMA buffer to pin.
194  * @interruptible:  Use interruptible wait.
195  * Return: Zero on success, Negative error code on failure. In particular
196  * -ERESTARTSYS if interrupted by a signal
197  */
198 int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv,
199                                 struct vmw_bo *buf,
200                                 bool interruptible)
201 {
202         struct ttm_operation_ctx ctx = {interruptible, false };
203         struct ttm_buffer_object *bo = &buf->tbo;
204         int ret = 0;
205
206         vmw_execbuf_release_pinned_bo(dev_priv);
207         ret = ttm_bo_reserve(bo, interruptible, false, NULL);
208         if (unlikely(ret != 0))
209                 goto err_unlock;
210
211         /*
212          * Is this buffer already in vram but not at the start of it?
213          * In that case, evict it first because TTM isn't good at handling
214          * that situation.
215          */
216         if (bo->resource->mem_type == TTM_PL_VRAM &&
217             bo->resource->start < PFN_UP(bo->resource->size) &&
218             bo->resource->start > 0 &&
219             buf->tbo.pin_count == 0) {
220                 ctx.interruptible = false;
221                 vmw_bo_placement_set(buf,
222                                      VMW_BO_DOMAIN_SYS,
223                                      VMW_BO_DOMAIN_SYS);
224                 (void)ttm_bo_validate(bo, &buf->placement, &ctx);
225         }
226
227         vmw_bo_placement_set(buf,
228                              VMW_BO_DOMAIN_VRAM,
229                              VMW_BO_DOMAIN_VRAM);
230         buf->places[0].lpfn = PFN_UP(bo->resource->size);
231         ret = ttm_bo_validate(bo, &buf->placement, &ctx);
232
233         /* For some reason we didn't end up at the start of vram */
234         WARN_ON(ret == 0 && bo->resource->start != 0);
235         if (!ret)
236                 vmw_bo_pin_reserved(buf, true);
237
238         ttm_bo_unreserve(bo);
239 err_unlock:
240
241         return ret;
242 }
243
244
245 /**
246  * vmw_bo_unpin - Unpin the buffer given buffer, does not move the buffer.
247  *
248  * This function takes the reservation_sem in write mode.
249  *
250  * @dev_priv:  Driver private.
251  * @buf:  DMA buffer to unpin.
252  * @interruptible:  Use interruptible wait.
253  * Return: Zero on success, Negative error code on failure. In particular
254  * -ERESTARTSYS if interrupted by a signal
255  */
256 int vmw_bo_unpin(struct vmw_private *dev_priv,
257                  struct vmw_bo *buf,
258                  bool interruptible)
259 {
260         struct ttm_buffer_object *bo = &buf->tbo;
261         int ret;
262
263         ret = ttm_bo_reserve(bo, interruptible, false, NULL);
264         if (unlikely(ret != 0))
265                 goto err;
266
267         vmw_bo_pin_reserved(buf, false);
268
269         ttm_bo_unreserve(bo);
270
271 err:
272         return ret;
273 }
274
275 /**
276  * vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement
277  * of a buffer.
278  *
279  * @bo: Pointer to a struct ttm_buffer_object. Must be pinned or reserved.
280  * @ptr: SVGAGuestPtr returning the result.
281  */
282 void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo,
283                           SVGAGuestPtr *ptr)
284 {
285         if (bo->resource->mem_type == TTM_PL_VRAM) {
286                 ptr->gmrId = SVGA_GMR_FRAMEBUFFER;
287                 ptr->offset = bo->resource->start << PAGE_SHIFT;
288         } else {
289                 ptr->gmrId = bo->resource->start;
290                 ptr->offset = 0;
291         }
292 }
293
294
295 /**
296  * vmw_bo_pin_reserved - Pin or unpin a buffer object without moving it.
297  *
298  * @vbo: The buffer object. Must be reserved.
299  * @pin: Whether to pin or unpin.
300  *
301  */
302 void vmw_bo_pin_reserved(struct vmw_bo *vbo, bool pin)
303 {
304         struct ttm_operation_ctx ctx = { false, true };
305         struct ttm_place pl;
306         struct ttm_placement placement;
307         struct ttm_buffer_object *bo = &vbo->tbo;
308         uint32_t old_mem_type = bo->resource->mem_type;
309         int ret;
310
311         dma_resv_assert_held(bo->base.resv);
312
313         if (pin == !!bo->pin_count)
314                 return;
315
316         pl.fpfn = 0;
317         pl.lpfn = 0;
318         pl.mem_type = bo->resource->mem_type;
319         pl.flags = bo->resource->placement;
320
321         memset(&placement, 0, sizeof(placement));
322         placement.num_placement = 1;
323         placement.placement = &pl;
324
325         ret = ttm_bo_validate(bo, &placement, &ctx);
326
327         BUG_ON(ret != 0 || bo->resource->mem_type != old_mem_type);
328
329         if (pin)
330                 ttm_bo_pin(bo);
331         else
332                 ttm_bo_unpin(bo);
333 }
334
335 /**
336  * vmw_bo_map_and_cache - Map a buffer object and cache the map
337  *
338  * @vbo: The buffer object to map
339  * Return: A kernel virtual address or NULL if mapping failed.
340  *
341  * This function maps a buffer object into the kernel address space, or
342  * returns the virtual kernel address of an already existing map. The virtual
343  * address remains valid as long as the buffer object is pinned or reserved.
344  * The cached map is torn down on either
345  * 1) Buffer object move
346  * 2) Buffer object swapout
347  * 3) Buffer object destruction
348  *
349  */
350 void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
351 {
352         return vmw_bo_map_and_cache_size(vbo, vbo->tbo.base.size);
353 }
354
355 void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size)
356 {
357         struct ttm_buffer_object *bo = &vbo->tbo;
358         bool not_used;
359         void *virtual;
360         int ret;
361
362         atomic_inc(&vbo->map_count);
363
364         virtual = ttm_kmap_obj_virtual(&vbo->map, &not_used);
365         if (virtual)
366                 return virtual;
367
368         ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vbo->map);
369         if (ret)
370                 DRM_ERROR("Buffer object map failed: %d (size: bo = %zu, map = %zu).\n",
371                           ret, bo->base.size, size);
372
373         return ttm_kmap_obj_virtual(&vbo->map, &not_used);
374 }
375
376
377 /**
378  * vmw_bo_unmap - Tear down a cached buffer object map.
379  *
380  * @vbo: The buffer object whose map we are tearing down.
381  *
382  * This function tears down a cached map set up using
383  * vmw_bo_map_and_cache().
384  */
385 void vmw_bo_unmap(struct vmw_bo *vbo)
386 {
387         int map_count;
388
389         if (vbo->map.bo == NULL)
390                 return;
391
392         map_count = atomic_dec_return(&vbo->map_count);
393
394         if (!map_count) {
395                 ttm_bo_kunmap(&vbo->map);
396                 vbo->map.bo = NULL;
397         }
398 }
399
400
401 /**
402  * vmw_bo_init - Initialize a vmw buffer object
403  *
404  * @dev_priv: Pointer to the device private struct
405  * @vmw_bo: Buffer object to initialize
406  * @params: Parameters used to initialize the buffer object
407  * @destroy: The function used to delete the buffer object
408  * Returns: Zero on success, negative error code on error.
409  *
410  */
411 static int vmw_bo_init(struct vmw_private *dev_priv,
412                        struct vmw_bo *vmw_bo,
413                        struct vmw_bo_params *params,
414                        void (*destroy)(struct ttm_buffer_object *))
415 {
416         struct ttm_operation_ctx ctx = {
417                 .interruptible = params->bo_type != ttm_bo_type_kernel,
418                 .no_wait_gpu = false,
419                 .resv = params->resv,
420         };
421         struct ttm_device *bdev = &dev_priv->bdev;
422         struct drm_device *vdev = &dev_priv->drm;
423         int ret;
424
425         memset(vmw_bo, 0, sizeof(*vmw_bo));
426
427         BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3);
428         vmw_bo->tbo.priority = 3;
429         vmw_bo->res_tree = RB_ROOT;
430         xa_init(&vmw_bo->detached_resources);
431         atomic_set(&vmw_bo->map_count, 0);
432
433         params->size = ALIGN(params->size, PAGE_SIZE);
434         drm_gem_private_object_init(vdev, &vmw_bo->tbo.base, params->size);
435
436         vmw_bo_placement_set(vmw_bo, params->domain, params->busy_domain);
437         ret = ttm_bo_init_reserved(bdev, &vmw_bo->tbo, params->bo_type,
438                                    &vmw_bo->placement, 0, &ctx,
439                                    params->sg, params->resv, destroy);
440         if (unlikely(ret))
441                 return ret;
442
443         if (params->pin)
444                 ttm_bo_pin(&vmw_bo->tbo);
445         if (!params->keep_resv)
446                 ttm_bo_unreserve(&vmw_bo->tbo);
447
448         return 0;
449 }
450
451 int vmw_bo_create(struct vmw_private *vmw,
452                   struct vmw_bo_params *params,
453                   struct vmw_bo **p_bo)
454 {
455         int ret;
456
457         *p_bo = kmalloc(sizeof(**p_bo), GFP_KERNEL);
458         if (unlikely(!*p_bo)) {
459                 DRM_ERROR("Failed to allocate a buffer.\n");
460                 return -ENOMEM;
461         }
462
463         /*
464          * vmw_bo_init will delete the *p_bo object if it fails
465          */
466         ret = vmw_bo_init(vmw, *p_bo, params, vmw_bo_free);
467         if (unlikely(ret != 0))
468                 goto out_error;
469
470         return ret;
471 out_error:
472         *p_bo = NULL;
473         return ret;
474 }
475
476 /**
477  * vmw_user_bo_synccpu_grab - Grab a struct vmw_bo for cpu
478  * access, idling previous GPU operations on the buffer and optionally
479  * blocking it for further command submissions.
480  *
481  * @vmw_bo: Pointer to the buffer object being grabbed for CPU access
482  * @flags: Flags indicating how the grab should be performed.
483  * Return: Zero on success, Negative error code on error. In particular,
484  * -EBUSY will be returned if a dontblock operation is requested and the
485  * buffer object is busy, and -ERESTARTSYS will be returned if a wait is
486  * interrupted by a signal.
487  *
488  * A blocking grab will be automatically released when @tfile is closed.
489  */
490 static int vmw_user_bo_synccpu_grab(struct vmw_bo *vmw_bo,
491                                     uint32_t flags)
492 {
493         bool nonblock = !!(flags & drm_vmw_synccpu_dontblock);
494         struct ttm_buffer_object *bo = &vmw_bo->tbo;
495         int ret;
496
497         if (flags & drm_vmw_synccpu_allow_cs) {
498                 long lret;
499
500                 lret = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_READ,
501                                              true, nonblock ? 0 :
502                                              MAX_SCHEDULE_TIMEOUT);
503                 if (!lret)
504                         return -EBUSY;
505                 else if (lret < 0)
506                         return lret;
507                 return 0;
508         }
509
510         ret = ttm_bo_reserve(bo, true, nonblock, NULL);
511         if (unlikely(ret != 0))
512                 return ret;
513
514         ret = ttm_bo_wait(bo, true, nonblock);
515         if (likely(ret == 0))
516                 atomic_inc(&vmw_bo->cpu_writers);
517
518         ttm_bo_unreserve(bo);
519         if (unlikely(ret != 0))
520                 return ret;
521
522         return ret;
523 }
524
525 /**
526  * vmw_user_bo_synccpu_release - Release a previous grab for CPU access,
527  * and unblock command submission on the buffer if blocked.
528  *
529  * @filp: Identifying the caller.
530  * @handle: Handle identifying the buffer object.
531  * @flags: Flags indicating the type of release.
532  */
533 static int vmw_user_bo_synccpu_release(struct drm_file *filp,
534                                        uint32_t handle,
535                                        uint32_t flags)
536 {
537         struct vmw_bo *vmw_bo;
538         int ret = vmw_user_bo_lookup(filp, handle, &vmw_bo);
539
540         if (!ret) {
541                 if (!(flags & drm_vmw_synccpu_allow_cs)) {
542                         atomic_dec(&vmw_bo->cpu_writers);
543                 }
544                 vmw_user_bo_unref(&vmw_bo);
545         }
546
547         return ret;
548 }
549
550
551 /**
552  * vmw_user_bo_synccpu_ioctl - ioctl function implementing the synccpu
553  * functionality.
554  *
555  * @dev: Identifies the drm device.
556  * @data: Pointer to the ioctl argument.
557  * @file_priv: Identifies the caller.
558  * Return: Zero on success, negative error code on error.
559  *
560  * This function checks the ioctl arguments for validity and calls the
561  * relevant synccpu functions.
562  */
563 int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data,
564                               struct drm_file *file_priv)
565 {
566         struct drm_vmw_synccpu_arg *arg =
567                 (struct drm_vmw_synccpu_arg *) data;
568         struct vmw_bo *vbo;
569         int ret;
570
571         if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0
572             || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write |
573                                drm_vmw_synccpu_dontblock |
574                                drm_vmw_synccpu_allow_cs)) != 0) {
575                 DRM_ERROR("Illegal synccpu flags.\n");
576                 return -EINVAL;
577         }
578
579         switch (arg->op) {
580         case drm_vmw_synccpu_grab:
581                 ret = vmw_user_bo_lookup(file_priv, arg->handle, &vbo);
582                 if (unlikely(ret != 0))
583                         return ret;
584
585                 ret = vmw_user_bo_synccpu_grab(vbo, arg->flags);
586                 vmw_user_bo_unref(&vbo);
587                 if (unlikely(ret != 0)) {
588                         if (ret == -ERESTARTSYS || ret == -EBUSY)
589                                 return -EBUSY;
590                         DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n",
591                                   (unsigned int) arg->handle);
592                         return ret;
593                 }
594                 break;
595         case drm_vmw_synccpu_release:
596                 ret = vmw_user_bo_synccpu_release(file_priv,
597                                                   arg->handle,
598                                                   arg->flags);
599                 if (unlikely(ret != 0)) {
600                         DRM_ERROR("Failed synccpu release on handle 0x%08x.\n",
601                                   (unsigned int) arg->handle);
602                         return ret;
603                 }
604                 break;
605         default:
606                 DRM_ERROR("Invalid synccpu operation.\n");
607                 return -EINVAL;
608         }
609
610         return 0;
611 }
612
613 /**
614  * vmw_bo_unref_ioctl - Generic handle close ioctl.
615  *
616  * @dev: Identifies the drm device.
617  * @data: Pointer to the ioctl argument.
618  * @file_priv: Identifies the caller.
619  * Return: Zero on success, negative error code on error.
620  *
621  * This function checks the ioctl arguments for validity and closes a
622  * handle to a TTM base object, optionally freeing the object.
623  */
624 int vmw_bo_unref_ioctl(struct drm_device *dev, void *data,
625                        struct drm_file *file_priv)
626 {
627         struct drm_vmw_unref_dmabuf_arg *arg =
628             (struct drm_vmw_unref_dmabuf_arg *)data;
629
630         return drm_gem_handle_delete(file_priv, arg->handle);
631 }
632
633
634 /**
635  * vmw_user_bo_lookup - Look up a vmw user buffer object from a handle.
636  *
637  * @filp: The file the handle is registered with.
638  * @handle: The user buffer object handle
639  * @out: Pointer to a where a pointer to the embedded
640  * struct vmw_bo should be placed.
641  * Return: Zero on success, Negative error code on error.
642  *
643  * The vmw buffer object pointer will be refcounted (both ttm and gem)
644  */
645 int vmw_user_bo_lookup(struct drm_file *filp,
646                        u32 handle,
647                        struct vmw_bo **out)
648 {
649         struct drm_gem_object *gobj;
650
651         gobj = drm_gem_object_lookup(filp, handle);
652         if (!gobj) {
653                 DRM_ERROR("Invalid buffer object handle 0x%08lx.\n",
654                           (unsigned long)handle);
655                 return -ESRCH;
656         }
657
658         *out = to_vmw_bo(gobj);
659
660         return 0;
661 }
662
663 /**
664  * vmw_bo_fence_single - Utility function to fence a single TTM buffer
665  *                       object without unreserving it.
666  *
667  * @bo:             Pointer to the struct ttm_buffer_object to fence.
668  * @fence:          Pointer to the fence. If NULL, this function will
669  *                  insert a fence into the command stream..
670  *
671  * Contrary to the ttm_eu version of this function, it takes only
672  * a single buffer object instead of a list, and it also doesn't
673  * unreserve the buffer object, which needs to be done separately.
674  */
675 void vmw_bo_fence_single(struct ttm_buffer_object *bo,
676                          struct vmw_fence_obj *fence)
677 {
678         struct ttm_device *bdev = bo->bdev;
679         struct vmw_private *dev_priv = vmw_priv_from_ttm(bdev);
680         int ret;
681
682         if (fence == NULL)
683                 vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
684         else
685                 dma_fence_get(&fence->base);
686
687         ret = dma_resv_reserve_fences(bo->base.resv, 1);
688         if (!ret)
689                 dma_resv_add_fence(bo->base.resv, &fence->base,
690                                    DMA_RESV_USAGE_KERNEL);
691         else
692                 /* Last resort fallback when we are OOM */
693                 dma_fence_wait(&fence->base, false);
694         dma_fence_put(&fence->base);
695 }
696
697 /**
698  * vmw_bo_swap_notify - swapout notify callback.
699  *
700  * @bo: The buffer object to be swapped out.
701  */
702 void vmw_bo_swap_notify(struct ttm_buffer_object *bo)
703 {
704         /* Kill any cached kernel maps before swapout */
705         vmw_bo_unmap(to_vmw_bo(&bo->base));
706 }
707
708
709 /**
710  * vmw_bo_move_notify - TTM move_notify_callback
711  *
712  * @bo: The TTM buffer object about to move.
713  * @mem: The struct ttm_resource indicating to what memory
714  *       region the move is taking place.
715  *
716  * Detaches cached maps and device bindings that require that the
717  * buffer doesn't move.
718  */
719 void vmw_bo_move_notify(struct ttm_buffer_object *bo,
720                         struct ttm_resource *mem)
721 {
722         struct vmw_bo *vbo = to_vmw_bo(&bo->base);
723
724         /*
725          * Kill any cached kernel maps before move to or from VRAM.
726          * With other types of moves, the underlying pages stay the same,
727          * and the map can be kept.
728          */
729         if (mem->mem_type == TTM_PL_VRAM || bo->resource->mem_type == TTM_PL_VRAM)
730                 vmw_bo_unmap(vbo);
731
732         /*
733          * If we're moving a backup MOB out of MOB placement, then make sure we
734          * read back all resource content first, and unbind the MOB from
735          * the resource.
736          */
737         if (mem->mem_type != VMW_PL_MOB && bo->resource->mem_type == VMW_PL_MOB)
738                 vmw_resource_unbind_list(vbo);
739 }
740
741 static u32 placement_flags(u32 domain, u32 desired, u32 fallback)
742 {
743         if (desired & fallback & domain)
744                 return 0;
745
746         if (desired & domain)
747                 return TTM_PL_FLAG_DESIRED;
748
749         return TTM_PL_FLAG_FALLBACK;
750 }
751
752 static u32
753 set_placement_list(struct ttm_place *pl, u32 desired, u32 fallback)
754 {
755         u32 domain = desired | fallback;
756         u32 n = 0;
757
758         /*
759          * The placements are ordered according to our preferences
760          */
761         if (domain & VMW_BO_DOMAIN_MOB) {
762                 pl[n].mem_type = VMW_PL_MOB;
763                 pl[n].flags = placement_flags(VMW_BO_DOMAIN_MOB, desired,
764                                               fallback);
765                 pl[n].fpfn = 0;
766                 pl[n].lpfn = 0;
767                 n++;
768         }
769         if (domain & VMW_BO_DOMAIN_GMR) {
770                 pl[n].mem_type = VMW_PL_GMR;
771                 pl[n].flags = placement_flags(VMW_BO_DOMAIN_GMR, desired,
772                                               fallback);
773                 pl[n].fpfn = 0;
774                 pl[n].lpfn = 0;
775                 n++;
776         }
777         if (domain & VMW_BO_DOMAIN_VRAM) {
778                 pl[n].mem_type = TTM_PL_VRAM;
779                 pl[n].flags = placement_flags(VMW_BO_DOMAIN_VRAM, desired,
780                                               fallback);
781                 pl[n].fpfn = 0;
782                 pl[n].lpfn = 0;
783                 n++;
784         }
785         if (domain & VMW_BO_DOMAIN_WAITABLE_SYS) {
786                 pl[n].mem_type = VMW_PL_SYSTEM;
787                 pl[n].flags = placement_flags(VMW_BO_DOMAIN_WAITABLE_SYS,
788                                               desired, fallback);
789                 pl[n].fpfn = 0;
790                 pl[n].lpfn = 0;
791                 n++;
792         }
793         if (domain & VMW_BO_DOMAIN_SYS) {
794                 pl[n].mem_type = TTM_PL_SYSTEM;
795                 pl[n].flags = placement_flags(VMW_BO_DOMAIN_SYS, desired,
796                                               fallback);
797                 pl[n].fpfn = 0;
798                 pl[n].lpfn = 0;
799                 n++;
800         }
801
802         WARN_ON(!n);
803         if (!n) {
804                 pl[n].mem_type = TTM_PL_SYSTEM;
805                 pl[n].flags = 0;
806                 pl[n].fpfn = 0;
807                 pl[n].lpfn = 0;
808                 n++;
809         }
810         return n;
811 }
812
813 void vmw_bo_placement_set(struct vmw_bo *bo, u32 domain, u32 busy_domain)
814 {
815         struct ttm_device *bdev = bo->tbo.bdev;
816         struct vmw_private *vmw = vmw_priv_from_ttm(bdev);
817         struct ttm_placement *pl = &bo->placement;
818         bool mem_compatible = false;
819         u32 i;
820
821         pl->placement = bo->places;
822         pl->num_placement = set_placement_list(bo->places, domain, busy_domain);
823
824         if (drm_debug_enabled(DRM_UT_DRIVER) && bo->tbo.resource) {
825                 for (i = 0; i < pl->num_placement; ++i) {
826                         if (bo->tbo.resource->mem_type == TTM_PL_SYSTEM ||
827                             bo->tbo.resource->mem_type == pl->placement[i].mem_type)
828                                 mem_compatible = true;
829                 }
830                 if (!mem_compatible)
831                         drm_warn(&vmw->drm,
832                                  "%s: Incompatible transition from "
833                                  "bo->base.resource->mem_type = %u to domain = %u\n",
834                                  __func__, bo->tbo.resource->mem_type, domain);
835         }
836
837 }
838
839 void vmw_bo_placement_set_default_accelerated(struct vmw_bo *bo)
840 {
841         struct ttm_device *bdev = bo->tbo.bdev;
842         struct vmw_private *vmw = vmw_priv_from_ttm(bdev);
843         u32 domain = VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM;
844
845         if (vmw->has_mob)
846                 domain = VMW_BO_DOMAIN_MOB;
847
848         vmw_bo_placement_set(bo, domain, domain);
849 }
850
851 void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
852 {
853         xa_store(&vbo->detached_resources, (unsigned long)res, res, GFP_KERNEL);
854 }
855
856 void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
857 {
858         xa_erase(&vbo->detached_resources, (unsigned long)res);
859 }
860
861 struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo)
862 {
863         unsigned long index;
864         struct vmw_resource *res = NULL;
865         struct vmw_surface *surf = NULL;
866         struct rb_node *rb_itr = vbo->res_tree.rb_node;
867
868         if (vbo->is_dumb && vbo->dumb_surface) {
869                 res = &vbo->dumb_surface->res;
870                 goto out;
871         }
872
873         xa_for_each(&vbo->detached_resources, index, res) {
874                 if (res->func->res_type == vmw_res_surface)
875                         goto out;
876         }
877
878         for (rb_itr = rb_first(&vbo->res_tree); rb_itr;
879              rb_itr = rb_next(rb_itr)) {
880                 res = rb_entry(rb_itr, struct vmw_resource, mob_node);
881                 if (res->func->res_type == vmw_res_surface)
882                         goto out;
883         }
884
885 out:
886         if (res)
887                 surf = vmw_res_to_srf(res);
888         return surf;
889 }
This page took 0.085586 seconds and 4 git commands to generate.