162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT
262306a36Sopenharmony_ci/**************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2011-2023 VMware, Inc., Palo Alto, CA., USA
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
762306a36Sopenharmony_ci * copy of this software and associated documentation files (the
862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1262306a36Sopenharmony_ci * the following conditions:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
1662306a36Sopenharmony_ci * of the Software.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci **************************************************************************/
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/sched/signal.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "vmwgfx_drv.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define VMW_FENCE_WRAP (1 << 31)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct vmw_fence_manager {
3562306a36Sopenharmony_ci	int num_fence_objects;
3662306a36Sopenharmony_ci	struct vmw_private *dev_priv;
3762306a36Sopenharmony_ci	spinlock_t lock;
3862306a36Sopenharmony_ci	struct list_head fence_list;
3962306a36Sopenharmony_ci	struct work_struct work;
4062306a36Sopenharmony_ci	bool fifo_down;
4162306a36Sopenharmony_ci	struct list_head cleanup_list;
4262306a36Sopenharmony_ci	uint32_t pending_actions[VMW_ACTION_MAX];
4362306a36Sopenharmony_ci	struct mutex goal_irq_mutex;
4462306a36Sopenharmony_ci	bool goal_irq_on; /* Protected by @goal_irq_mutex */
4562306a36Sopenharmony_ci	bool seqno_valid; /* Protected by @lock, and may not be set to true
4662306a36Sopenharmony_ci			     without the @goal_irq_mutex held. */
4762306a36Sopenharmony_ci	u64 ctx;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistruct vmw_user_fence {
5162306a36Sopenharmony_ci	struct ttm_base_object base;
5262306a36Sopenharmony_ci	struct vmw_fence_obj fence;
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/**
5662306a36Sopenharmony_ci * struct vmw_event_fence_action - fence action that delivers a drm event.
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * @action: A struct vmw_fence_action to hook up to a fence.
5962306a36Sopenharmony_ci * @event: A pointer to the pending event.
6062306a36Sopenharmony_ci * @fence: A referenced pointer to the fence to keep it alive while @action
6162306a36Sopenharmony_ci * hangs on it.
6262306a36Sopenharmony_ci * @dev: Pointer to a struct drm_device so we can access the event stuff.
6362306a36Sopenharmony_ci * @tv_sec: If non-null, the variable pointed to will be assigned
6462306a36Sopenharmony_ci * current time tv_sec val when the fence signals.
6562306a36Sopenharmony_ci * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
6662306a36Sopenharmony_ci * be assigned the current time tv_usec val when the fence signals.
6762306a36Sopenharmony_ci */
6862306a36Sopenharmony_cistruct vmw_event_fence_action {
6962306a36Sopenharmony_ci	struct vmw_fence_action action;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	struct drm_pending_event *event;
7262306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
7362306a36Sopenharmony_ci	struct drm_device *dev;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	uint32_t *tv_sec;
7662306a36Sopenharmony_ci	uint32_t *tv_usec;
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic struct vmw_fence_manager *
8062306a36Sopenharmony_cifman_from_fence(struct vmw_fence_obj *fence)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	return container_of(fence->base.lock, struct vmw_fence_manager, lock);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic u32 vmw_fence_goal_read(struct vmw_private *vmw)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
8862306a36Sopenharmony_ci		return vmw_read(vmw, SVGA_REG_FENCE_GOAL);
8962306a36Sopenharmony_ci	else
9062306a36Sopenharmony_ci		return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void vmw_fence_goal_write(struct vmw_private *vmw, u32 value)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
9662306a36Sopenharmony_ci		vmw_write(vmw, SVGA_REG_FENCE_GOAL, value);
9762306a36Sopenharmony_ci	else
9862306a36Sopenharmony_ci		vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * Note on fencing subsystem usage of irqs:
10362306a36Sopenharmony_ci * Typically the vmw_fences_update function is called
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * a) When a new fence seqno has been submitted by the fifo code.
10662306a36Sopenharmony_ci * b) On-demand when we have waiters. Sleeping waiters will switch on the
10762306a36Sopenharmony_ci * ANY_FENCE irq and call vmw_fences_update function each time an ANY_FENCE
10862306a36Sopenharmony_ci * irq is received. When the last fence waiter is gone, that IRQ is masked
10962306a36Sopenharmony_ci * away.
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * In situations where there are no waiters and we don't submit any new fences,
11262306a36Sopenharmony_ci * fence objects may not be signaled. This is perfectly OK, since there are
11362306a36Sopenharmony_ci * no consumers of the signaled data, but that is NOT ok when there are fence
11462306a36Sopenharmony_ci * actions attached to a fence. The fencing subsystem then makes use of the
11562306a36Sopenharmony_ci * FENCE_GOAL irq and sets the fence goal seqno to that of the next fence
11662306a36Sopenharmony_ci * which has an action attached, and each time vmw_fences_update is called,
11762306a36Sopenharmony_ci * the subsystem makes sure the fence goal seqno is updated.
11862306a36Sopenharmony_ci *
11962306a36Sopenharmony_ci * The fence goal seqno irq is on as long as there are unsignaled fence
12062306a36Sopenharmony_ci * objects with actions attached to them.
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic void vmw_fence_obj_destroy(struct dma_fence *f)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct vmw_fence_obj *fence =
12662306a36Sopenharmony_ci		container_of(f, struct vmw_fence_obj, base);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	spin_lock(&fman->lock);
13162306a36Sopenharmony_ci	list_del_init(&fence->head);
13262306a36Sopenharmony_ci	--fman->num_fence_objects;
13362306a36Sopenharmony_ci	spin_unlock(&fman->lock);
13462306a36Sopenharmony_ci	fence->destroy(fence);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const char *vmw_fence_get_driver_name(struct dma_fence *f)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	return "vmwgfx";
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const char *vmw_fence_get_timeline_name(struct dma_fence *f)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	return "svga";
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic bool vmw_fence_enable_signaling(struct dma_fence *f)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct vmw_fence_obj *fence =
15062306a36Sopenharmony_ci		container_of(f, struct vmw_fence_obj, base);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
15362306a36Sopenharmony_ci	struct vmw_private *dev_priv = fman->dev_priv;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	u32 seqno = vmw_fence_read(dev_priv);
15662306a36Sopenharmony_ci	if (seqno - fence->base.seqno < VMW_FENCE_WRAP)
15762306a36Sopenharmony_ci		return false;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return true;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistruct vmwgfx_wait_cb {
16362306a36Sopenharmony_ci	struct dma_fence_cb base;
16462306a36Sopenharmony_ci	struct task_struct *task;
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic void
16862306a36Sopenharmony_civmwgfx_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct vmwgfx_wait_cb *wait =
17162306a36Sopenharmony_ci		container_of(cb, struct vmwgfx_wait_cb, base);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	wake_up_process(wait->task);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic void __vmw_fences_update(struct vmw_fence_manager *fman);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct vmw_fence_obj *fence =
18162306a36Sopenharmony_ci		container_of(f, struct vmw_fence_obj, base);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
18462306a36Sopenharmony_ci	struct vmw_private *dev_priv = fman->dev_priv;
18562306a36Sopenharmony_ci	struct vmwgfx_wait_cb cb;
18662306a36Sopenharmony_ci	long ret = timeout;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (likely(vmw_fence_obj_signaled(fence)))
18962306a36Sopenharmony_ci		return timeout;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	vmw_seqno_waiter_add(dev_priv);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	spin_lock(f->lock);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
19662306a36Sopenharmony_ci		goto out;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (intr && signal_pending(current)) {
19962306a36Sopenharmony_ci		ret = -ERESTARTSYS;
20062306a36Sopenharmony_ci		goto out;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	cb.base.func = vmwgfx_wait_cb;
20462306a36Sopenharmony_ci	cb.task = current;
20562306a36Sopenharmony_ci	list_add(&cb.base.node, &f->cb_list);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	for (;;) {
20862306a36Sopenharmony_ci		__vmw_fences_update(fman);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		/*
21162306a36Sopenharmony_ci		 * We can use the barrier free __set_current_state() since
21262306a36Sopenharmony_ci		 * DMA_FENCE_FLAG_SIGNALED_BIT + wakeup is protected by the
21362306a36Sopenharmony_ci		 * fence spinlock.
21462306a36Sopenharmony_ci		 */
21562306a36Sopenharmony_ci		if (intr)
21662306a36Sopenharmony_ci			__set_current_state(TASK_INTERRUPTIBLE);
21762306a36Sopenharmony_ci		else
21862306a36Sopenharmony_ci			__set_current_state(TASK_UNINTERRUPTIBLE);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) {
22162306a36Sopenharmony_ci			if (ret == 0 && timeout > 0)
22262306a36Sopenharmony_ci				ret = 1;
22362306a36Sopenharmony_ci			break;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		if (intr && signal_pending(current)) {
22762306a36Sopenharmony_ci			ret = -ERESTARTSYS;
22862306a36Sopenharmony_ci			break;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		if (ret == 0)
23262306a36Sopenharmony_ci			break;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		spin_unlock(f->lock);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		ret = schedule_timeout(ret);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		spin_lock(f->lock);
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci	__set_current_state(TASK_RUNNING);
24162306a36Sopenharmony_ci	if (!list_empty(&cb.base.node))
24262306a36Sopenharmony_ci		list_del(&cb.base.node);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ciout:
24562306a36Sopenharmony_ci	spin_unlock(f->lock);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	vmw_seqno_waiter_remove(dev_priv);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return ret;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic const struct dma_fence_ops vmw_fence_ops = {
25362306a36Sopenharmony_ci	.get_driver_name = vmw_fence_get_driver_name,
25462306a36Sopenharmony_ci	.get_timeline_name = vmw_fence_get_timeline_name,
25562306a36Sopenharmony_ci	.enable_signaling = vmw_fence_enable_signaling,
25662306a36Sopenharmony_ci	.wait = vmw_fence_wait,
25762306a36Sopenharmony_ci	.release = vmw_fence_obj_destroy,
25862306a36Sopenharmony_ci};
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/*
26262306a36Sopenharmony_ci * Execute signal actions on fences recently signaled.
26362306a36Sopenharmony_ci * This is done from a workqueue so we don't have to execute
26462306a36Sopenharmony_ci * signal actions from atomic context.
26562306a36Sopenharmony_ci */
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void vmw_fence_work_func(struct work_struct *work)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	struct vmw_fence_manager *fman =
27062306a36Sopenharmony_ci		container_of(work, struct vmw_fence_manager, work);
27162306a36Sopenharmony_ci	struct list_head list;
27262306a36Sopenharmony_ci	struct vmw_fence_action *action, *next_action;
27362306a36Sopenharmony_ci	bool seqno_valid;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	do {
27662306a36Sopenharmony_ci		INIT_LIST_HEAD(&list);
27762306a36Sopenharmony_ci		mutex_lock(&fman->goal_irq_mutex);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		spin_lock(&fman->lock);
28062306a36Sopenharmony_ci		list_splice_init(&fman->cleanup_list, &list);
28162306a36Sopenharmony_ci		seqno_valid = fman->seqno_valid;
28262306a36Sopenharmony_ci		spin_unlock(&fman->lock);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		if (!seqno_valid && fman->goal_irq_on) {
28562306a36Sopenharmony_ci			fman->goal_irq_on = false;
28662306a36Sopenharmony_ci			vmw_goal_waiter_remove(fman->dev_priv);
28762306a36Sopenharmony_ci		}
28862306a36Sopenharmony_ci		mutex_unlock(&fman->goal_irq_mutex);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		if (list_empty(&list))
29162306a36Sopenharmony_ci			return;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		/*
29462306a36Sopenharmony_ci		 * At this point, only we should be able to manipulate the
29562306a36Sopenharmony_ci		 * list heads of the actions we have on the private list.
29662306a36Sopenharmony_ci		 * hence fman::lock not held.
29762306a36Sopenharmony_ci		 */
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		list_for_each_entry_safe(action, next_action, &list, head) {
30062306a36Sopenharmony_ci			list_del_init(&action->head);
30162306a36Sopenharmony_ci			if (action->cleanup)
30262306a36Sopenharmony_ci				action->cleanup(action);
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci	} while (1);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistruct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct vmw_fence_manager *fman = kzalloc(sizeof(*fman), GFP_KERNEL);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (unlikely(!fman))
31262306a36Sopenharmony_ci		return NULL;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	fman->dev_priv = dev_priv;
31562306a36Sopenharmony_ci	spin_lock_init(&fman->lock);
31662306a36Sopenharmony_ci	INIT_LIST_HEAD(&fman->fence_list);
31762306a36Sopenharmony_ci	INIT_LIST_HEAD(&fman->cleanup_list);
31862306a36Sopenharmony_ci	INIT_WORK(&fman->work, &vmw_fence_work_func);
31962306a36Sopenharmony_ci	fman->fifo_down = true;
32062306a36Sopenharmony_ci	mutex_init(&fman->goal_irq_mutex);
32162306a36Sopenharmony_ci	fman->ctx = dma_fence_context_alloc(1);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return fman;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_civoid vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	bool lists_empty;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	(void) cancel_work_sync(&fman->work);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	spin_lock(&fman->lock);
33362306a36Sopenharmony_ci	lists_empty = list_empty(&fman->fence_list) &&
33462306a36Sopenharmony_ci		list_empty(&fman->cleanup_list);
33562306a36Sopenharmony_ci	spin_unlock(&fman->lock);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	BUG_ON(!lists_empty);
33862306a36Sopenharmony_ci	kfree(fman);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int vmw_fence_obj_init(struct vmw_fence_manager *fman,
34262306a36Sopenharmony_ci			      struct vmw_fence_obj *fence, u32 seqno,
34362306a36Sopenharmony_ci			      void (*destroy) (struct vmw_fence_obj *fence))
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	int ret = 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	dma_fence_init(&fence->base, &vmw_fence_ops, &fman->lock,
34862306a36Sopenharmony_ci		       fman->ctx, seqno);
34962306a36Sopenharmony_ci	INIT_LIST_HEAD(&fence->seq_passed_actions);
35062306a36Sopenharmony_ci	fence->destroy = destroy;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	spin_lock(&fman->lock);
35362306a36Sopenharmony_ci	if (unlikely(fman->fifo_down)) {
35462306a36Sopenharmony_ci		ret = -EBUSY;
35562306a36Sopenharmony_ci		goto out_unlock;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci	list_add_tail(&fence->head, &fman->fence_list);
35862306a36Sopenharmony_ci	++fman->num_fence_objects;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ciout_unlock:
36162306a36Sopenharmony_ci	spin_unlock(&fman->lock);
36262306a36Sopenharmony_ci	return ret;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic void vmw_fences_perform_actions(struct vmw_fence_manager *fman,
36762306a36Sopenharmony_ci				struct list_head *list)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct vmw_fence_action *action, *next_action;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	list_for_each_entry_safe(action, next_action, list, head) {
37262306a36Sopenharmony_ci		list_del_init(&action->head);
37362306a36Sopenharmony_ci		fman->pending_actions[action->type]--;
37462306a36Sopenharmony_ci		if (action->seq_passed != NULL)
37562306a36Sopenharmony_ci			action->seq_passed(action);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		/*
37862306a36Sopenharmony_ci		 * Add the cleanup action to the cleanup list so that
37962306a36Sopenharmony_ci		 * it will be performed by a worker task.
38062306a36Sopenharmony_ci		 */
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		list_add_tail(&action->head, &fman->cleanup_list);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * vmw_fence_goal_new_locked - Figure out a new device fence goal
38862306a36Sopenharmony_ci * seqno if needed.
38962306a36Sopenharmony_ci *
39062306a36Sopenharmony_ci * @fman: Pointer to a fence manager.
39162306a36Sopenharmony_ci * @passed_seqno: The seqno the device currently signals as passed.
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * This function should be called with the fence manager lock held.
39462306a36Sopenharmony_ci * It is typically called when we have a new passed_seqno, and
39562306a36Sopenharmony_ci * we might need to update the fence goal. It checks to see whether
39662306a36Sopenharmony_ci * the current fence goal has already passed, and, in that case,
39762306a36Sopenharmony_ci * scans through all unsignaled fences to get the next fence object with an
39862306a36Sopenharmony_ci * action attached, and sets the seqno of that fence as a new fence goal.
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * returns true if the device goal seqno was updated. False otherwise.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_cistatic bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
40362306a36Sopenharmony_ci				      u32 passed_seqno)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	u32 goal_seqno;
40662306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (likely(!fman->seqno_valid))
40962306a36Sopenharmony_ci		return false;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	goal_seqno = vmw_fence_goal_read(fman->dev_priv);
41262306a36Sopenharmony_ci	if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
41362306a36Sopenharmony_ci		return false;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	fman->seqno_valid = false;
41662306a36Sopenharmony_ci	list_for_each_entry(fence, &fman->fence_list, head) {
41762306a36Sopenharmony_ci		if (!list_empty(&fence->seq_passed_actions)) {
41862306a36Sopenharmony_ci			fman->seqno_valid = true;
41962306a36Sopenharmony_ci			vmw_fence_goal_write(fman->dev_priv,
42062306a36Sopenharmony_ci					     fence->base.seqno);
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci		}
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	return true;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/**
43062306a36Sopenharmony_ci * vmw_fence_goal_check_locked - Replace the device fence goal seqno if
43162306a36Sopenharmony_ci * needed.
43262306a36Sopenharmony_ci *
43362306a36Sopenharmony_ci * @fence: Pointer to a struct vmw_fence_obj the seqno of which should be
43462306a36Sopenharmony_ci * considered as a device fence goal.
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci * This function should be called with the fence manager lock held.
43762306a36Sopenharmony_ci * It is typically called when an action has been attached to a fence to
43862306a36Sopenharmony_ci * check whether the seqno of that fence should be used for a fence
43962306a36Sopenharmony_ci * goal interrupt. This is typically needed if the current fence goal is
44062306a36Sopenharmony_ci * invalid, or has a higher seqno than that of the current fence object.
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * returns true if the device goal seqno was updated. False otherwise.
44362306a36Sopenharmony_ci */
44462306a36Sopenharmony_cistatic bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
44762306a36Sopenharmony_ci	u32 goal_seqno;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (dma_fence_is_signaled_locked(&fence->base))
45062306a36Sopenharmony_ci		return false;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	goal_seqno = vmw_fence_goal_read(fman->dev_priv);
45362306a36Sopenharmony_ci	if (likely(fman->seqno_valid &&
45462306a36Sopenharmony_ci		   goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
45562306a36Sopenharmony_ci		return false;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	vmw_fence_goal_write(fman->dev_priv, fence->base.seqno);
45862306a36Sopenharmony_ci	fman->seqno_valid = true;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return true;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic void __vmw_fences_update(struct vmw_fence_manager *fman)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct vmw_fence_obj *fence, *next_fence;
46662306a36Sopenharmony_ci	struct list_head action_list;
46762306a36Sopenharmony_ci	bool needs_rerun;
46862306a36Sopenharmony_ci	uint32_t seqno, new_seqno;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	seqno = vmw_fence_read(fman->dev_priv);
47162306a36Sopenharmony_cirerun:
47262306a36Sopenharmony_ci	list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
47362306a36Sopenharmony_ci		if (seqno - fence->base.seqno < VMW_FENCE_WRAP) {
47462306a36Sopenharmony_ci			list_del_init(&fence->head);
47562306a36Sopenharmony_ci			dma_fence_signal_locked(&fence->base);
47662306a36Sopenharmony_ci			INIT_LIST_HEAD(&action_list);
47762306a36Sopenharmony_ci			list_splice_init(&fence->seq_passed_actions,
47862306a36Sopenharmony_ci					 &action_list);
47962306a36Sopenharmony_ci			vmw_fences_perform_actions(fman, &action_list);
48062306a36Sopenharmony_ci		} else
48162306a36Sopenharmony_ci			break;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * Rerun if the fence goal seqno was updated, and the
48662306a36Sopenharmony_ci	 * hardware might have raced with that update, so that
48762306a36Sopenharmony_ci	 * we missed a fence_goal irq.
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	needs_rerun = vmw_fence_goal_new_locked(fman, seqno);
49162306a36Sopenharmony_ci	if (unlikely(needs_rerun)) {
49262306a36Sopenharmony_ci		new_seqno = vmw_fence_read(fman->dev_priv);
49362306a36Sopenharmony_ci		if (new_seqno != seqno) {
49462306a36Sopenharmony_ci			seqno = new_seqno;
49562306a36Sopenharmony_ci			goto rerun;
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (!list_empty(&fman->cleanup_list))
50062306a36Sopenharmony_ci		(void) schedule_work(&fman->work);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_civoid vmw_fences_update(struct vmw_fence_manager *fman)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	spin_lock(&fman->lock);
50662306a36Sopenharmony_ci	__vmw_fences_update(fman);
50762306a36Sopenharmony_ci	spin_unlock(&fman->lock);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cibool vmw_fence_obj_signaled(struct vmw_fence_obj *fence)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
51562306a36Sopenharmony_ci		return true;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	vmw_fences_update(fman);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return dma_fence_is_signaled(&fence->base);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ciint vmw_fence_obj_wait(struct vmw_fence_obj *fence, bool lazy,
52362306a36Sopenharmony_ci		       bool interruptible, unsigned long timeout)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	long ret = dma_fence_wait_timeout(&fence->base, interruptible, timeout);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (likely(ret > 0))
52862306a36Sopenharmony_ci		return 0;
52962306a36Sopenharmony_ci	else if (ret == 0)
53062306a36Sopenharmony_ci		return -EBUSY;
53162306a36Sopenharmony_ci	else
53262306a36Sopenharmony_ci		return ret;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic void vmw_fence_destroy(struct vmw_fence_obj *fence)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	dma_fence_free(&fence->base);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ciint vmw_fence_create(struct vmw_fence_manager *fman,
54162306a36Sopenharmony_ci		     uint32_t seqno,
54262306a36Sopenharmony_ci		     struct vmw_fence_obj **p_fence)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
54562306a36Sopenharmony_ci 	int ret;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
54862306a36Sopenharmony_ci	if (unlikely(!fence))
54962306a36Sopenharmony_ci		return -ENOMEM;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	ret = vmw_fence_obj_init(fman, fence, seqno,
55262306a36Sopenharmony_ci				 vmw_fence_destroy);
55362306a36Sopenharmony_ci	if (unlikely(ret != 0))
55462306a36Sopenharmony_ci		goto out_err_init;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	*p_fence = fence;
55762306a36Sopenharmony_ci	return 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ciout_err_init:
56062306a36Sopenharmony_ci	kfree(fence);
56162306a36Sopenharmony_ci	return ret;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void vmw_user_fence_destroy(struct vmw_fence_obj *fence)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct vmw_user_fence *ufence =
56862306a36Sopenharmony_ci		container_of(fence, struct vmw_user_fence, fence);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	ttm_base_object_kfree(ufence, base);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void vmw_user_fence_base_release(struct ttm_base_object **p_base)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct ttm_base_object *base = *p_base;
57662306a36Sopenharmony_ci	struct vmw_user_fence *ufence =
57762306a36Sopenharmony_ci		container_of(base, struct vmw_user_fence, base);
57862306a36Sopenharmony_ci	struct vmw_fence_obj *fence = &ufence->fence;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	*p_base = NULL;
58162306a36Sopenharmony_ci	vmw_fence_obj_unreference(&fence);
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ciint vmw_user_fence_create(struct drm_file *file_priv,
58562306a36Sopenharmony_ci			  struct vmw_fence_manager *fman,
58662306a36Sopenharmony_ci			  uint32_t seqno,
58762306a36Sopenharmony_ci			  struct vmw_fence_obj **p_fence,
58862306a36Sopenharmony_ci			  uint32_t *p_handle)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
59162306a36Sopenharmony_ci	struct vmw_user_fence *ufence;
59262306a36Sopenharmony_ci	struct vmw_fence_obj *tmp;
59362306a36Sopenharmony_ci	int ret;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
59662306a36Sopenharmony_ci	if (unlikely(!ufence)) {
59762306a36Sopenharmony_ci		ret = -ENOMEM;
59862306a36Sopenharmony_ci		goto out_no_object;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	ret = vmw_fence_obj_init(fman, &ufence->fence, seqno,
60262306a36Sopenharmony_ci				 vmw_user_fence_destroy);
60362306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
60462306a36Sopenharmony_ci		kfree(ufence);
60562306a36Sopenharmony_ci		goto out_no_object;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/*
60962306a36Sopenharmony_ci	 * The base object holds a reference which is freed in
61062306a36Sopenharmony_ci	 * vmw_user_fence_base_release.
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci	tmp = vmw_fence_obj_reference(&ufence->fence);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	ret = ttm_base_object_init(tfile, &ufence->base, false,
61562306a36Sopenharmony_ci				   VMW_RES_FENCE,
61662306a36Sopenharmony_ci				   &vmw_user_fence_base_release);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
62062306a36Sopenharmony_ci		/*
62162306a36Sopenharmony_ci		 * Free the base object's reference
62262306a36Sopenharmony_ci		 */
62362306a36Sopenharmony_ci		vmw_fence_obj_unreference(&tmp);
62462306a36Sopenharmony_ci		goto out_err;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	*p_fence = &ufence->fence;
62862306a36Sopenharmony_ci	*p_handle = ufence->base.handle;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ciout_err:
63262306a36Sopenharmony_ci	tmp = &ufence->fence;
63362306a36Sopenharmony_ci	vmw_fence_obj_unreference(&tmp);
63462306a36Sopenharmony_ciout_no_object:
63562306a36Sopenharmony_ci	return ret;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci/*
63962306a36Sopenharmony_ci * vmw_fence_fifo_down - signal all unsignaled fence objects.
64062306a36Sopenharmony_ci */
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_civoid vmw_fence_fifo_down(struct vmw_fence_manager *fman)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	struct list_head action_list;
64562306a36Sopenharmony_ci	int ret;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/*
64862306a36Sopenharmony_ci	 * The list may be altered while we traverse it, so always
64962306a36Sopenharmony_ci	 * restart when we've released the fman->lock.
65062306a36Sopenharmony_ci	 */
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	spin_lock(&fman->lock);
65362306a36Sopenharmony_ci	fman->fifo_down = true;
65462306a36Sopenharmony_ci	while (!list_empty(&fman->fence_list)) {
65562306a36Sopenharmony_ci		struct vmw_fence_obj *fence =
65662306a36Sopenharmony_ci			list_entry(fman->fence_list.prev, struct vmw_fence_obj,
65762306a36Sopenharmony_ci				   head);
65862306a36Sopenharmony_ci		dma_fence_get(&fence->base);
65962306a36Sopenharmony_ci		spin_unlock(&fman->lock);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		ret = vmw_fence_obj_wait(fence, false, false,
66262306a36Sopenharmony_ci					 VMW_FENCE_WAIT_TIMEOUT);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		if (unlikely(ret != 0)) {
66562306a36Sopenharmony_ci			list_del_init(&fence->head);
66662306a36Sopenharmony_ci			dma_fence_signal(&fence->base);
66762306a36Sopenharmony_ci			INIT_LIST_HEAD(&action_list);
66862306a36Sopenharmony_ci			list_splice_init(&fence->seq_passed_actions,
66962306a36Sopenharmony_ci					 &action_list);
67062306a36Sopenharmony_ci			vmw_fences_perform_actions(fman, &action_list);
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		BUG_ON(!list_empty(&fence->head));
67462306a36Sopenharmony_ci		dma_fence_put(&fence->base);
67562306a36Sopenharmony_ci		spin_lock(&fman->lock);
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	spin_unlock(&fman->lock);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_civoid vmw_fence_fifo_up(struct vmw_fence_manager *fman)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	spin_lock(&fman->lock);
68362306a36Sopenharmony_ci	fman->fifo_down = false;
68462306a36Sopenharmony_ci	spin_unlock(&fman->lock);
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci/**
68962306a36Sopenharmony_ci * vmw_fence_obj_lookup - Look up a user-space fence object
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci * @tfile: A struct ttm_object_file identifying the caller.
69262306a36Sopenharmony_ci * @handle: A handle identifying the fence object.
69362306a36Sopenharmony_ci * @return: A struct vmw_user_fence base ttm object on success or
69462306a36Sopenharmony_ci * an error pointer on failure.
69562306a36Sopenharmony_ci *
69662306a36Sopenharmony_ci * The fence object is looked up and type-checked. The caller needs
69762306a36Sopenharmony_ci * to have opened the fence object first, but since that happens on
69862306a36Sopenharmony_ci * creation and fence objects aren't shareable, that's not an
69962306a36Sopenharmony_ci * issue currently.
70062306a36Sopenharmony_ci */
70162306a36Sopenharmony_cistatic struct ttm_base_object *
70262306a36Sopenharmony_civmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct ttm_base_object *base = ttm_base_object_lookup(tfile, handle);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (!base) {
70762306a36Sopenharmony_ci		pr_err("Invalid fence object handle 0x%08lx.\n",
70862306a36Sopenharmony_ci		       (unsigned long)handle);
70962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (base->refcount_release != vmw_user_fence_base_release) {
71362306a36Sopenharmony_ci		pr_err("Invalid fence object handle 0x%08lx.\n",
71462306a36Sopenharmony_ci		       (unsigned long)handle);
71562306a36Sopenharmony_ci		ttm_base_object_unref(&base);
71662306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	return base;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ciint vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
72462306a36Sopenharmony_ci			     struct drm_file *file_priv)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct drm_vmw_fence_wait_arg *arg =
72762306a36Sopenharmony_ci	    (struct drm_vmw_fence_wait_arg *)data;
72862306a36Sopenharmony_ci	unsigned long timeout;
72962306a36Sopenharmony_ci	struct ttm_base_object *base;
73062306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
73162306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
73262306a36Sopenharmony_ci	int ret;
73362306a36Sopenharmony_ci	uint64_t wait_timeout = ((uint64_t)arg->timeout_us * HZ);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/*
73662306a36Sopenharmony_ci	 * 64-bit division not present on 32-bit systems, so do an
73762306a36Sopenharmony_ci	 * approximation. (Divide by 1000000).
73862306a36Sopenharmony_ci	 */
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	wait_timeout = (wait_timeout >> 20) + (wait_timeout >> 24) -
74162306a36Sopenharmony_ci	  (wait_timeout >> 26);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (!arg->cookie_valid) {
74462306a36Sopenharmony_ci		arg->cookie_valid = 1;
74562306a36Sopenharmony_ci		arg->kernel_cookie = jiffies + wait_timeout;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	base = vmw_fence_obj_lookup(tfile, arg->handle);
74962306a36Sopenharmony_ci	if (IS_ERR(base))
75062306a36Sopenharmony_ci		return PTR_ERR(base);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	timeout = jiffies;
75562306a36Sopenharmony_ci	if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie)) {
75662306a36Sopenharmony_ci		ret = ((vmw_fence_obj_signaled(fence)) ?
75762306a36Sopenharmony_ci		       0 : -EBUSY);
75862306a36Sopenharmony_ci		goto out;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	timeout = (unsigned long)arg->kernel_cookie - timeout;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	ret = vmw_fence_obj_wait(fence, arg->lazy, true, timeout);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ciout:
76662306a36Sopenharmony_ci	ttm_base_object_unref(&base);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/*
76962306a36Sopenharmony_ci	 * Optionally unref the fence object.
77062306a36Sopenharmony_ci	 */
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (ret == 0 && (arg->wait_options & DRM_VMW_WAIT_OPTION_UNREF))
77362306a36Sopenharmony_ci		return ttm_ref_object_base_unref(tfile, arg->handle);
77462306a36Sopenharmony_ci	return ret;
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ciint vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
77862306a36Sopenharmony_ci				 struct drm_file *file_priv)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	struct drm_vmw_fence_signaled_arg *arg =
78162306a36Sopenharmony_ci		(struct drm_vmw_fence_signaled_arg *) data;
78262306a36Sopenharmony_ci	struct ttm_base_object *base;
78362306a36Sopenharmony_ci	struct vmw_fence_obj *fence;
78462306a36Sopenharmony_ci	struct vmw_fence_manager *fman;
78562306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
78662306a36Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	base = vmw_fence_obj_lookup(tfile, arg->handle);
78962306a36Sopenharmony_ci	if (IS_ERR(base))
79062306a36Sopenharmony_ci		return PTR_ERR(base);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
79362306a36Sopenharmony_ci	fman = fman_from_fence(fence);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	arg->signaled = vmw_fence_obj_signaled(fence);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	arg->signaled_flags = arg->flags;
79862306a36Sopenharmony_ci	spin_lock(&fman->lock);
79962306a36Sopenharmony_ci	arg->passed_seqno = dev_priv->last_read_seqno;
80062306a36Sopenharmony_ci	spin_unlock(&fman->lock);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	ttm_base_object_unref(&base);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return 0;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ciint vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
80962306a36Sopenharmony_ci			      struct drm_file *file_priv)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct drm_vmw_fence_arg *arg =
81262306a36Sopenharmony_ci		(struct drm_vmw_fence_arg *) data;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
81562306a36Sopenharmony_ci					 arg->handle);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci/**
81962306a36Sopenharmony_ci * vmw_event_fence_action_seq_passed
82062306a36Sopenharmony_ci *
82162306a36Sopenharmony_ci * @action: The struct vmw_fence_action embedded in a struct
82262306a36Sopenharmony_ci * vmw_event_fence_action.
82362306a36Sopenharmony_ci *
82462306a36Sopenharmony_ci * This function is called when the seqno of the fence where @action is
82562306a36Sopenharmony_ci * attached has passed. It queues the event on the submitter's event list.
82662306a36Sopenharmony_ci * This function is always called from atomic context.
82762306a36Sopenharmony_ci */
82862306a36Sopenharmony_cistatic void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	struct vmw_event_fence_action *eaction =
83162306a36Sopenharmony_ci		container_of(action, struct vmw_event_fence_action, action);
83262306a36Sopenharmony_ci	struct drm_device *dev = eaction->dev;
83362306a36Sopenharmony_ci	struct drm_pending_event *event = eaction->event;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	if (unlikely(event == NULL))
83662306a36Sopenharmony_ci		return;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	spin_lock_irq(&dev->event_lock);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (likely(eaction->tv_sec != NULL)) {
84162306a36Sopenharmony_ci		struct timespec64 ts;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		ktime_get_ts64(&ts);
84462306a36Sopenharmony_ci		/* monotonic time, so no y2038 overflow */
84562306a36Sopenharmony_ci		*eaction->tv_sec = ts.tv_sec;
84662306a36Sopenharmony_ci		*eaction->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	drm_send_event_locked(dev, eaction->event);
85062306a36Sopenharmony_ci	eaction->event = NULL;
85162306a36Sopenharmony_ci	spin_unlock_irq(&dev->event_lock);
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci/**
85562306a36Sopenharmony_ci * vmw_event_fence_action_cleanup
85662306a36Sopenharmony_ci *
85762306a36Sopenharmony_ci * @action: The struct vmw_fence_action embedded in a struct
85862306a36Sopenharmony_ci * vmw_event_fence_action.
85962306a36Sopenharmony_ci *
86062306a36Sopenharmony_ci * This function is the struct vmw_fence_action destructor. It's typically
86162306a36Sopenharmony_ci * called from a workqueue.
86262306a36Sopenharmony_ci */
86362306a36Sopenharmony_cistatic void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct vmw_event_fence_action *eaction =
86662306a36Sopenharmony_ci		container_of(action, struct vmw_event_fence_action, action);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	vmw_fence_obj_unreference(&eaction->fence);
86962306a36Sopenharmony_ci	kfree(eaction);
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci/**
87462306a36Sopenharmony_ci * vmw_fence_obj_add_action - Add an action to a fence object.
87562306a36Sopenharmony_ci *
87662306a36Sopenharmony_ci * @fence: The fence object.
87762306a36Sopenharmony_ci * @action: The action to add.
87862306a36Sopenharmony_ci *
87962306a36Sopenharmony_ci * Note that the action callbacks may be executed before this function
88062306a36Sopenharmony_ci * returns.
88162306a36Sopenharmony_ci */
88262306a36Sopenharmony_cistatic void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
88362306a36Sopenharmony_ci			      struct vmw_fence_action *action)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
88662306a36Sopenharmony_ci	bool run_update = false;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	mutex_lock(&fman->goal_irq_mutex);
88962306a36Sopenharmony_ci	spin_lock(&fman->lock);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	fman->pending_actions[action->type]++;
89262306a36Sopenharmony_ci	if (dma_fence_is_signaled_locked(&fence->base)) {
89362306a36Sopenharmony_ci		struct list_head action_list;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		INIT_LIST_HEAD(&action_list);
89662306a36Sopenharmony_ci		list_add_tail(&action->head, &action_list);
89762306a36Sopenharmony_ci		vmw_fences_perform_actions(fman, &action_list);
89862306a36Sopenharmony_ci	} else {
89962306a36Sopenharmony_ci		list_add_tail(&action->head, &fence->seq_passed_actions);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		/*
90262306a36Sopenharmony_ci		 * This function may set fman::seqno_valid, so it must
90362306a36Sopenharmony_ci		 * be run with the goal_irq_mutex held.
90462306a36Sopenharmony_ci		 */
90562306a36Sopenharmony_ci		run_update = vmw_fence_goal_check_locked(fence);
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	spin_unlock(&fman->lock);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (run_update) {
91162306a36Sopenharmony_ci		if (!fman->goal_irq_on) {
91262306a36Sopenharmony_ci			fman->goal_irq_on = true;
91362306a36Sopenharmony_ci			vmw_goal_waiter_add(fman->dev_priv);
91462306a36Sopenharmony_ci		}
91562306a36Sopenharmony_ci		vmw_fences_update(fman);
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci	mutex_unlock(&fman->goal_irq_mutex);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci/**
92262306a36Sopenharmony_ci * vmw_event_fence_action_queue - Post an event for sending when a fence
92362306a36Sopenharmony_ci * object seqno has passed.
92462306a36Sopenharmony_ci *
92562306a36Sopenharmony_ci * @file_priv: The file connection on which the event should be posted.
92662306a36Sopenharmony_ci * @fence: The fence object on which to post the event.
92762306a36Sopenharmony_ci * @event: Event to be posted. This event should've been alloced
92862306a36Sopenharmony_ci * using k[mz]alloc, and should've been completely initialized.
92962306a36Sopenharmony_ci * @tv_sec: If non-null, the variable pointed to will be assigned
93062306a36Sopenharmony_ci * current time tv_sec val when the fence signals.
93162306a36Sopenharmony_ci * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
93262306a36Sopenharmony_ci * be assigned the current time tv_usec val when the fence signals.
93362306a36Sopenharmony_ci * @interruptible: Interruptible waits if possible.
93462306a36Sopenharmony_ci *
93562306a36Sopenharmony_ci * As a side effect, the object pointed to by @event may have been
93662306a36Sopenharmony_ci * freed when this function returns. If this function returns with
93762306a36Sopenharmony_ci * an error code, the caller needs to free that object.
93862306a36Sopenharmony_ci */
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ciint vmw_event_fence_action_queue(struct drm_file *file_priv,
94162306a36Sopenharmony_ci				 struct vmw_fence_obj *fence,
94262306a36Sopenharmony_ci				 struct drm_pending_event *event,
94362306a36Sopenharmony_ci				 uint32_t *tv_sec,
94462306a36Sopenharmony_ci				 uint32_t *tv_usec,
94562306a36Sopenharmony_ci				 bool interruptible)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct vmw_event_fence_action *eaction;
94862306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
95162306a36Sopenharmony_ci	if (unlikely(!eaction))
95262306a36Sopenharmony_ci		return -ENOMEM;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	eaction->event = event;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
95762306a36Sopenharmony_ci	eaction->action.cleanup = vmw_event_fence_action_cleanup;
95862306a36Sopenharmony_ci	eaction->action.type = VMW_ACTION_EVENT;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	eaction->fence = vmw_fence_obj_reference(fence);
96162306a36Sopenharmony_ci	eaction->dev = &fman->dev_priv->drm;
96262306a36Sopenharmony_ci	eaction->tv_sec = tv_sec;
96362306a36Sopenharmony_ci	eaction->tv_usec = tv_usec;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	vmw_fence_obj_add_action(fence, &eaction->action);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	return 0;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistruct vmw_event_fence_pending {
97162306a36Sopenharmony_ci	struct drm_pending_event base;
97262306a36Sopenharmony_ci	struct drm_vmw_event_fence event;
97362306a36Sopenharmony_ci};
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int vmw_event_fence_action_create(struct drm_file *file_priv,
97662306a36Sopenharmony_ci				  struct vmw_fence_obj *fence,
97762306a36Sopenharmony_ci				  uint32_t flags,
97862306a36Sopenharmony_ci				  uint64_t user_data,
97962306a36Sopenharmony_ci				  bool interruptible)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	struct vmw_event_fence_pending *event;
98262306a36Sopenharmony_ci	struct vmw_fence_manager *fman = fman_from_fence(fence);
98362306a36Sopenharmony_ci	struct drm_device *dev = &fman->dev_priv->drm;
98462306a36Sopenharmony_ci	int ret;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	event = kzalloc(sizeof(*event), GFP_KERNEL);
98762306a36Sopenharmony_ci	if (unlikely(!event)) {
98862306a36Sopenharmony_ci		DRM_ERROR("Failed to allocate an event.\n");
98962306a36Sopenharmony_ci		ret = -ENOMEM;
99062306a36Sopenharmony_ci		goto out_no_space;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
99462306a36Sopenharmony_ci	event->event.base.length = sizeof(*event);
99562306a36Sopenharmony_ci	event->event.user_data = user_data;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	ret = drm_event_reserve_init(dev, file_priv, &event->base, &event->event.base);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
100062306a36Sopenharmony_ci		DRM_ERROR("Failed to allocate event space for this file.\n");
100162306a36Sopenharmony_ci		kfree(event);
100262306a36Sopenharmony_ci		goto out_no_space;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
100662306a36Sopenharmony_ci		ret = vmw_event_fence_action_queue(file_priv, fence,
100762306a36Sopenharmony_ci						   &event->base,
100862306a36Sopenharmony_ci						   &event->event.tv_sec,
100962306a36Sopenharmony_ci						   &event->event.tv_usec,
101062306a36Sopenharmony_ci						   interruptible);
101162306a36Sopenharmony_ci	else
101262306a36Sopenharmony_ci		ret = vmw_event_fence_action_queue(file_priv, fence,
101362306a36Sopenharmony_ci						   &event->base,
101462306a36Sopenharmony_ci						   NULL,
101562306a36Sopenharmony_ci						   NULL,
101662306a36Sopenharmony_ci						   interruptible);
101762306a36Sopenharmony_ci	if (ret != 0)
101862306a36Sopenharmony_ci		goto out_no_queue;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	return 0;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ciout_no_queue:
102362306a36Sopenharmony_ci	drm_event_cancel_free(dev, &event->base);
102462306a36Sopenharmony_ciout_no_space:
102562306a36Sopenharmony_ci	return ret;
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ciint vmw_fence_event_ioctl(struct drm_device *dev, void *data,
102962306a36Sopenharmony_ci			  struct drm_file *file_priv)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	struct vmw_private *dev_priv = vmw_priv(dev);
103262306a36Sopenharmony_ci	struct drm_vmw_fence_event_arg *arg =
103362306a36Sopenharmony_ci		(struct drm_vmw_fence_event_arg *) data;
103462306a36Sopenharmony_ci	struct vmw_fence_obj *fence = NULL;
103562306a36Sopenharmony_ci	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
103662306a36Sopenharmony_ci	struct ttm_object_file *tfile = vmw_fp->tfile;
103762306a36Sopenharmony_ci	struct drm_vmw_fence_rep __user *user_fence_rep =
103862306a36Sopenharmony_ci		(struct drm_vmw_fence_rep __user *)(unsigned long)
103962306a36Sopenharmony_ci		arg->fence_rep;
104062306a36Sopenharmony_ci	uint32_t handle;
104162306a36Sopenharmony_ci	int ret;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/*
104462306a36Sopenharmony_ci	 * Look up an existing fence object,
104562306a36Sopenharmony_ci	 * and if user-space wants a new reference,
104662306a36Sopenharmony_ci	 * add one.
104762306a36Sopenharmony_ci	 */
104862306a36Sopenharmony_ci	if (arg->handle) {
104962306a36Sopenharmony_ci		struct ttm_base_object *base =
105062306a36Sopenharmony_ci			vmw_fence_obj_lookup(tfile, arg->handle);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		if (IS_ERR(base))
105362306a36Sopenharmony_ci			return PTR_ERR(base);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		fence = &(container_of(base, struct vmw_user_fence,
105662306a36Sopenharmony_ci				       base)->fence);
105762306a36Sopenharmony_ci		(void) vmw_fence_obj_reference(fence);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		if (user_fence_rep != NULL) {
106062306a36Sopenharmony_ci			ret = ttm_ref_object_add(vmw_fp->tfile, base,
106162306a36Sopenharmony_ci						 NULL, false);
106262306a36Sopenharmony_ci			if (unlikely(ret != 0)) {
106362306a36Sopenharmony_ci				DRM_ERROR("Failed to reference a fence "
106462306a36Sopenharmony_ci					  "object.\n");
106562306a36Sopenharmony_ci				goto out_no_ref_obj;
106662306a36Sopenharmony_ci			}
106762306a36Sopenharmony_ci			handle = base->handle;
106862306a36Sopenharmony_ci		}
106962306a36Sopenharmony_ci		ttm_base_object_unref(&base);
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/*
107362306a36Sopenharmony_ci	 * Create a new fence object.
107462306a36Sopenharmony_ci	 */
107562306a36Sopenharmony_ci	if (!fence) {
107662306a36Sopenharmony_ci		ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
107762306a36Sopenharmony_ci						 &fence,
107862306a36Sopenharmony_ci						 (user_fence_rep) ?
107962306a36Sopenharmony_ci						 &handle : NULL);
108062306a36Sopenharmony_ci		if (unlikely(ret != 0)) {
108162306a36Sopenharmony_ci			DRM_ERROR("Fence event failed to create fence.\n");
108262306a36Sopenharmony_ci			return ret;
108362306a36Sopenharmony_ci		}
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	BUG_ON(fence == NULL);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	ret = vmw_event_fence_action_create(file_priv, fence,
108962306a36Sopenharmony_ci					    arg->flags,
109062306a36Sopenharmony_ci					    arg->user_data,
109162306a36Sopenharmony_ci					    true);
109262306a36Sopenharmony_ci	if (unlikely(ret != 0)) {
109362306a36Sopenharmony_ci		if (ret != -ERESTARTSYS)
109462306a36Sopenharmony_ci			DRM_ERROR("Failed to attach event to fence.\n");
109562306a36Sopenharmony_ci		goto out_no_create;
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
109962306a36Sopenharmony_ci				    handle, -1);
110062306a36Sopenharmony_ci	vmw_fence_obj_unreference(&fence);
110162306a36Sopenharmony_ci	return 0;
110262306a36Sopenharmony_ciout_no_create:
110362306a36Sopenharmony_ci	if (user_fence_rep != NULL)
110462306a36Sopenharmony_ci		ttm_ref_object_base_unref(tfile, handle);
110562306a36Sopenharmony_ciout_no_ref_obj:
110662306a36Sopenharmony_ci	vmw_fence_obj_unreference(&fence);
110762306a36Sopenharmony_ci	return ret;
110862306a36Sopenharmony_ci}
1109