summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drm_bo.c286
1 files changed, 152 insertions, 134 deletions
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index cd0f4765..74476d35 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -55,6 +55,8 @@
* 2.) Refer to ttm locking orders.
*/
+static void drm_bo_destroy_locked(drm_buffer_object_t *bo);
+
#define DRM_FLAG_MASKED(_old, _new, _mask) {\
(_old) ^= (((_old) ^ (_new)) & (_mask)); \
}
@@ -130,79 +132,6 @@ static int drm_move_tt_to_local(drm_buffer_object_t * bo, int evict,
return 0;
}
-/*
- * Lock dev->struct_mutex
- */
-
-static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo)
-{
-
- drm_buffer_manager_t *bm = &dev->bm;
-
- DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
-
- /*
- * Somone might try to access us through the still active BM lists.
- */
-
- if (atomic_read(&bo->usage) != 0)
- return;
- if (!list_empty(&bo->ddestroy))
- return;
-
- if (bo->fence) {
- if (!drm_fence_object_signaled(bo->fence, bo->fence_type)) {
-
- drm_fence_object_flush(dev, bo->fence, bo->fence_type);
- list_add_tail(&bo->ddestroy, &bm->ddestroy);
- schedule_delayed_work(&bm->wq,
- ((DRM_HZ / 100) <
- 1) ? 1 : DRM_HZ / 100);
- return;
- } else {
- drm_fence_usage_deref_locked(dev, bo->fence);
- bo->fence = NULL;
- }
- }
- /*
- * Take away from lru lists.
- */
-
- list_del_init(&bo->lru);
-
- if (bo->ttm) {
- unsigned long _end = jiffies + DRM_HZ;
- int ret;
-
- /*
- * This temporarily unlocks struct_mutex.
- */
-
- do {
- ret = drm_unbind_ttm(bo->ttm);
- if (ret == -EAGAIN) {
- mutex_unlock(&dev->struct_mutex);
- schedule();
- mutex_lock(&dev->struct_mutex);
- }
- } while (ret == -EAGAIN && !time_after_eq(jiffies, _end));
-
- if (ret) {
- DRM_ERROR("Couldn't unbind buffer. "
- "Bad. Continuing anyway\n");
- }
- }
-
- if (bo->mm_node) {
- drm_mm_put_block(bo->mm_node);
- bo->mm_node = NULL;
- }
- if (bo->ttm_object) {
- drm_ttm_object_deref_locked(dev, bo->ttm_object);
- }
- atomic_dec(&bm->count);
- drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ);
-}
/*
* Call bo->mutex locked.
@@ -241,6 +170,136 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals,
/*
* Call dev->struct_mutex locked.
+ * Attempts to remove all private references to a buffer by expiring its
+ * fence object and removing from lru lists and memory managers.
+ */
+
+
+static void drm_bo_cleanup_refs(drm_buffer_object_t *bo, int remove_all)
+{
+ drm_device_t *dev = bo->dev;
+ drm_buffer_manager_t *bm = &dev->bm;
+
+ atomic_inc(&bo->usage);
+ mutex_unlock(&dev->struct_mutex);
+ mutex_lock(&bo->mutex);
+
+ DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
+
+ if (bo->fence && drm_fence_object_signaled(bo->fence,
+ bo->fence_type)) {
+ drm_fence_usage_deref_locked(dev, bo->fence);
+ bo->fence = NULL;
+ }
+
+ if (bo->fence && remove_all) {
+ if (bm->nice_mode) {
+ unsigned long _end = jiffies + 3 * DRM_HZ;
+ int ret;
+ do {
+ ret = drm_bo_wait(bo, 0, 1, 0);
+ } while (ret && !time_after_eq(jiffies, _end));
+
+ if (bo->fence) {
+ bm->nice_mode = 0;
+ DRM_ERROR("Detected GPU lockup or "
+ "fence driver was taken down. "
+ "Evicting waiting buffers.\n");
+ }
+ if (bo->fence) {
+ drm_fence_usage_deref_unlocked(dev, bo->fence);
+ bo->fence = NULL;
+ }
+ }
+ }
+ mutex_lock(&dev->struct_mutex);
+
+ if (!atomic_dec_and_test(&bo->usage)) {
+ goto out;
+ }
+
+ if (!bo->fence) {
+ list_del_init(&bo->lru);
+ if (bo->mm_node) {
+ drm_mm_put_block(bo->mm_node);
+ bo->mm_node = NULL;
+ }
+ list_del_init(&bo->ddestroy);
+ mutex_unlock(&bo->mutex);
+ drm_bo_destroy_locked(bo);
+ return;
+ }
+
+ if (list_empty(&bo->ddestroy)) {
+ drm_fence_object_flush(dev, bo->fence, bo->fence_type);
+ list_add_tail(&bo->ddestroy, &bm->ddestroy);
+ schedule_delayed_work(&bm->wq,
+ ((DRM_HZ / 100) <
+ 1) ? 1 : DRM_HZ / 100);
+ }
+
+out:
+ mutex_unlock(&bo->mutex);
+ return;
+}
+
+
+/*
+ * Verify that refcount is 0 and that there are no internal references
+ * to the buffer object. Then destroy it.
+ */
+
+static void drm_bo_destroy_locked(drm_buffer_object_t *bo)
+{
+ drm_device_t *dev = bo->dev;
+ drm_buffer_manager_t *bm = &dev->bm;
+
+ if (list_empty(&bo->lru) && bo->mm_node == NULL && atomic_read(&bo->usage) == 0) {
+ BUG_ON(bo->fence != NULL);
+
+ if (bo->ttm) {
+ unsigned long _end = jiffies + DRM_HZ;
+ int ret;
+
+ do {
+ ret = drm_unbind_ttm(bo->ttm);
+ if (ret == -EAGAIN) {
+ mutex_unlock(&dev->struct_mutex);
+ schedule();
+ mutex_lock(&dev->struct_mutex);
+ }
+ } while (ret == -EAGAIN && !time_after_eq(jiffies, _end));
+
+ if (ret) {
+ DRM_ERROR("Couldn't unbind TTM region while destroying a buffer. "
+ "Bad. Continuing anyway\n");
+ }
+ }
+
+ if (bo->ttm_object) {
+ drm_ttm_object_deref_locked(dev, bo->ttm_object);
+ }
+
+ atomic_dec(&bm->count);
+
+ drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ);
+
+ return;
+ }
+
+ /*
+ * Some stuff is still trying to reference the buffer object.
+ * Get rid of those references.
+ */
+
+ drm_bo_cleanup_refs(bo, 0);
+
+ return;
+}
+
+
+/*
+ * Call dev->struct_mutex locked.
*/
static void drm_bo_delayed_delete(drm_device_t * dev, int remove_all)
@@ -249,15 +308,9 @@ static void drm_bo_delayed_delete(drm_device_t * dev, int remove_all)
drm_buffer_object_t *entry, *nentry;
struct list_head *list, *next;
- drm_fence_object_t *fence;
list_for_each_safe(list, next, &bm->ddestroy) {
entry = list_entry(list, drm_buffer_object_t, ddestroy);
- atomic_inc(&entry->usage);
- if (atomic_read(&entry->usage) != 1) {
- atomic_dec(&entry->usage);
- continue;
- }
nentry = NULL;
if (next != &bm->ddestroy) {
@@ -266,42 +319,8 @@ static void drm_bo_delayed_delete(drm_device_t * dev, int remove_all)
atomic_inc(&nentry->usage);
}
- mutex_unlock(&dev->struct_mutex);
- mutex_lock(&entry->mutex);
- fence = entry->fence;
- if (fence && drm_fence_object_signaled(fence,
- entry->fence_type)) {
- drm_fence_usage_deref_locked(dev, fence);
- entry->fence = NULL;
- }
-
- if (entry->fence && remove_all) {
- if (bm->nice_mode) {
- unsigned long _end = jiffies + 3 * DRM_HZ;
- int ret;
- do {
- ret = drm_bo_wait(entry, 0, 1, 0);
- } while (ret && !time_after_eq(jiffies, _end));
+ drm_bo_cleanup_refs(entry, remove_all);
- if (entry->fence) {
- bm->nice_mode = 0;
- DRM_ERROR("Detected GPU lockup or "
- "fence driver was taken down. "
- "Evicting waiting buffers.\n");
- }
- }
- if (entry->fence) {
- drm_fence_usage_deref_unlocked(dev,
- entry->fence);
- entry->fence = NULL;
- }
- }
- mutex_lock(&dev->struct_mutex);
- mutex_unlock(&entry->mutex);
- if (atomic_dec_and_test(&entry->usage) && (!entry->fence)) {
- list_del_init(&entry->ddestroy);
- drm_bo_destroy_locked(dev, entry);
- }
if (nentry) {
atomic_dec(&nentry->usage);
}
@@ -339,27 +358,26 @@ static void drm_bo_delayed_workqueue(struct work_struct *work)
mutex_unlock(&dev->struct_mutex);
}
-void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo)
+static void drm_bo_usage_deref_locked(drm_buffer_object_t * bo)
{
if (atomic_dec_and_test(&bo->usage)) {
- drm_bo_destroy_locked(dev, bo);
+ drm_bo_destroy_locked(bo);
}
}
static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo)
{
- drm_bo_usage_deref_locked(priv->head->dev,
- drm_user_object_entry(uo, drm_buffer_object_t,
+ drm_bo_usage_deref_locked(drm_user_object_entry(uo, drm_buffer_object_t,
base));
}
-void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo)
+static void drm_bo_usage_deref_unlocked(drm_buffer_object_t * bo)
{
if (atomic_dec_and_test(&bo->usage)) {
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&bo->dev->struct_mutex);
if (atomic_read(&bo->usage) == 0)
- drm_bo_destroy_locked(dev, bo);
- mutex_unlock(&dev->struct_mutex);
+ drm_bo_destroy_locked(bo);
+ mutex_unlock(&bo->dev->struct_mutex);
}
}
@@ -451,7 +469,7 @@ int drm_fence_buffer_objects(drm_file_t * priv,
drm_bo_add_to_lru(entry, bm);
}
mutex_unlock(&entry->mutex);
- drm_bo_usage_deref_locked(dev, entry);
+ drm_bo_usage_deref_locked(entry);
l = f_list.next;
}
atomic_add(count, &fence->usage);
@@ -546,7 +564,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * bo, unsigned mem_type,
BUG_ON(bo->flags & DRM_BO_FLAG_NO_MOVE);
ret = drm_bo_evict(entry, mem_type, no_wait, 0);
mutex_unlock(&entry->mutex);
- drm_bo_usage_deref_unlocked(dev, entry);
+ drm_bo_usage_deref_unlocked(entry);
if (ret)
return ret;
mutex_lock(&dev->struct_mutex);
@@ -1002,7 +1020,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle,
drm_bo_fill_rep_arg(bo, rep);
out:
mutex_unlock(&bo->mutex);
- drm_bo_usage_deref_unlocked(dev, bo);
+ drm_bo_usage_deref_unlocked(bo);
return ret;
}
@@ -1028,7 +1046,7 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle)
}
drm_remove_ref_object(priv, ro);
- drm_bo_usage_deref_locked(dev, bo);
+ drm_bo_usage_deref_locked(bo);
out:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -1237,7 +1255,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle,
out:
mutex_unlock(&bo->mutex);
- drm_bo_usage_deref_unlocked(dev, bo);
+ drm_bo_usage_deref_unlocked(bo);
return ret;
}
@@ -1255,7 +1273,7 @@ static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle,
(void)drm_bo_busy(bo);
drm_bo_fill_rep_arg(bo, rep);
mutex_unlock(&bo->mutex);
- drm_bo_usage_deref_unlocked(bo->dev, bo);
+ drm_bo_usage_deref_unlocked(bo);
return 0;
}
@@ -1283,7 +1301,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle,
out:
mutex_unlock(&bo->mutex);
- drm_bo_usage_deref_unlocked(bo->dev, bo);
+ drm_bo_usage_deref_unlocked(bo);
return ret;
}
@@ -1400,7 +1418,7 @@ int drm_buffer_object_create(drm_file_t * priv,
out_err:
mutex_unlock(&bo->mutex);
- drm_bo_usage_deref_unlocked(dev, bo);
+ drm_bo_usage_deref_unlocked(bo);
return ret;
}
@@ -1473,7 +1491,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
mask &
DRM_BO_FLAG_SHAREABLE);
if (rep.ret)
- drm_bo_usage_deref_unlocked(dev, entry);
+ drm_bo_usage_deref_unlocked(entry);
if (rep.ret)
break;
@@ -1594,7 +1612,7 @@ static int drm_bo_force_list_clean(drm_device_t * dev,
if (prev != list->prev || next != list->next) {
mutex_unlock(&entry->mutex);
- drm_bo_usage_deref_locked(dev, entry);
+ drm_bo_usage_deref_locked(entry);
goto retry;
}
if (entry->mm_node) {
@@ -1654,7 +1672,7 @@ static int drm_bo_force_list_clean(drm_device_t * dev,
mutex_lock(&dev->struct_mutex);
}
mutex_unlock(&entry->mutex);
- drm_bo_usage_deref_locked(dev, entry);
+ drm_bo_usage_deref_locked(entry);
if (prev != list->prev || next != list->next) {
goto retry;
}
@@ -1664,7 +1682,7 @@ static int drm_bo_force_list_clean(drm_device_t * dev,
return 0;
out_err:
mutex_unlock(&entry->mutex);
- drm_bo_usage_deref_unlocked(dev, entry);
+ drm_bo_usage_deref_unlocked(entry);
mutex_lock(&dev->struct_mutex);
return ret;
}