瀏覽代碼

drm/nouveau: split ramin_lock into two locks, one hardirq safe

Fixes a possible lock ordering reversal between context_switch_lock
and ramin_lock.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Ben Skeggs 14 年之前
父節點
當前提交
04eb34a43c

+ 3 - 0
drivers/gpu/drm/nouveau/nouveau_drv.h

@@ -682,6 +682,9 @@ struct drm_nouveau_private {
 	/* For PFIFO and PGRAPH. */
 	/* For PFIFO and PGRAPH. */
 	spinlock_t context_switch_lock;
 	spinlock_t context_switch_lock;
 
 
+	/* VM/PRAMIN flush, legacy PRAMIN aperture */
+	spinlock_t vm_lock;
+
 	/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
 	/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
 	struct nouveau_ramht  *ramht;
 	struct nouveau_ramht  *ramht;
 	struct nouveau_gpuobj *ramfc;
 	struct nouveau_gpuobj *ramfc;

+ 6 - 4
drivers/gpu/drm/nouveau/nouveau_object.c

@@ -1039,19 +1039,20 @@ nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
 {
 {
 	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
 	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
 	struct drm_device *dev = gpuobj->dev;
 	struct drm_device *dev = gpuobj->dev;
+	unsigned long flags;
 
 
 	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
 	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
 		u64  ptr = gpuobj->vinst + offset;
 		u64  ptr = gpuobj->vinst + offset;
 		u32 base = ptr >> 16;
 		u32 base = ptr >> 16;
 		u32  val;
 		u32  val;
 
 
-		spin_lock(&dev_priv->ramin_lock);
+		spin_lock_irqsave(&dev_priv->vm_lock, flags);
 		if (dev_priv->ramin_base != base) {
 		if (dev_priv->ramin_base != base) {
 			dev_priv->ramin_base = base;
 			dev_priv->ramin_base = base;
 			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
 			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
 		}
 		}
 		val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
 		val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
-		spin_unlock(&dev_priv->ramin_lock);
+		spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 		return val;
 		return val;
 	}
 	}
 
 
@@ -1063,18 +1064,19 @@ nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
 {
 {
 	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
 	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
 	struct drm_device *dev = gpuobj->dev;
 	struct drm_device *dev = gpuobj->dev;
+	unsigned long flags;
 
 
 	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
 	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
 		u64  ptr = gpuobj->vinst + offset;
 		u64  ptr = gpuobj->vinst + offset;
 		u32 base = ptr >> 16;
 		u32 base = ptr >> 16;
 
 
-		spin_lock(&dev_priv->ramin_lock);
+		spin_lock_irqsave(&dev_priv->vm_lock, flags);
 		if (dev_priv->ramin_base != base) {
 		if (dev_priv->ramin_base != base) {
 			dev_priv->ramin_base = base;
 			dev_priv->ramin_base = base;
 			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
 			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
 		}
 		}
 		nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
 		nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
-		spin_unlock(&dev_priv->ramin_lock);
+		spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 		return;
 		return;
 	}
 	}
 
 

+ 1 - 0
drivers/gpu/drm/nouveau/nouveau_state.c

@@ -608,6 +608,7 @@ nouveau_card_init(struct drm_device *dev)
 	spin_lock_init(&dev_priv->channels.lock);
 	spin_lock_init(&dev_priv->channels.lock);
 	spin_lock_init(&dev_priv->tile.lock);
 	spin_lock_init(&dev_priv->tile.lock);
 	spin_lock_init(&dev_priv->context_switch_lock);
 	spin_lock_init(&dev_priv->context_switch_lock);
+	spin_lock_init(&dev_priv->vm_lock);
 
 
 	/* Make the CRTCs and I2C buses accessible */
 	/* Make the CRTCs and I2C buses accessible */
 	ret = engine->display.early_init(dev);
 	ret = engine->display.early_init(dev);

+ 6 - 4
drivers/gpu/drm/nouveau/nv50_instmem.c

@@ -404,23 +404,25 @@ void
 nv50_instmem_flush(struct drm_device *dev)
 nv50_instmem_flush(struct drm_device *dev)
 {
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	unsigned long flags;
 
 
-	spin_lock(&dev_priv->ramin_lock);
+	spin_lock_irqsave(&dev_priv->vm_lock, flags);
 	nv_wr32(dev, 0x00330c, 0x00000001);
 	nv_wr32(dev, 0x00330c, 0x00000001);
 	if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
 	if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
-	spin_unlock(&dev_priv->ramin_lock);
+	spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 }
 
 
 void
 void
 nv84_instmem_flush(struct drm_device *dev)
 nv84_instmem_flush(struct drm_device *dev)
 {
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	unsigned long flags;
 
 
-	spin_lock(&dev_priv->ramin_lock);
+	spin_lock_irqsave(&dev_priv->vm_lock, flags);
 	nv_wr32(dev, 0x070000, 0x00000001);
 	nv_wr32(dev, 0x070000, 0x00000001);
 	if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
 	if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
-	spin_unlock(&dev_priv->ramin_lock);
+	spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 }
 
 

+ 3 - 2
drivers/gpu/drm/nouveau/nv50_vm.c

@@ -174,10 +174,11 @@ void
 nv50_vm_flush_engine(struct drm_device *dev, int engine)
 nv50_vm_flush_engine(struct drm_device *dev, int engine)
 {
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	unsigned long flags;
 
 
-	spin_lock(&dev_priv->ramin_lock);
+	spin_lock_irqsave(&dev_priv->vm_lock, flags);
 	nv_wr32(dev, 0x100c80, (engine << 16) | 1);
 	nv_wr32(dev, 0x100c80, (engine << 16) | 1);
 	if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
 	if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
 		NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
 		NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
-	spin_unlock(&dev_priv->ramin_lock);
+	spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 }

+ 3 - 2
drivers/gpu/drm/nouveau/nvc0_vm.c

@@ -104,11 +104,12 @@ nvc0_vm_flush(struct nouveau_vm *vm)
 	struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
 	struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
 	struct drm_device *dev = vm->dev;
 	struct drm_device *dev = vm->dev;
 	struct nouveau_vm_pgd *vpgd;
 	struct nouveau_vm_pgd *vpgd;
+	unsigned long flags;
 	u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5;
 	u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5;
 
 
 	pinstmem->flush(vm->dev);
 	pinstmem->flush(vm->dev);
 
 
-	spin_lock(&dev_priv->ramin_lock);
+	spin_lock_irqsave(&dev_priv->vm_lock, flags);
 	list_for_each_entry(vpgd, &vm->pgd_list, head) {
 	list_for_each_entry(vpgd, &vm->pgd_list, head) {
 		/* looks like maybe a "free flush slots" counter, the
 		/* looks like maybe a "free flush slots" counter, the
 		 * faster you write to 0x100cbc to more it decreases
 		 * faster you write to 0x100cbc to more it decreases
@@ -125,5 +126,5 @@ nvc0_vm_flush(struct nouveau_vm *vm)
 				 nv_rd32(dev, 0x100c80), engine);
 				 nv_rd32(dev, 0x100c80), engine);
 		}
 		}
 	}
 	}
-	spin_unlock(&dev_priv->ramin_lock);
+	spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 }