aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_fence.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_fence.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c117
1 files changed, 74 insertions, 43 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index ab1bbfbf266e..221b8462ea37 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -32,7 +32,8 @@
32#include "nouveau_dma.h" 32#include "nouveau_dma.h"
33 33
34#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) 34#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
35#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17) 35#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \
36 nouveau_private(dev)->card_type < NV_C0)
36 37
37struct nouveau_fence { 38struct nouveau_fence {
38 struct nouveau_channel *channel; 39 struct nouveau_channel *channel;
@@ -64,6 +65,7 @@ nouveau_fence_del(struct kref *ref)
64 struct nouveau_fence *fence = 65 struct nouveau_fence *fence =
65 container_of(ref, struct nouveau_fence, refcount); 66 container_of(ref, struct nouveau_fence, refcount);
66 67
68 nouveau_channel_ref(NULL, &fence->channel);
67 kfree(fence); 69 kfree(fence);
68} 70}
69 71
@@ -76,14 +78,17 @@ nouveau_fence_update(struct nouveau_channel *chan)
76 78
77 spin_lock(&chan->fence.lock); 79 spin_lock(&chan->fence.lock);
78 80
79 if (USE_REFCNT(dev)) 81 /* Fetch the last sequence if the channel is still up and running */
80 sequence = nvchan_rd32(chan, 0x48); 82 if (likely(!list_empty(&chan->fence.pending))) {
81 else 83 if (USE_REFCNT(dev))
82 sequence = atomic_read(&chan->fence.last_sequence_irq); 84 sequence = nvchan_rd32(chan, 0x48);
85 else
86 sequence = atomic_read(&chan->fence.last_sequence_irq);
83 87
84 if (chan->fence.sequence_ack == sequence) 88 if (chan->fence.sequence_ack == sequence)
85 goto out; 89 goto out;
86 chan->fence.sequence_ack = sequence; 90 chan->fence.sequence_ack = sequence;
91 }
87 92
88 list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { 93 list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
89 sequence = fence->sequence; 94 sequence = fence->sequence;
@@ -113,13 +118,13 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence,
113 if (!fence) 118 if (!fence)
114 return -ENOMEM; 119 return -ENOMEM;
115 kref_init(&fence->refcount); 120 kref_init(&fence->refcount);
116 fence->channel = chan; 121 nouveau_channel_ref(chan, &fence->channel);
117 122
118 if (emit) 123 if (emit)
119 ret = nouveau_fence_emit(fence); 124 ret = nouveau_fence_emit(fence);
120 125
121 if (ret) 126 if (ret)
122 nouveau_fence_unref((void *)&fence); 127 nouveau_fence_unref(&fence);
123 *pfence = fence; 128 *pfence = fence;
124 return ret; 129 return ret;
125} 130}
@@ -127,7 +132,7 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence,
127struct nouveau_channel * 132struct nouveau_channel *
128nouveau_fence_channel(struct nouveau_fence *fence) 133nouveau_fence_channel(struct nouveau_fence *fence)
129{ 134{
130 return fence ? fence->channel : NULL; 135 return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
131} 136}
132 137
133int 138int
@@ -135,6 +140,7 @@ nouveau_fence_emit(struct nouveau_fence *fence)
135{ 140{
136 struct nouveau_channel *chan = fence->channel; 141 struct nouveau_channel *chan = fence->channel;
137 struct drm_device *dev = chan->dev; 142 struct drm_device *dev = chan->dev;
143 struct drm_nouveau_private *dev_priv = dev->dev_private;
138 int ret; 144 int ret;
139 145
140 ret = RING_SPACE(chan, 2); 146 ret = RING_SPACE(chan, 2);
@@ -155,8 +161,15 @@ nouveau_fence_emit(struct nouveau_fence *fence)
155 list_add_tail(&fence->entry, &chan->fence.pending); 161 list_add_tail(&fence->entry, &chan->fence.pending);
156 spin_unlock(&chan->fence.lock); 162 spin_unlock(&chan->fence.lock);
157 163
158 BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1); 164 if (USE_REFCNT(dev)) {
159 OUT_RING(chan, fence->sequence); 165 if (dev_priv->card_type < NV_C0)
166 BEGIN_RING(chan, NvSubSw, 0x0050, 1);
167 else
168 BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0050, 1);
169 } else {
170 BEGIN_RING(chan, NvSubSw, 0x0150, 1);
171 }
172 OUT_RING (chan, fence->sequence);
160 FIRE_RING(chan); 173 FIRE_RING(chan);
161 174
162 return 0; 175 return 0;
@@ -182,7 +195,7 @@ nouveau_fence_work(struct nouveau_fence *fence,
182} 195}
183 196
184void 197void
185nouveau_fence_unref(void **sync_obj) 198__nouveau_fence_unref(void **sync_obj)
186{ 199{
187 struct nouveau_fence *fence = nouveau_fence(*sync_obj); 200 struct nouveau_fence *fence = nouveau_fence(*sync_obj);
188 201
@@ -192,7 +205,7 @@ nouveau_fence_unref(void **sync_obj)
192} 205}
193 206
194void * 207void *
195nouveau_fence_ref(void *sync_obj) 208__nouveau_fence_ref(void *sync_obj)
196{ 209{
197 struct nouveau_fence *fence = nouveau_fence(sync_obj); 210 struct nouveau_fence *fence = nouveau_fence(sync_obj);
198 211
@@ -201,7 +214,7 @@ nouveau_fence_ref(void *sync_obj)
201} 214}
202 215
203bool 216bool
204nouveau_fence_signalled(void *sync_obj, void *sync_arg) 217__nouveau_fence_signalled(void *sync_obj, void *sync_arg)
205{ 218{
206 struct nouveau_fence *fence = nouveau_fence(sync_obj); 219 struct nouveau_fence *fence = nouveau_fence(sync_obj);
207 struct nouveau_channel *chan = fence->channel; 220 struct nouveau_channel *chan = fence->channel;
@@ -214,13 +227,14 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg)
214} 227}
215 228
216int 229int
217nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) 230__nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
218{ 231{
219 unsigned long timeout = jiffies + (3 * DRM_HZ); 232 unsigned long timeout = jiffies + (3 * DRM_HZ);
233 unsigned long sleep_time = jiffies + 1;
220 int ret = 0; 234 int ret = 0;
221 235
222 while (1) { 236 while (1) {
223 if (nouveau_fence_signalled(sync_obj, sync_arg)) 237 if (__nouveau_fence_signalled(sync_obj, sync_arg))
224 break; 238 break;
225 239
226 if (time_after_eq(jiffies, timeout)) { 240 if (time_after_eq(jiffies, timeout)) {
@@ -230,7 +244,7 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
230 244
231 __set_current_state(intr ? TASK_INTERRUPTIBLE 245 __set_current_state(intr ? TASK_INTERRUPTIBLE
232 : TASK_UNINTERRUPTIBLE); 246 : TASK_UNINTERRUPTIBLE);
233 if (lazy) 247 if (lazy && time_after_eq(jiffies, sleep_time))
234 schedule_timeout(1); 248 schedule_timeout(1);
235 249
236 if (intr && signal_pending(current)) { 250 if (intr && signal_pending(current)) {
@@ -368,7 +382,7 @@ emit_semaphore(struct nouveau_channel *chan, int method,
368 382
369 kref_get(&sema->ref); 383 kref_get(&sema->ref);
370 nouveau_fence_work(fence, semaphore_work, sema); 384 nouveau_fence_work(fence, semaphore_work, sema);
371 nouveau_fence_unref((void *)&fence); 385 nouveau_fence_unref(&fence);
372 386
373 return 0; 387 return 0;
374} 388}
@@ -380,33 +394,49 @@ nouveau_fence_sync(struct nouveau_fence *fence,
380 struct nouveau_channel *chan = nouveau_fence_channel(fence); 394 struct nouveau_channel *chan = nouveau_fence_channel(fence);
381 struct drm_device *dev = wchan->dev; 395 struct drm_device *dev = wchan->dev;
382 struct nouveau_semaphore *sema; 396 struct nouveau_semaphore *sema;
383 int ret; 397 int ret = 0;
384 398
385 if (likely(!fence || chan == wchan || 399 if (likely(!chan || chan == wchan ||
386 nouveau_fence_signalled(fence, NULL))) 400 nouveau_fence_signalled(fence)))
387 return 0; 401 goto out;
388 402
389 sema = alloc_semaphore(dev); 403 sema = alloc_semaphore(dev);
390 if (!sema) { 404 if (!sema) {
391 /* Early card or broken userspace, fall back to 405 /* Early card or broken userspace, fall back to
392 * software sync. */ 406 * software sync. */
393 return nouveau_fence_wait(fence, NULL, false, false); 407 ret = nouveau_fence_wait(fence, true, false);
408 goto out;
409 }
410
411 /* try to take chan's mutex, if we can't take it right away
412 * we have to fallback to software sync to prevent locking
413 * order issues
414 */
415 if (!mutex_trylock(&chan->mutex)) {
416 ret = nouveau_fence_wait(fence, true, false);
417 goto out_unref;
394 } 418 }
395 419
396 /* Make wchan wait until it gets signalled */ 420 /* Make wchan wait until it gets signalled */
397 ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); 421 ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema);
398 if (ret) 422 if (ret)
399 goto out; 423 goto out_unlock;
400 424
401 /* Signal the semaphore from chan */ 425 /* Signal the semaphore from chan */
402 ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); 426 ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema);
403out: 427
428out_unlock:
429 mutex_unlock(&chan->mutex);
430out_unref:
404 kref_put(&sema->ref, free_semaphore); 431 kref_put(&sema->ref, free_semaphore);
432out:
433 if (chan)
434 nouveau_channel_put_unlocked(&chan);
405 return ret; 435 return ret;
406} 436}
407 437
408int 438int
409nouveau_fence_flush(void *sync_obj, void *sync_arg) 439__nouveau_fence_flush(void *sync_obj, void *sync_arg)
410{ 440{
411 return 0; 441 return 0;
412} 442}
@@ -420,30 +450,27 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
420 int ret; 450 int ret;
421 451
422 /* Create an NV_SW object for various sync purposes */ 452 /* Create an NV_SW object for various sync purposes */
423 ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj); 453 ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
424 if (ret) 454 if (ret)
425 return ret; 455 return ret;
426 456
427 ret = nouveau_ramht_insert(chan, NvSw, obj); 457 /* we leave subchannel empty for nvc0 */
428 nouveau_gpuobj_ref(NULL, &obj); 458 if (dev_priv->card_type < NV_C0) {
429 if (ret) 459 ret = RING_SPACE(chan, 2);
430 return ret; 460 if (ret)
431 461 return ret;
432 ret = RING_SPACE(chan, 2); 462 BEGIN_RING(chan, NvSubSw, 0, 1);
433 if (ret) 463 OUT_RING(chan, NvSw);
434 return ret; 464 }
435 BEGIN_RING(chan, NvSubSw, 0, 1);
436 OUT_RING(chan, NvSw);
437 465
438 /* Create a DMA object for the shared cross-channel sync area. */ 466 /* Create a DMA object for the shared cross-channel sync area. */
439 if (USE_SEMA(dev)) { 467 if (USE_SEMA(dev)) {
440 struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node; 468 struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
441 469
442 ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 470 ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
443 mem->start << PAGE_SHIFT, 471 mem->start << PAGE_SHIFT,
444 mem->size << PAGE_SHIFT, 472 mem->size, NV_MEM_ACCESS_RW,
445 NV_DMA_ACCESS_RW, 473 NV_MEM_TARGET_VRAM, &obj);
446 NV_DMA_TARGET_VIDMEM, &obj);
447 if (ret) 474 if (ret)
448 return ret; 475 return ret;
449 476
@@ -473,6 +500,8 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan)
473{ 500{
474 struct nouveau_fence *tmp, *fence; 501 struct nouveau_fence *tmp, *fence;
475 502
503 spin_lock(&chan->fence.lock);
504
476 list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { 505 list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
477 fence->signalled = true; 506 fence->signalled = true;
478 list_del(&fence->entry); 507 list_del(&fence->entry);
@@ -482,6 +511,8 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan)
482 511
483 kref_put(&fence->refcount, nouveau_fence_del); 512 kref_put(&fence->refcount, nouveau_fence_del);
484 } 513 }
514
515 spin_unlock(&chan->fence.lock);
485} 516}
486 517
487int 518int