Commit d87c0e3d authored by Dave Airlie's avatar Dave Airlie

Merge branch 'linux-3.18' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-fixes

Just a couple of fixes for the fallout from the fence rework.

* 'linux-3.18' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  drm/nouveau/gf116: remove copy1 engine
  drm/nouveau: prevent stale fence->channel pointers, and protect with rcu
  drm/nouveau/fifo/g84-: ack non-stall interrupt before handling it
parents 009d0431 226d63a1
...@@ -218,7 +218,6 @@ nvc0_identify(struct nouveau_device *device) ...@@ -218,7 +218,6 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
break; break;
......
...@@ -551,8 +551,8 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) ...@@ -551,8 +551,8 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
} }
if (status & 0x40000000) { if (status & 0x40000000) {
nouveau_fifo_uevent(&priv->base);
nv_wr32(priv, 0x002100, 0x40000000); nv_wr32(priv, 0x002100, 0x40000000);
nouveau_fifo_uevent(&priv->base);
status &= ~0x40000000; status &= ~0x40000000;
} }
} }
......
...@@ -740,6 +740,8 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) ...@@ -740,6 +740,8 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
u32 inte = nv_rd32(priv, 0x002628); u32 inte = nv_rd32(priv, 0x002628);
u32 unkn; u32 unkn;
nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
for (unkn = 0; unkn < 8; unkn++) { for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte; u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) { if (ints & 0x1) {
...@@ -751,8 +753,6 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) ...@@ -751,8 +753,6 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
nv_mask(priv, 0x002628, ints, 0); nv_mask(priv, 0x002628, ints, 0);
} }
} }
nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
} }
static void static void
......
...@@ -952,8 +952,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) ...@@ -952,8 +952,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
} }
if (stat & 0x80000000) { if (stat & 0x80000000) {
nve0_fifo_intr_engine(priv);
nv_wr32(priv, 0x002100, 0x80000000); nv_wr32(priv, 0x002100, 0x80000000);
nve0_fifo_intr_engine(priv);
stat &= ~0x80000000; stat &= ~0x80000000;
} }
......
...@@ -52,20 +52,24 @@ nouveau_fctx(struct nouveau_fence *fence) ...@@ -52,20 +52,24 @@ nouveau_fctx(struct nouveau_fence *fence)
return container_of(fence->base.lock, struct nouveau_fence_chan, lock); return container_of(fence->base.lock, struct nouveau_fence_chan, lock);
} }
static void static int
nouveau_fence_signal(struct nouveau_fence *fence) nouveau_fence_signal(struct nouveau_fence *fence)
{ {
int drop = 0;
fence_signal_locked(&fence->base); fence_signal_locked(&fence->base);
list_del(&fence->head); list_del(&fence->head);
rcu_assign_pointer(fence->channel, NULL);
if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) { if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) {
struct nouveau_fence_chan *fctx = nouveau_fctx(fence); struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
if (!--fctx->notify_ref) if (!--fctx->notify_ref)
nvif_notify_put(&fctx->notify); drop = 1;
} }
fence_put(&fence->base); fence_put(&fence->base);
return drop;
} }
static struct nouveau_fence * static struct nouveau_fence *
...@@ -88,16 +92,23 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx) ...@@ -88,16 +92,23 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{ {
struct nouveau_fence *fence; struct nouveau_fence *fence;
nvif_notify_fini(&fctx->notify);
spin_lock_irq(&fctx->lock); spin_lock_irq(&fctx->lock);
while (!list_empty(&fctx->pending)) { while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head); fence = list_entry(fctx->pending.next, typeof(*fence), head);
nouveau_fence_signal(fence); if (nouveau_fence_signal(fence))
fence->channel = NULL; nvif_notify_put(&fctx->notify);
} }
spin_unlock_irq(&fctx->lock); spin_unlock_irq(&fctx->lock);
nvif_notify_fini(&fctx->notify);
fctx->dead = 1;
/*
* Ensure that all accesses to fence->channel complete before freeing
* the channel.
*/
synchronize_rcu();
} }
static void static void
...@@ -112,21 +123,23 @@ nouveau_fence_context_free(struct nouveau_fence_chan *fctx) ...@@ -112,21 +123,23 @@ nouveau_fence_context_free(struct nouveau_fence_chan *fctx)
kref_put(&fctx->fence_ref, nouveau_fence_context_put); kref_put(&fctx->fence_ref, nouveau_fence_context_put);
} }
static void static int
nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
{ {
struct nouveau_fence *fence; struct nouveau_fence *fence;
int drop = 0;
u32 seq = fctx->read(chan); u32 seq = fctx->read(chan);
while (!list_empty(&fctx->pending)) { while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head); fence = list_entry(fctx->pending.next, typeof(*fence), head);
if ((int)(seq - fence->base.seqno) < 0) if ((int)(seq - fence->base.seqno) < 0)
return; break;
nouveau_fence_signal(fence); drop |= nouveau_fence_signal(fence);
} }
return drop;
} }
static int static int
...@@ -135,18 +148,21 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) ...@@ -135,18 +148,21 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
struct nouveau_fence_chan *fctx = struct nouveau_fence_chan *fctx =
container_of(notify, typeof(*fctx), notify); container_of(notify, typeof(*fctx), notify);
unsigned long flags; unsigned long flags;
int ret = NVIF_NOTIFY_KEEP;
spin_lock_irqsave(&fctx->lock, flags); spin_lock_irqsave(&fctx->lock, flags);
if (!list_empty(&fctx->pending)) { if (!list_empty(&fctx->pending)) {
struct nouveau_fence *fence; struct nouveau_fence *fence;
struct nouveau_channel *chan;
fence = list_entry(fctx->pending.next, typeof(*fence), head); fence = list_entry(fctx->pending.next, typeof(*fence), head);
nouveau_fence_update(fence->channel, fctx); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
if (nouveau_fence_update(fence->channel, fctx))
ret = NVIF_NOTIFY_DROP;
} }
spin_unlock_irqrestore(&fctx->lock, flags); spin_unlock_irqrestore(&fctx->lock, flags);
/* Always return keep here. NVIF refcount is handled with nouveau_fence_update */ return ret;
return NVIF_NOTIFY_KEEP;
} }
void void
...@@ -262,7 +278,10 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) ...@@ -262,7 +278,10 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
if (!ret) { if (!ret) {
fence_get(&fence->base); fence_get(&fence->base);
spin_lock_irq(&fctx->lock); spin_lock_irq(&fctx->lock);
nouveau_fence_update(chan, fctx);
if (nouveau_fence_update(chan, fctx))
nvif_notify_put(&fctx->notify);
list_add_tail(&fence->head, &fctx->pending); list_add_tail(&fence->head, &fctx->pending);
spin_unlock_irq(&fctx->lock); spin_unlock_irq(&fctx->lock);
} }
...@@ -276,13 +295,16 @@ nouveau_fence_done(struct nouveau_fence *fence) ...@@ -276,13 +295,16 @@ nouveau_fence_done(struct nouveau_fence *fence)
if (fence->base.ops == &nouveau_fence_ops_legacy || if (fence->base.ops == &nouveau_fence_ops_legacy ||
fence->base.ops == &nouveau_fence_ops_uevent) { fence->base.ops == &nouveau_fence_ops_uevent) {
struct nouveau_fence_chan *fctx = nouveau_fctx(fence); struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
struct nouveau_channel *chan;
unsigned long flags; unsigned long flags;
if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
return true; return true;
spin_lock_irqsave(&fctx->lock, flags); spin_lock_irqsave(&fctx->lock, flags);
nouveau_fence_update(fence->channel, fctx); chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
if (chan && nouveau_fence_update(chan, fctx))
nvif_notify_put(&fctx->notify);
spin_unlock_irqrestore(&fctx->lock, flags); spin_unlock_irqrestore(&fctx->lock, flags);
} }
return fence_is_signaled(&fence->base); return fence_is_signaled(&fence->base);
...@@ -387,12 +409,18 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e ...@@ -387,12 +409,18 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
if (fence && (!exclusive || !fobj || !fobj->shared_count)) { if (fence && (!exclusive || !fobj || !fobj->shared_count)) {
struct nouveau_channel *prev = NULL; struct nouveau_channel *prev = NULL;
bool must_wait = true;
f = nouveau_local_fence(fence, chan->drm); f = nouveau_local_fence(fence, chan->drm);
if (f) if (f) {
prev = f->channel; rcu_read_lock();
prev = rcu_dereference(f->channel);
if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0))
must_wait = false;
rcu_read_unlock();
}
if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) if (must_wait)
ret = fence_wait(fence, intr); ret = fence_wait(fence, intr);
return ret; return ret;
...@@ -403,19 +431,22 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e ...@@ -403,19 +431,22 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
for (i = 0; i < fobj->shared_count && !ret; ++i) { for (i = 0; i < fobj->shared_count && !ret; ++i) {
struct nouveau_channel *prev = NULL; struct nouveau_channel *prev = NULL;
bool must_wait = true;
fence = rcu_dereference_protected(fobj->shared[i], fence = rcu_dereference_protected(fobj->shared[i],
reservation_object_held(resv)); reservation_object_held(resv));
f = nouveau_local_fence(fence, chan->drm); f = nouveau_local_fence(fence, chan->drm);
if (f) if (f) {
prev = f->channel; rcu_read_lock();
prev = rcu_dereference(f->channel);
if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0))
must_wait = false;
rcu_read_unlock();
}
if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) if (must_wait)
ret = fence_wait(fence, intr); ret = fence_wait(fence, intr);
if (ret)
break;
} }
return ret; return ret;
...@@ -463,7 +494,7 @@ static const char *nouveau_fence_get_timeline_name(struct fence *f) ...@@ -463,7 +494,7 @@ static const char *nouveau_fence_get_timeline_name(struct fence *f)
struct nouveau_fence *fence = from_fence(f); struct nouveau_fence *fence = from_fence(f);
struct nouveau_fence_chan *fctx = nouveau_fctx(fence); struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
return fence->channel ? fctx->name : "dead channel"; return !fctx->dead ? fctx->name : "dead channel";
} }
/* /*
...@@ -476,9 +507,16 @@ static bool nouveau_fence_is_signaled(struct fence *f) ...@@ -476,9 +507,16 @@ static bool nouveau_fence_is_signaled(struct fence *f)
{ {
struct nouveau_fence *fence = from_fence(f); struct nouveau_fence *fence = from_fence(f);
struct nouveau_fence_chan *fctx = nouveau_fctx(fence); struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
struct nouveau_channel *chan = fence->channel; struct nouveau_channel *chan;
bool ret = false;
rcu_read_lock();
chan = rcu_dereference(fence->channel);
if (chan)
ret = (int)(fctx->read(chan) - fence->base.seqno) >= 0;
rcu_read_unlock();
return (int)(fctx->read(chan) - fence->base.seqno) >= 0; return ret;
} }
static bool nouveau_fence_no_signaling(struct fence *f) static bool nouveau_fence_no_signaling(struct fence *f)
......
...@@ -14,7 +14,7 @@ struct nouveau_fence { ...@@ -14,7 +14,7 @@ struct nouveau_fence {
bool sysmem; bool sysmem;
struct nouveau_channel *channel; struct nouveau_channel __rcu *channel;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -47,7 +47,7 @@ struct nouveau_fence_chan { ...@@ -47,7 +47,7 @@ struct nouveau_fence_chan {
char name[32]; char name[32];
struct nvif_notify notify; struct nvif_notify notify;
int notify_ref; int notify_ref, dead;
}; };
struct nouveau_fence_priv { struct nouveau_fence_priv {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment