vmwgfx_fence.c 30.4 KB
Newer Older
1
2
/**************************************************************************
 *
3
 * Copyright © 2011-2014 VMware, Inc., Palo Alto, CA., USA
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************/

28
#include <drm/drmP.h>
29
30
31
32
33
34
35
36
37
#include "vmwgfx_drv.h"

#define VMW_FENCE_WRAP (1 << 31)

struct vmw_fence_manager {
	int num_fence_objects;
	struct vmw_private *dev_priv;
	spinlock_t lock;
	struct list_head fence_list;
38
	struct work_struct work;
39
40
	u32 user_fence_size;
	u32 fence_size;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
41
	u32 event_fence_action_size;
42
43
	bool fifo_down;
	struct list_head cleanup_list;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
44
45
46
47
48
	uint32_t pending_actions[VMW_ACTION_MAX];
	struct mutex goal_irq_mutex;
	bool goal_irq_on; /* Protected by @goal_irq_mutex */
	bool seqno_valid; /* Protected by @lock, and may not be set to true
			     without the @goal_irq_mutex held. */
49
	u64 ctx;
50
51
52
53
54
55
56
57
};

struct vmw_user_fence {
	struct ttm_base_object base;
	struct vmw_fence_obj fence;
};

/**
Thomas Hellstrom's avatar
Thomas Hellstrom committed
58
 * struct vmw_event_fence_action - fence action that delivers a drm event.
59
 *
Thomas Hellstrom's avatar
Thomas Hellstrom committed
60
61
62
63
64
65
66
67
68
69
70
71
72
73
 * @e: A struct drm_pending_event that controls the event delivery.
 * @action: A struct vmw_fence_action to hook up to a fence.
 * @fence: A referenced pointer to the fence to keep it alive while @action
 * hangs on it.
 * @dev: Pointer to a struct drm_device so we can access the event stuff.
 * @kref: Both @e and @action has destructors, so we need to refcount.
 * @size: Size accounted for this object.
 * @tv_sec: If non-null, the variable pointed to will be assigned
 * current time tv_sec val when the fence signals.
 * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
 * be assigned the current time tv_usec val when the fence signals.
 */
struct vmw_event_fence_action {
	struct vmw_fence_action action;
74
75

	struct drm_pending_event *event;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
76
77
	struct vmw_fence_obj *fence;
	struct drm_device *dev;
78

Thomas Hellstrom's avatar
Thomas Hellstrom committed
79
80
81
82
	uint32_t *tv_sec;
	uint32_t *tv_usec;
};

83
84
85
86
87
88
static struct vmw_fence_manager *
fman_from_fence(struct vmw_fence_obj *fence)
{
	return container_of(fence->base.lock, struct vmw_fence_manager, lock);
}

Thomas Hellstrom's avatar
Thomas Hellstrom committed
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
 * Note on fencing subsystem usage of irqs:
 * Typically the vmw_fences_update function is called
 *
 * a) When a new fence seqno has been submitted by the fifo code.
 * b) On-demand when we have waiters. Sleeping waiters will switch on the
 * ANY_FENCE irq and call vmw_fences_update function each time an ANY_FENCE
 * irq is received. When the last fence waiter is gone, that IRQ is masked
 * away.
 *
 * In situations where there are no waiters and we don't submit any new fences,
 * fence objects may not be signaled. This is perfectly OK, since there are
 * no consumers of the signaled data, but that is NOT ok when there are fence
 * actions attached to a fence. The fencing subsystem then makes use of the
 * FENCE_GOAL irq and sets the fence goal seqno to that of the next fence
 * which has an action attached, and each time vmw_fences_update is called,
 * the subsystem makes sure the fence goal seqno is updated.
 *
 * The fence goal seqno irq is on as long as there are unsignaled fence
 * objects with actions attached to them.
109
110
 */

111
static void vmw_fence_obj_destroy(struct dma_fence *f)
112
113
{
	struct vmw_fence_obj *fence =
114
		container_of(f, struct vmw_fence_obj, base);
115

116
	struct vmw_fence_manager *fman = fman_from_fence(fence);
117

118
	spin_lock(&fman->lock);
119
	list_del_init(&fence->head);
120
	--fman->num_fence_objects;
121
	spin_unlock(&fman->lock);
122
123
	fence->destroy(fence);
}
124

125
static const char *vmw_fence_get_driver_name(struct dma_fence *f)
126
127
128
129
{
	return "vmwgfx";
}

130
static const char *vmw_fence_get_timeline_name(struct dma_fence *f)
131
132
{
	return "svga";
133
134
}

