Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 OR MIT */
0002 /**************************************************************************
0003  *
0004  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
0005  * All Rights Reserved.
0006  *
0007  * Permission is hereby granted, free of charge, to any person obtaining a
0008  * copy of this software and associated documentation files (the
0009  * "Software"), to deal in the Software without restriction, including
0010  * without limitation the rights to use, copy, modify, merge, publish,
0011  * distribute, sub license, and/or sell copies of the Software, and to
0012  * permit persons to whom the Software is furnished to do so, subject to
0013  * the following conditions:
0014  *
0015  * The above copyright notice and this permission notice (including the
0016  * next paragraph) shall be included in all copies or substantial portions
0017  * of the Software.
0018  *
0019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0020  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0021  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
0022  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
0023  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
0024  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
0025  * USE OR OTHER DEALINGS IN THE SOFTWARE.
0026  *
0027  **************************************************************************/
0028 
0029 #include <drm/ttm/ttm_execbuf_util.h>
0030 #include <drm/ttm/ttm_bo_driver.h>
0031 #include <drm/ttm/ttm_placement.h>
0032 #include <linux/wait.h>
0033 #include <linux/sched.h>
0034 #include <linux/module.h>
0035 
0036 static void ttm_eu_backoff_reservation_reverse(struct list_head *list,
0037                           struct ttm_validate_buffer *entry)
0038 {
0039     list_for_each_entry_continue_reverse(entry, list, head) {
0040         struct ttm_buffer_object *bo = entry->bo;
0041 
0042         dma_resv_unlock(bo->base.resv);
0043     }
0044 }
0045 
0046 void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
0047                 struct list_head *list)
0048 {
0049     struct ttm_validate_buffer *entry;
0050 
0051     if (list_empty(list))
0052         return;
0053 
0054     list_for_each_entry(entry, list, head) {
0055         struct ttm_buffer_object *bo = entry->bo;
0056 
0057         ttm_bo_move_to_lru_tail_unlocked(bo);
0058         dma_resv_unlock(bo->base.resv);
0059     }
0060 
0061     if (ticket)
0062         ww_acquire_fini(ticket);
0063 }
0064 EXPORT_SYMBOL(ttm_eu_backoff_reservation);
0065 
0066 /*
0067  * Reserve buffers for validation.
0068  *
0069  * If a buffer in the list is marked for CPU access, we back off and
0070  * wait for that buffer to become free for GPU access.
0071  *
0072  * If a buffer is reserved for another validation, the validator with
0073  * the highest validation sequence backs off and waits for that buffer
0074  * to become unreserved. This prevents deadlocks when validating multiple
0075  * buffers in different orders.
0076  */
0077 
0078 int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
0079                struct list_head *list, bool intr,
0080                struct list_head *dups)
0081 {
0082     struct ttm_validate_buffer *entry;
0083     int ret;
0084 
0085     if (list_empty(list))
0086         return 0;
0087 
0088     if (ticket)
0089         ww_acquire_init(ticket, &reservation_ww_class);
0090 
0091     list_for_each_entry(entry, list, head) {
0092         struct ttm_buffer_object *bo = entry->bo;
0093         unsigned int num_fences;
0094 
0095         ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
0096         if (ret == -EALREADY && dups) {
0097             struct ttm_validate_buffer *safe = entry;
0098             entry = list_prev_entry(entry, head);
0099             list_del(&safe->head);
0100             list_add(&safe->head, dups);
0101             continue;
0102         }
0103 
0104         num_fences = max(entry->num_shared, 1u);
0105         if (!ret) {
0106             ret = dma_resv_reserve_fences(bo->base.resv,
0107                               num_fences);
0108             if (!ret)
0109                 continue;
0110         }
0111 
0112         /* uh oh, we lost out, drop every reservation and try
0113          * to only reserve this buffer, then start over if
0114          * this succeeds.
0115          */
0116         ttm_eu_backoff_reservation_reverse(list, entry);
0117 
0118         if (ret == -EDEADLK) {
0119             ret = ttm_bo_reserve_slowpath(bo, intr, ticket);
0120         }
0121 
0122         if (!ret)
0123             ret = dma_resv_reserve_fences(bo->base.resv,
0124                               num_fences);
0125 
0126         if (unlikely(ret != 0)) {
0127             if (ticket) {
0128                 ww_acquire_done(ticket);
0129                 ww_acquire_fini(ticket);
0130             }
0131             return ret;
0132         }
0133 
0134         /* move this item to the front of the list,
0135          * forces correct iteration of the loop without keeping track
0136          */
0137         list_del(&entry->head);
0138         list_add(&entry->head, list);
0139     }
0140 
0141     return 0;
0142 }
0143 EXPORT_SYMBOL(ttm_eu_reserve_buffers);
0144 
0145 void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
0146                  struct list_head *list,
0147                  struct dma_fence *fence)
0148 {
0149     struct ttm_validate_buffer *entry;
0150 
0151     if (list_empty(list))
0152         return;
0153 
0154     list_for_each_entry(entry, list, head) {
0155         struct ttm_buffer_object *bo = entry->bo;
0156 
0157         dma_resv_add_fence(bo->base.resv, fence, entry->num_shared ?
0158                    DMA_RESV_USAGE_READ : DMA_RESV_USAGE_WRITE);
0159         ttm_bo_move_to_lru_tail_unlocked(bo);
0160         dma_resv_unlock(bo->base.resv);
0161     }
0162     if (ticket)
0163         ww_acquire_fini(ticket);
0164 }
0165 EXPORT_SYMBOL(ttm_eu_fence_buffer_objects);