1ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom/**************************************************************************
2ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
3ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA
4ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * All Rights Reserved.
5ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
6ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * Permission is hereby granted, free of charge, to any person obtaining a
7ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * copy of this software and associated documentation files (the
8ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * "Software"), to deal in the Software without restriction, including
9ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * without limitation the rights to use, copy, modify, merge, publish,
10ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * distribute, sub license, and/or sell copies of the Software, and to
11ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * permit persons to whom the Software is furnished to do so, subject to
12ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * the following conditions:
13ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
14ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * The above copyright notice and this permission notice (including the
15ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * next paragraph) shall be included in all copies or substantial portions
16ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * of the Software.
17ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
18ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * USE OR OTHER DEALINGS IN THE SOFTWARE.
25ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
26ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom **************************************************************************/
27ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
28ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom#include "drmP.h"
29ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom#include "vmwgfx_drv.h"
30ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
31ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom#define VMW_FENCE_WRAP (1 << 31)
32ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
33ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstruct vmw_fence_manager {
34ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	int num_fence_objects;
35ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_private *dev_priv;
36ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spinlock_t lock;
37ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct list_head fence_list;
38ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct work_struct work;
39ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	u32 user_fence_size;
40ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	u32 fence_size;
4157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	u32 event_fence_action_size;
42ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	bool fifo_down;
43ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct list_head cleanup_list;
4457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	uint32_t pending_actions[VMW_ACTION_MAX];
4557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct mutex goal_irq_mutex;
4657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	bool goal_irq_on; /* Protected by @goal_irq_mutex */
4757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	bool seqno_valid; /* Protected by @lock, and may not be set to true
4857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			     without the @goal_irq_mutex held. */
49ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom};
50ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
51ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstruct vmw_user_fence {
52ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_base_object base;
53ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj fence;
54ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom};
55ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
56ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom/**
5757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * struct vmw_event_fence_action - fence action that delivers a drm event.
58ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
5957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @e: A struct drm_pending_event that controls the event delivery.
6057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @action: A struct vmw_fence_action to hook up to a fence.
6157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @fence: A referenced pointer to the fence to keep it alive while @action
6257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * hangs on it.
6357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @dev: Pointer to a struct drm_device so we can access the event stuff.
6457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @kref: Both @e and @action has destructors, so we need to refcount.
6557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @size: Size accounted for this object.
6657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @tv_sec: If non-null, the variable pointed to will be assigned
6757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * current time tv_sec val when the fence signals.
6857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
6957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * be assigned the current time tv_usec val when the fence signals.
7057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
7157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromstruct vmw_event_fence_action {
7257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fence_action action;
736b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct list_head fpriv_head;
748b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
758b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	struct drm_pending_event *event;
7657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fence_obj *fence;
7757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct drm_device *dev;
788b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
7957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	uint32_t *tv_sec;
8057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	uint32_t *tv_usec;
8157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom};
8257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
8357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
8457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * Note on fencing subsystem usage of irqs:
8557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * Typically the vmw_fences_update function is called
8657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
8757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * a) When a new fence seqno has been submitted by the fifo code.
8857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * b) On-demand when we have waiters. Sleeping waiters will switch on the
8957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * ANY_FENCE irq and call vmw_fences_update function each time an ANY_FENCE
9057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * irq is received. When the last fence waiter is gone, that IRQ is masked
9157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * away.
9257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
9357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * In situations where there are no waiters and we don't submit any new fences,
9457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * fence objects may not be signaled. This is perfectly OK, since there are
9557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * no consumers of the signaled data, but that is NOT ok when there are fence
9657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * actions attached to a fence. The fencing subsystem then makes use of the
9757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * FENCE_GOAL irq and sets the fence goal seqno to that of the next fence
9857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * which has an action attached, and each time vmw_fences_update is called,
9957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * the subsystem makes sure the fence goal seqno is updated.
10057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
10157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * The fence goal seqno irq is on as long as there are unsignaled fence
10257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * objects with actions attached to them.
103ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom */
104ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
105ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstatic void vmw_fence_obj_destroy_locked(struct kref *kref)
106ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
107ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence =
108ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		container_of(kref, struct vmw_fence_obj, kref);
109ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
110ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman = fence->fman;
111ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned int num_fences;
112ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
113ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	list_del_init(&fence->head);
114ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	num_fences = --fman->num_fence_objects;
115ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irq(&fman->lock);
116ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (fence->destroy)
117ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		fence->destroy(fence);
118ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	else
119ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		kfree(fence);
120ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
121ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irq(&fman->lock);
122ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
123ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
124ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
125ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom/**
126ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * Execute signal actions on fences recently signaled.
127ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * This is done from a workqueue so we don't have to execute
128ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * signal actions from atomic context.
129ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom */
130ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
131ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstatic void vmw_fence_work_func(struct work_struct *work)
132ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
133ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman =
134ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		container_of(work, struct vmw_fence_manager, work);
135ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct list_head list;
136ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_action *action, *next_action;
13757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	bool seqno_valid;
138ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
139ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	do {
140ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		INIT_LIST_HEAD(&list);
14157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		mutex_lock(&fman->goal_irq_mutex);
14257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
143ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		spin_lock_irq(&fman->lock);
144ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		list_splice_init(&fman->cleanup_list, &list);
14557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		seqno_valid = fman->seqno_valid;
146ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		spin_unlock_irq(&fman->lock);
147ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
14857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (!seqno_valid && fman->goal_irq_on) {
14957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			fman->goal_irq_on = false;
15057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			vmw_goal_waiter_remove(fman->dev_priv);
15157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
15257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		mutex_unlock(&fman->goal_irq_mutex);
15357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
154ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		if (list_empty(&list))
155ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			return;
156ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
157ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		/*
158ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 * At this point, only we should be able to manipulate the
159ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 * list heads of the actions we have on the private list.
16057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		 * hence fman::lock not held.
161ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 */
162ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
163ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		list_for_each_entry_safe(action, next_action, &list, head) {
164ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			list_del_init(&action->head);
16557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			if (action->cleanup)
16657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				action->cleanup(action);
167ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		}
168ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	} while (1);
169ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
170ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
171ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstruct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
172ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
173ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman = kzalloc(sizeof(*fman), GFP_KERNEL);
174ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
175ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(fman == NULL))
176ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return NULL;
177ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
178ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman->dev_priv = dev_priv;
179ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_init(&fman->lock);
180ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	INIT_LIST_HEAD(&fman->fence_list);
181ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	INIT_LIST_HEAD(&fman->cleanup_list);
182ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	INIT_WORK(&fman->work, &vmw_fence_work_func);
183ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman->fifo_down = true;
184ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman->user_fence_size = ttm_round_pot(sizeof(struct vmw_user_fence));
185ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman->fence_size = ttm_round_pot(sizeof(struct vmw_fence_obj));
18657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	fman->event_fence_action_size =
18757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		ttm_round_pot(sizeof(struct vmw_event_fence_action));
18857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_init(&fman->goal_irq_mutex);
189ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
190ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return fman;
191ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
192ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
193ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
194ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
195ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long irq_flags;
196ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	bool lists_empty;
197ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
198ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	(void) cancel_work_sync(&fman->work);
199ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
200ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
201ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	lists_empty = list_empty(&fman->fence_list) &&
202ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		list_empty(&fman->cleanup_list);
203ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
204ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
205ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	BUG_ON(!lists_empty);
206ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kfree(fman);
207ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
208ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
209ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstatic int vmw_fence_obj_init(struct vmw_fence_manager *fman,
210ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			      struct vmw_fence_obj *fence,
211ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			      u32 seqno,
212ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			      uint32_t mask,
213ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			      void (*destroy) (struct vmw_fence_obj *fence))
214ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
215ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long irq_flags;
216ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned int num_fences;
217ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	int ret = 0;
218ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
219ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence->seqno = seqno;
220ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	INIT_LIST_HEAD(&fence->seq_passed_actions);
221ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence->fman = fman;
222ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence->signaled = 0;
223ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence->signal_mask = mask;
224ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kref_init(&fence->kref);
225ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence->destroy = destroy;
226ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	init_waitqueue_head(&fence->queue);
227ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
228ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
229ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(fman->fifo_down)) {
230ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = -EBUSY;
231ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out_unlock;
232ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
233ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	list_add_tail(&fence->head, &fman->fence_list);
234ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	num_fences = ++fman->num_fence_objects;
235ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
236ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromout_unlock:
237ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
238ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ret;
239ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
240ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
241ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
242ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstruct vmw_fence_obj *vmw_fence_obj_reference(struct vmw_fence_obj *fence)
243ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
244e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom	if (unlikely(fence == NULL))
245e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom		return NULL;
246e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom
247ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kref_get(&fence->kref);
248ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return fence;
249ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
250ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
251ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom/**
252ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * vmw_fence_obj_unreference
253ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
254ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * Note that this function may not be entered with disabled irqs since
255ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * it may re-enable them in the destroy function.
256ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom *
257ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom */
258ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p)
259ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
260ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence = *fence_p;
261e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom	struct vmw_fence_manager *fman;
262e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom
263e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom	if (unlikely(fence == NULL))
264e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom		return;
265ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
266e93daed8e2fd5ce3dc98efe9938426127a534cccThomas Hellstrom	fman = fence->fman;
267ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	*fence_p = NULL;
268ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irq(&fman->lock);
269ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	BUG_ON(atomic_read(&fence->kref.refcount) == 0);
270ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kref_put(&fence->kref, vmw_fence_obj_destroy_locked);
271ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irq(&fman->lock);
272ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
273ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
274ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_fences_perform_actions(struct vmw_fence_manager *fman,
275ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				struct list_head *list)
276ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
277ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_action *action, *next_action;
278ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
279ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	list_for_each_entry_safe(action, next_action, list, head) {
280ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		list_del_init(&action->head);
28157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		fman->pending_actions[action->type]--;
282ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		if (action->seq_passed != NULL)
283ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			action->seq_passed(action);
284ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
285ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		/*
286ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 * Add the cleanup action to the cleanup list so that
287ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 * it will be performed by a worker task.
288ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 */
289ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
29057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		list_add_tail(&action->head, &fman->cleanup_list);
29157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
29257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
29357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
29457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
29557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_fence_goal_new_locked - Figure out a new device fence goal
29657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * seqno if needed.
29757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
29857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @fman: Pointer to a fence manager.
29957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @passed_seqno: The seqno the device currently signals as passed.
30057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
30157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * This function should be called with the fence manager lock held.
30257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * It is typically called when we have a new passed_seqno, and
30357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * we might need to update the fence goal. It checks to see whether
30457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * the current fence goal has already passed, and, in that case,
30557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * scans through all unsignaled fences to get the next fence object with an
30657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * action attached, and sets the seqno of that fence as a new fence goal.
30757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
30857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * returns true if the device goal seqno was updated. False otherwise.
30957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
31057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromstatic bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
31157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				      u32 passed_seqno)
31257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
31357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	u32 goal_seqno;
31457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	__le32 __iomem *fifo_mem;
31557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fence_obj *fence;
31657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
31757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (likely(!fman->seqno_valid))
31857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		return false;
31957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
32057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	fifo_mem = fman->dev_priv->mmio_virt;
32157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	goal_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE_GOAL);
32257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
32357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		return false;
32457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
32557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	fman->seqno_valid = false;
32657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	list_for_each_entry(fence, &fman->fence_list, head) {
32757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (!list_empty(&fence->seq_passed_actions)) {
32857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			fman->seqno_valid = true;
32957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			iowrite32(fence->seqno,
33057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				  fifo_mem + SVGA_FIFO_FENCE_GOAL);
33157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			break;
33257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
333ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
33457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
33557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	return true;
33657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
33757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
33857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
33957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
34057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_fence_goal_check_locked - Replace the device fence goal seqno if
34157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * needed.
34257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
34357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @fence: Pointer to a struct vmw_fence_obj the seqno of which should be
34457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * considered as a device fence goal.
34557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
34657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * This function should be called with the fence manager lock held.
34757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * It is typically called when an action has been attached to a fence to
34857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * check whether the seqno of that fence should be used for a fence
34957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * goal interrupt. This is typically needed if the current fence goal is
35057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * invalid, or has a higher seqno than that of the current fence object.
35157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
35257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * returns true if the device goal seqno was updated. False otherwise.
35357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
35457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromstatic bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
35557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
35657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	u32 goal_seqno;
35757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	__le32 __iomem *fifo_mem;
35857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
35957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (fence->signaled & DRM_VMW_FENCE_FLAG_EXEC)
36057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		return false;
36157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
36257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	fifo_mem = fence->fman->dev_priv->mmio_virt;
36357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	goal_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE_GOAL);
36457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (likely(fence->fman->seqno_valid &&
36557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		   goal_seqno - fence->seqno < VMW_FENCE_WRAP))
36657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		return false;
36757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
36857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	iowrite32(fence->seqno, fifo_mem + SVGA_FIFO_FENCE_GOAL);
36957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	fence->fman->seqno_valid = true;
37057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
37157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	return true;
372ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
373ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
37457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromvoid vmw_fences_update(struct vmw_fence_manager *fman)
375ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
376ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long flags;
377ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence, *next_fence;
378ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct list_head action_list;
37957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	bool needs_rerun;
38057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	uint32_t seqno, new_seqno;
38157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	__le32 __iomem *fifo_mem = fman->dev_priv->mmio_virt;
382ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
38357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
38457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromrerun:
385ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, flags);
386ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
387ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		if (seqno - fence->seqno < VMW_FENCE_WRAP) {
388ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			list_del_init(&fence->head);
389ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			fence->signaled |= DRM_VMW_FENCE_FLAG_EXEC;
390ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			INIT_LIST_HEAD(&action_list);
391ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			list_splice_init(&fence->seq_passed_actions,
392ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom					 &action_list);
393ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			vmw_fences_perform_actions(fman, &action_list);
394ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			wake_up_all(&fence->queue);
39557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		} else
39657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			break;
397ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
39857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
39957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	needs_rerun = vmw_fence_goal_new_locked(fman, seqno);
40057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
401ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (!list_empty(&fman->cleanup_list))
402ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		(void) schedule_work(&fman->work);
403ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, flags);
404ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
40557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	/*
40657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * Rerun if the fence goal seqno was updated, and the
40757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * hardware might have raced with that update, so that
40857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * we missed a fence_goal irq.
40957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 */
41057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
41157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (unlikely(needs_rerun)) {
41257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		new_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
41357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (new_seqno != seqno) {
41457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			seqno = new_seqno;
41557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			goto rerun;
41657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
41757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
41857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
419ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
420ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrombool vmw_fence_obj_signaled(struct vmw_fence_obj *fence,
421ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			    uint32_t flags)
422ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
423ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman = fence->fman;
424ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long irq_flags;
425ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	uint32_t signaled;
426ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
427ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
428ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	signaled = fence->signaled;
429ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
430ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
431ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	flags &= fence->signal_mask;
432ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if ((signaled & flags) == flags)
433ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return 1;
434ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
43557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if ((signaled & DRM_VMW_FENCE_FLAG_EXEC) == 0)
43657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_fences_update(fman);
437ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
438ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
439ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	signaled = fence->signaled;
440ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
441ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
442ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ((signaled & flags) == flags);
443ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
444ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
445ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromint vmw_fence_obj_wait(struct vmw_fence_obj *fence,
446ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       uint32_t flags, bool lazy,
447ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       bool interruptible, unsigned long timeout)
448ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
449ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_private *dev_priv = fence->fman->dev_priv;
450ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	long ret;
451ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
452ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (likely(vmw_fence_obj_signaled(fence, flags)))
453ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return 0;
454ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
455ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
456ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	vmw_seqno_waiter_add(dev_priv);
457ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
458ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (interruptible)
459ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = wait_event_interruptible_timeout
460ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			(fence->queue,
461ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			 vmw_fence_obj_signaled(fence, flags),
462ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			 timeout);
463ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	else
464ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = wait_event_timeout
465ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			(fence->queue,
466ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			 vmw_fence_obj_signaled(fence, flags),
467ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			 timeout);
468ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
469ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	vmw_seqno_waiter_remove(dev_priv);
470ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
471ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ret == 0))
472ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = -EBUSY;
473ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	else if (likely(ret > 0))
474ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = 0;
475ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
476ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ret;
477ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
478ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
479ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_fence_obj_flush(struct vmw_fence_obj *fence)
480ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
481ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_private *dev_priv = fence->fman->dev_priv;
482ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
483ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
484ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
485ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
486ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstatic void vmw_fence_destroy(struct vmw_fence_obj *fence)
487ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
488ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman = fence->fman;
489ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
490ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kfree(fence);
491ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
492ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * Free kernel space accounting.
493ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
494ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ttm_mem_global_free(vmw_mem_glob(fman->dev_priv),
495ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			    fman->fence_size);
496ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
497ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
498ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromint vmw_fence_create(struct vmw_fence_manager *fman,
499ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		     uint32_t seqno,
500ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		     uint32_t mask,
501ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		     struct vmw_fence_obj **p_fence)
502ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
503ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_mem_global *mem_glob = vmw_mem_glob(fman->dev_priv);
504ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence;
505ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	int ret;
506ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
507ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ret = ttm_mem_global_alloc(mem_glob, fman->fence_size,
508ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				   false, false);
509ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ret != 0))
510ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return ret;
511ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
512ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
513ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(fence == NULL)) {
514ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = -ENOMEM;
515ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out_no_object;
516ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
517ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
518ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ret = vmw_fence_obj_init(fman, fence, seqno, mask,
519ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				 vmw_fence_destroy);
520ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ret != 0))
521ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out_err_init;
522ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
523ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	*p_fence = fence;
524ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return 0;
525ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
526ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromout_err_init:
527ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kfree(fence);
528ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromout_no_object:
529ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ttm_mem_global_free(mem_glob, fman->fence_size);
530ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ret;
531ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
532ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
533ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
534ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstatic void vmw_user_fence_destroy(struct vmw_fence_obj *fence)
535ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
536ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_user_fence *ufence =
537ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		container_of(fence, struct vmw_user_fence, fence);
538ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman = fence->fman;
539ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
540ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	kfree(ufence);
541ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
542ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * Free kernel space accounting.
543ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
544ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ttm_mem_global_free(vmw_mem_glob(fman->dev_priv),
545ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			    fman->user_fence_size);
546ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
547ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
548ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromstatic void vmw_user_fence_base_release(struct ttm_base_object **p_base)
549ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
550ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_base_object *base = *p_base;
551ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_user_fence *ufence =
552ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		container_of(base, struct vmw_user_fence, base);
553ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence = &ufence->fence;
554ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
555ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	*p_base = NULL;
556ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	vmw_fence_obj_unreference(&fence);
557ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
558ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
559ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromint vmw_user_fence_create(struct drm_file *file_priv,
560ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			  struct vmw_fence_manager *fman,
561ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			  uint32_t seqno,
562ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			  uint32_t mask,
563ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			  struct vmw_fence_obj **p_fence,
564ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			  uint32_t *p_handle)
565ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
566ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
567ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_user_fence *ufence;
568ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *tmp;
569ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_mem_global *mem_glob = vmw_mem_glob(fman->dev_priv);
570ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	int ret;
571ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
572ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
573ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * Kernel memory space accounting, since this object may
574ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * be created by a user-space request.
575ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
576ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
577ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ret = ttm_mem_global_alloc(mem_glob, fman->user_fence_size,
578ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				   false, false);
579ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ret != 0))
580ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return ret;
581ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
582ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
583ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ufence == NULL)) {
584ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = -ENOMEM;
585ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out_no_object;
586ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
587ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
588ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ret = vmw_fence_obj_init(fman, &ufence->fence, seqno,
589ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				 mask, vmw_user_fence_destroy);
590ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ret != 0)) {
591ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		kfree(ufence);
592ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out_no_object;
593ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
594ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
595ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
596ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * The base object holds a reference which is freed in
597ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * vmw_user_fence_base_release.
598ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
599ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	tmp = vmw_fence_obj_reference(&ufence->fence);
600ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ret = ttm_base_object_init(tfile, &ufence->base, false,
601ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				   VMW_RES_FENCE,
602ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				   &vmw_user_fence_base_release, NULL);
603ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
604ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
605ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(ret != 0)) {
606ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		/*
607ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 * Free the base object's reference
608ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		 */
609ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		vmw_fence_obj_unreference(&tmp);
610ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out_err;
611ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
612ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
613ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	*p_fence = &ufence->fence;
614ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	*p_handle = ufence->base.hash.key;
615ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
616ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return 0;
617ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromout_err:
618ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	tmp = &ufence->fence;
619ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	vmw_fence_obj_unreference(&tmp);
620ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromout_no_object:
621ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ttm_mem_global_free(mem_glob, fman->user_fence_size);
622ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ret;
623ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
624ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
625ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
626ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom/**
627ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom * vmw_fence_fifo_down - signal all unsignaled fence objects.
628ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom */
629ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
630ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_fence_fifo_down(struct vmw_fence_manager *fman)
631ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
632ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long irq_flags;
633ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct list_head action_list;
634ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	int ret;
635ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
636ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
637ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * The list may be altered while we traverse it, so always
638ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * restart when we've released the fman->lock.
639ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
640ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
641ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
642ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman->fifo_down = true;
643ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	while (!list_empty(&fman->fence_list)) {
644ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		struct vmw_fence_obj *fence =
645ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			list_entry(fman->fence_list.prev, struct vmw_fence_obj,
646ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				   head);
647ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		kref_get(&fence->kref);
648ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		spin_unlock_irq(&fman->lock);
649ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
650ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = vmw_fence_obj_wait(fence, fence->signal_mask,
651ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom					 false, false,
652ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom					 VMW_FENCE_WAIT_TIMEOUT);
653ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
654ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		if (unlikely(ret != 0)) {
655ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			list_del_init(&fence->head);
656ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			fence->signaled |= DRM_VMW_FENCE_FLAG_EXEC;
657ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			INIT_LIST_HEAD(&action_list);
658ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			list_splice_init(&fence->seq_passed_actions,
659ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom					 &action_list);
660ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			vmw_fences_perform_actions(fman, &action_list);
661ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			wake_up_all(&fence->queue);
662ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		}
663ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
664ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		spin_lock_irq(&fman->lock);
665ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
666ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		BUG_ON(!list_empty(&fence->head));
667ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		kref_put(&fence->kref, vmw_fence_obj_destroy_locked);
668ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
669ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
670ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
671ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
672ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_fence_fifo_up(struct vmw_fence_manager *fman)
673ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
674ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long irq_flags;
675ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
676ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
677ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman->fifo_down = false;
678ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
679ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
680ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
681ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
682ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromint vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
683ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			     struct drm_file *file_priv)
684ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
685ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct drm_vmw_fence_wait_arg *arg =
686ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	    (struct drm_vmw_fence_wait_arg *)data;
687ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	unsigned long timeout;
688ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_base_object *base;
689ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence;
690ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
691ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	int ret;
692ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	uint64_t wait_timeout = ((uint64_t)arg->timeout_us * HZ);
693ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
694ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
695ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * 64-bit division not present on 32-bit systems, so do an
696ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * approximation. (Divide by 1000000).
697ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
698ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
699ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	wait_timeout = (wait_timeout >> 20) + (wait_timeout >> 24) -
700ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	  (wait_timeout >> 26);
701ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
702ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (!arg->cookie_valid) {
703ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		arg->cookie_valid = 1;
704ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		arg->kernel_cookie = jiffies + wait_timeout;
705ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
706ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
707ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	base = ttm_base_object_lookup(tfile, arg->handle);
708ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(base == NULL)) {
709ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		printk(KERN_ERR "Wait invalid fence object handle "
710ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       "0x%08lx.\n",
711ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       (unsigned long)arg->handle);
712ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return -EINVAL;
713ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
714ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
715ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
716ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
717ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	timeout = jiffies;
718ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie)) {
719ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		ret = ((vmw_fence_obj_signaled(fence, arg->flags)) ?
720ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       0 : -EBUSY);
721ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		goto out;
722ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
723ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
724ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	timeout = (unsigned long)arg->kernel_cookie - timeout;
725ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
726ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ret = vmw_fence_obj_wait(fence, arg->flags, arg->lazy, true, timeout);
727ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
728ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromout:
729ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ttm_base_object_unref(&base);
730ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
731ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	/*
732ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 * Optionally unref the fence object.
733ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	 */
734ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
735ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (ret == 0 && (arg->wait_options & DRM_VMW_WAIT_OPTION_UNREF))
736ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return ttm_ref_object_base_unref(tfile, arg->handle,
737ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom						 TTM_REF_USAGE);
738ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ret;
739ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
740ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
741ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromint vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
742ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom				 struct drm_file *file_priv)
743ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
744ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct drm_vmw_fence_signaled_arg *arg =
745ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		(struct drm_vmw_fence_signaled_arg *) data;
746ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_base_object *base;
747ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_obj *fence;
748ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_fence_manager *fman;
749ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
750ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct vmw_private *dev_priv = vmw_priv(dev);
751ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
752ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	base = ttm_base_object_lookup(tfile, arg->handle);
753ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	if (unlikely(base == NULL)) {
754ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		printk(KERN_ERR "Fence signaled invalid fence object handle "
755ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       "0x%08lx.\n",
756ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		       (unsigned long)arg->handle);
757ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		return -EINVAL;
758ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
759ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
760ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
761ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	fman = fence->fman;
762ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
763ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	arg->signaled = vmw_fence_obj_signaled(fence, arg->flags);
764ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_lock_irq(&fman->lock);
765ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
766ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	arg->signaled_flags = fence->signaled;
767ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	arg->passed_seqno = dev_priv->last_read_seqno;
768ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	spin_unlock_irq(&fman->lock);
769ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
770ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	ttm_base_object_unref(&base);
771ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
772ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return 0;
773ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
774ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
775ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
776ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromint vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
777ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom			      struct drm_file *file_priv)
778ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom{
779ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	struct drm_vmw_fence_arg *arg =
780ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom		(struct drm_vmw_fence_arg *) data;
781ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
782ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
783ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom					 arg->handle,
784ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom					 TTM_REF_USAGE);
785ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom}
78657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
7876b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom/**
7886b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * vmw_event_fence_fpriv_gone - Remove references to struct drm_file objects
7896b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom *
7906b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * @fman: Pointer to a struct vmw_fence_manager
7916b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * @event_list: Pointer to linked list of struct vmw_event_fence_action objects
7926b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * with pointers to a struct drm_file object about to be closed.
7936b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom *
7946b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * This function removes all pending fence events with references to a
7956b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * specific struct drm_file object about to be closed. The caller is required
7966b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * to pass a list of all struct vmw_event_fence_action objects with such
7976b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * events attached. This function is typically called before the
7986b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom * struct drm_file object's event management is taken down.
7996b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom */
8006b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstromvoid vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
8016b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom				struct list_head *event_list)
8026b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom{
8036b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct vmw_event_fence_action *eaction;
8046b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct drm_pending_event *event;
8056b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	unsigned long irq_flags;
8066b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom
8076b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	while (1) {
8086b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		spin_lock_irqsave(&fman->lock, irq_flags);
8096b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		if (list_empty(event_list))
8106b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom			goto out_unlock;
8116b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		eaction = list_first_entry(event_list,
8126b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom					   struct vmw_event_fence_action,
8136b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom					   fpriv_head);
8146b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		list_del_init(&eaction->fpriv_head);
8156b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		event = eaction->event;
8166b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		eaction->event = NULL;
8176b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		spin_unlock_irqrestore(&fman->lock, irq_flags);
8186b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		event->destroy(event);
8196b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	}
8206b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstromout_unlock:
8216b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
8226b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom}
8236b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom
82457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
82557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
82657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_event_fence_action_seq_passed
82757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
82857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @action: The struct vmw_fence_action embedded in a struct
82957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_event_fence_action.
83057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
83157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * This function is called when the seqno of the fence where @action is
83257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * attached has passed. It queues the event on the submitter's event list.
83357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * This function is always called from atomic context, and may be called
8348b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz * from irq context.
83557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
83657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromstatic void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
83757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
83857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_event_fence_action *eaction =
83957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		container_of(action, struct vmw_event_fence_action, action);
84057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct drm_device *dev = eaction->dev;
8416b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct drm_pending_event *event = eaction->event;
8426b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct drm_file *file_priv;
84357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	unsigned long irq_flags;
84457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
8456b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	if (unlikely(event == NULL))
8466b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom		return;
8476b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom
8486b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	file_priv = event->file_priv;
84957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	spin_lock_irqsave(&dev->event_lock, irq_flags);
85057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
85157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (likely(eaction->tv_sec != NULL)) {
85257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		struct timeval tv;
85357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
85457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		do_gettimeofday(&tv);
85557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		*eaction->tv_sec = tv.tv_sec;
85657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		*eaction->tv_usec = tv.tv_usec;
85757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
85857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
8596b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	list_del_init(&eaction->fpriv_head);
8608b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	list_add_tail(&eaction->event->link, &file_priv->event_list);
8616b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	eaction->event = NULL;
86257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	wake_up_all(&file_priv->event_wait);
86357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
86457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
86557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
86657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
86757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_event_fence_action_cleanup
86857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
86957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @action: The struct vmw_fence_action embedded in a struct
87057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_event_fence_action.
87157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
87257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * This function is the struct vmw_fence_action destructor. It's typically
87357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * called from a workqueue.
87457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
87557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromstatic void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
87657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
87757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_event_fence_action *eaction =
87857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		container_of(action, struct vmw_event_fence_action, action);
8796b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct vmw_fence_manager *fman = eaction->fence->fman;
8806b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	unsigned long irq_flags;
8816b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom
8826b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
8836b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	list_del(&eaction->fpriv_head);
8846b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
88557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
88657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	vmw_fence_obj_unreference(&eaction->fence);
8878b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	kfree(eaction);
88857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
88957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
89057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
89157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
89257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_fence_obj_add_action - Add an action to a fence object.
89357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
89457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @fence - The fence object.
89557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @action - The action to add.
89657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
89757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * Note that the action callbacks may be executed before this function
89857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * returns.
89957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
90057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromvoid vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
90157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			      struct vmw_fence_action *action)
90257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
90357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fence_manager *fman = fence->fman;
90457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	unsigned long irq_flags;
90557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	bool run_update = false;
90657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
90757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_lock(&fman->goal_irq_mutex);
90857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
90957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
91057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	fman->pending_actions[action->type]++;
91157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (fence->signaled & DRM_VMW_FENCE_FLAG_EXEC) {
91257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		struct list_head action_list;
91357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
91457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		INIT_LIST_HEAD(&action_list);
91557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		list_add_tail(&action->head, &action_list);
91657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_fences_perform_actions(fman, &action_list);
91757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	} else {
91857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		list_add_tail(&action->head, &fence->seq_passed_actions);
91957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
92057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		/*
92157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		 * This function may set fman::seqno_valid, so it must
92257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		 * be run with the goal_irq_mutex held.
92357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		 */
92457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		run_update = vmw_fence_goal_check_locked(fence);
92557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
92657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
92757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
92857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
92957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (run_update) {
93057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (!fman->goal_irq_on) {
93157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			fman->goal_irq_on = true;
93257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			vmw_goal_waiter_add(fman->dev_priv);
93357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
93457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_fences_update(fman);
93557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
93657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_unlock(&fman->goal_irq_mutex);
93757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
93857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
93957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
94057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom/**
94157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * vmw_event_fence_action_create - Post an event for sending when a fence
94257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * object seqno has passed.
94357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
94457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @file_priv: The file connection on which the event should be posted.
94557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @fence: The fence object on which to post the event.
94657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @event: Event to be posted. This event should've been alloced
94757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * using k[mz]alloc, and should've been completely initialized.
94857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * @interruptible: Interruptible waits if possible.
94957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom *
95057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * As a side effect, the object pointed to by @event may have been
95157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * freed when this function returns. If this function returns with
95257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom * an error code, the caller needs to free that object.
95357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom */
95457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
9558b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzint vmw_event_fence_action_queue(struct drm_file *file_priv,
9568b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				 struct vmw_fence_obj *fence,
9578b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				 struct drm_pending_event *event,
9588b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				 uint32_t *tv_sec,
9598b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				 uint32_t *tv_usec,
9608b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				 bool interruptible)
96157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
9620c5d37033b3a16fdf6442730cee82dd3e8465fb1Dan Carpenter	struct vmw_event_fence_action *eaction;
96357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fence_manager *fman = fence->fman;
9646b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
9656b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	unsigned long irq_flags;
96657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
96757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
9688b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	if (unlikely(eaction == NULL))
96957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		return -ENOMEM;
97057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
9718b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	eaction->event = event;
97257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
97357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
97457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->action.cleanup = vmw_event_fence_action_cleanup;
97557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->action.type = VMW_ACTION_EVENT;
97657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
97757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->fence = vmw_fence_obj_reference(fence);
97857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->dev = fman->dev_priv->dev;
97957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->tv_sec = tv_sec;
98057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	eaction->tv_usec = tv_usec;
98157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
9826b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	spin_lock_irqsave(&fman->lock, irq_flags);
9836b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	list_add_tail(&eaction->fpriv_head, &vmw_fp->fence_events);
9846b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom	spin_unlock_irqrestore(&fman->lock, irq_flags);
9856b82ef50d8617f3fcd51dda9d89d973fe3bc65b8Thomas Hellstrom
98657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	vmw_fence_obj_add_action(fence, &eaction->action);
98757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
98857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	return 0;
98957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
99057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
9918b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzstruct vmw_event_fence_pending {
9928b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	struct drm_pending_event base;
9938b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	struct drm_vmw_event_fence event;
9948b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz};
9958b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
9968b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzint vmw_event_fence_action_create(struct drm_file *file_priv,
9978b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				  struct vmw_fence_obj *fence,
9988b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				  uint32_t flags,
9998b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				  uint64_t user_data,
10008b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz				  bool interruptible)
10018b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz{
10028b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	struct vmw_event_fence_pending *event;
10038b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	struct drm_device *dev = fence->fman->dev_priv->dev;
10048b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	unsigned long irq_flags;
10058b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	int ret;
10068b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10078b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	spin_lock_irqsave(&dev->event_lock, irq_flags);
10088b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10098b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	ret = (file_priv->event_space < sizeof(event->event)) ? -EBUSY : 0;
10108b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	if (likely(ret == 0))
10118b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		file_priv->event_space -= sizeof(event->event);
10128b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10138b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
10148b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10158b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	if (unlikely(ret != 0)) {
10168b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		DRM_ERROR("Failed to allocate event space for this file.\n");
10178b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		goto out_no_space;
10188b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	}
10198b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10208b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10218b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event = kzalloc(sizeof(event->event), GFP_KERNEL);
10228b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	if (unlikely(event == NULL)) {
10238b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		DRM_ERROR("Failed to allocate an event.\n");
10248b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		ret = -ENOMEM;
10258b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		goto out_no_event;
10268b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	}
10278b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10288b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
10298b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->event.base.length = sizeof(*event);
10308b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->event.user_data = user_data;
10318b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10328b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->base.event = &event->event.base;
10338b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->base.file_priv = file_priv;
10348b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
10358b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10368b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10378b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
10388b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		ret = vmw_event_fence_action_queue(file_priv, fence,
10398b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   &event->base,
10408b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   &event->event.tv_sec,
10418b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   &event->event.tv_usec,
10428b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   interruptible);
10438b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	else
10448b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		ret = vmw_event_fence_action_queue(file_priv, fence,
10458b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   &event->base,
10468b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   NULL,
10478b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   NULL,
10488b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						   interruptible);
10498b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	if (ret != 0)
10508b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		goto out_no_queue;
10518b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
10528b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzout_no_queue:
10538b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	event->base.destroy(&event->base);
10548b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzout_no_event:
10558b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	spin_lock_irqsave(&dev->event_lock, irq_flags);
10568b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	file_priv->event_space += sizeof(*event);
10578b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
10588b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzout_no_space:
10598b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz	return ret;
10608b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz}
10618b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz
106257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromint vmw_fence_event_ioctl(struct drm_device *dev, void *data,
106357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			  struct drm_file *file_priv)
106457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
106557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_private *dev_priv = vmw_priv(dev);
106657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct drm_vmw_fence_event_arg *arg =
106757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		(struct drm_vmw_fence_event_arg *) data;
106857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fence_obj *fence = NULL;
106957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
107057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	struct drm_vmw_fence_rep __user *user_fence_rep =
107157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		(struct drm_vmw_fence_rep __user *)(unsigned long)
107257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		arg->fence_rep;
107357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	uint32_t handle;
107457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	int ret;
107557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
107657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	/*
107757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * Look up an existing fence object,
107857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * and if user-space wants a new reference,
107957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * add one.
108057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 */
108157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (arg->handle) {
108257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		struct ttm_base_object *base =
108357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			ttm_base_object_lookup(vmw_fp->tfile, arg->handle);
108457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
108557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (unlikely(base == NULL)) {
108657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			DRM_ERROR("Fence event invalid fence object handle "
108757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				  "0x%08lx.\n",
108857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				  (unsigned long)arg->handle);
108957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			return -EINVAL;
109057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
109157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		fence = &(container_of(base, struct vmw_user_fence,
109257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				       base)->fence);
109357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		(void) vmw_fence_obj_reference(fence);
109457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
109557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (user_fence_rep != NULL) {
109657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			bool existed;
109757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
109857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			ret = ttm_ref_object_add(vmw_fp->tfile, base,
109957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom						 TTM_REF_USAGE, &existed);
110057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			if (unlikely(ret != 0)) {
110157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				DRM_ERROR("Failed to reference a fence "
110257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom					  "object.\n");
110357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				goto out_no_ref_obj;
110457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			}
110557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			handle = base->hash.key;
110657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
110757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		ttm_base_object_unref(&base);
110857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
110957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
111057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	/*
111157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 * Create a new fence object.
111257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	 */
111357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (!fence) {
111457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
111557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom						 &fence,
111657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom						 (user_fence_rep) ?
111757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom						 &handle : NULL);
111857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (unlikely(ret != 0)) {
111957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			DRM_ERROR("Fence event failed to create fence.\n");
112057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			return ret;
112157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		}
112257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
112357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
112457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	BUG_ON(fence == NULL);
112557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
112657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (arg->flags & DRM_VMW_FE_FLAG_REQ_TIME)
112757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		ret = vmw_event_fence_action_create(file_priv, fence,
11288b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						    arg->flags,
11298b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						    arg->user_data,
113057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom						    true);
113157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	else
113257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		ret = vmw_event_fence_action_create(file_priv, fence,
11338b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						    arg->flags,
11348b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz						    arg->user_data,
113557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom						    true);
113657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
113757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (unlikely(ret != 0)) {
113857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		if (ret != -ERESTARTSYS)
113957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			DRM_ERROR("Failed to attach event to fence.\n");
11408b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantz		goto out_no_create;
114157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
114257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
114357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
114457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom				    handle);
114557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	vmw_fence_obj_unreference(&fence);
114657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	return 0;
11478b7de6aa84682a3396544fd88cd457f95484573aJakob Bornecrantzout_no_create:
114857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (user_fence_rep != NULL)
114957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
115057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom					  handle, TTM_REF_USAGE);
115157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromout_no_ref_obj:
115257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	vmw_fence_obj_unreference(&fence);
115357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	return ret;
115457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
1155