2 * Copyright (C) 2007 Ben Skeggs.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include "nouveau_drv.h"
31 #include "nouveau_ramht.h"
32 #include "nouveau_dma.h"
34 #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
35 #define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
37 struct nouveau_fence
{
38 struct nouveau_channel
*channel
;
40 struct list_head entry
;
45 void (*work
)(void *priv
, bool signalled
);
49 struct nouveau_semaphore
{
51 struct drm_device
*dev
;
52 struct drm_mm_node
*mem
;
55 static inline struct nouveau_fence
*
56 nouveau_fence(void *sync_obj
)
58 return (struct nouveau_fence
*)sync_obj
;
62 nouveau_fence_del(struct kref
*ref
)
64 struct nouveau_fence
*fence
=
65 container_of(ref
, struct nouveau_fence
, refcount
);
67 nouveau_channel_ref(NULL
, &fence
->channel
);
72 nouveau_fence_update(struct nouveau_channel
*chan
)
74 struct drm_device
*dev
= chan
->dev
;
75 struct nouveau_fence
*tmp
, *fence
;
78 spin_lock(&chan
->fence
.lock
);
81 sequence
= nvchan_rd32(chan
, 0x48);
83 sequence
= atomic_read(&chan
->fence
.last_sequence_irq
);
85 if (chan
->fence
.sequence_ack
== sequence
)
87 chan
->fence
.sequence_ack
= sequence
;
89 list_for_each_entry_safe(fence
, tmp
, &chan
->fence
.pending
, entry
) {
90 sequence
= fence
->sequence
;
91 fence
->signalled
= true;
92 list_del(&fence
->entry
);
94 if (unlikely(fence
->work
))
95 fence
->work(fence
->priv
, true);
97 kref_put(&fence
->refcount
, nouveau_fence_del
);
99 if (sequence
== chan
->fence
.sequence_ack
)
103 spin_unlock(&chan
->fence
.lock
);
107 nouveau_fence_new(struct nouveau_channel
*chan
, struct nouveau_fence
**pfence
,
110 struct nouveau_fence
*fence
;
113 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
116 kref_init(&fence
->refcount
);
117 nouveau_channel_ref(chan
, &fence
->channel
);
120 ret
= nouveau_fence_emit(fence
);
123 nouveau_fence_unref((void *)&fence
);
128 struct nouveau_channel
*
129 nouveau_fence_channel(struct nouveau_fence
*fence
)
131 return fence
? fence
->channel
: NULL
;
135 nouveau_fence_emit(struct nouveau_fence
*fence
)
137 struct nouveau_channel
*chan
= fence
->channel
;
138 struct drm_device
*dev
= chan
->dev
;
141 ret
= RING_SPACE(chan
, 2);
145 if (unlikely(chan
->fence
.sequence
== chan
->fence
.sequence_ack
- 1)) {
146 nouveau_fence_update(chan
);
148 BUG_ON(chan
->fence
.sequence
==
149 chan
->fence
.sequence_ack
- 1);
152 fence
->sequence
= ++chan
->fence
.sequence
;
154 kref_get(&fence
->refcount
);
155 spin_lock(&chan
->fence
.lock
);
156 list_add_tail(&fence
->entry
, &chan
->fence
.pending
);
157 spin_unlock(&chan
->fence
.lock
);
159 BEGIN_RING(chan
, NvSubSw
, USE_REFCNT(dev
) ? 0x0050 : 0x0150, 1);
160 OUT_RING(chan
, fence
->sequence
);
167 nouveau_fence_work(struct nouveau_fence
*fence
,
168 void (*work
)(void *priv
, bool signalled
),
173 spin_lock(&fence
->channel
->fence
.lock
);
175 if (fence
->signalled
) {
182 spin_unlock(&fence
->channel
->fence
.lock
);
186 nouveau_fence_unref(void **sync_obj
)
188 struct nouveau_fence
*fence
= nouveau_fence(*sync_obj
);
191 kref_put(&fence
->refcount
, nouveau_fence_del
);
196 nouveau_fence_ref(void *sync_obj
)
198 struct nouveau_fence
*fence
= nouveau_fence(sync_obj
);
200 kref_get(&fence
->refcount
);
205 nouveau_fence_signalled(void *sync_obj
, void *sync_arg
)
207 struct nouveau_fence
*fence
= nouveau_fence(sync_obj
);
208 struct nouveau_channel
*chan
= fence
->channel
;
210 if (fence
->signalled
)
213 nouveau_fence_update(chan
);
214 return fence
->signalled
;
218 nouveau_fence_wait(void *sync_obj
, void *sync_arg
, bool lazy
, bool intr
)
220 unsigned long timeout
= jiffies
+ (3 * DRM_HZ
);
224 if (nouveau_fence_signalled(sync_obj
, sync_arg
))
227 if (time_after_eq(jiffies
, timeout
)) {
232 __set_current_state(intr
? TASK_INTERRUPTIBLE
233 : TASK_UNINTERRUPTIBLE
);
237 if (intr
&& signal_pending(current
)) {
243 __set_current_state(TASK_RUNNING
);
248 static struct nouveau_semaphore
*
249 alloc_semaphore(struct drm_device
*dev
)
251 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
252 struct nouveau_semaphore
*sema
;
258 sema
= kmalloc(sizeof(*sema
), GFP_KERNEL
);
262 ret
= drm_mm_pre_get(&dev_priv
->fence
.heap
);
266 spin_lock(&dev_priv
->fence
.lock
);
267 sema
->mem
= drm_mm_search_free(&dev_priv
->fence
.heap
, 4, 0, 0);
269 sema
->mem
= drm_mm_get_block_atomic(sema
->mem
, 4, 0);
270 spin_unlock(&dev_priv
->fence
.lock
);
275 kref_init(&sema
->ref
);
277 nouveau_bo_wr32(dev_priv
->fence
.bo
, sema
->mem
->start
/ 4, 0);
286 free_semaphore(struct kref
*ref
)
288 struct nouveau_semaphore
*sema
=
289 container_of(ref
, struct nouveau_semaphore
, ref
);
290 struct drm_nouveau_private
*dev_priv
= sema
->dev
->dev_private
;
292 spin_lock(&dev_priv
->fence
.lock
);
293 drm_mm_put_block(sema
->mem
);
294 spin_unlock(&dev_priv
->fence
.lock
);
300 semaphore_work(void *priv
, bool signalled
)
302 struct nouveau_semaphore
*sema
= priv
;
303 struct drm_nouveau_private
*dev_priv
= sema
->dev
->dev_private
;
305 if (unlikely(!signalled
))
306 nouveau_bo_wr32(dev_priv
->fence
.bo
, sema
->mem
->start
/ 4, 1);
308 kref_put(&sema
->ref
, free_semaphore
);
312 emit_semaphore(struct nouveau_channel
*chan
, int method
,
313 struct nouveau_semaphore
*sema
)
315 struct drm_nouveau_private
*dev_priv
= sema
->dev
->dev_private
;
316 struct nouveau_fence
*fence
;
317 bool smart
= (dev_priv
->card_type
>= NV_50
);
320 ret
= RING_SPACE(chan
, smart
? 8 : 4);
325 BEGIN_RING(chan
, NvSubSw
, NV_SW_DMA_SEMAPHORE
, 1);
326 OUT_RING(chan
, NvSema
);
328 BEGIN_RING(chan
, NvSubSw
, NV_SW_SEMAPHORE_OFFSET
, 1);
329 OUT_RING(chan
, sema
->mem
->start
);
331 if (smart
&& method
== NV_SW_SEMAPHORE_ACQUIRE
) {
333 * NV50 tries to be too smart and context-switch
334 * between semaphores instead of doing a "first come,
335 * first served" strategy like previous cards
338 * That's bad because the ACQUIRE latency can get as
339 * large as the PFIFO context time slice in the
340 * typical DRI2 case where you have several
341 * outstanding semaphores at the same moment.
343 * If we're going to ACQUIRE, force the card to
344 * context switch before, just in case the matching
345 * RELEASE is already scheduled to be executed in
348 BEGIN_RING(chan
, NvSubSw
, NV_SW_YIELD
, 1);
352 BEGIN_RING(chan
, NvSubSw
, method
, 1);
355 if (smart
&& method
== NV_SW_SEMAPHORE_RELEASE
) {
357 * Force the card to context switch, there may be
358 * another channel waiting for the semaphore we just
361 BEGIN_RING(chan
, NvSubSw
, NV_SW_YIELD
, 1);
365 /* Delay semaphore destruction until its work is done */
366 ret
= nouveau_fence_new(chan
, &fence
, true);
370 kref_get(&sema
->ref
);
371 nouveau_fence_work(fence
, semaphore_work
, sema
);
372 nouveau_fence_unref((void *)&fence
);
378 nouveau_fence_sync(struct nouveau_fence
*fence
,
379 struct nouveau_channel
*wchan
)
381 struct nouveau_channel
*chan
= nouveau_fence_channel(fence
);
382 struct drm_device
*dev
= wchan
->dev
;
383 struct nouveau_semaphore
*sema
;
386 if (likely(!fence
|| chan
== wchan
||
387 nouveau_fence_signalled(fence
, NULL
)))
390 sema
= alloc_semaphore(dev
);
392 /* Early card or broken userspace, fall back to
394 return nouveau_fence_wait(fence
, NULL
, true, false);
397 /* try to take chan's mutex, if we can't take it right away
398 * we have to fallback to software sync to prevent locking
401 if (!mutex_trylock(&chan
->mutex
)) {
402 free_semaphore(&sema
->ref
);
403 return nouveau_fence_wait(fence
, NULL
, true, false);
406 /* Make wchan wait until it gets signalled */
407 ret
= emit_semaphore(wchan
, NV_SW_SEMAPHORE_ACQUIRE
, sema
);
411 /* Signal the semaphore from chan */
412 ret
= emit_semaphore(chan
, NV_SW_SEMAPHORE_RELEASE
, sema
);
413 mutex_unlock(&chan
->mutex
);
415 kref_put(&sema
->ref
, free_semaphore
);
420 nouveau_fence_flush(void *sync_obj
, void *sync_arg
)
426 nouveau_fence_channel_init(struct nouveau_channel
*chan
)
428 struct drm_device
*dev
= chan
->dev
;
429 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
430 struct nouveau_gpuobj
*obj
= NULL
;
433 /* Create an NV_SW object for various sync purposes */
434 ret
= nouveau_gpuobj_sw_new(chan
, NV_SW
, &obj
);
438 ret
= nouveau_ramht_insert(chan
, NvSw
, obj
);
439 nouveau_gpuobj_ref(NULL
, &obj
);
443 ret
= RING_SPACE(chan
, 2);
446 BEGIN_RING(chan
, NvSubSw
, 0, 1);
447 OUT_RING(chan
, NvSw
);
449 /* Create a DMA object for the shared cross-channel sync area. */
451 struct drm_mm_node
*mem
= dev_priv
->fence
.bo
->bo
.mem
.mm_node
;
453 ret
= nouveau_gpuobj_dma_new(chan
, NV_CLASS_DMA_IN_MEMORY
,
454 mem
->start
<< PAGE_SHIFT
,
455 mem
->size
<< PAGE_SHIFT
,
457 NV_DMA_TARGET_VIDMEM
, &obj
);
461 ret
= nouveau_ramht_insert(chan
, NvSema
, obj
);
462 nouveau_gpuobj_ref(NULL
, &obj
);
466 ret
= RING_SPACE(chan
, 2);
469 BEGIN_RING(chan
, NvSubSw
, NV_SW_DMA_SEMAPHORE
, 1);
470 OUT_RING(chan
, NvSema
);
475 INIT_LIST_HEAD(&chan
->fence
.pending
);
476 spin_lock_init(&chan
->fence
.lock
);
477 atomic_set(&chan
->fence
.last_sequence_irq
, 0);
483 nouveau_fence_channel_fini(struct nouveau_channel
*chan
)
485 struct nouveau_fence
*tmp
, *fence
;
487 list_for_each_entry_safe(fence
, tmp
, &chan
->fence
.pending
, entry
) {
488 fence
->signalled
= true;
489 list_del(&fence
->entry
);
491 if (unlikely(fence
->work
))
492 fence
->work(fence
->priv
, false);
494 kref_put(&fence
->refcount
, nouveau_fence_del
);
499 nouveau_fence_init(struct drm_device
*dev
)
501 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
504 /* Create a shared VRAM heap for cross-channel sync. */
506 ret
= nouveau_bo_new(dev
, NULL
, 4096, 0, TTM_PL_FLAG_VRAM
,
507 0, 0, false, true, &dev_priv
->fence
.bo
);
511 ret
= nouveau_bo_pin(dev_priv
->fence
.bo
, TTM_PL_FLAG_VRAM
);
515 ret
= nouveau_bo_map(dev_priv
->fence
.bo
);
519 ret
= drm_mm_init(&dev_priv
->fence
.heap
, 0,
520 dev_priv
->fence
.bo
->bo
.mem
.size
);
524 spin_lock_init(&dev_priv
->fence
.lock
);
529 nouveau_bo_unmap(dev_priv
->fence
.bo
);
530 nouveau_bo_ref(NULL
, &dev_priv
->fence
.bo
);
535 nouveau_fence_fini(struct drm_device
*dev
)
537 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
540 drm_mm_takedown(&dev_priv
->fence
.heap
);
541 nouveau_bo_unmap(dev_priv
->fence
.bo
);
542 nouveau_bo_unpin(dev_priv
->fence
.bo
);
543 nouveau_bo_ref(NULL
, &dev_priv
->fence
.bo
);
This page took 0.046011 seconds and 5 git commands to generate.