Skip to content

Commit

Permalink
drm/nouveau: protect channel create/destroy and irq handler with a sp…
Browse files Browse the repository at this point in the history
…inlock

The nv50 pgraph handler (for example) could reenable pgraph fifo access
and that would be bad when pgraph context is being unloaded (we need the
guarantee a ctxprog isn't running).

Signed-off-by: Maarten Maathuis <madman2003@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information
Maarten Maathuis authored and Ben Skeggs committed Feb 25, 2010
1 parent 6c42966 commit ff9e527
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 1 deletion.
13 changes: 12 additions & 1 deletion drivers/gpu/drm/nouveau/nouveau_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,18 @@ nouveau_channel_free(struct nouveau_channel *chan)
*/
nouveau_fence_fini(chan);

/* Ensure the channel is no longer active on the GPU */
/* This will prevent pfifo from switching channels. */
pfifo->reassign(dev, false);

/* We want to give pgraph a chance to idle and get rid of all potential
* errors. We need to do this before the lock, otherwise the irq handler
* is unable to process them.
*/
if (pgraph->channel(dev) == chan)
nouveau_wait_for_idle(dev);

spin_lock_irqsave(&dev_priv->context_switch_lock, flags);

pgraph->fifo_access(dev, false);
if (pgraph->channel(dev) == chan)
pgraph->unload_context(dev);
Expand All @@ -293,6 +302,8 @@ nouveau_channel_free(struct nouveau_channel *chan)

pfifo->reassign(dev, true);

spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);

/* Release the channel's resources */
nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
if (chan->pushbuf_bo) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,9 @@ struct drm_nouveau_private {
struct nouveau_engine engine;
struct nouveau_channel *channel;

/* For PFIFO and PGRAPH. */
spinlock_t context_switch_lock;

/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
struct nouveau_gpuobj *ramht;
uint32_t ramin_rsvd_vram;
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,11 +691,14 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
struct drm_device *dev = (struct drm_device *)arg;
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t status, fbdev_flags = 0;
unsigned long flags;

status = nv_rd32(dev, NV03_PMC_INTR_0);
if (!status)
return IRQ_NONE;

spin_lock_irqsave(&dev_priv->context_switch_lock, flags);

if (dev_priv->fbdev_info) {
fbdev_flags = dev_priv->fbdev_info->flags;
dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
Expand Down Expand Up @@ -733,5 +736,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
if (dev_priv->fbdev_info)
dev_priv->fbdev_info->flags = fbdev_flags;

spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);

return IRQ_HANDLED;
}
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/nouveau_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ nouveau_card_init(struct drm_device *dev)
goto out;
engine = &dev_priv->engine;
dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
spin_lock_init(&dev_priv->context_switch_lock);

/* Parse BIOS tables / Run init tables if card not POSTed */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/nouveau/nv04_fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
unsigned long flags;
int ret;

ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0,
Expand All @@ -127,6 +128,8 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;

spin_lock_irqsave(&dev_priv->context_switch_lock, flags);

/* Setup initial state */
dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
Expand All @@ -144,6 +147,8 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));

spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}

Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/nouveau/nv40_fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV40_RAMFC(chan->id);
unsigned long flags;
int ret;

ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
Expand All @@ -45,6 +46,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
if (ret)
return ret;

spin_lock_irqsave(&dev_priv->context_switch_lock, flags);

dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
Expand All @@ -63,6 +66,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));

spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}

Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/nouveau/nv50_fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramfc = NULL;
unsigned long flags;
int ret;

NV_DEBUG(dev, "ch%d\n", chan->id);
Expand Down Expand Up @@ -278,6 +279,8 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
return ret;
}

spin_lock_irqsave(&dev_priv->context_switch_lock, flags);

dev_priv->engine.instmem.prepare_access(dev, true);

nv_wo32(dev, ramfc, 0x08/4, chan->pushbuf_base);
Expand Down Expand Up @@ -306,10 +309,12 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
ret = nv50_fifo_channel_enable(dev, chan->id, false);
if (ret) {
NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
return ret;
}

spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}

Expand Down

0 comments on commit ff9e527

Please sign in to comment.