]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
drm/nouveau: protect gpuobj list + global instmem heap with spinlock
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Sep 2010 05:24:38 +0000 (15:24 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 24 Sep 2010 06:23:41 +0000 (16:23 +1000)
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_object.c

index 8ee854a4b3f5bdfe60db7907027fd0c67b96dfd9..0844f27651c0370754f56bfad88fd6a993a6cb6b 100644 (file)
@@ -514,11 +514,13 @@ struct drm_nouveau_private {
 
        void __iomem *mmio;
 
+       spinlock_t ramin_lock;
        void __iomem *ramin;
        u32 ramin_size;
        u32 ramin_base;
        bool ramin_available;
-       spinlock_t ramin_lock;
+       struct drm_mm ramin_heap;
+       struct list_head gpuobj_list;
 
        struct nouveau_bo *vga_ram;
 
@@ -592,10 +594,6 @@ struct drm_nouveau_private {
        struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
        int vm_vram_pt_nr;
 
-       struct drm_mm ramin_heap;
-
-       struct list_head gpuobj_list;
-
        struct nvbios vbios;
 
        struct nv04_mode_state mode_reg;
index 02a0151b073855a91c883928b642707e99890d9d..37615a447a4a7918e8ddbe06a7c113cf8c5b6663 100644 (file)
@@ -93,7 +93,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        kref_init(&gpuobj->refcount);
        gpuobj->size = size;
 
+       spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+       spin_unlock(&dev_priv->ramin_lock);
 
        if (chan) {
                NV_DEBUG(dev, "channel heap\n");
@@ -117,9 +119,22 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
                }
 
                /* try and get aperture space */
-               ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0);
-               if (ramin)
-                       ramin = drm_mm_get_block(ramin, size, align);
+               do {
+                       if (drm_mm_pre_get(&dev_priv->ramin_heap))
+                               return -ENOMEM;
+
+                       spin_lock(&dev_priv->ramin_lock);
+                       ramin = drm_mm_search_free(&dev_priv->ramin_heap, size,
+                                                  align, 0);
+                       if (ramin == NULL) {
+                               spin_unlock(&dev_priv->ramin_lock);
+                               nouveau_gpuobj_ref(NULL, &gpuobj);
+                               return ret;
+                       }
+
+                       ramin = drm_mm_get_block_atomic(ramin, size, align);
+                       spin_unlock(&dev_priv->ramin_lock);
+               } while (ramin == NULL);
 
                /* on nv50 it's ok to fail, we have a fallback path */
                if (!ramin && dev_priv->card_type < NV_50) {
@@ -226,10 +241,11 @@ nouveau_gpuobj_del(struct kref *ref)
        if (gpuobj->im_backing)
                engine->instmem.clear(dev, gpuobj);
 
+       spin_lock(&dev_priv->ramin_lock);
        if (gpuobj->im_pramin)
                drm_mm_put_block(gpuobj->im_pramin);
-
        list_del(&gpuobj->list);
+       spin_unlock(&dev_priv->ramin_lock);
 
        kfree(gpuobj);
 }
@@ -276,7 +292,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
                dev_priv->engine.instmem.flush(dev);
        }
 
+       spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+       spin_unlock(&dev_priv->ramin_lock);
        *pgpuobj = gpuobj;
        return 0;
 }
@@ -553,7 +571,9 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
        kref_init(&gpuobj->refcount);
        gpuobj->cinst = 0x40;
 
+       spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+       spin_unlock(&dev_priv->ramin_lock);
        *gpuobj_ret = gpuobj;
        return 0;
 }