drm/nouveau: split ramin_lock into two locks, one hardirq safe
authorBen Skeggs <bskeggs@redhat.com>
Wed, 6 Apr 2011 03:28:35 +0000 (13:28 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 19 Apr 2011 22:50:14 +0000 (08:50 +1000)
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>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nvc0_vm.c

index 856d56a..a76514a 100644 (file)
@@ -682,6 +682,9 @@ struct drm_nouveau_private {
        /* For PFIFO and PGRAPH. */
        spinlock_t context_switch_lock;
 
+       /* VM/PRAMIN flush, legacy PRAMIN aperture */
+       spinlock_t vm_lock;
+
        /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
        struct nouveau_ramht  *ramht;
        struct nouveau_gpuobj *ramfc;
index 4f00c87..67a16e0 100644 (file)
@@ -1039,19 +1039,20 @@ nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
 {
        struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
        struct drm_device *dev = gpuobj->dev;
+       unsigned long flags;
 
        if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
                u64  ptr = gpuobj->vinst + offset;
                u32 base = ptr >> 16;
                u32  val;
 
-               spin_lock(&dev_priv->ramin_lock);
+               spin_lock_irqsave(&dev_priv->vm_lock, flags);
                if (dev_priv->ramin_base != base) {
                        dev_priv->ramin_base = base;
                        nv_wr32(dev, 0x001700, dev_priv->ramin_base);
                }
                val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
-               spin_unlock(&dev_priv->ramin_lock);
+               spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
                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_device *dev = gpuobj->dev;
+       unsigned long flags;
 
        if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
                u64  ptr = gpuobj->vinst + offset;
                u32 base = ptr >> 16;
 
-               spin_lock(&dev_priv->ramin_lock);
+               spin_lock_irqsave(&dev_priv->vm_lock, flags);
                if (dev_priv->ramin_base != base) {
                        dev_priv->ramin_base = base;
                        nv_wr32(dev, 0x001700, dev_priv->ramin_base);
                }
                nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
-               spin_unlock(&dev_priv->ramin_lock);
+               spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
                return;
        }
 
index 6e2b1a6..a30adec 100644 (file)
@@ -608,6 +608,7 @@ nouveau_card_init(struct drm_device *dev)
        spin_lock_init(&dev_priv->channels.lock);
        spin_lock_init(&dev_priv->tile.lock);
        spin_lock_init(&dev_priv->context_switch_lock);
+       spin_lock_init(&dev_priv->vm_lock);
 
        /* Make the CRTCs and I2C buses accessible */
        ret = engine->display.early_init(dev);
index a6f8aa6..4f95a1e 100644 (file)
@@ -404,23 +404,25 @@ void
 nv50_instmem_flush(struct drm_device *dev)
 {
        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);
        if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 
 void
 nv84_instmem_flush(struct drm_device *dev)
 {
        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);
        if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
 
index 4fd3432..6c26944 100644 (file)
@@ -174,10 +174,11 @@ void
 nv50_vm_flush_engine(struct drm_device *dev, int engine)
 {
        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);
        if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
                NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }
index a0a2a02..a179e6c 100644 (file)
@@ -104,11 +104,12 @@ nvc0_vm_flush(struct nouveau_vm *vm)
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
        struct drm_device *dev = vm->dev;
        struct nouveau_vm_pgd *vpgd;
+       unsigned long flags;
        u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5;
 
        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) {
                /* looks like maybe a "free flush slots" counter, the
                 * 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);
                }
        }
-       spin_unlock(&dev_priv->ramin_lock);
+       spin_unlock_irqrestore(&dev_priv->vm_lock, flags);
 }