nouveau: make sure there's always room to emit a fence

I started seeing a lot of situations on nv30 where fence emission
wouldn't fit into the previous buffer (causing assertions). This ensures
that whenever checking for space, we always leave a bit of extra room
for the fence emission commands. Adjusts the nv30 and nvc0 fence
emission logic to bypass the space checking as well.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Cc: mesa-stable@lists.freedesktop.org
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
(cherry picked from commit 47d11990b2)

Squashed with commit

nouveau: avoid emitting new fences unnecessarily

Right now we emit on every kick, but this is only necessary if something
will ever be able to observe that the fence completed. If there are no
refs, leave the fence alone and emit it another day.

This also happens to work around an issue for the kick handler -- a kick
can be a result of e.g. nouveau_bo_wait or explicit kick, or it can be
due to lack of space in the pushbuf. We want the emit to happen in the
current batch, so we want there to always be enough space. However an
explicit kick could take the reserved space for the implicitly-triggered
kick's fence emission if it happened right after. With the new mechanism,
hopefully there's no way to cause two fences to be emitted into the same
reserved space.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Fixes: 47d11990b (nouveau: make sure there's always room to emit a fence)
Cc: mesa-stable@lists.freedesktop.org
(cherry picked from commit 8053c9208f)

Squashed with commit

nv50,nvc0: don't base decisions on available pushbuf space

We still have to push everything out, might as well kick earlier and
flip pushbufs when we know we'll need it. This resolves some issues with
the new policy of making sure that we always leave a bit of room at the
end for fences.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Fixes: 47d11990b (nouveau: make sure there's always room to emit a fence)
Cc: mesa-stable@lists.freedesktop.org
(cherry picked from commit 9fe458335f)

Squashed with commit

nouveau: avoid double-emitting fence

The act of ensuring that there is space can cause a flush to happen,
which will emit the current screen fence. If that is the fence we're
trying to wait on, then it will have been emitted as a result of doing
the PUSH_SPACE. Don't attempt to emit it a second time.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Fixes: 8053c9208f (nouveau: avoid emitting new fences unnecessarily)
Cc: mesa-stable@lists.freedesktop.org
(cherry picked from commit bf97f8d467)
This commit is contained in:
Ilia Mirkin 2015-10-05 15:19:05 -04:00 committed by Emil Velikov
parent b4bfea0094
commit 3f802ebaf8
8 changed files with 32 additions and 41 deletions

View file

@ -190,8 +190,14 @@ nouveau_fence_wait(struct nouveau_fence *fence)
/* wtf, someone is waiting on a fence in flush_notify handler? */
assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
if (fence->state < NOUVEAU_FENCE_STATE_EMITTED)
nouveau_fence_emit(fence);
if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) {
PUSH_SPACE(screen->pushbuf, 8);
/* The space allocation might trigger a flush, which could emit the
* current fence. So check again.
*/
if (fence->state < NOUVEAU_FENCE_STATE_EMITTED)
nouveau_fence_emit(fence);
}
if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED)
if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel))
@ -224,8 +230,12 @@ nouveau_fence_wait(struct nouveau_fence *fence)
void
nouveau_fence_next(struct nouveau_screen *screen)
{
if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING)
nouveau_fence_emit(screen->fence.current);
if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING) {
if (screen->fence.current->ref > 1)
nouveau_fence_emit(screen->fence.current);
else
return;
}
nouveau_fence_ref(NULL, &screen->fence.current);

View file

@ -24,6 +24,8 @@ PUSH_AVAIL(struct nouveau_pushbuf *push)
static inline bool
PUSH_SPACE(struct nouveau_pushbuf *push, uint32_t size)
{
/* Provide a buffer so that fences always have room to be emitted */
size += 8;
if (PUSH_AVAIL(push) < size)
return nouveau_pushbuf_space(push, size, 0, 0) == 0;
return true;

View file

@ -345,7 +345,9 @@ nv30_screen_fence_emit(struct pipe_screen *pscreen, uint32_t *sequence)
*sequence = ++screen->base.fence.sequence;
BEGIN_NV04(push, NV30_3D(FENCE_OFFSET), 2);
assert(PUSH_AVAIL(push) >= 3);
PUSH_DATA (push, NV30_3D_FENCE_OFFSET |
(2 /* size */ << 18) | (7 /* subchan */ << 13));
PUSH_DATA (push, 0);
PUSH_DATA (push, *sequence);
}

View file

