162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR MIT */
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
862306a36Sopenharmony_ci * copy of this software and associated documentation files (the
962306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
1062306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1162306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1262306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1362306a36Sopenharmony_ci * the following conditions:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1662306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1762306a36Sopenharmony_ci * of the Software.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2062306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2162306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2262306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2362306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2462306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2562306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci **************************************************************************/
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <drm/ttm/ttm_execbuf_util.h>
3062306a36Sopenharmony_ci#include <drm/ttm/ttm_bo.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void ttm_eu_backoff_reservation_reverse(struct list_head *list,
3362306a36Sopenharmony_ci					      struct ttm_validate_buffer *entry)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	list_for_each_entry_continue_reverse(entry, list, head) {
3662306a36Sopenharmony_ci		struct ttm_buffer_object *bo = entry->bo;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci		dma_resv_unlock(bo->base.resv);
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
4362306a36Sopenharmony_ci				struct list_head *list)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct ttm_validate_buffer *entry;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (list_empty(list))
4862306a36Sopenharmony_ci		return;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	list_for_each_entry(entry, list, head) {
5162306a36Sopenharmony_ci		struct ttm_buffer_object *bo = entry->bo;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		ttm_bo_move_to_lru_tail_unlocked(bo);
5462306a36Sopenharmony_ci		dma_resv_unlock(bo->base.resv);
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (ticket)
5862306a36Sopenharmony_ci		ww_acquire_fini(ticket);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_eu_backoff_reservation);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * Reserve buffers for validation.
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * If a buffer in the list is marked for CPU access, we back off and
6662306a36Sopenharmony_ci * wait for that buffer to become free for GPU access.
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * If a buffer is reserved for another validation, the validator with
6962306a36Sopenharmony_ci * the highest validation sequence backs off and waits for that buffer
7062306a36Sopenharmony_ci * to become unreserved. This prevents deadlocks when validating multiple
7162306a36Sopenharmony_ci * buffers in different orders.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciint ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
7562306a36Sopenharmony_ci			   struct list_head *list, bool intr,
7662306a36Sopenharmony_ci			   struct list_head *dups)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct ttm_validate_buffer *entry;
7962306a36Sopenharmony_ci	int ret;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (list_empty(list))
8262306a36Sopenharmony_ci		return 0;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (ticket)
8562306a36Sopenharmony_ci		ww_acquire_init(ticket, &reservation_ww_class);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	list_for_each_entry(entry, list, head) {
8862306a36Sopenharmony_ci		struct ttm_buffer_object *bo = entry->bo;
8962306a36Sopenharmony_ci		unsigned int num_fences;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
9262306a36Sopenharmony_ci		if (ret == -EALREADY && dups) {
9362306a36Sopenharmony_ci			struct ttm_validate_buffer *safe = entry;
9462306a36Sopenharmony_ci			entry = list_prev_entry(entry, head);
9562306a36Sopenharmony_ci			list_del(&safe->head);
9662306a36Sopenharmony_ci			list_add(&safe->head, dups);
9762306a36Sopenharmony_ci			continue;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		num_fences = max(entry->num_shared, 1u);
10162306a36Sopenharmony_ci		if (!ret) {
10262306a36Sopenharmony_ci			ret = dma_resv_reserve_fences(bo->base.resv,
10362306a36Sopenharmony_ci						      num_fences);
10462306a36Sopenharmony_ci			if (!ret)
10562306a36Sopenharmony_ci				continue;
10662306a36Sopenharmony_ci		}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		/* uh oh, we lost out, drop every reservation and try
10962306a36Sopenharmony_ci		 * to only reserve this buffer, then start over if
11062306a36Sopenharmony_ci		 * this succeeds.
11162306a36Sopenharmony_ci		 */
11262306a36Sopenharmony_ci		ttm_eu_backoff_reservation_reverse(list, entry);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		if (ret == -EDEADLK) {
11562306a36Sopenharmony_ci			ret = ttm_bo_reserve_slowpath(bo, intr, ticket);
11662306a36Sopenharmony_ci		}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		if (!ret)
11962306a36Sopenharmony_ci			ret = dma_resv_reserve_fences(bo->base.resv,
12062306a36Sopenharmony_ci						      num_fences);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		if (unlikely(ret != 0)) {
12362306a36Sopenharmony_ci			if (ticket) {
12462306a36Sopenharmony_ci				ww_acquire_done(ticket);
12562306a36Sopenharmony_ci				ww_acquire_fini(ticket);
12662306a36Sopenharmony_ci			}
12762306a36Sopenharmony_ci			return ret;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		/* move this item to the front of the list,
13162306a36Sopenharmony_ci		 * forces correct iteration of the loop without keeping track
13262306a36Sopenharmony_ci		 */
13362306a36Sopenharmony_ci		list_del(&entry->head);
13462306a36Sopenharmony_ci		list_add(&entry->head, list);
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_eu_reserve_buffers);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_civoid ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
14262306a36Sopenharmony_ci				 struct list_head *list,
14362306a36Sopenharmony_ci				 struct dma_fence *fence)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct ttm_validate_buffer *entry;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (list_empty(list))
14862306a36Sopenharmony_ci		return;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	list_for_each_entry(entry, list, head) {
15162306a36Sopenharmony_ci		struct ttm_buffer_object *bo = entry->bo;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		dma_resv_add_fence(bo->base.resv, fence, entry->num_shared ?
15462306a36Sopenharmony_ci				   DMA_RESV_USAGE_READ : DMA_RESV_USAGE_WRITE);
15562306a36Sopenharmony_ci		ttm_bo_move_to_lru_tail_unlocked(bo);
15662306a36Sopenharmony_ci		dma_resv_unlock(bo->base.resv);
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	if (ticket)
15962306a36Sopenharmony_ci		ww_acquire_fini(ticket);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ciEXPORT_SYMBOL(ttm_eu_fence_buffer_objects);
162