135
static bool vmw_fence_enable_signaling(struct dma_fence *f)
136
137
138
139
140
141
142
{
	struct vmw_fence_obj *fence =
		container_of(f, struct vmw_fence_obj, base);

	struct vmw_fence_manager *fman = fman_from_fence(fence);
	struct vmw_private *dev_priv = fman->dev_priv;

143
144
	u32 *fifo_mem = dev_priv->mmio_virt;
	u32 seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
145
146
147
	if (seqno - fence->base.seqno < VMW_FENCE_WRAP)
		return false;

148
	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
149
150
151
152
153

	return true;
}

struct vmwgfx_wait_cb {
154
	struct dma_fence_cb base;
155
156
157
158
	struct task_struct *task;
};

static void
159
vmwgfx_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
160
161
162
163
164
165
166
167
168
{
	struct vmwgfx_wait_cb *wait =
		container_of(cb, struct vmwgfx_wait_cb, base);

	wake_up_process(wait->task);
}

static void __vmw_fences_update(struct vmw_fence_manager *fman);

169
static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout)
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
{
	struct vmw_fence_obj *fence =
		container_of(f, struct vmw_fence_obj, base);

	struct vmw_fence_manager *fman = fman_from_fence(fence);
	struct vmw_private *dev_priv = fman->dev_priv;
	struct vmwgfx_wait_cb cb;
	long ret = timeout;
	unsigned long irq_flags;

	if (likely(vmw_fence_obj_signaled(fence)))
		return timeout;

	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
	vmw_seqno_waiter_add(dev_priv);

	spin_lock_irqsave(f->lock, irq_flags);

	if (intr && signal_pending(current)) {
		ret = -ERESTARTSYS;
		goto out;
	}

	cb.base.func = vmwgfx_wait_cb;
	cb.task = current;
	list_add(&cb.base.node, &f->cb_list);

	while (ret > 0) {
		__vmw_fences_update(fman);
199
		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
			break;

		if (intr)
			__set_current_state(TASK_INTERRUPTIBLE);
		else
			__set_current_state(TASK_UNINTERRUPTIBLE);
		spin_unlock_irqrestore(f->lock, irq_flags);

		ret = schedule_timeout(ret);

		spin_lock_irqsave(f->lock, irq_flags);
		if (ret > 0 && intr && signal_pending(current))
			ret = -ERESTARTSYS;
	}

	if (!list_empty(&cb.base.node))
		list_del(&cb.base.node);
	__set_current_state(TASK_RUNNING);

out:
	spin_unlock_irqrestore(f->lock, irq_flags);

	vmw_seqno_waiter_remove(dev_priv);

	return ret;
}

227
static const struct dma_fence_ops vmw_fence_ops = {
228
229
230
231
232
233
234
	.get_driver_name = vmw_fence_get_driver_name,
	.get_timeline_name = vmw_fence_get_timeline_name,
	.enable_signaling = vmw_fence_enable_signaling,
	.wait = vmw_fence_wait,
	.release = vmw_fence_obj_destroy,
};

235
236
237
238
239
240
241
242
243
244
245
246
247

/**
 * Execute signal actions on fences recently signaled.
 * This is done from a workqueue so we don't have to execute
 * signal actions from atomic context.
 */

static void vmw_fence_work_func(struct work_struct *work)
{
	struct vmw_fence_manager *fman =
		container_of(work, struct vmw_fence_manager, work);
	struct list_head list;
	struct vmw_fence_action *action, *next_action;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
248
	bool seqno_valid;
249
250
251

	do {
		INIT_LIST_HEAD(&list);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
252
253
		mutex_lock(&fman->goal_irq_mutex);

254
		spin_lock(&fman->lock);
255
		list_splice_init(&fman->cleanup_list, &list);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
256
		seqno_valid = fman->seqno_valid;
257
		spin_unlock(&fman->lock);
258

Thomas Hellstrom's avatar
Thomas Hellstrom committed
259
260
261
262
263
264
		if (!seqno_valid && fman->goal_irq_on) {
			fman->goal_irq_on = false;
			vmw_goal_waiter_remove(fman->dev_priv);
		}
		mutex_unlock(&fman->goal_irq_mutex);

265
266
267
268
269
270
		if (list_empty(&list))
			return;

		/*
		 * At this point, only we should be able to manipulate the
		 * list heads of the actions we have on the private list.
Thomas Hellstrom's avatar
Thomas Hellstrom committed
271
		 * hence fman::lock not held.
272
273
274
275
		 */

		list_for_each_entry_safe(action, next_action, &list, head) {
			list_del_init(&action->head);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
276
277
			if (action->cleanup)
				action->cleanup(action);
278
279
280
281
282
283
284
285
		}
	} while (1);
}

struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
{
	struct vmw_fence_manager *fman = kzalloc(sizeof(*fman), GFP_KERNEL);

286
	if (unlikely(!fman))
287
288
289
290
291
292
293
294
295
296
		return NULL;

	fman->dev_priv = dev_priv;
	spin_lock_init(&fman->lock);
	INIT_LIST_HEAD(&fman->fence_list);
	INIT_LIST_HEAD(&fman->cleanup_list);
	INIT_WORK(&fman->work, &vmw_fence_work_func);
	fman->fifo_down = true;
	fman->user_fence_size = ttm_round_pot(sizeof(struct vmw_user_fence));
	fman->fence_size = ttm_round_pot(sizeof(struct vmw_fence_obj));
Thomas Hellstrom's avatar
Thomas Hellstrom committed
297
298
299
	fman->event_fence_action_size =
		ttm_round_pot(sizeof(struct vmw_event_fence_action));
	mutex_init(&fman->goal_irq_mutex);
300
	fman->ctx = dma_fence_context_alloc(1);
301
302
303
304
305
306
307
308
309
310

	return fman;
}

void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
{
	bool lists_empty;

	(void) cancel_work_sync(&fman->work);

311
	spin_lock(&fman->lock);
312
313
	lists_empty = list_empty(&fman->fence_list) &&
		list_empty(&fman->cleanup_list);
314
	spin_unlock(&fman->lock);
315
316
317
318
319
320

	BUG_ON(!lists_empty);
	kfree(fman);
}

static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
321
			      struct vmw_fence_obj *fence, u32 seqno,
322
323
324
325
			      void (*destroy) (struct vmw_fence_obj *fence))
{
	int ret = 0;

326
327
	dma_fence_init(&fence->base, &vmw_fence_ops, &fman->lock,
		       fman->ctx, seqno);
328
329
330
	INIT_LIST_HEAD(&fence->seq_passed_actions);
	fence->destroy = destroy;

331
	spin_lock(&fman->lock);
332
333
334
335
336
	if (unlikely(fman->fifo_down)) {
		ret = -EBUSY;
		goto out_unlock;
	}
	list_add_tail(&fence->head, &fman->fence_list);
337
	++fman->num_fence_objects;
338
339

out_unlock:
340
	spin_unlock(&fman->lock);
341
342
343
344
	return ret;

}

345
static void vmw_fences_perform_actions(struct vmw_fence_manager *fman,
346
347
348
349
350
351
				struct list_head *list)
{
	struct vmw_fence_action *action, *next_action;

	list_for_each_entry_safe(action, next_action, list, head) {
		list_del_init(&action->head);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
352
		fman->pending_actions[action->type]--;
353
354
355
356
357
358
359
360
		if (action->seq_passed != NULL)
			action->seq_passed(action);

		/*
		 * Add the cleanup action to the cleanup list so that
		 * it will be performed by a worker task.
		 */

Thomas Hellstrom's avatar
Thomas Hellstrom committed
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
		list_add_tail(&action->head, &fman->cleanup_list);
	}
}

/**
 * vmw_fence_goal_new_locked - Figure out a new device fence goal
 * seqno if needed.
 *
 * @fman: Pointer to a fence manager.
 * @passed_seqno: The seqno the device currently signals as passed.
 *
 * This function should be called with the fence manager lock held.
 * It is typically called when we have a new passed_seqno, and
 * we might need to update the fence goal. It checks to see whether
 * the current fence goal has already passed, and, in that case,
 * scans through all unsignaled fences to get the next fence object with an
 * action attached, and sets the seqno of that fence as a new fence goal.
 *
 * returns true if the device goal seqno was updated. False otherwise.
 */
static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
				      u32 passed_seqno)
{
	u32 goal_seqno;
385
	u32 *fifo_mem;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
386
387
388
389
390
391
	struct vmw_fence_obj *fence;

	if (likely(!fman->seqno_valid))
		return false;

	fifo_mem = fman->dev_priv->mmio_virt;
392
	goal_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE_GOAL);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
393
394
395
396
397
398
399
	if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
		return false;

	fman->seqno_valid = false;
	list_for_each_entry(fence, &fman->fence_list, head) {
		if (!list_empty(&fence->seq_passed_actions)) {
			fman->seqno_valid = true;
400
401
			vmw_mmio_write(fence->base.seqno,
				       fifo_mem + SVGA_FIFO_FENCE_GOAL);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
402
403
			break;
		}
404
	}
Thomas Hellstrom's avatar
Thomas Hellstrom committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

	return true;
}


/**
 * vmw_fence_goal_check_locked - Replace the device fence goal seqno if
 * needed.
 *
 * @fence: Pointer to a struct vmw_fence_obj the seqno of which should be
 * considered as a device fence goal.
 *
 * This function should be called with the fence manager lock held.
 * It is typically called when an action has been attached to a fence to
 * check whether the seqno of that fence should be used for a fence
 * goal interrupt. This is typically needed if the current fence goal is
 * invalid, or has a higher seqno than that of the current fence object.
 *
 * returns true if the device goal seqno was updated. False otherwise.
 */
