Skip to content

Commit

Permalink
Merge branch 'linux-3.18' of git://anongit.freedesktop.org/git/nouvea…
Browse files Browse the repository at this point in the history
…u/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
  • Loading branch information
airlied committed Dec 2, 2014
2 parents 009d043 + 226d63a commit d87c0e3
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 34 deletions.
1 change: 0 additions & 1 deletion drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_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_PERFMON] = &nvc0_perfmon_oclass;
break;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
}

if (status & 0x40000000) {
nouveau_fifo_uevent(&priv->base);
nv_wr32(priv, 0x002100, 0x40000000);
nouveau_fifo_uevent(&priv->base);
status &= ~0x40000000;
}
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,8 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
u32 inte = nv_rd32(priv, 0x002628);
u32 unkn;

nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);

for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) {
Expand All @@ -751,8 +753,6 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
nv_mask(priv, 0x002628, ints, 0);
}
}

nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
}

static void
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,8 +952,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
}

if (stat & 0x80000000) {
nve0_fifo_intr_engine(priv);
nv_wr32(priv, 0x002100, 0x80000000);
nve0_fifo_intr_engine(priv);
stat &= ~0x80000000;
}

Expand Down
92 changes: 65 additions & 27 deletions drivers/gpu/drm/nouveau/nouveau_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,24 @@ nouveau_fctx(struct nouveau_fence *fence)
return container_of(fence->base.lock, struct nouveau_fence_chan, lock);
}

static void
static int
nouveau_fence_signal(struct nouveau_fence *fence)
{
int drop = 0;

fence_signal_locked(&fence->base);
list_del(&fence->head);
rcu_assign_pointer(fence->channel, NULL);

if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) {
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);

if (!--fctx->notify_ref)
nvif_notify_put(&fctx->notify);
drop = 1;
}

fence_put(&fence->base);
return drop;
}

static struct nouveau_fence *
Expand All @@ -88,16 +92,23 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
struct nouveau_fence *fence;

nvif_notify_fini(&fctx->notify);

spin_lock_irq(&fctx->lock);
while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head);

nouveau_fence_signal(fence);
fence->channel = NULL;
if (nouveau_fence_signal(fence))
nvif_notify_put(&fctx->notify);
}
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
Expand All @@ -112,21 +123,23 @@ nouveau_fence_context_free(struct nouveau_fence_chan *fctx)
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)
{
struct nouveau_fence *fence;

int drop = 0;
u32 seq = fctx->read(chan);

while (!list_empty(&fctx->pending)) {
fence = list_entry(fctx->pending.next, typeof(*fence), head);

if ((int)(seq - fence->base.seqno) < 0)
return;
break;

nouveau_fence_signal(fence);
drop |= nouveau_fence_signal(fence);
}

return drop;
}

static int
Expand All @@ -135,18 +148,21 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
struct nouveau_fence_chan *fctx =
container_of(notify, typeof(*fctx), notify);
unsigned long flags;
int ret = NVIF_NOTIFY_KEEP;

spin_lock_irqsave(&fctx->lock, flags);
if (!list_empty(&fctx->pending)) {
struct nouveau_fence *fence;
struct nouveau_channel *chan;

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);

/* Always return keep here. NVIF refcount is handled with nouveau_fence_update */
return NVIF_NOTIFY_KEEP;
return ret;
}

void
Expand Down Expand Up @@ -262,7 +278,10 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
if (!ret) {
fence_get(&fence->base);
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);
spin_unlock_irq(&fctx->lock);
}
Expand All @@ -276,13 +295,16 @@ nouveau_fence_done(struct nouveau_fence *fence)
if (fence->base.ops == &nouveau_fence_ops_legacy ||
fence->base.ops == &nouveau_fence_ops_uevent) {
struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
struct nouveau_channel *chan;
unsigned long flags;

if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
return true;

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);
}
return fence_is_signaled(&fence->base);
Expand Down Expand Up @@ -387,12 +409,18 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e

if (fence && (!exclusive || !fobj || !fobj->shared_count)) {
struct nouveau_channel *prev = NULL;
bool must_wait = true;

f = nouveau_local_fence(fence, chan->drm);
if (f)
prev = f->channel;
if (f) {
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);

return ret;
Expand All @@ -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) {
struct nouveau_channel *prev = NULL;
bool must_wait = true;

fence = rcu_dereference_protected(fobj->shared[i],
reservation_object_held(resv));

f = nouveau_local_fence(fence, chan->drm);
if (f)
prev = f->channel;
if (f) {
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);

if (ret)
break;
}

return ret;
Expand Down Expand Up @@ -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_chan *fctx = nouveau_fctx(fence);

return fence->channel ? fctx->name : "dead channel";
return !fctx->dead ? fctx->name : "dead channel";
}

/*
Expand All @@ -476,9 +507,16 @@ static bool nouveau_fence_is_signaled(struct fence *f)
{
struct nouveau_fence *fence = from_fence(f);
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)
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/nouveau/nouveau_fence.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct nouveau_fence {

bool sysmem;

struct nouveau_channel *channel;
struct nouveau_channel __rcu *channel;
unsigned long timeout;
};

Expand Down Expand Up @@ -47,7 +47,7 @@ struct nouveau_fence_chan {
char name[32];

struct nvif_notify notify;
int notify_ref;
int notify_ref, dead;
};

struct nouveau_fence_priv {
Expand Down

0 comments on commit d87c0e3

Please sign in to comment.