@ -386,6 +386,7 @@ nv50_screen_fence_emit(struct pipe_screen *pscreen, u32 *sequence)
/* we need to do it after possible flush in MARK_RING */
*sequence = ++screen->base.fence.sequence;
assert(PUSH_AVAIL(push) >= 5);
PUSH_DATA (push, NV50_FIFO_PKHDR(NV50_3D(QUERY_ADDRESS_HIGH), 4));
PUSH_DATAh(push, screen->fence.bo->offset);
PUSH_DATA (push, screen->fence.bo->offset);

View file

@ -65,14 +65,9 @@ nv50_constbufs_validate(struct nv50_context *nv50)
PUSH_DATA (push, (b << 12) | (i << 8) | p | 1);
}
while (words) {
unsigned nr;
if (!PUSH_SPACE(push, 16))
break;
nr = PUSH_AVAIL(push);
assert(nr >= 16);
nr = MIN2(MIN2(nr - 3, words), NV04_PFIFO_MAX_PACKET_LEN);
unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN);
PUSH_SPACE(push, nr + 3);
BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
PUSH_DATA (push, (start << 8) | b);
BEGIN_NI04(push, NV50_3D(CB_DATA(0)), nr);

View file

@ -187,14 +187,7 @@ nv50_sifc_linear_u8(struct nouveau_context *nv,
PUSH_DATA (push, 0);
while (count) {
unsigned nr;
if (!PUSH_SPACE(push, 16))
break;
nr = PUSH_AVAIL(push);
assert(nr >= 16);
nr = MIN2(count, nr - 1);
nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN);
unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
BEGIN_NI04(push, NV50_2D(SIFC_DATA), nr);
PUSH_DATAp(push, src, nr);
@ -395,12 +388,9 @@ nv50_cb_push(struct nouveau_context *nv,
nouveau_pushbuf_validate(push);
while (words) {
unsigned nr;
nr = PUSH_AVAIL(push);
nr = MIN2(nr - 7, words);
nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1);
unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN);
PUSH_SPACE(push, nr + 7);
BEGIN_NV04(push, NV50_3D(CB_DEF_ADDRESS_HIGH), 3);
PUSH_DATAh(push, bo->offset + base);
PUSH_DATA (push, bo->offset + base);

View file

@ -535,7 +535,8 @@ nvc0_screen_fence_emit(struct pipe_screen *pscreen, u32 *sequence)
/* we need to do it after possible flush in MARK_RING */
*sequence = ++screen->base.fence.sequence;
BEGIN_NVC0(push, NVC0_3D(QUERY_ADDRESS_HIGH), 4);
assert(PUSH_AVAIL(push) >= 5);
PUSH_DATA (push, NVC0_FIFO_PKHDR_SQ(NVC0_3D(QUERY_ADDRESS_HIGH), 4));
PUSH_DATAh(push, screen->fence.bo->offset);
PUSH_DATA (push, screen->fence.bo->offset);
PUSH_DATA (push, *sequence);

View file

@ -188,14 +188,10 @@ nvc0_m2mf_push_linear(struct nouveau_context *nv,
nouveau_pushbuf_validate(push);
while (count) {
unsigned nr;
unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
if (!PUSH_SPACE(push, 16))
if (!PUSH_SPACE(push, nr + 9))
break;
nr = PUSH_AVAIL(push);
assert(nr >= 16);
nr = MIN2(count, nr - 9);
nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN);
BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
PUSH_DATAh(push, dst->offset + offset);
@ -234,14 +230,10 @@ nve4_p2mf_push_linear(struct nouveau_context *nv,
nouveau_pushbuf_validate(push);
while (count) {
unsigned nr;
unsigned nr = MIN2(count, (NV04_PFIFO_MAX_PACKET_LEN - 1));
if (!PUSH_SPACE(push, 16))
if (!PUSH_SPACE(push, nr + 10))
break;
nr = PUSH_AVAIL(push);
assert(nr >= 16);
nr = MIN2(count, nr - 8);
nr = MIN2(nr, (NV04_PFIFO_MAX_PACKET_LEN - 1));
BEGIN_NVC0(push, NVE4_P2MF(UPLOAD_DST_ADDRESS_HIGH), 2);
PUSH_DATAh(push, dst->offset + offset);
@ -571,9 +563,7 @@ nvc0_cb_bo_push(struct nouveau_context *nv,
PUSH_DATA (push, bo->offset + base);
while (words) {
unsigned nr = PUSH_AVAIL(push);
nr = MIN2(nr, words);
nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1);
unsigned nr = MIN2(words, NV04_PFIFO_MAX_PACKET_LEN - 1);
PUSH_SPACE(push, nr + 2);
PUSH_REFN (push, bo, NOUVEAU_BO_WR | domain);