]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/drm_gem.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[karo-tx-linux.git] / drivers / gpu / drm / drm_gem.c
index 8bf3770f294e12feb562d046a5de4ed281b9ce45..aa89d4b0b4c44e87e2726c8945895e96280dc7bb 100644 (file)
@@ -192,9 +192,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
        idr_remove(&filp->object_idr, handle);
        spin_unlock(&filp->table_lock);
 
-       mutex_lock(&dev->struct_mutex);
-       drm_gem_object_handle_unreference(obj);
-       mutex_unlock(&dev->struct_mutex);
+       drm_gem_object_handle_unreference_unlocked(obj);
 
        return 0;
 }
@@ -325,9 +323,7 @@ again:
        }
 
 err:
-       mutex_lock(&dev->struct_mutex);
-       drm_gem_object_unreference(obj);
-       mutex_unlock(&dev->struct_mutex);
+       drm_gem_object_unreference_unlocked(obj);
        return ret;
 }
 
@@ -358,9 +354,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
 
        ret = drm_gem_handle_create(file_priv, obj, &handle);
-       mutex_lock(&dev->struct_mutex);
-       drm_gem_object_unreference(obj);
-       mutex_unlock(&dev->struct_mutex);
+       drm_gem_object_unreference_unlocked(obj);
        if (ret)
                return ret;
 
@@ -390,7 +384,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
 {
        struct drm_gem_object *obj = ptr;
 
-       drm_gem_object_handle_unreference(obj);
+       drm_gem_object_handle_unreference_unlocked(obj);
 
        return 0;
 }
@@ -403,16 +397,25 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
 void
 drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
 {
-       mutex_lock(&dev->struct_mutex);
        idr_for_each(&file_private->object_idr,
                     &drm_gem_object_release_handle, NULL);
 
        idr_destroy(&file_private->object_idr);
-       mutex_unlock(&dev->struct_mutex);
+}
+
+static void
+drm_gem_object_free_common(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       fput(obj->filp);
+       atomic_dec(&dev->object_count);
+       atomic_sub(obj->size, &dev->object_memory);
+       kfree(obj);
 }
 
 /**
  * Called after the last reference to the object has been lost.
+ * Must be called holding struct_ mutex
  *
  * Frees the object
  */
@@ -427,13 +430,39 @@ drm_gem_object_free(struct kref *kref)
        if (dev->driver->gem_free_object != NULL)
                dev->driver->gem_free_object(obj);
 
-       fput(obj->filp);
-       atomic_dec(&dev->object_count);
-       atomic_sub(obj->size, &dev->object_memory);
-       kfree(obj);
+       drm_gem_object_free_common(obj);
 }
 EXPORT_SYMBOL(drm_gem_object_free);
 
+/**
+ * Called after the last reference to the object has been lost.
+ * Must be called without holding struct_mutex
+ *
+ * Frees the object
+ */
+void
+drm_gem_object_free_unlocked(struct kref *kref)
+{
+       struct drm_gem_object *obj = (struct drm_gem_object *) kref;
+       struct drm_device *dev = obj->dev;
+
+       if (dev->driver->gem_free_object_unlocked != NULL)
+               dev->driver->gem_free_object_unlocked(obj);
+       else if (dev->driver->gem_free_object != NULL) {
+               mutex_lock(&dev->struct_mutex);
+               dev->driver->gem_free_object(obj);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       drm_gem_object_free_common(obj);
+}
+EXPORT_SYMBOL(drm_gem_object_free_unlocked);
+
+static void drm_gem_object_ref_bug(struct kref *list_kref)
+{
+       BUG();
+}
+
 /**
  * Called after the last handle to the object has been closed
  *
@@ -458,8 +487,10 @@ drm_gem_object_handle_free(struct kref *kref)
                /*
                 * The object name held a reference to this object, drop
                 * that now.
+               *
+               * This cannot be the last reference, since the handle holds one too.
                 */
-               drm_gem_object_unreference(obj);
+               kref_put(&obj->refcount, drm_gem_object_ref_bug);
        } else
                spin_unlock(&dev->object_name_lock);
 
@@ -477,11 +508,8 @@ EXPORT_SYMBOL(drm_gem_vm_open);
 void drm_gem_vm_close(struct vm_area_struct *vma)
 {
        struct drm_gem_object *obj = vma->vm_private_data;
-       struct drm_device *dev = obj->dev;
 
-       mutex_lock(&dev->struct_mutex);
-       drm_gem_object_unreference(obj);
-       mutex_unlock(&dev->struct_mutex);
+       drm_gem_object_unreference_unlocked(obj);
 }
 EXPORT_SYMBOL(drm_gem_vm_close);