|
@@ -100,6 +100,18 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
|
|
|
spin_unlock_irq(&fctx->lock);
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+nouveau_fence_context_put(struct kref *fence_ref)
|
|
|
+{
|
|
|
+ kfree(container_of(fence_ref, struct nouveau_fence_chan, fence_ref));
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+nouveau_fence_context_free(struct nouveau_fence_chan *fctx)
|
|
|
+{
|
|
|
+ kref_put(&fctx->fence_ref, nouveau_fence_context_put);
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
|
|
|
{
|
|
@@ -141,6 +153,7 @@ void
|
|
|
nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
|
|
|
{
|
|
|
struct nouveau_fence_priv *priv = (void*)chan->drm->fence;
|
|
|
+ struct nouveau_cli *cli = (void *)nvif_client(chan->object);
|
|
|
int ret;
|
|
|
|
|
|
INIT_LIST_HEAD(&fctx->flip);
|
|
@@ -148,6 +161,14 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
|
|
|
spin_lock_init(&fctx->lock);
|
|
|
fctx->context = priv->context_base + chan->chid;
|
|
|
|
|
|
+ if (chan == chan->drm->cechan)
|
|
|
+ strcpy(fctx->name, "copy engine channel");
|
|
|
+ else if (chan == chan->drm->channel)
|
|
|
+ strcpy(fctx->name, "generic kernel channel");
|
|
|
+ else
|
|
|
+ strcpy(fctx->name, nvkm_client(&cli->base)->name);
|
|
|
+
|
|
|
+ kref_init(&fctx->fence_ref);
|
|
|
if (!priv->uevent)
|
|
|
return;
|
|
|
|
|
@@ -195,8 +216,12 @@ nouveau_fence_work(struct fence *fence,
|
|
|
|
|
|
work = kmalloc(sizeof(*work), GFP_KERNEL);
|
|
|
if (!work) {
|
|
|
+ /*
|
|
|
+ * this might not be a nouveau fence any more,
|
|
|
+ * so force a lazy wait here
|
|
|
+ */
|
|
|
WARN_ON(nouveau_fence_wait((struct nouveau_fence *)fence,
|
|
|
- false, false));
|
|
|
+ true, false));
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
@@ -226,12 +251,11 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
|
|
|
|
|
|
if (priv->uevent)
|
|
|
fence_init(&fence->base, &nouveau_fence_ops_uevent,
|
|
|
- &fctx->lock,
|
|
|
- priv->context_base + chan->chid, ++fctx->sequence);
|
|
|
+ &fctx->lock, fctx->context, ++fctx->sequence);
|
|
|
else
|
|
|
fence_init(&fence->base, &nouveau_fence_ops_legacy,
|
|
|
- &fctx->lock,
|
|
|
- priv->context_base + chan->chid, ++fctx->sequence);
|
|
|
+ &fctx->lock, fctx->context, ++fctx->sequence);
|
|
|
+ kref_get(&fctx->fence_ref);
|
|
|
|
|
|
trace_fence_emit(&fence->base);
|
|
|
ret = fctx->emit(fence);
|
|
@@ -342,7 +366,7 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
|
|
|
}
|
|
|
|
|
|
int
|
|
|
-nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool exclusive)
|
|
|
+nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool exclusive, bool intr)
|
|
|
{
|
|
|
struct nouveau_fence_chan *fctx = chan->fence;
|
|
|
struct fence *fence;
|
|
@@ -369,7 +393,7 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
|
|
|
prev = f->channel;
|
|
|
|
|
|
if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
|
|
|
- ret = fence_wait(fence, true);
|
|
|
+ ret = fence_wait(fence, intr);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -387,8 +411,8 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
|
|
|
if (f)
|
|
|
prev = f->channel;
|
|
|
|
|
|
- if (!prev || (ret = fctx->sync(f, prev, chan)))
|
|
|
- ret = fence_wait(fence, true);
|
|
|
+ if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
|
|
|
+ ret = fence_wait(fence, intr);
|
|
|
|
|
|
if (ret)
|
|
|
break;
|
|
@@ -482,13 +506,22 @@ static bool nouveau_fence_no_signaling(struct fence *f)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static void nouveau_fence_release(struct fence *f)
|
|
|
+{
|
|
|
+ struct nouveau_fence *fence = from_fence(f);
|
|
|
+ struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
|
|
|
+
|
|
|
+ kref_put(&fctx->fence_ref, nouveau_fence_context_put);
|
|
|
+ fence_free(&fence->base);
|
|
|
+}
|
|
|
+
|
|
|
static const struct fence_ops nouveau_fence_ops_legacy = {
|
|
|
.get_driver_name = nouveau_fence_get_get_driver_name,
|
|
|
.get_timeline_name = nouveau_fence_get_timeline_name,
|
|
|
.enable_signaling = nouveau_fence_no_signaling,
|
|
|
.signaled = nouveau_fence_is_signaled,
|
|
|
.wait = nouveau_fence_wait_legacy,
|
|
|
- .release = NULL
|
|
|
+ .release = nouveau_fence_release
|
|
|
};
|
|
|
|
|
|
static bool nouveau_fence_enable_signaling(struct fence *f)
|