summaryrefslogtreecommitdiff
path: root/linux-core/drm_bo.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-02-06 14:20:33 +0100
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-02-06 14:20:33 +0100
commit609e3b037526021d20c7cc18b7fed1152206dc68 (patch)
treef5244753ff65773e6079692a832b39ff8fb83be0 /linux-core/drm_bo.c
parent2d962332dea5ed328ae45c6ef7298ea15216b635 (diff)
Implement a policy for selecting memory types.
Diffstat (limited to 'linux-core/drm_bo.c')
-rw-r--r--linux-core/drm_bo.c212
1 files changed, 167 insertions, 45 deletions
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 9a27a4b5..fa659d04 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -56,6 +56,8 @@ static void drm_bo_destroy_locked(drm_buffer_object_t *bo);
static int drm_bo_setup_vm_locked(drm_buffer_object_t *bo);
static void drm_bo_takedown_vm_locked(drm_buffer_object_t *bo);
static void drm_bo_unmap_virtual(drm_buffer_object_t *bo);
+static int drm_bo_mem_space(drm_device_t *dev, drm_bo_mem_reg_t *mem,
+ int no_wait);
#define DRM_FLAG_MASKED(_old, _new, _mask) {\
(_old) ^= (((_old) ^ (_new)) & (_mask)); \
@@ -497,6 +499,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type,
int ret = 0;
drm_device_t *dev = bo->dev;
drm_buffer_manager_t *bm = &dev->bm;
+ drm_bo_mem_reg_t evict_mem;
/*
* Someone might have modified the buffer before we took the buffer mutex.
@@ -509,22 +512,39 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type,
ret = drm_bo_wait(bo, 0, 0, no_wait);
- if (ret) {
- if (ret != -EAGAIN)
- DRM_ERROR("Failed to expire fence before "
- "buffer eviction.\n");
+ if (ret && ret != -EAGAIN) {
+ DRM_ERROR("Failed to expire fence before "
+ "buffer eviction.\n");
goto out;
}
- if (mem_type == DRM_BO_MEM_TT) {
- ret = drm_move_tt_to_local(bo, 1, force_no_move);
- if (ret)
- goto out;
- mutex_lock(&dev->struct_mutex);
- list_del_init(&bo->lru);
- drm_bo_add_to_lru(bo, bm);
- mutex_unlock(&dev->struct_mutex);
+ evict_mem.num_pages = bo->num_pages;
+ evict_mem.page_alignment = bo->page_alignment;
+ evict_mem.size = evict_mem.num_pages << PAGE_SHIFT;
+ evict_mem.mask = dev->driver->bo_driver->evict_flags(dev, mem_type);
+
+ ret = drm_bo_mem_space(dev, &evict_mem, no_wait);
+
+ if (ret && ret != -EAGAIN) {
+ DRM_ERROR("Failed to find memory space for "
+ "buffer eviction.\n");
+ goto out;
+ }
+
+ if ((mem_type != DRM_BO_MEM_TT) &&
+ (evict_mem.mem_type != DRM_BO_MEM_LOCAL)) {
+ ret = -EINVAL;
+ DRM_ERROR("Unsupported memory types for eviction.\n");
+ goto out;
}
+
+ ret = drm_move_tt_to_local(bo, 1, force_no_move);
+ if (ret)
+ goto out;
+ mutex_lock(&dev->struct_mutex);
+ list_del_init(&bo->lru);
+ drm_bo_add_to_lru(bo, bm);
+ mutex_unlock(&dev->struct_mutex);
if (ret)
goto out;
@@ -535,26 +555,25 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type,
return ret;
}
-/*
- * bo->mutex locked.
- */
-int drm_bo_alloc_space(drm_buffer_object_t * bo, unsigned mem_type,
- int no_wait)
+
+static int drm_bo_mem_force_space(drm_device_t *dev,
+ drm_bo_mem_reg_t *mem,
+ uint32_t mem_type,
+ int no_wait)
{
- drm_device_t *dev = bo->dev;
drm_mm_node_t *node;
drm_buffer_manager_t *bm = &dev->bm;
drm_buffer_object_t *entry;
drm_mem_type_manager_t *man = &bm->man[mem_type];
- drm_mm_t *mm = &man->manager;
struct list_head *lru;
- unsigned long size = bo->num_pages;
+ unsigned long num_pages = mem->num_pages;
int ret;
mutex_lock(&dev->struct_mutex);
do {
- node = drm_mm_search_free(mm, size, bo->page_alignment, 1);
+ node = drm_mm_search_free(&man->manager, num_pages,
+ mem->page_alignment, 1);
if (node)
break;
@@ -563,11 +582,11 @@ int drm_bo_alloc_space(drm_buffer_object_t * bo, unsigned mem_type,
break;
entry = list_entry(lru->next, drm_buffer_object_t, lru);
-
atomic_inc(&entry->usage);
mutex_unlock(&dev->struct_mutex);
mutex_lock(&entry->mutex);
- BUG_ON(bo->flags & DRM_BO_FLAG_NO_MOVE);
+ BUG_ON(entry->flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT));
+
ret = drm_bo_evict(entry, mem_type, no_wait, 0);
mutex_unlock(&entry->mutex);
drm_bo_usage_deref_unlocked(entry);
@@ -577,34 +596,108 @@ int drm_bo_alloc_space(drm_buffer_object_t * bo, unsigned mem_type,
} while (1);
if (!node) {
- DRM_ERROR("Out of videoram / aperture space\n");
mutex_unlock(&dev->struct_mutex);
return -ENOMEM;
}
- node = drm_mm_get_block(node, size, bo->page_alignment);
+ node = drm_mm_get_block(node, num_pages, mem->page_alignment);
mutex_unlock(&dev->struct_mutex);
- BUG_ON(!node);
- node->private = (void *)bo;
-
- bo->mm_node = node;
- bo->offset = node->start * PAGE_SIZE;
+ mem->mm_node = node;
+ mem->mem_type = mem_type;
+ mem->flags = drm_bo_type_flags(mem_type);
return 0;
}
-static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait)
+
+static int drm_bo_mem_space(drm_device_t *dev,
+ drm_bo_mem_reg_t *mem,
+ int no_wait)
{
- drm_device_t *dev = bo->dev;
- int ret = 0;
+ drm_buffer_manager_t *bm= &dev->bm;
+ drm_mem_type_manager_t *man;
- if (!(bo->mm_node && (bo->flags & DRM_BO_FLAG_NO_MOVE))) {
- BUG_ON(bo->mm_node);
- ret = drm_bo_alloc_space(bo, DRM_BO_MEM_TT, no_wait);
- if (ret)
- return ret;
+ uint32_t num_prios = dev->driver->bo_driver->num_mem_type_prio;
+ const uint32_t *prios = dev->driver->bo_driver->mem_type_prio;
+ uint32_t i;
+ uint32_t mem_type = DRM_BO_MEM_LOCAL;
+ int type_found = 0;
+ int type_ok = 0;
+ int has_eagain = 0;
+ drm_mm_node_t *node = NULL;
+ int ret;
+
+ for (i=0; i<num_prios; ++i) {
+ mem_type = prios[i];
+ type_ok = drm_bo_type_flags(mem_type) & mem->mask ;
+ if (!type_ok)
+ continue;
+
+ if (mem_type == DRM_BO_MEM_LOCAL)
+ break;
+
+ man = &bm->man[mem_type];
+ mutex_lock(&dev->struct_mutex);
+ if (man->has_type && man->use_type) {
+ type_found = 1;
+ node = drm_mm_search_free(&man->manager, mem->num_pages,
+ mem->page_alignment, 1);
+ if (node)
+ node = drm_mm_get_block(node, mem->num_pages,
+ mem->page_alignment);
+ }
+ mutex_unlock(&dev->struct_mutex);
+ if (node)
+ break;
}
+
+ if ((type_ok && (mem_type == DRM_BO_MEM_LOCAL)) || node) {
+ mem->mm_node = node;
+ mem->mem_type = mem_type;
+ mem->flags = drm_bo_type_flags(mem_type);
+ return 0;
+ }
+
+ if (!type_found) {
+ DRM_ERROR("Requested memory types are not supported\n");
+ return -EINVAL;
+ }
+
+ num_prios = dev->driver->bo_driver->num_mem_busy_prio;
+ prios = dev->driver->bo_driver->mem_busy_prio;
+
+ for (i=0; i<num_prios; ++i) {
+ mem_type = prios[i];
+ if (!(drm_bo_type_flags(mem_type) & mem->mask))
+ continue;
+
+ man = &bm->man[mem_type];
+ ret = drm_bo_mem_force_space(dev, mem, mem_type, no_wait);
+
+ if (ret == 0)
+ return 0;
+
+ if (ret == -EAGAIN)
+ has_eagain = 1;
+ }
+
+ ret = (has_eagain) ? -EAGAIN : -ENOMEM;
+ return ret;
+}
+
- DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->mm_node->start);
+
+
+static int drm_move_local_to_tt(drm_buffer_object_t * bo,
+ drm_bo_mem_reg_t * mem,
+ int no_wait)
+{
+ drm_device_t *dev = bo->dev;
+ int ret = 0;
+
+ bo->mm_node = mem->mm_node;
+
+ DRM_DEBUG("Flipping in to AGP 0x%08lx 0x%08lx\n",
+ bo->mm_node->start, bo->mm_node->size);
#ifdef DRM_ODD_MM_COMPAT
mutex_lock(&dev->struct_mutex);
@@ -631,6 +724,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait)
bo->flags &= ~DRM_BO_MASK_MEM;
bo->flags |= DRM_BO_FLAG_MEM_TT;
bo->mem_type = DRM_BO_MEM_TT;
+ bo->offset = bo->mm_node->start << PAGE_SHIFT;
#ifdef DRM_ODD_MM_COMPAT
ret = drm_bo_remap_bound(bo);
@@ -1103,14 +1197,18 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv,
* bo->mutex locked.
*/
-static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags,
+static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags,
int no_wait, int force_no_move)
{
+ drm_device_t *dev = bo->dev;
+ drm_buffer_manager_t *bm = &dev->bm;
int ret = 0;
+ drm_bo_mem_reg_t mem;
/*
* Flush outstanding fences.
*/
+
drm_bo_busy(bo);
/*
@@ -1126,16 +1224,38 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags,
*/
ret = drm_bo_wait(bo, 0, 0, no_wait);
+ if (ret)
+ return ret;
- if (ret == -EINTR)
- return -EAGAIN;
+
+ mem.num_pages = bo->num_pages;
+ mem.size = mem.num_pages << PAGE_SHIFT;
+ mem.mask = new_mem_flags;
+ mem.page_alignment = bo->page_alignment;
+
+ mutex_lock(&bm->evict_mutex);
+ mutex_lock(&dev->struct_mutex);
+ list_del(&bo->lru);
+ list_add_tail(&bo->lru,&bm->unfenced);
+ DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, _DRM_BO_FLAG_UNFENCED);
+ mutex_unlock(&dev->struct_mutex);
+
+ ret = drm_bo_mem_space(dev, &mem, no_wait);
+ mutex_unlock(&bm->evict_mutex);
+
if (ret)
return ret;
- if (new_flags & DRM_BO_FLAG_MEM_TT) {
- ret = drm_move_local_to_tt(bo, no_wait);
- if (ret)
+ if (mem.mem_type == DRM_BO_MEM_TT) {
+ ret = drm_move_local_to_tt(bo, &mem, no_wait);
+ if (ret) {
+ mutex_lock(&dev->struct_mutex);
+ list_del_init(&bo->lru);
+ drm_bo_add_to_lru(bo, bm);
+ mutex_unlock(&dev->struct_mutex);
+ DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
return ret;
+ }
} else {
drm_move_tt_to_local(bo, 0, force_no_move);
}
@@ -1231,6 +1351,8 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo,
list_add_tail(&bo->lru, &bm->unfenced);
mutex_unlock(&dev->struct_mutex);
} else {
+ DRM_FLAG_MASKED(bo->priv_flags, 0,
+ _DRM_BO_FLAG_UNFENCED);
mutex_lock(&dev->struct_mutex);
list_del_init(&bo->lru);
drm_bo_add_to_lru(bo, bm);