]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/gpu/drm/nouveau/nouveau_object.c
Merge branch 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ickle...
[linux-beck.git] / drivers / gpu / drm / nouveau / nouveau_object.c
index b68922f2fe544b18d6de24df7003c5e014a99d7f..dd572adca02ad0232df35715257ccc597adf86f3 100644 (file)
@@ -90,10 +90,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
        gpuobj->dev = dev;
        gpuobj->flags = flags;
-       gpuobj->refcount = 1;
+       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 -ENOMEM;
+                       }
+
+                       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) {
@@ -193,32 +208,15 @@ nouveau_gpuobj_takedown(struct drm_device *dev)
 
        NV_DEBUG(dev, "\n");
 
-       nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
+       BUG_ON(!list_empty(&dev_priv->gpuobj_list));
 }
 
-void
-nouveau_gpuobj_late_takedown(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *gpuobj = NULL;
-       struct list_head *entry, *tmp;
-
-       NV_DEBUG(dev, "\n");
-
-       list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
-               gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
-
-               NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
-                        gpuobj, gpuobj->refcount);
 
-               gpuobj->refcount = 1;
-               nouveau_gpuobj_ref(NULL, &gpuobj);
-       }
-}
-
-static int
-nouveau_gpuobj_del(struct nouveau_gpuobj *gpuobj)
+static void
+nouveau_gpuobj_del(struct kref *ref)
 {
+       struct nouveau_gpuobj *gpuobj =
+               container_of(ref, struct nouveau_gpuobj, refcount);
        struct drm_device *dev = gpuobj->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
@@ -238,23 +236,23 @@ nouveau_gpuobj_del(struct nouveau_gpuobj *gpuobj)
        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);
-       return 0;
 }
 
 void
 nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr)
 {
        if (ref)
-               ref->refcount++;
+               kref_get(&ref->refcount);
 
-       if (*ptr && --(*ptr)->refcount == 0)
-               nouveau_gpuobj_del(*ptr);
+       if (*ptr)
+               kref_put(&(*ptr)->refcount, nouveau_gpuobj_del);
 
        *ptr = ref;
 }
@@ -277,7 +275,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
        NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
        gpuobj->dev = dev;
        gpuobj->flags = flags;
-       gpuobj->refcount = 1;
+       kref_init(&gpuobj->refcount);
        gpuobj->size  = size;
        gpuobj->pinst = pinst;
        gpuobj->cinst = 0xdeadbeef;
@@ -289,7 +287,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;
 }
@@ -563,10 +563,12 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
        gpuobj->dev = chan->dev;
        gpuobj->engine = NVOBJ_ENGINE_SW;
        gpuobj->class = class;
-       gpuobj->refcount = 1;
+       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;
 }