nouveau_fence.c 13.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * Copyright (C) 2007 Ben Skeggs.
 * 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, sublicense, 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 NONINFRINGEMENT.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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.
 *
 */

#include "drmP.h"
#include "drm.h"

30 31 32
#include <linux/ktime.h>
#include <linux/hrtimer.h>

33
#include "nouveau_drv.h"
34
#include "nouveau_ramht.h"
35
#include "nouveau_fence.h"
36
#include "nouveau_software.h"
37 38
#include "nouveau_dma.h"

39
#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
40
#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
41 42 43 44

void
nouveau_fence_update(struct nouveau_channel *chan)
{
45 46
	struct drm_device *dev = chan->dev;
	struct nouveau_fence *tmp, *fence;
47 48
	uint32_t sequence;

49 50
	spin_lock(&chan->fence.lock);

51 52 53 54 55 56 57 58 59 60 61
	/* Fetch the last sequence if the channel is still up and running */
	if (likely(!list_empty(&chan->fence.pending))) {
		if (USE_REFCNT(dev))
			sequence = nvchan_rd32(chan, 0x48);
		else
			sequence = atomic_read(&chan->fence.last_sequence_irq);

		if (chan->fence.sequence_ack == sequence)
			goto out;
		chan->fence.sequence_ack = sequence;
	}
62

63
	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, head) {
64 65 66
		if (fence->sequence > chan->fence.sequence_ack)
			break;

67 68
		fence->channel = NULL;
		list_del(&fence->head);
69
		if (fence->work)
70 71
			fence->work(fence->priv, true);

72
		nouveau_fence_unref(&fence);
73
	}
74

75
out:
76
	spin_unlock(&chan->fence.lock);
77 78 79
}

int
80
nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
81
{
82
	struct drm_device *dev = chan->dev;
B
Ben Skeggs 已提交
83
	struct drm_nouveau_private *dev_priv = dev->dev_private;
84 85 86 87 88 89 90 91 92 93 94 95 96 97
	int ret;

	ret = RING_SPACE(chan, 2);
	if (ret)
		return ret;

	if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) {
		nouveau_fence_update(chan);

		BUG_ON(chan->fence.sequence ==
		       chan->fence.sequence_ack - 1);
	}

	fence->sequence = ++chan->fence.sequence;
98
	fence->channel = chan;
99

100
	kref_get(&fence->kref);
101
	spin_lock(&chan->fence.lock);
102
	list_add_tail(&fence->head, &chan->fence.pending);
103
	spin_unlock(&chan->fence.lock);
104

B
Ben Skeggs 已提交
105 106
	if (USE_REFCNT(dev)) {
		if (dev_priv->card_type < NV_C0)
107
			BEGIN_NV04(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
B
Ben Skeggs 已提交
108
		else
109
			BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
B
Ben Skeggs 已提交
110
	} else {
111
		BEGIN_NV04(chan, NvSubSw, 0x0150, 1);
B
Ben Skeggs 已提交
112 113
	}
	OUT_RING (chan, fence->sequence);
114
	FIRE_RING(chan);
115
	fence->timeout = jiffies + 3 * DRM_HZ;
116 117 118 119 120

	return 0;
}

bool
121
nouveau_fence_done(struct nouveau_fence *fence)
122
{
123 124 125
	if (fence->channel)
		nouveau_fence_update(fence->channel);
	return !fence->channel;
126 127 128
}

int
129
nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
130
{
131 132
	unsigned long sleep_time = NSEC_PER_MSEC / 1000;
	ktime_t t;
133 134
	int ret = 0;

135 136
	while (!nouveau_fence_done(fence)) {
		if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
137 138 139 140
			ret = -EBUSY;
			break;
		}

141 142
		__set_current_state(intr ? TASK_INTERRUPTIBLE :
					   TASK_UNINTERRUPTIBLE);
143 144 145 146 147 148 149
		if (lazy) {
			t = ktime_set(0, sleep_time);
			schedule_hrtimeout(&t, HRTIMER_MODE_REL);
			sleep_time *= 2;
			if (sleep_time > NSEC_PER_MSEC)
				sleep_time = NSEC_PER_MSEC;
		}
150 151

		if (intr && signal_pending(current)) {
B
Ben Skeggs 已提交
152
			ret = -ERESTARTSYS;
153 154 155 156 157
			break;
		}
	}

	__set_current_state(TASK_RUNNING);
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	return ret;
}

