162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2015 Red Hat, Inc.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
662306a36Sopenharmony_ci * a copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1462306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial
1562306a36Sopenharmony_ci * portions of the Software.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1862306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1962306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2062306a36Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
2162306a36Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2262306a36Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2362306a36Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <trace/events/dma_fence.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "virtgpu_drv.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define to_virtio_gpu_fence(x) \
3162306a36Sopenharmony_ci	container_of(x, struct virtio_gpu_fence, f)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic const char *virtio_gpu_get_driver_name(struct dma_fence *f)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	return "virtio_gpu";
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic const char *virtio_gpu_get_timeline_name(struct dma_fence *f)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	return "controlq";
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic bool virtio_gpu_fence_signaled(struct dma_fence *f)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	/* leaked fence outside driver before completing
4662306a36Sopenharmony_ci	 * initialization with virtio_gpu_fence_emit.
4762306a36Sopenharmony_ci	 */
4862306a36Sopenharmony_ci	WARN_ON_ONCE(f->seqno == 0);
4962306a36Sopenharmony_ci	return false;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void virtio_gpu_fence_value_str(struct dma_fence *f, char *str, int size)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	snprintf(str, size, "[%llu, %llu]", f->context, f->seqno);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void virtio_gpu_timeline_value_str(struct dma_fence *f, char *str,
5862306a36Sopenharmony_ci					  int size)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct virtio_gpu_fence *fence = to_virtio_gpu_fence(f);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	snprintf(str, size, "%llu",
6362306a36Sopenharmony_ci		 (u64)atomic64_read(&fence->drv->last_fence_id));
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic const struct dma_fence_ops virtio_gpu_fence_ops = {
6762306a36Sopenharmony_ci	.get_driver_name     = virtio_gpu_get_driver_name,
6862306a36Sopenharmony_ci	.get_timeline_name   = virtio_gpu_get_timeline_name,
6962306a36Sopenharmony_ci	.signaled            = virtio_gpu_fence_signaled,
7062306a36Sopenharmony_ci	.fence_value_str     = virtio_gpu_fence_value_str,
7162306a36Sopenharmony_ci	.timeline_value_str  = virtio_gpu_timeline_value_str,
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct virtio_gpu_fence *virtio_gpu_fence_alloc(struct virtio_gpu_device *vgdev,
7562306a36Sopenharmony_ci						uint64_t base_fence_ctx,
7662306a36Sopenharmony_ci						uint32_t ring_idx)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	uint64_t fence_context = base_fence_ctx + ring_idx;
7962306a36Sopenharmony_ci	struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv;
8062306a36Sopenharmony_ci	struct virtio_gpu_fence *fence = kzalloc(sizeof(struct virtio_gpu_fence),
8162306a36Sopenharmony_ci							GFP_KERNEL);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (!fence)
8462306a36Sopenharmony_ci		return fence;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	fence->drv = drv;
8762306a36Sopenharmony_ci	fence->ring_idx = ring_idx;
8862306a36Sopenharmony_ci	fence->emit_fence_info = !(base_fence_ctx == drv->context);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* This only partially initializes the fence because the seqno is
9162306a36Sopenharmony_ci	 * unknown yet.  The fence must not be used outside of the driver
9262306a36Sopenharmony_ci	 * until virtio_gpu_fence_emit is called.
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	dma_fence_init(&fence->f, &virtio_gpu_fence_ops, &drv->lock,
9662306a36Sopenharmony_ci		       fence_context, 0);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return fence;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_civoid virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
10262306a36Sopenharmony_ci			  struct virtio_gpu_ctrl_hdr *cmd_hdr,
10362306a36Sopenharmony_ci			  struct virtio_gpu_fence *fence)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv;
10662306a36Sopenharmony_ci	unsigned long irq_flags;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	spin_lock_irqsave(&drv->lock, irq_flags);
10962306a36Sopenharmony_ci	fence->fence_id = fence->f.seqno = ++drv->current_fence_id;
11062306a36Sopenharmony_ci	dma_fence_get(&fence->f);
11162306a36Sopenharmony_ci	list_add_tail(&fence->node, &drv->fences);
11262306a36Sopenharmony_ci	spin_unlock_irqrestore(&drv->lock, irq_flags);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	trace_dma_fence_emit(&fence->f);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	cmd_hdr->flags |= cpu_to_le32(VIRTIO_GPU_FLAG_FENCE);
11762306a36Sopenharmony_ci	cmd_hdr->fence_id = cpu_to_le64(fence->fence_id);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* Only currently defined fence param. */
12062306a36Sopenharmony_ci	if (fence->emit_fence_info) {
12162306a36Sopenharmony_ci		cmd_hdr->flags |=
12262306a36Sopenharmony_ci			cpu_to_le32(VIRTIO_GPU_FLAG_INFO_RING_IDX);
12362306a36Sopenharmony_ci		cmd_hdr->ring_idx = (u8)fence->ring_idx;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_civoid virtio_gpu_fence_event_process(struct virtio_gpu_device *vgdev,
12862306a36Sopenharmony_ci				    u64 fence_id)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv;
13162306a36Sopenharmony_ci	struct virtio_gpu_fence *signaled, *curr, *tmp;
13262306a36Sopenharmony_ci	unsigned long irq_flags;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	spin_lock_irqsave(&drv->lock, irq_flags);
13562306a36Sopenharmony_ci	atomic64_set(&vgdev->fence_drv.last_fence_id, fence_id);
13662306a36Sopenharmony_ci	list_for_each_entry_safe(curr, tmp, &drv->fences, node) {
13762306a36Sopenharmony_ci		if (fence_id != curr->fence_id)
13862306a36Sopenharmony_ci			continue;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		signaled = curr;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		/*
14362306a36Sopenharmony_ci		 * Signal any fences with a strictly smaller sequence number
14462306a36Sopenharmony_ci		 * than the current signaled fence.
14562306a36Sopenharmony_ci		 */
14662306a36Sopenharmony_ci		list_for_each_entry_safe(curr, tmp, &drv->fences, node) {
14762306a36Sopenharmony_ci			/* dma-fence contexts must match */
14862306a36Sopenharmony_ci			if (signaled->f.context != curr->f.context)
14962306a36Sopenharmony_ci				continue;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci			if (!dma_fence_is_later(&signaled->f, &curr->f))
15262306a36Sopenharmony_ci				continue;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci			dma_fence_signal_locked(&curr->f);
15562306a36Sopenharmony_ci			if (curr->e) {
15662306a36Sopenharmony_ci				drm_send_event(vgdev->ddev, &curr->e->base);
15762306a36Sopenharmony_ci				curr->e = NULL;
15862306a36Sopenharmony_ci			}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci			list_del(&curr->node);
16162306a36Sopenharmony_ci			dma_fence_put(&curr->f);
16262306a36Sopenharmony_ci		}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		dma_fence_signal_locked(&signaled->f);
16562306a36Sopenharmony_ci		if (signaled->e) {
16662306a36Sopenharmony_ci			drm_send_event(vgdev->ddev, &signaled->e->base);
16762306a36Sopenharmony_ci			signaled->e = NULL;
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		list_del(&signaled->node);
17162306a36Sopenharmony_ci		dma_fence_put(&signaled->f);
17262306a36Sopenharmony_ci		break;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	spin_unlock_irqrestore(&drv->lock, irq_flags);
17562306a36Sopenharmony_ci}
176