Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff9e5279 authored by Maarten Maathuis's avatar Maarten Maathuis Committed by Ben Skeggs
Browse files

drm/nouveau: protect channel create/destroy and irq handler with a spinlock



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: default avatarMaarten Maathuis <madman2003@gmail.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 6c429667
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -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);
@@ -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) {
+3 −0
Original line number Diff line number Diff line
@@ -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;
+5 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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 −0
Original line number Diff line number Diff line
@@ -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)) {
+5 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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);
@@ -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;
}

Loading