static void
nouveau_fence_del(struct kref *kref)
{
	struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref);
	kfree(fence);
}

void
nouveau_fence_unref(struct nouveau_fence **pfence)
{
	if (*pfence)
		kref_put(&(*pfence)->kref, nouveau_fence_del);
	*pfence = NULL;
}

struct nouveau_fence *
nouveau_fence_ref(struct nouveau_fence *fence)
{
	kref_get(&fence->kref);
	return fence;
}

int
nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence)
{
	struct nouveau_fence *fence;
	int ret = 0;
188

189 190 191 192 193 194 195 196 197 198 199 200
	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
	if (!fence)
		return -ENOMEM;
	kref_init(&fence->kref);

	if (chan) {
		ret = nouveau_fence_emit(fence, chan);
		if (ret)
			nouveau_fence_unref(&fence);
	}

	*pfence = fence;
201 202 203
	return ret;
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
struct nouveau_semaphore {
	struct kref ref;
	struct drm_device *dev;
	struct drm_mm_node *mem;
};

void
nouveau_fence_work(struct nouveau_fence *fence,
		   void (*work)(void *priv, bool signalled),
		   void *priv)
{
	if (!fence->channel) {
		work(priv, true);
	} else {
		fence->work = work;
		fence->priv = priv;
	}
}

223
static struct nouveau_semaphore *
224
semaphore_alloc(struct drm_device *dev)
225 226 227
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_semaphore *sema;
228 229
	int size = (dev_priv->chipset < 0x84) ? 4 : 16;
	int ret, i;
230 231 232 233 234 235 236 237

	if (!USE_SEMA(dev))
		return NULL;

	sema = kmalloc(sizeof(*sema), GFP_KERNEL);
	if (!sema)
		goto fail;

238 239 240 241
	ret = drm_mm_pre_get(&dev_priv->fence.heap);
	if (ret)
		goto fail;

242
	spin_lock(&dev_priv->fence.lock);
243
	sema->mem = drm_mm_search_free(&dev_priv->fence.heap, size, 0, 0);
244
	if (sema->mem)
245
		sema->mem = drm_mm_get_block_atomic(sema->mem, size, 0);
246 247 248 249 250 251 252
	spin_unlock(&dev_priv->fence.lock);

	if (!sema->mem)
		goto fail;

	kref_init(&sema->ref);
	sema->dev = dev;
253 254
	for (i = sema->mem->start; i < sema->mem->start + size; i += 4)
		nouveau_bo_wr32(dev_priv->fence.bo, i / 4, 0);
255 256 257 258 259 260 261 262

	return sema;
fail:
	kfree(sema);
	return NULL;
}

static void
263
semaphore_free(struct kref *ref)
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
{
	struct nouveau_semaphore *sema =
		container_of(ref, struct nouveau_semaphore, ref);
	struct drm_nouveau_private *dev_priv = sema->dev->dev_private;

	spin_lock(&dev_priv->fence.lock);
	drm_mm_put_block(sema->mem);
	spin_unlock(&dev_priv->fence.lock);

	kfree(sema);
}

static void
semaphore_work(void *priv, bool signalled)
{
	struct nouveau_semaphore *sema = priv;
	struct drm_nouveau_private *dev_priv = sema->dev->dev_private;

	if (unlikely(!signalled))
		nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1);

285
	kref_put(&sema->ref, semaphore_free);
286 287 288
}

