summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Ĺšlusarz <marcin.slusarz@gmail.com>2015-03-31 22:04:31 +0200
committerEmil Velikov <emil.l.velikov@gmail.com>2015-04-08 19:09:02 +0100
commit64bb117f6dc80103b7be6a3971a93195dc5f1917 (patch)
tree029c6f669802828d7413297be54c9740ef0b1747
parentb7c44cd5abcd2d6dd7b525368ed93f0f35d87644 (diff)
downloadmesa-64bb117f6dc80103b7be6a3971a93195dc5f1917.tar.gz
nouveau: synchronize "scratch runout" destruction with the command stream
When nvc0_push_vbo calls nouveau_scratch_done it does not mean scratch buffers can be freed immediately. It means "when hardware advances to this place in the command stream the scratch buffers can be freed". To fix it, just postpone scratch runout destruction after current fence is signalled. The bug existed for a very long time. Nobody noticed, because "scratch runout" code path is rarely executed. Fixes hang at the very beginning of first mission in "Serious Sam 3" on nve7/gk107. It manifested as: nouveau E[ PFIFO][0000:01:00.0] read fault at 0x000a9e0000 [PTE] from GR/GPC0/PE_2 on channel 0x007f853000 [Sam3[17056]] Cc: "10.4 10.5" <mesa-stable@lists.freedesktop.org> Reviewed-by: Ilia Mirkin <imirkin@alum.mit.edu> (cherry picked from commit f9e2295560f9b4869fa2a94933c1881ec7970af4)
-rw-r--r--src/gallium/drivers/nouveau/nouveau_buffer.c48
-rw-r--r--src/gallium/drivers/nouveau/nouveau_context.h8
2 files changed, 37 insertions, 19 deletions
diff --git a/src/gallium/drivers/nouveau/nouveau_buffer.c b/src/gallium/drivers/nouveau/nouveau_buffer.c
index 49ff100c4ec..32fa65c8a51 100644
--- a/src/gallium/drivers/nouveau/nouveau_buffer.c
+++ b/src/gallium/drivers/nouveau/nouveau_buffer.c
@@ -846,17 +846,28 @@ nouveau_scratch_bo_alloc(struct nouveau_context *nv, struct nouveau_bo **pbo,
4096, size, NULL, pbo);
}
+static void
+nouveau_scratch_unref_bos(void *d)
+{
+ struct runout *b = d;
+ int i;
+
+ for (i = 0; i < b->nr; ++i)
+ nouveau_bo_ref(NULL, &b->bo[i]);
+
+ FREE(b);
+}
+
void
nouveau_scratch_runout_release(struct nouveau_context *nv)
{
- if (!nv->scratch.nr_runout)
+ if (!nv->scratch.runout)
+ return;
+
+ if (!nouveau_fence_work(nv->screen->fence.current, nouveau_scratch_unref_bos,
+ nv->scratch.runout))
return;
- do {
- --nv->scratch.nr_runout;
- nouveau_bo_ref(NULL, &nv->scratch.runout[nv->scratch.nr_runout]);
- } while (nv->scratch.nr_runout);
- FREE(nv->scratch.runout);
nv->scratch.end = 0;
nv->scratch.runout = NULL;
}
@@ -868,21 +879,26 @@ static INLINE boolean
nouveau_scratch_runout(struct nouveau_context *nv, unsigned size)
{
int ret;
- const unsigned n = nv->scratch.nr_runout++;
+ unsigned n;
- nv->scratch.runout = REALLOC(nv->scratch.runout,
- (n + 0) * sizeof(*nv->scratch.runout),
- (n + 1) * sizeof(*nv->scratch.runout));
- nv->scratch.runout[n] = NULL;
-
- ret = nouveau_scratch_bo_alloc(nv, &nv->scratch.runout[n], size);
+ if (nv->scratch.runout)
+ n = nv->scratch.runout->nr;
+ else
+ n = 0;
+ nv->scratch.runout = REALLOC(nv->scratch.runout, n == 0 ? 0 :
+ (sizeof(*nv->scratch.runout) + (n + 0) * sizeof(void *)),
+ sizeof(*nv->scratch.runout) + (n + 1) * sizeof(void *));
+ nv->scratch.runout->nr = n + 1;
+ nv->scratch.runout->bo[n] = NULL;
+
+ ret = nouveau_scratch_bo_alloc(nv, &nv->scratch.runout->bo[n], size);
if (!ret) {
- ret = nouveau_bo_map(nv->scratch.runout[n], 0, NULL);
+ ret = nouveau_bo_map(nv->scratch.runout->bo[n], 0, NULL);
if (ret)
- nouveau_bo_ref(NULL, &nv->scratch.runout[--nv->scratch.nr_runout]);
+ nouveau_bo_ref(NULL, &nv->scratch.runout->bo[--nv->scratch.runout->nr]);
}
if (!ret) {
- nv->scratch.current = nv->scratch.runout[n];
+ nv->scratch.current = nv->scratch.runout->bo[n];
nv->scratch.offset = 0;
nv->scratch.end = size;
nv->scratch.map = nv->scratch.current->map;
diff --git a/src/gallium/drivers/nouveau/nouveau_context.h b/src/gallium/drivers/nouveau/nouveau_context.h
index 14608d33c52..c2ba0159afe 100644
--- a/src/gallium/drivers/nouveau/nouveau_context.h
+++ b/src/gallium/drivers/nouveau/nouveau_context.h
@@ -40,8 +40,10 @@ struct nouveau_context {
unsigned end;
struct nouveau_bo *bo[NOUVEAU_MAX_SCRATCH_BUFS];
struct nouveau_bo *current;
- struct nouveau_bo **runout;
- unsigned nr_runout;
+ struct runout {
+ unsigned nr;
+ struct nouveau_bo *bo[0];
+ } *runout;
unsigned bo_size;
} scratch;
@@ -71,7 +73,7 @@ static INLINE void
nouveau_scratch_done(struct nouveau_context *nv)
{
nv->scratch.wrap = nv->scratch.id;
- if (unlikely(nv->scratch.nr_runout))
+ if (unlikely(nv->scratch.runout))
nouveau_scratch_runout_release(nv);
}