summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h6
-rw-r--r--linux-core/drm_bo.c268
2 files changed, 177 insertions, 97 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 6cce6b8d..bbf9da0b 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -951,6 +951,12 @@ typedef struct drm_fence_object{
typedef struct drm_buffer_object{
drm_device_t *dev;
drm_user_object_t base;
+
+ /*
+ * If there is a possibility that the usage variable is zero,
+ * then dev->struct_mutext should be locked before incrementing it.
+ */
+
atomic_t usage;
drm_ttm_object_t *ttm_object;
drm_ttm_backend_list_t *ttm_region;
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index f3105283..18cfadc5 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -126,6 +126,7 @@ int drm_fence_buffer_objects(drm_file_t * priv)
return 0;
}
+
/*
* bo locked.
*/
@@ -148,6 +149,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf)
return 0;
}
+
+
static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo)
{
@@ -197,6 +200,13 @@ void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * 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,
+ base));
+}
+
void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo)
{
if (atomic_dec_and_test(&bo->usage)) {
@@ -207,13 +217,167 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo)
}
}
-static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo)
+
+/*
+ * Call bo->mutex locked.
+ * Wait until the buffer is idle.
+ */
+
+static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait)
{
- drm_bo_usage_deref_locked(priv->head->dev,
- drm_user_object_entry(uo, drm_buffer_object_t,
- base));
+
+ drm_fence_object_t *fence = bo->fence;
+ int ret;
+
+ if (fence) {
+ drm_device_t *dev = bo->dev;
+ if (drm_fence_object_signaled(fence, bo->fence_flags)) {
+ drm_fence_usage_deref_unlocked(dev, fence);
+ bo->fence = NULL;
+ return 0;
+ }
+ if (no_wait)
+ return -EBUSY;
+
+ ret =
+ drm_fence_object_wait(dev, fence, lazy, !lazy,
+ bo->fence_flags);
+ if (ret)
+ return ret;
+
+ drm_fence_usage_deref_unlocked(dev, fence);
+ bo->fence = NULL;
+
+ }
+ return 0;
+}
+
+/*
+ * No locking required.
+ */
+
+static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait)
+{
+ int ret = 0;
+
+ /*
+ * Someone might have taken out the buffer before we took the buffer mutex.
+ */
+
+ mutex_lock(&bo->mutex);
+ if (bo->unfenced)
+ goto out;
+ if (tt && !bo->tt)
+ goto out;
+ if (!tt && !bo->vram)
+ goto out;
+
+ ret = drm_bo_wait(bo, 0, no_wait);
+ if (ret)
+ goto out;
+
+ if (tt) {
+ ret = drm_move_tt_to_local(bo);
+ }
+#if 0
+ else {
+ ret = drm_move_vram_to_local(bo);
+ }
+#endif
+out:
+ mutex_unlock(&bo->mutex);
+ return ret;
+}
+
+/*
+ * buf->mutex locked.
+ */
+
+int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait)
+{
+ drm_device_t *dev = buf->dev;
+ drm_mm_node_t *node;
+ drm_buffer_manager_t *bm = &dev->bm;
+ drm_buffer_object_t *bo;
+ drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager;
+ struct list_head *lru;
+ unsigned long size = buf->num_pages;
+ int ret;
+
+ mutex_lock(&bm->mutex);
+ do {
+ node = drm_mm_search_free(mm, size, 0, 1);
+ if (node)
+ break;
+
+ lru = (tt) ? &bm->tt_lru : &bm->vram_lru;
+ if (lru->next == lru)
+ break;
+
+ bo = list_entry(lru->next, drm_buffer_object_t, head);
+
+ /*
+ * No need to take dev->struct_mutex here, because bo->usage is at least 1 already,
+ * since it's on the lru list, and the bm->mutex is held.
+ */
+
+ atomic_inc(&bo->usage);
+ mutex_unlock(&bm->mutex);
+ ret = drm_bo_evict(bo, tt, no_wait);
+ drm_bo_usage_deref_unlocked(dev, bo);
+ if (ret)
+ return ret;
+ mutex_lock(&bm->mutex);
+ } while (1);
+
+ if (!node) {
+ DRM_ERROR("Out of aperture space\n");
+ mutex_lock(&bm->mutex);
+ return -ENOMEM;
+ }
+
+ node = drm_mm_get_block(node, size, 0);
+ mutex_unlock(&bm->mutex);
+ BUG_ON(!node);
+ node->private = (void *)buf;
+
+ if (tt) {
+ buf->tt = node;
+ } else {
+ buf->vram = node;
+ }
+ return 0;
+}
+
+
+static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait)
+{
+ drm_device_t *dev = bo->dev;
+ drm_buffer_manager_t *bm = &dev->bm;
+ int ret;
+
+
+ BUG_ON(bo->tt);
+ ret = drm_bo_alloc_space(bo, 1, no_wait);
+
+ if (ret)
+ return ret;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start);
+ mutex_unlock(&dev->struct_mutex);
+
+ if (ret) {
+ mutex_lock(&bm->mutex);
+ drm_mm_put_block(&bm->tt_manager, bo->tt);
+ mutex_unlock(&bm->mutex);
+ }
+
+ return ret;
}
+
+
static int drm_bo_new_flags(drm_bo_driver_t * driver,
uint32_t flags, uint32_t new_mask, uint32_t hint,
int init, uint32_t * n_flags)
@@ -289,64 +453,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver,
return 0;
}
-#if 0
-
-static int drm_bo_evict(drm_device_t * dev, drm_buffer_object_t * buf, int tt);
-{
- int ret;
- if (tt) {
- ret = drm_move_tt_to_local(buf);
- } else {
- ret = drm_move_vram_to_local(buf);
- }
- return ret;
-}
-
-int drm_bo_alloc_space(drm_device_t * dev, int tt, drm_buffer_object_t * buf)
-{
- drm_mm_node_t *node;
- drm_buffer_manager_t *bm = &dev->bm;
- drm_buffer_object_t *bo;
- drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager;
-
- lru = (tt) ? &bm->tt_lru : &bm->vram_lru;
-
- do {
- node = drm_mm_search_free(mm, size, 0, 1);
- if (node)
- break;
-
- if (lru->next == lru)
- break;
-
- if (tt) {
- bo = list_entry(lru->next, drm_buffer_object_t, tt_lru);
- } else {
- bo = list_entry(lru->next, drm_buffer_object_t,
- vram_lru);
- }
-
- drm_bo_evict(dev, bo, tt);
- } while (1);
-
- if (!node) {
- DRM_ERROR("Out of aperture space\n");
- return -ENOMEM;
- }
-
- node = drm_mm_get_block(node, size, 0);
- BUG_ON(!node);
- node->private = (void *)buf;
-
- if (tt) {
- buf->tt = node;
- } else {
- buf->vram = node;
- }
- return 0;
-}
-#endif
-
/*
* Call dev->struct_mutex locked.
*/
@@ -377,40 +483,6 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv,
/*
* Call bo->mutex locked.
- * Wait until the buffer is idle.
- */
-
-static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait)
-{
-
- drm_fence_object_t *fence = bo->fence;
- int ret;
-
- if (fence) {
- drm_device_t *dev = bo->dev;
- if (drm_fence_object_signaled(fence, bo->fence_flags)) {
- drm_fence_usage_deref_unlocked(dev, fence);
- bo->fence = NULL;
- return 0;
- }
- if (no_wait)
- return -EBUSY;
-
- ret =
- drm_fence_object_wait(dev, fence, lazy, !lazy,
- bo->fence_flags);
- if (ret)
- return ret;
-
- drm_fence_usage_deref_unlocked(dev, fence);
- bo->fence = NULL;
-
- }
- return 0;
-}
-
-/*
- * Call bo->mutex locked.
* Returns 1 if the buffer is currently rendered to or from. 0 otherwise.
*/
@@ -581,7 +653,9 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags,
return ret;
if (new_flags & DRM_BO_FLAG_MEM_TT) {
- drm_move_local_to_tt(bo);
+ ret = drm_move_local_to_tt(bo, no_wait);
+ if (ret)
+ return ret;
} else {
drm_move_tt_to_local(bo);
}