static int
289
semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
290
{
291 292
	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
	struct nouveau_fence *fence = NULL;
293
	u64 offset = chan->fence.vma.offset + sema->mem->start;
294 295
	int ret;

296
	if (dev_priv->chipset < 0x84) {
297
		ret = RING_SPACE(chan, 4);
298 299
		if (ret)
			return ret;
300

301
		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 3);
302
		OUT_RING  (chan, NvSema);
303
		OUT_RING  (chan, offset);
304
		OUT_RING  (chan, 1);
305 306
	} else
	if (dev_priv->chipset < 0xc0) {
307
		ret = RING_SPACE(chan, 7);
308 309 310
		if (ret)
			return ret;

311
		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
312
		OUT_RING  (chan, chan->vram_handle);
313
		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
314 315
		OUT_RING  (chan, upper_32_bits(offset));
		OUT_RING  (chan, lower_32_bits(offset));
316 317
		OUT_RING  (chan, 1);
		OUT_RING  (chan, 1); /* ACQUIRE_EQ */
318 319 320 321 322
	} else {
		ret = RING_SPACE(chan, 5);
		if (ret)
			return ret;

323
		BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
324 325 326 327
		OUT_RING  (chan, upper_32_bits(offset));
		OUT_RING  (chan, lower_32_bits(offset));
		OUT_RING  (chan, 1);
		OUT_RING  (chan, 0x1001); /* ACQUIRE_EQ */
328 329
	}

330
	/* Delay semaphore destruction until its work is done */
331
	ret = nouveau_fence_new(chan, &fence);
332 333
	if (ret)
		return ret;
334

335 336 337 338 339 340 341 342 343 344 345
	kref_get(&sema->ref);
	nouveau_fence_work(fence, semaphore_work, sema);
	nouveau_fence_unref(&fence);
	return 0;
}

static int
semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
{
	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
	struct nouveau_fence *fence = NULL;
346
	u64 offset = chan->fence.vma.offset + sema->mem->start;
347 348 349
	int ret;

	if (dev_priv->chipset < 0x84) {
350
		ret = RING_SPACE(chan, 5);
351 352 353
		if (ret)
			return ret;

354
		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
355
		OUT_RING  (chan, NvSema);
356
		OUT_RING  (chan, offset);
357
		BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
358
		OUT_RING  (chan, 1);
359 360
	} else
	if (dev_priv->chipset < 0xc0) {
361
		ret = RING_SPACE(chan, 7);
362 363 364
		if (ret)
			return ret;

365
		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
366
		OUT_RING  (chan, chan->vram_handle);
367
		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
368 369
		OUT_RING  (chan, upper_32_bits(offset));
		OUT_RING  (chan, lower_32_bits(offset));
370 371
		OUT_RING  (chan, 1);
		OUT_RING  (chan, 2); /* RELEASE */
372 373 374 375 376
	} else {
		ret = RING_SPACE(chan, 5);
		if (ret)
			return ret;

377
		BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
378 379 380 381
		OUT_RING  (chan, upper_32_bits(offset));
		OUT_RING  (chan, lower_32_bits(offset));
		OUT_RING  (chan, 1);
		OUT_RING  (chan, 0x1002); /* RELEASE */
382 383
	}

384
	/* Delay semaphore destruction until its work is done */
385
	ret = nouveau_fence_new(chan, &fence);
386 387 388 389 390
	if (ret)
		return ret;

	kref_get(&sema->ref);
	nouveau_fence_work(fence, semaphore_work, sema);
391
	nouveau_fence_unref(&fence);
392 393 394
	return 0;
}

395 396 397 398
int
nouveau_fence_sync(struct nouveau_fence *fence,
		   struct nouveau_channel *wchan)
{
399
	struct nouveau_channel *chan;
400 401
	struct drm_device *dev = wchan->dev;
	struct nouveau_semaphore *sema;
402
	int ret = 0;
403

404 405
	chan = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
	if (likely(!chan || chan == wchan || nouveau_fence_done(fence)))
406
		goto out;
407

408
	sema = semaphore_alloc(dev);
409 410 411
	if (!sema) {
		/* Early card or broken userspace, fall back to
		 * software sync. */
412
		ret = nouveau_fence_wait(fence, true, false);
413
		goto out;
414 415
	}

416
	/* try to take chan's mutex, if we can't take it right away
417 418 419
	 * we have to fallback to software sync to prevent locking
	 * order issues
	 */
420
	if (!mutex_trylock(&chan->mutex)) {
421
		ret = nouveau_fence_wait(fence, true, false);
422
		goto out_unref;
423 424
	}

425
	/* Make wchan wait until it gets signalled */
426
	ret = semaphore_acquire(wchan, sema);
427
	if (ret)
428
		goto out_unlock;
429

430
	/* Signal the semaphore from chan */
431
	ret = semaphore_release(chan, sema);
432 433

out_unlock:
434
	mutex_unlock(&chan->mutex);
435
out_unref:
436
	kref_put(&sema->ref, semaphore_free);
437 438 439
out:
	if (chan)
		nouveau_channel_put_unlocked(&chan);
440
	return ret;
441 442
}