static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
{
427
	struct vmw_fence_manager *fman = fman_from_fence(fence);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
428
	u32 goal_seqno;
429
	u32 *fifo_mem;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
430

431
	if (dma_fence_is_signaled_locked(&fence->base))
Thomas Hellstrom's avatar
Thomas Hellstrom committed
432
433
		return false;

434
	fifo_mem = fman->dev_priv->mmio_virt;
435
	goal_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE_GOAL);
436
437
	if (likely(fman->seqno_valid &&
		   goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
Thomas Hellstrom's avatar
Thomas Hellstrom committed
438
439
		return false;

440
	vmw_mmio_write(fence->base.seqno, fifo_mem + SVGA_FIFO_FENCE_GOAL);
441
	fman->seqno_valid = true;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
442
443

	return true;
444
445
}

446
static void __vmw_fences_update(struct vmw_fence_manager *fman)
447
448
449
{
	struct vmw_fence_obj *fence, *next_fence;
	struct list_head action_list;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
450
451
	bool needs_rerun;
	uint32_t seqno, new_seqno;
452
	u32 *fifo_mem = fman->dev_priv->mmio_virt;
453

454
	seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
455
rerun:
456
	list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
457
		if (seqno - fence->base.seqno < VMW_FENCE_WRAP) {
458
			list_del_init(&fence->head);
459
			dma_fence_signal_locked(&fence->base);
460
461
462
463
			INIT_LIST_HEAD(&action_list);
			list_splice_init(&fence->seq_passed_actions,
					 &action_list);
			vmw_fences_perform_actions(fman, &action_list);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
464
465
		} else
			break;
466
	}
Thomas Hellstrom's avatar
Thomas Hellstrom committed
467
468
469
470
471
472
473

	/*
	 * Rerun if the fence goal seqno was updated, and the
	 * hardware might have raced with that update, so that
	 * we missed a fence_goal irq.
	 */

474
	needs_rerun = vmw_fence_goal_new_locked(fman, seqno);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
475
	if (unlikely(needs_rerun)) {
476
		new_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
477
478
479
480
481
		if (new_seqno != seqno) {
			seqno = new_seqno;
			goto rerun;
		}
	}
482
483
484

	if (!list_empty(&fman->cleanup_list))
		(void) schedule_work(&fman->work);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
485
}
486

487
void vmw_fences_update(struct vmw_fence_manager *fman)
488
{
489
	spin_lock(&fman->lock);
490
	__vmw_fences_update(fman);
491
	spin_unlock(&fman->lock);
492
493
494
495
496
}

bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence)
{
	struct vmw_fence_manager *fman = fman_from_fence(fence);
497

498
	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
499
500
		return 1;

501
	vmw_fences_update(fman);
502

503
	return dma_fence_is_signaled(&fence->base);
504
505
}

506
int vmw_fence_obj_wait(struct vmw_fence_obj *fence, bool lazy,
507
508
		       bool interruptible, unsigned long timeout)
{
509
	long ret = dma_fence_wait_timeout(&fence->base, interruptible, timeout);
510

511
	if (likely(ret > 0))
512
		return 0;
513
514
	else if (ret == 0)
		return -EBUSY;
515
	else
516
		return ret;
517
518
519
520
}

void vmw_fence_obj_flush(struct vmw_fence_obj *fence)
{
521
	struct vmw_private *dev_priv = fman_from_fence(fence)->dev_priv;
522
523
524
525
526
527

	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
}

static void vmw_fence_destroy(struct vmw_fence_obj *fence)
{
528
	dma_fence_free(&fence->base);
529
530
531
532
533
534
535
}

int vmw_fence_create(struct vmw_fence_manager *fman,
		     uint32_t seqno,
		     struct vmw_fence_obj **p_fence)
{
	struct vmw_fence_obj *fence;
536
 	int ret;
537
538

	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
539
	if (unlikely(!fence))
540
		return -ENOMEM;
541

542
	ret = vmw_fence_obj_init(fman, fence, seqno,
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
				 vmw_fence_destroy);
	if (unlikely(ret != 0))
		goto out_err_init;

	*p_fence = fence;
	return 0;

out_err_init:
	kfree(fence);
	return ret;
}


static void vmw_user_fence_destroy(struct vmw_fence_obj *fence)
{
	struct vmw_user_fence *ufence =
		container_of(fence, struct vmw_user_fence, fence);
560
	struct vmw_fence_manager *fman = fman_from_fence(fence);
561

562
	ttm_base_object_kfree(ufence, base);
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
	/*
	 * Free kernel space accounting.
	 */
	ttm_mem_global_free(vmw_mem_glob(fman->dev_priv),
			    fman->user_fence_size);
}

