Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/external/bsd/drm2/dist/drm/nouveau Defer nouveau_fence_u...
details: https://anonhg.NetBSD.org/src/rev/ea51861bf6a5
branches: trunk
changeset: 365590:ea51861bf6a5
user: riastradh <riastradh%NetBSD.org@localhost>
date: Thu Aug 23 01:10:21 2018 +0000
description:
Defer nouveau_fence_unref until spin unlock.
- kfree while holding a spin lock is not a good idea.
- Make sure we GC every time we might signal fences.
PR kern/53441
XXX pullup-7
XXX pullup-8
diffstat:
sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.c | 77 ++++++++++++++++-
sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.h | 1 +
2 files changed, 72 insertions(+), 6 deletions(-)
diffs (211 lines):
diff -r cbb2908b0d5a -r ea51861bf6a5 sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.c
--- a/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.c Thu Aug 23 01:10:04 2018 +0000
+++ b/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.c Thu Aug 23 01:10:21 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nouveau_fence.c,v 1.6 2018/08/23 01:10:04 riastradh Exp $ */
+/* $NetBSD: nouveau_fence.c,v 1.7 2018/08/23 01:10:21 riastradh Exp $ */
/*
* Copyright (C) 2007 Ben Skeggs.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nouveau_fence.c,v 1.6 2018/08/23 01:10:04 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nouveau_fence.c,v 1.7 2018/08/23 01:10:21 riastradh Exp $");
#include <sys/types.h>
#include <sys/xcall.h>
@@ -87,6 +87,43 @@
}
/*
+ * nouveau_fence_gc_grab(fctx, list)
+ *
+ * Move all of channel's done fences to list.
+ *
+ * Caller must hold channel's fence lock.
+ */
+static void
+nouveau_fence_gc_grab(struct nouveau_fence_chan *fctx, struct list_head *list)
+{
+ struct list_head *node, *next;
+
+ BUG_ON(!spin_is_locked(&fctx->lock));
+
+ list_for_each_safe(node, next, &fctx->done) {
+ list_move_tail(node, list);
+ }
+}
+
+/*
+ * nouveau_fence_gc_free(list)
+ *
+ * Unreference all of the fences in the list.
+ *
+ * Caller MUST NOT hold the fences' channel's fence lock.
+ */
+static void
+nouveau_fence_gc_free(struct list_head *list)
+{
+ struct nouveau_fence *fence, *next;
+
+ list_for_each_entry_safe(fence, next, list, head) {
+ list_del(&fence->head);
+ nouveau_fence_unref(&fence);
+ }
+}
+
+/*
* nouveau_fence_channel_release(channel)
*
* Release the channel acquired with nouveau_fence_channel_acquire.
@@ -114,7 +151,8 @@
/*
* nouveau_fence_signal(fence)
*
- * Schedule all the work for fence's completion, and mark it done.
+ * Schedule all the work for fence's completion, mark it done, and
+ * move it from the pending list to the done list.
*
* Caller must hold fence's channel's fence lock.
*/
@@ -136,7 +174,9 @@
/* Note that the fence is done. */
fence->done = true;
- list_del(&fence->head);
+
+ /* Move it from the pending list to the done list. */
+ list_move_tail(&fence->head, &fctx->done);
}
static void
@@ -154,16 +194,22 @@
nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
struct nouveau_fence *fence, *fnext;
+ struct list_head done_list;
int ret __diagused;
+ INIT_LIST_HEAD(&done_list);
+
/* Signal all the fences in fctx. */
spin_lock(&fctx->lock);
list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
nouveau_fence_signal(fence);
- /* XXX Doesn't this leak fence? */
}
+ nouveau_fence_gc_grab(fctx, &done_list);
spin_unlock(&fctx->lock);
+ /* Release any fences that we signalled. */
+ nouveau_fence_gc_free(&done_list);
+
/* Wait for the workqueue to drain. */
flush_scheduled_work();
@@ -177,6 +223,11 @@
BUG_ON(ret);
spin_unlock(&fctx->lock);
+ /* Make sure there are no more fences on the list. */
+ BUG_ON(!list_empty(&fctx->done));
+ BUG_ON(!list_empty(&fctx->flip));
+ BUG_ON(!list_empty(&fctx->pending));
+
/* Destroy the fence context. */
DRM_DESTROY_WAITQUEUE(&fctx->waitqueue);
spin_lock_destroy(&fctx->lock);
@@ -193,6 +244,7 @@
INIT_LIST_HEAD(&fctx->flip);
INIT_LIST_HEAD(&fctx->pending);
+ INIT_LIST_HEAD(&fctx->done);
spin_lock_init(&fctx->lock);
DRM_INIT_WAITQUEUE(&fctx->waitqueue, "nvfnchan");
fctx->refcnt = 0;
@@ -275,7 +327,6 @@
if (fctx->read(chan) < fence->sequence)
break;
nouveau_fence_signal(fence);
- nouveau_fence_unref(&fence);
}
BUG_ON(!spin_is_locked(&fctx->lock));
}
@@ -349,18 +400,24 @@
{
struct nouveau_channel *chan;
struct nouveau_fence_chan *fctx;
+ struct list_head done_list;
bool done;
if ((chan = nouveau_fence_channel_acquire(fence)) == NULL)
return true;
+ INIT_LIST_HEAD(&done_list);
+
fctx = chan->fence;
spin_lock(&fctx->lock);
done = nouveau_fence_done_locked(fence, chan);
+ nouveau_fence_gc_grab(fctx, &done_list);
spin_unlock(&fctx->lock);
nouveau_fence_channel_release(chan);
+ nouveau_fence_gc_free(&done_list);
+
return done;
}
@@ -397,6 +454,7 @@
struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
struct nouveau_fence_chan *fctx = chan->fence;
struct nouveau_eventh *handler;
+ struct list_head done_list;
int ret = 0;
BUG_ON(fence->channel != chan);
@@ -409,6 +467,8 @@
nouveau_event_get(handler);
+ INIT_LIST_HEAD(&done_list);
+
if (fence->timeout) {
unsigned long timeout = fence->timeout - jiffies;
@@ -425,6 +485,7 @@
timeout,
nouveau_fence_done_locked(fence, chan));
}
+ nouveau_fence_gc_grab(fctx, &done_list);
spin_unlock(&fctx->lock);
}
@@ -444,10 +505,14 @@
&fctx->lock,
nouveau_fence_done_locked(fence, chan));
}
+ nouveau_fence_gc_grab(fctx, &done_list);
spin_unlock(&fctx->lock);
}
nouveau_event_ref(NULL, &handler);
+
+ nouveau_fence_gc_free(&done_list);
+
if (unlikely(ret < 0))
return ret;
diff -r cbb2908b0d5a -r ea51861bf6a5 sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.h
--- a/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.h Thu Aug 23 01:10:04 2018 +0000
+++ b/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_fence.h Thu Aug 23 01:10:21 2018 +0000
@@ -36,6 +36,7 @@
struct nouveau_fence_chan {
struct list_head pending;
struct list_head flip;
+ struct list_head done;
int (*emit)(struct nouveau_fence *);
int (*sync)(struct nouveau_fence *, struct nouveau_channel *,
Home |
Main Index |
Thread Index |
Old Index