443
int
444
nouveau_fence_channel_init(struct nouveau_channel *chan)
445
{
446 447
	struct drm_device *dev = chan->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
448 449 450
	struct nouveau_gpuobj *obj = NULL;
	int ret;

451 452 453 454
	if (dev_priv->card_type < NV_C0) {
		ret = RING_SPACE(chan, 2);
		if (ret)
			return ret;
455

456
		BEGIN_NV04(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1);
457 458 459
		OUT_RING  (chan, NvSw);
		FIRE_RING (chan);
	}
460

461
	/* Setup area of memory shared between all channels for x-chan sync */
462
	if (USE_SEMA(dev) && dev_priv->chipset < 0x84) {
463
		struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
464

465
		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
466
					     mem->start << PAGE_SHIFT,
467
					     mem->size, NV_MEM_ACCESS_RW,
468
					     NV_MEM_TARGET_VRAM, &obj);
469 470 471 472 473 474 475
		if (ret)
			return ret;

		ret = nouveau_ramht_insert(chan, NvSema, obj);
		nouveau_gpuobj_ref(NULL, &obj);
		if (ret)
			return ret;
476 477
	} else
	if (USE_SEMA(dev)) {
478 479 480 481 482
		/* map fence bo into channel's vm */
		ret = nouveau_bo_vma_add(dev_priv->fence.bo, chan->vm,
					 &chan->fence.vma);
		if (ret)
			return ret;
483 484
	}

485
	atomic_set(&chan->fence.last_sequence_irq, 0);
486 487 488 489
	return 0;
}

void
490
nouveau_fence_channel_fini(struct nouveau_channel *chan)
491
{
492
	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
493
	struct nouveau_fence *tmp, *fence;
494

495
	spin_lock(&chan->fence.lock);
496 497 498
	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, head) {
		fence->channel = NULL;
		list_del(&fence->head);
499 500 501 502

		if (unlikely(fence->work))
			fence->work(fence->priv, false);

503
		kref_put(&fence->kref, nouveau_fence_del);
504
	}
505
	spin_unlock(&chan->fence.lock);
506 507

	nouveau_bo_vma_del(dev_priv->fence.bo, &chan->fence.vma);
508 509
}

510 511 512 513
int
nouveau_fence_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
514
	int size = (dev_priv->chipset < 0x84) ? 4096 : 16384;
515 516 517 518
	int ret;

	/* Create a shared VRAM heap for cross-channel sync. */
	if (USE_SEMA(dev)) {
519
		ret = nouveau_bo_new(dev, size, 0, TTM_PL_FLAG_VRAM,
D
Dave Airlie 已提交
520
				     0, 0, NULL, &dev_priv->fence.bo);
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
		if (ret)
			return ret;

		ret = nouveau_bo_pin(dev_priv->fence.bo, TTM_PL_FLAG_VRAM);
		if (ret)
			goto fail;

		ret = nouveau_bo_map(dev_priv->fence.bo);
		if (ret)
			goto fail;

		ret = drm_mm_init(&dev_priv->fence.heap, 0,
				  dev_priv->fence.bo->bo.mem.size);
		if (ret)
			goto fail;

		spin_lock_init(&dev_priv->fence.lock);
	}

	return 0;
fail:
	nouveau_bo_unmap(dev_priv->fence.bo);
	nouveau_bo_ref(NULL, &dev_priv->fence.bo);
	return ret;
}

void
nouveau_fence_fini(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;

	if (USE_SEMA(dev)) {
		drm_mm_takedown(&dev_priv->fence.heap);
		nouveau_bo_unmap(dev_priv->fence.bo);
		nouveau_bo_unpin(dev_priv->fence.bo);
		nouveau_bo_ref(NULL, &dev_priv->fence.bo);
	}
}