static void vmw_user_fence_base_release(struct ttm_base_object **p_base)
{
	struct ttm_base_object *base = *p_base;
	struct vmw_user_fence *ufence =
		container_of(base, struct vmw_user_fence, base);
	struct vmw_fence_obj *fence = &ufence->fence;

	*p_base = NULL;
	vmw_fence_obj_unreference(&fence);
}

int vmw_user_fence_create(struct drm_file *file_priv,
			  struct vmw_fence_manager *fman,
			  uint32_t seqno,
			  struct vmw_fence_obj **p_fence,
			  uint32_t *p_handle)
{
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
	struct vmw_user_fence *ufence;
	struct vmw_fence_obj *tmp;
	struct ttm_mem_global *mem_glob = vmw_mem_glob(fman->dev_priv);
	int ret;

	/*
	 * Kernel memory space accounting, since this object may
	 * be created by a user-space request.
	 */

	ret = ttm_mem_global_alloc(mem_glob, fman->user_fence_size,
				   false, false);
	if (unlikely(ret != 0))
		return ret;

	ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
604
	if (unlikely(!ufence)) {
605
606
607
608
609
		ret = -ENOMEM;
		goto out_no_object;
	}

	ret = vmw_fence_obj_init(fman, &ufence->fence, seqno,
610
				 vmw_user_fence_destroy);
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
	if (unlikely(ret != 0)) {
		kfree(ufence);
		goto out_no_object;
	}

	/*
	 * The base object holds a reference which is freed in
	 * vmw_user_fence_base_release.
	 */
	tmp = vmw_fence_obj_reference(&ufence->fence);
	ret = ttm_base_object_init(tfile, &ufence->base, false,
				   VMW_RES_FENCE,
				   &vmw_user_fence_base_release, NULL);


	if (unlikely(ret != 0)) {
		/*
		 * Free the base object's reference
		 */
		vmw_fence_obj_unreference(&tmp);
		goto out_err;
	}

	*p_fence = &ufence->fence;
	*p_handle = ufence->base.hash.key;

	return 0;
out_err:
	tmp = &ufence->fence;
	vmw_fence_obj_unreference(&tmp);
out_no_object:
	ttm_mem_global_free(mem_glob, fman->user_fence_size);
	return ret;
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
}


/**
 * vmw_wait_dma_fence - Wait for a dma fence
 *
 * @fman: pointer to a fence manager
 * @fence: DMA fence to wait on
 *
 * This function handles the case when the fence is actually a fence
 * array.  If that's the case, it'll wait on each of the child fence
 */
int vmw_wait_dma_fence(struct vmw_fence_manager *fman,
		       struct dma_fence *fence)
{
	struct dma_fence_array *fence_array;
	int ret = 0;
	int i;


	if (dma_fence_is_signaled(fence))
		return 0;

	if (!dma_fence_is_array(fence))
		return dma_fence_wait(fence, true);

	/* From i915: Note that if the fence-array was created in
	 * signal-on-any mode, we should *not* decompose it into its individual
	 * fences. However, we don't currently store which mode the fence-array
	 * is operating in. Fortunately, the only user of signal-on-any is
	 * private to amdgpu and we should not see any incoming fence-array
	 * from sync-file being in signal-on-any mode.
	 */

	fence_array = to_dma_fence_array(fence);
	for (i = 0; i < fence_array->num_fences; i++) {
		struct dma_fence *child = fence_array->fences[i];

		ret = dma_fence_wait(child, true);

		if (ret < 0)
			return ret;
	}

	return 0;
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
}


/**
 * vmw_fence_fifo_down - signal all unsignaled fence objects.
 */

void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
{
	struct list_head action_list;
	int ret;

	/*
	 * The list may be altered while we traverse it, so always
	 * restart when we've released the fman->lock.
	 */

706
	spin_lock(&fman->lock);
707
708
709
710
711
	fman->fifo_down = true;
	while (!list_empty(&fman->fence_list)) {
		struct vmw_fence_obj *fence =
			list_entry(fman->fence_list.prev, struct vmw_fence_obj,
				   head);
712
		dma_fence_get(&fence->base);
713
		spin_unlock(&fman->lock);
714

715
		ret = vmw_fence_obj_wait(fence, false, false,
716
717
718
719
					 VMW_FENCE_WAIT_TIMEOUT);

		if (unlikely(ret != 0)) {
			list_del_init(&fence->head);
720
			dma_fence_signal(&fence->base);
721
722
723
724
725
726
727
			INIT_LIST_HEAD(&action_list);
			list_splice_init(&fence->seq_passed_actions,
					 &action_list);
			vmw_fences_perform_actions(fman, &action_list);
		}

		BUG_ON(!list_empty(&fence->head));
728
		dma_fence_put(&fence->base);
729
		spin_lock(&fman->lock);
730
	}
731
	spin_unlock(&fman->lock);
732
733
734
735
}

