Skip to content

Commit

Permalink
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
Browse files Browse the repository at this point in the history
Pull drm fixes from Dave Airlie:
 "Radeon and Nouveau fixes:

  So nouveau had a few regression introduced, Ben and Maarten finally
  tracked down the one that was causing problems on my MacBookPro, also
  nvidia gave some info on the an engine we were using incorrectly, so
  disable our use of it, and one regresion with pci hotplug affecting
  optimus users.

  Radeon has an oops fixs, sync fix, and one workaround to avoid broken
  functionality on 32-bit x86, this needs better root causing and a
  better fix, but the bandaid is a lot safer at this point"

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux:
  drm/radeon: kernel panic in drm_calc_vbltimestamp_from_scanoutpos with 3.18.0-rc6
  drm/radeon: Ignore RADEON_GEM_GTT_WC on 32-bit x86
  drm/radeon: sync all BOs involved in a CS v2
  nouveau: move the hotplug ignore to correct place.
  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
Linus Torvalds committed Dec 3, 2014
2 parents 9044f94 + 00d6a9b commit 46d967a
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 45 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
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/nouveau_drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,6 @@ int nouveau_pmops_suspend(struct device *dev)

pci_save_state(pdev);
pci_disable_device(pdev);
pci_ignore_hotplug(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
Expand Down Expand Up @@ -933,6 +932,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
ret = nouveau_do_suspend(drm_dev, true);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_ignore_hotplug(pdev);
pci_set_power_state(pdev, PCI_D3cold);
drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
return ret;
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
17 changes: 7 additions & 10 deletions drivers/gpu/drm/radeon/radeon_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,22 +251,19 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority

static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
{
int i, r = 0;
struct radeon_cs_reloc *reloc;
int r;

for (i = 0; i < p->nrelocs; i++) {
list_for_each_entry(reloc, &p->validated, tv.head) {
struct reservation_object *resv;

if (!p->relocs[i].robj)
continue;

resv = p->relocs[i].robj->tbo.resv;
resv = reloc->robj->tbo.resv;
r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv,
p->relocs[i].tv.shared);

reloc->tv.shared);
if (r)
break;
return r;
}
return r;
return 0;
}

/* XXX: note that this is called from the legacy UMS CS ioctl as well */
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/radeon/radeon_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,8 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,

/* Get associated drm_crtc: */
drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
if (!drmcrtc)
return -EINVAL;

/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpu/drm/radeon/radeon_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ int radeon_bo_create(struct radeon_device *rdev,
if (!(rdev->flags & RADEON_IS_PCIE))
bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);

#ifdef CONFIG_X86_32
/* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
* See https://bugs.freedesktop.org/show_bug.cgi?id=84627
*/
bo->flags &= ~RADEON_GEM_GTT_WC;
#endif

radeon_ttm_placement_from_domain(bo, domain);
/* Kernel allocation are uninterruptible */
down_read(&rdev->pm.mclk_lock);
Expand Down

0 comments on commit 46d967a

Please sign in to comment.