drm/doc: Appease sphinx
[cascardo/linux.git] / drivers / gpu / drm / drm_gem.c
index da0c532..5c19dde 100644 (file)
@@ -279,7 +279,6 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
 int
 drm_gem_handle_delete(struct drm_file *filp, u32 handle)
 {
-       struct drm_device *dev;
        struct drm_gem_object *obj;
 
        /* This is gross. The idr system doesn't let us try a delete and
@@ -294,18 +293,19 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
        spin_lock(&filp->table_lock);
 
        /* Check if we currently have a reference on the object */
-       obj = idr_find(&filp->object_idr, handle);
-       if (obj == NULL) {
-               spin_unlock(&filp->table_lock);
+       obj = idr_replace(&filp->object_idr, NULL, handle);
+       spin_unlock(&filp->table_lock);
+       if (IS_ERR_OR_NULL(obj))
                return -EINVAL;
-       }
-       dev = obj->dev;
 
-       /* Release reference and decrement refcount. */
+       /* Release driver's reference and decrement refcount. */
+       drm_gem_object_release_handle(handle, obj, filp);
+
+       /* And finally make the handle available for future allocations. */
+       spin_lock(&filp->table_lock);
        idr_remove(&filp->object_idr, handle);
        spin_unlock(&filp->table_lock);
 
-       drm_gem_object_release_handle(handle, obj, filp);
        return 0;
 }
 EXPORT_SYMBOL(drm_gem_handle_delete);
@@ -422,6 +422,10 @@ EXPORT_SYMBOL(drm_gem_handle_create);
  * @obj: obj in question
  *
  * This routine frees fake offsets allocated by drm_gem_create_mmap_offset().
+ *
+ * Note that drm_gem_object_release() already calls this function, so drivers
+ * don't have to take care of releasing the mmap offset themselves when freeing
+ * the GEM object.
  */
 void
 drm_gem_free_mmap_offset(struct drm_gem_object *obj)
@@ -445,6 +449,9 @@ EXPORT_SYMBOL(drm_gem_free_mmap_offset);
  * This routine allocates and attaches a fake offset for @obj, in cases where
  * the virtual size differs from the physical size (ie. obj->size).  Otherwise
  * just use drm_gem_create_mmap_offset().
+ *
+ * This function is idempotent and handles an already allocated mmap offset
+ * transparently. Drivers do not need to check for this case.
  */
 int
 drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
@@ -466,6 +473,9 @@ EXPORT_SYMBOL(drm_gem_create_mmap_offset_size);
  * structures.
  *
  * This routine allocates and attaches a fake offset for @obj.
+ *
+ * Drivers can call drm_gem_free_mmap_offset() before freeing @obj to release
+ * the fake offset again.
  */
 int drm_gem_create_mmap_offset(struct drm_gem_object *obj)
 {
@@ -578,7 +588,6 @@ EXPORT_SYMBOL(drm_gem_put_pages);
 
 /**
  * drm_gem_object_lookup - look up a GEM object from it's handle
- * @dev: DRM device
  * @filp: DRM file private date
  * @handle: userspace handle
  *
@@ -588,8 +597,7 @@ EXPORT_SYMBOL(drm_gem_put_pages);
  * otherwise.
  */
 struct drm_gem_object *
-drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
-                     u32 handle)
+drm_gem_object_lookup(struct drm_file *filp, u32 handle)
 {
        struct drm_gem_object *obj;
 
@@ -597,12 +605,8 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
 
        /* Check if we currently have a reference on the object */
        obj = idr_find(&filp->object_idr, handle);
-       if (obj == NULL) {
-               spin_unlock(&filp->table_lock);
-               return NULL;
-       }
-
-       drm_gem_object_reference(obj);
+       if (obj)
+               drm_gem_object_reference(obj);
 
        spin_unlock(&filp->table_lock);
 
@@ -655,7 +659,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
        if (!drm_core_check_feature(dev, DRIVER_GEM))
                return -ENODEV;
 
-       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       obj = drm_gem_object_lookup(file_priv, args->handle);
        if (obj == NULL)
                return -ENOENT;
 
@@ -759,6 +763,13 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
        idr_destroy(&file_private->object_idr);
 }
 
+/**
+ * drm_gem_object_release - release GEM buffer object resources
+ * @obj: GEM buffer object
+ *
+ * This releases any structures and resources used by @obj and is the invers of
+ * drm_gem_object_init().
+ */
 void
 drm_gem_object_release(struct drm_gem_object *obj)
 {
@@ -776,7 +787,7 @@ EXPORT_SYMBOL(drm_gem_object_release);
  * @kref: kref of the object to free
  *
  * Called after the last reference to the object has been lost.
- * Must be called holding struct_ mutex
+ * Must be called holding &drm_device->struct_mutex.
  *
  * Frees the object
  */
@@ -787,13 +798,66 @@ drm_gem_object_free(struct kref *kref)
                container_of(kref, struct drm_gem_object, refcount);
        struct drm_device *dev = obj->dev;
 
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+       if (dev->driver->gem_free_object_unlocked) {
+               dev->driver->gem_free_object_unlocked(obj);
+       } else if (dev->driver->gem_free_object) {
+               WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       if (dev->driver->gem_free_object != NULL)
                dev->driver->gem_free_object(obj);
+       }
 }
 EXPORT_SYMBOL(drm_gem_object_free);
 
+/**
+ * drm_gem_object_unreference_unlocked - release a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This releases a reference to @obj. Callers must not hold the
+ * dev->struct_mutex lock when calling this function.
+ *
+ * See also __drm_gem_object_unreference().
+ */
+void
+drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
+{
+       struct drm_device *dev;
+
+       if (!obj)
+               return;
+
+       dev = obj->dev;
+       might_lock(&dev->struct_mutex);
+
+       if (dev->driver->gem_free_object_unlocked)
+               kref_put(&obj->refcount, drm_gem_object_free);
+       else if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
+                               &dev->struct_mutex))
+               mutex_unlock(&dev->struct_mutex);
+}
+EXPORT_SYMBOL(drm_gem_object_unreference_unlocked);
+
+/**
+ * drm_gem_object_unreference - release a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This releases a reference to @obj. Callers must hold the dev->struct_mutex
+ * lock when calling this function, even when the driver doesn't use
+ * dev->struct_mutex for anything.
+ *
+ * For drivers not encumbered with legacy locking use
+ * drm_gem_object_unreference_unlocked() instead.
+ */
+void
+drm_gem_object_unreference(struct drm_gem_object *obj)
+{
+       if (obj) {
+               WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
+
+               kref_put(&obj->refcount, drm_gem_object_free);
+       }
+}
+EXPORT_SYMBOL(drm_gem_object_unreference);
+
 /**
  * drm_gem_vm_open - vma->ops->open implementation for GEM
  * @vma: VM area structure