void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
{
736
	spin_lock(&fman->lock);
737
	fman->fifo_down = false;
738
	spin_unlock(&fman->lock);
739
740
741
}


742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
/**
 * vmw_fence_obj_lookup - Look up a user-space fence object
 *
 * @tfile: A struct ttm_object_file identifying the caller.
 * @handle: A handle identifying the fence object.
 * @return: A struct vmw_user_fence base ttm object on success or
 * an error pointer on failure.
 *
 * The fence object is looked up and type-checked. The caller needs
 * to have opened the fence object first, but since that happens on
 * creation and fence objects aren't shareable, that's not an
 * issue currently.
 */
static struct ttm_base_object *
vmw_fence_obj_lookup(struct ttm_object_file *tfile, u32 handle)
{
	struct ttm_base_object *base = ttm_base_object_lookup(tfile, handle);

	if (!base) {
		pr_err("Invalid fence object handle 0x%08lx.\n",
		       (unsigned long)handle);
		return ERR_PTR(-EINVAL);
	}

	if (base->refcount_release != vmw_user_fence_base_release) {
		pr_err("Invalid fence object handle 0x%08lx.\n",
		       (unsigned long)handle);
		ttm_base_object_unref(&base);
		return ERR_PTR(-EINVAL);
	}

	return base;
}


777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
			     struct drm_file *file_priv)
{
	struct drm_vmw_fence_wait_arg *arg =
	    (struct drm_vmw_fence_wait_arg *)data;
	unsigned long timeout;
	struct ttm_base_object *base;
	struct vmw_fence_obj *fence;
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
	int ret;
	uint64_t wait_timeout = ((uint64_t)arg->timeout_us * HZ);

	/*
	 * 64-bit division not present on 32-bit systems, so do an
	 * approximation. (Divide by 1000000).
	 */

	wait_timeout = (wait_timeout >> 20) + (wait_timeout >> 24) -
	  (wait_timeout >> 26);

	if (!arg->cookie_valid) {
		arg->cookie_valid = 1;
		arg->kernel_cookie = jiffies + wait_timeout;
	}

802
803
804
	base = vmw_fence_obj_lookup(tfile, arg->handle);
	if (IS_ERR(base))
		return PTR_ERR(base);
805
806
807
808
809

	fence = &(container_of(base, struct vmw_user_fence, base)->fence);

	timeout = jiffies;
	if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie)) {
810
		ret = ((vmw_fence_obj_signaled(fence)) ?
811
812
813
814
815
816
		       0 : -EBUSY);
		goto out;
	}

	timeout = (unsigned long)arg->kernel_cookie - timeout;

817
	ret = vmw_fence_obj_wait(fence, arg->lazy, true, timeout);
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842

out:
	ttm_base_object_unref(&base);

	/*
	 * Optionally unref the fence object.
	 */

	if (ret == 0 && (arg->wait_options & DRM_VMW_WAIT_OPTION_UNREF))
		return ttm_ref_object_base_unref(tfile, arg->handle,
						 TTM_REF_USAGE);
	return ret;
}

int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
				 struct drm_file *file_priv)
{
	struct drm_vmw_fence_signaled_arg *arg =
		(struct drm_vmw_fence_signaled_arg *) data;
	struct ttm_base_object *base;
	struct vmw_fence_obj *fence;
	struct vmw_fence_manager *fman;
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
	struct vmw_private *dev_priv = vmw_priv(dev);

843
844
845
	base = vmw_fence_obj_lookup(tfile, arg->handle);
	if (IS_ERR(base))
		return PTR_ERR(base);
846
847

	fence = &(container_of(base, struct vmw_user_fence, base)->fence);
848
	fman = fman_from_fence(fence);
849

850
	arg->signaled = vmw_fence_obj_signaled(fence);
851

852
	arg->signaled_flags = arg->flags;
853
	spin_lock(&fman->lock);
854
	arg->passed_seqno = dev_priv->last_read_seqno;
855
	spin_unlock(&fman->lock);
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872

	ttm_base_object_unref(&base);

	return 0;
}


int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
			      struct drm_file *file_priv)
{
	struct drm_vmw_fence_arg *arg =
		(struct drm_vmw_fence_arg *) data;

	return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
					 arg->handle,
					 TTM_REF_USAGE);
}
Thomas Hellstrom's avatar
Thomas Hellstrom committed
873
874
875
876
877
878
879
880
881

/**
 * vmw_event_fence_action_seq_passed
 *
 * @action: The struct vmw_fence_action embedded in a struct
 * vmw_event_fence_action.
 *
 * This function is called when the seqno of the fence where @action is
 * attached has passed. It queues the event on the submitter's event list.
882
 * This function is always called from atomic context.
Thomas Hellstrom's avatar
Thomas Hellstrom committed
883
884
885
886
887
888
 */
static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
{
	struct vmw_event_fence_action *eaction =
		container_of(action, struct vmw_event_fence_action, action);
	struct drm_device *dev = eaction->dev;
889
890
	struct drm_pending_event *event = eaction->event;
	struct drm_file *file_priv;
891

Thomas Hellstrom's avatar
Thomas Hellstrom committed
892

893
894
895
896
	if (unlikely(event == NULL))
		return;

	file_priv = event->file_priv;
897
	spin_lock_irq(&dev->event_lock);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
898
899
900
901
902
903
904
905
906

	if (likely(eaction->tv_sec != NULL)) {
		struct timeval tv;

		do_gettimeofday(&tv);
		*eaction->tv_sec = tv.tv_sec;
		*eaction->tv_usec = tv.tv_usec;
	}

907
	drm_send_event_locked(dev, eaction->event);
908
	eaction->event = NULL;
909
	spin_unlock_irq(&dev->event_lock);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
}

/**
 * vmw_event_fence_action_cleanup
 *
 * @action: The struct vmw_fence_action embedded in a struct
 * vmw_event_fence_action.
 *
 * This function is the struct vmw_fence_action destructor. It's typically
 * called from a workqueue.
 */
static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
{
	struct vmw_event_fence_action *eaction =
		container_of(action, struct vmw_event_fence_action, action);

	vmw_fence_obj_unreference(&eaction->fence);
927
	kfree(eaction);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
928
929
930
931
932
933
934
935
936
937
938
939
}


/**
 * vmw_fence_obj_add_action - Add an action to a fence object.
 *
 * @fence - The fence object.
 * @action - The action to add.
 *
 * Note that the action callbacks may be executed before this function
 * returns.
 */
940
static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
Thomas Hellstrom's avatar
Thomas Hellstrom committed
941
942
			      struct vmw_fence_action *action)
{
943
	struct vmw_fence_manager *fman = fman_from_fence(fence);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
944
945
946
	bool run_update = false;

	mutex_lock(&fman->goal_irq_mutex);
947
	spin_lock(&fman->lock);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
948
949

	fman->pending_actions[action->type]++;
950
	if (dma_fence_is_signaled_locked(&fence->base)) {
Thomas Hellstrom's avatar
Thomas Hellstrom committed
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
		struct list_head action_list;

		INIT_LIST_HEAD(&action_list);
		list_add_tail(&action->head, &action_list);
		vmw_fences_perform_actions(fman, &action_list);
	} else {
		list_add_tail(&action->head, &fence->seq_passed_actions);

		/*
		 * This function may set fman::seqno_valid, so it must
		 * be run with the goal_irq_mutex held.
		 */
		run_update = vmw_fence_goal_check_locked(fence);
	}

966
	spin_unlock(&fman->lock);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993

	if (run_update) {
		if (!fman->goal_irq_on) {
			fman->goal_irq_on = true;
			vmw_goal_waiter_add(fman->dev_priv);
		}
		vmw_fences_update(fman);
	}
	mutex_unlock(&fman->goal_irq_mutex);

}

/**
 * vmw_event_fence_action_create - Post an event for sending when a fence
 * object seqno has passed.
 *
 * @file_priv: The file connection on which the event should be posted.
 * @fence: The fence object on which to post the event.
 * @event: Event to be posted. This event should've been alloced
 * using k[mz]alloc, and should've been completely initialized.
 * @interruptible: Interruptible waits if possible.
 *
 * As a side effect, the object pointed to by @event may have been
 * freed when this function returns. If this function returns with
 * an error code, the caller needs to free that object.
 */

994
995
996
997
998
999
int vmw_event_fence_action_queue(struct drm_file *file_priv,
				 struct vmw_fence_obj *fence,
				 struct drm_pending_event *event,
				 uint32_t *tv_sec,
				 uint32_t *tv_usec,
				 bool interruptible)
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1000
{
1001
	struct vmw_event_fence_action *eaction;
1002
	struct vmw_fence_manager *fman = fman_from_fence(fence);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1003
1004

	eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
1005
	if (unlikely(!eaction))
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1006
1007
		return -ENOMEM;

1008
	eaction->event = event;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023

	eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
	eaction->action.cleanup = vmw_event_fence_action_cleanup;
	eaction->action.type = VMW_ACTION_EVENT;

	eaction->fence = vmw_fence_obj_reference(fence);
	eaction->dev = fman->dev_priv->dev;
	eaction->tv_sec = tv_sec;
	eaction->tv_usec = tv_usec;

	vmw_fence_obj_add_action(fence, &eaction->action);

	return 0;
}

1024
1025
1026
1027
1028
struct vmw_event_fence_pending {
	struct drm_pending_event base;
	struct drm_vmw_event_fence event;
};

1029
static int vmw_event_fence_action_create(struct drm_file *file_priv,
1030
1031
1032
1033
1034
1035
				  struct vmw_fence_obj *fence,
				  uint32_t flags,
				  uint64_t user_data,
				  bool interruptible)
{
	struct vmw_event_fence_pending *event;
1036
1037
	struct vmw_fence_manager *fman = fman_from_fence(fence);
	struct drm_device *dev = fman->dev_priv->dev;
1038
1039
	int ret;

1040
	event = kzalloc(sizeof(*event), GFP_KERNEL);
1041
	if (unlikely(!event)) {
1042
1043
		DRM_ERROR("Failed to allocate an event.\n");
		ret = -ENOMEM;
1044
		goto out_no_space;
1045
1046
1047
1048
1049
1050
	}

	event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
	event->event.base.length = sizeof(*event);
	event->event.user_data = user_data;

1051
	ret = drm_event_reserve_init(dev, file_priv, &event->base, &event->event.base);
1052

1053
1054
1055
1056
1057
	if (unlikely(ret != 0)) {
		DRM_ERROR("Failed to allocate event space for this file.\n");
		kfree(event);
		goto out_no_space;
	}
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073

	if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
		ret = vmw_event_fence_action_queue(file_priv, fence,
						   &event->base,
						   &event->event.tv_sec,
						   &event->event.tv_usec,
						   interruptible);
	else
		ret = vmw_event_fence_action_queue(file_priv, fence,
						   &event->base,
						   NULL,
						   NULL,
						   interruptible);
	if (ret != 0)
		goto out_no_queue;

1074
1075
	return 0;

1076
out_no_queue:
1077
	drm_event_cancel_free(dev, &event->base);
1078
1079
1080
1081
out_no_space:
	return ret;
}

Thomas Hellstrom's avatar
Thomas Hellstrom committed
1082
1083
1084
1085
1086
1087
1088
1089
int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
{
	struct vmw_private *dev_priv = vmw_priv(dev);
	struct drm_vmw_fence_event_arg *arg =
		(struct drm_vmw_fence_event_arg *) data;
	struct vmw_fence_obj *fence = NULL;
	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
1090
	struct ttm_object_file *tfile = vmw_fp->tfile;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
	struct drm_vmw_fence_rep __user *user_fence_rep =
		(struct drm_vmw_fence_rep __user *)(unsigned long)
		arg->fence_rep;
	uint32_t handle;
	int ret;

	/*
	 * Look up an existing fence object,
	 * and if user-space wants a new reference,
	 * add one.
	 */
	if (arg->handle) {
		struct ttm_base_object *base =
1104
1105
1106
1107
1108
			vmw_fence_obj_lookup(tfile, arg->handle);

		if (IS_ERR(base))
			return PTR_ERR(base);

Thomas Hellstrom's avatar
Thomas Hellstrom committed
1109
1110
1111
1112
1113
		fence = &(container_of(base, struct vmw_user_fence,
				       base)->fence);
		(void) vmw_fence_obj_reference(fence);

		if (user_fence_rep != NULL) {
1114
1115
			ret = ttm_ref_object_add(vmw_fp->tfile, base,
						 TTM_REF_USAGE, NULL, false);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
			if (unlikely(ret != 0)) {
				DRM_ERROR("Failed to reference a fence "
					  "object.\n");
				goto out_no_ref_obj;
			}
			handle = base->hash.key;
		}
		ttm_base_object_unref(&base);
	}

	/*
	 * Create a new fence object.
	 */
	if (!fence) {
		ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
						 &fence,
						 (user_fence_rep) ?
						 &handle : NULL);
		if (unlikely(ret != 0)) {
			DRM_ERROR("Fence event failed to create fence.\n");
			return ret;
		}
	}

	BUG_ON(fence == NULL);

1142
1143
1144
1145
	ret = vmw_event_fence_action_create(file_priv, fence,
					    arg->flags,
					    arg->user_data,
					    true);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1146
1147
1148
	if (unlikely(ret != 0)) {
		if (ret != -ERESTARTSYS)
			DRM_ERROR("Failed to attach event to fence.\n");
1149
		goto out_no_create;
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1150
1151
1152
	}

	vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
1153
				    handle, -1, NULL);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1154
1155
	vmw_fence_obj_unreference(&fence);
	return 0;
1156
out_no_create:
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1157
	if (user_fence_rep != NULL)
1158
		ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1159
1160
1161
1162
out_no_ref_obj:
	vmw_fence_obj_unreference(&fence);
	return ret;
}