summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h4
-rw-r--r--linux-core/drm_bo.c70
-rw-r--r--linux-core/drm_bo_move.c3
-rw-r--r--linux-core/drm_fence.c4
-rw-r--r--linux-core/drm_memory.c51
-rw-r--r--linux-core/drm_proc.c14
-rw-r--r--linux-core/drm_ttm.c12
7 files changed, 117 insertions, 41 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 7b21f8a1..8273c879 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -1076,8 +1076,10 @@ extern int drm_unbind_agp(DRM_AGP_MEM * handle);
extern void drm_free_memctl(size_t size);
extern int drm_alloc_memctl(size_t size);
extern void drm_query_memctl(uint64_t *cur_used,
+ uint64_t *emer_used,
uint64_t *low_threshold,
- uint64_t *high_threshold);
+ uint64_t *high_threshold,
+ uint64_t *emer_threshold);
extern void drm_init_memctl(size_t low_threshold,
size_t high_threshold,
size_t unit_size);
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 1d3f87e5..7e82080b 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -208,36 +208,35 @@ static int drm_bo_handle_move_mem(struct drm_buffer_object *bo,
if (ret)
goto out_err;
}
- }
-
- if ((bo->mem.mem_type == DRM_BO_MEM_LOCAL) && bo->ttm == NULL) {
-
- struct drm_bo_mem_reg *old_mem = &bo->mem;
- uint64_t save_flags = old_mem->flags;
- uint64_t save_proposed_flags = old_mem->proposed_flags;
- *old_mem = *mem;
- mem->mm_node = NULL;
- old_mem->proposed_flags = save_proposed_flags;
- DRM_FLAG_MASKED(save_flags, mem->flags, DRM_BO_MASK_MEMTYPE);
-
- } else if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) &&
- !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED)) {
+ if (bo->mem.mem_type == DRM_BO_MEM_LOCAL) {
+
+ struct drm_bo_mem_reg *old_mem = &bo->mem;
+ uint64_t save_flags = old_mem->flags;
+ uint64_t save_proposed_flags = old_mem->proposed_flags;
+
+ *old_mem = *mem;
+ mem->mm_node = NULL;
+ old_mem->proposed_flags = save_proposed_flags;
+ DRM_FLAG_MASKED(save_flags, mem->flags,
+ DRM_BO_MASK_MEMTYPE);
+ goto moved;
+ }
+
+ }
+ if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) &&
+ !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED))
ret = drm_bo_move_ttm(bo, evict, no_wait, mem);
-
- } else if (dev->driver->bo_driver->move) {
+ else if (dev->driver->bo_driver->move)
ret = dev->driver->bo_driver->move(bo, evict, no_wait, mem);
-
- } else {
-
+ else
ret = drm_bo_move_memcpy(bo, evict, no_wait, mem);
- }
-
if (ret)
goto out_err;
+moved:
if (old_is_pci || new_is_pci)
drm_bo_vm_post_move(bo);
@@ -789,6 +788,11 @@ static int drm_bo_mem_force_space(struct drm_device *dev,
}
node = drm_mm_get_block(node, num_pages, mem->page_alignment);
+ if (unlikely(!node)) {
+ mutex_unlock(&dev->struct_mutex);
+ return -ENOMEM;
+ }
+
mutex_unlock(&dev->struct_mutex);
mem->mm_node = node;
mem->mem_type = mem_type;
@@ -974,6 +978,20 @@ static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo,
return -EPERM;
}
+ if (likely(new_mask & DRM_BO_MASK_MEM) &&
+ (bo->mem.flags & DRM_BO_FLAG_NO_EVICT) &&
+ !DRM_SUSER(DRM_CURPROC)) {
+ if (likely(bo->mem.flags & new_flags & new_mask &
+ DRM_BO_MASK_MEM))
+ new_flags = (new_flags & ~DRM_BO_MASK_MEM) |
+ (bo->mem.flags & DRM_BO_MASK_MEM);
+ else {
+ DRM_ERROR("Incompatible memory type specification "
+ "for NO_EVICT buffer.\n");
+ return -EPERM;
+ }
+ }
+
if ((new_flags & DRM_BO_FLAG_NO_MOVE)) {
DRM_ERROR("DRM_BO_FLAG_NO_MOVE is not properly implemented yet.\n");
return -EPERM;
@@ -1482,6 +1500,9 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo,
if (ret) {
if (ret != -EAGAIN)
DRM_ERROR("Failed moving buffer.\n");
+ if (ret == -ENOMEM)
+ DRM_ERROR("Out of aperture space or "
+ "DRM memory quota.\n");
return ret;
}
}
@@ -2748,7 +2769,7 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo)
list->file_offset_node = drm_mm_search_free(&dev->offset_manager,
bo->mem.num_pages, 0, 0);
- if (!list->file_offset_node) {
+ if (unlikely(!list->file_offset_node)) {
drm_bo_takedown_vm_locked(bo);
return -ENOMEM;
}
@@ -2756,6 +2777,11 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo)
list->file_offset_node = drm_mm_get_block(list->file_offset_node,
bo->mem.num_pages, 0);
+ if (unlikely(!list->file_offset_node)) {
+ drm_bo_takedown_vm_locked(bo);
+ return -ENOMEM;
+ }
+
list->hash.key = list->file_offset_node->start;
if (drm_ht_insert_item(&dev->map_hash, &list->hash)) {
drm_bo_takedown_vm_locked(bo);
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c
index 536ff5d3..f10549ab 100644
--- a/linux-core/drm_bo_move.c
+++ b/linux-core/drm_bo_move.c
@@ -42,7 +42,6 @@ static void drm_bo_free_old_node(struct drm_buffer_object *bo)
if (old_mem->mm_node && (old_mem->mm_node != bo->pinned_node)) {
mutex_lock(&bo->dev->struct_mutex);
drm_mm_put_block(old_mem->mm_node);
- old_mem->mm_node = NULL;
mutex_unlock(&bo->dev->struct_mutex);
}
old_mem->mm_node = NULL;
@@ -57,7 +56,7 @@ int drm_bo_move_ttm(struct drm_buffer_object *bo,
uint64_t save_proposed_flags = old_mem->proposed_flags;
int ret;
- if (old_mem->mem_type == DRM_BO_MEM_TT) {
+ if (old_mem->mem_type != DRM_BO_MEM_LOCAL) {
if (evict)
drm_ttm_evict(ttm);
else
diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c
index 9d80327f..0ca0c408 100644
--- a/linux-core/drm_fence.c
+++ b/linux-core/drm_fence.c
@@ -520,8 +520,10 @@ int drm_fence_object_create(struct drm_device *dev, uint32_t fence_class,
struct drm_fence_manager *fm = &dev->fm;
fence = drm_ctl_calloc(1, sizeof(*fence), DRM_MEM_FENCE);
- if (!fence)
+ if (!fence) {
+ DRM_ERROR("Out of memory creating fence object\n");
return -ENOMEM;
+ }
ret = drm_fence_object_init(dev, fence_class, type, flags, fence);
if (ret) {
drm_fence_usage_deref_unlocked(&fence);
diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c
index 402a680f..12e01414 100644
--- a/linux-core/drm_memory.c
+++ b/linux-core/drm_memory.c
@@ -39,8 +39,10 @@
static struct {
spinlock_t lock;
uint64_t cur_used;
+ uint64_t emer_used;
uint64_t low_threshold;
uint64_t high_threshold;
+ uint64_t emer_threshold;
} drm_memctl = {
.lock = SPIN_LOCK_UNLOCKED
};
@@ -59,14 +61,30 @@ static inline size_t drm_size_align(size_t size)
int drm_alloc_memctl(size_t size)
{
- int ret;
+ int ret = 0;
unsigned long a_size = drm_size_align(size);
+ unsigned long new_used = drm_memctl.cur_used + a_size;
spin_lock(&drm_memctl.lock);
- ret = ((drm_memctl.cur_used + a_size) > drm_memctl.high_threshold) ?
- -ENOMEM : 0;
- if (!ret)
- drm_memctl.cur_used += a_size;
+ if (unlikely(new_used > drm_memctl.high_threshold)) {
+ if (!DRM_SUSER(DRM_CURPROC) ||
+ (new_used + drm_memctl.emer_used > drm_memctl.emer_threshold) ||
+ (a_size > 2*PAGE_SIZE)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Allow small root-only allocations, even if the
+ * high threshold is exceeded.
+ */
+
+ new_used -= drm_memctl.high_threshold;
+ drm_memctl.emer_used += new_used;
+ a_size -= new_used;
+ }
+ drm_memctl.cur_used += a_size;
+out:
spin_unlock(&drm_memctl.lock);
return ret;
}
@@ -77,19 +95,30 @@ void drm_free_memctl(size_t size)
unsigned long a_size = drm_size_align(size);
spin_lock(&drm_memctl.lock);
+ if (likely(a_size >= drm_memctl.emer_used)) {
+ a_size -= drm_memctl.emer_used;
+ drm_memctl.emer_used = 0;
+ } else {
+ drm_memctl.emer_used -= a_size;
+ a_size = 0;
+ }
drm_memctl.cur_used -= a_size;
spin_unlock(&drm_memctl.lock);
}
EXPORT_SYMBOL(drm_free_memctl);
void drm_query_memctl(uint64_t *cur_used,
+ uint64_t *emer_used,
uint64_t *low_threshold,
- uint64_t *high_threshold)
+ uint64_t *high_threshold,
+ uint64_t *emer_threshold)
{
spin_lock(&drm_memctl.lock);
*cur_used = drm_memctl.cur_used;
+ *emer_used = drm_memctl.emer_used;
*low_threshold = drm_memctl.low_threshold;
*high_threshold = drm_memctl.high_threshold;
+ *emer_threshold = drm_memctl.emer_threshold;
spin_unlock(&drm_memctl.lock);
}
EXPORT_SYMBOL(drm_query_memctl);
@@ -99,9 +128,12 @@ void drm_init_memctl(size_t p_low_threshold,
size_t unit_size)
{
spin_lock(&drm_memctl.lock);
+ drm_memctl.emer_used = 0;
drm_memctl.cur_used = 0;
drm_memctl.low_threshold = p_low_threshold * unit_size;
drm_memctl.high_threshold = p_high_threshold * unit_size;
+ drm_memctl.emer_threshold = (drm_memctl.high_threshold >> 4) +
+ drm_memctl.high_threshold;
spin_unlock(&drm_memctl.lock);
}
@@ -294,7 +326,12 @@ static void *agp_remap(unsigned long offset, unsigned long size,
return NULL;
}
#endif /* agp */
-
+#else
+static void *agp_remap(unsigned long offset, unsigned long size,
+ struct drm_device * dev)
+{
+ return NULL;
+}
#endif /* debug_memory */
void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c
index e10501f2..b6748b9b 100644
--- a/linux-core/drm_proc.c
+++ b/linux-core/drm_proc.c
@@ -446,9 +446,10 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
struct drm_buffer_manager *bm = &dev->bm;
struct drm_fence_manager *fm = &dev->fm;
uint64_t used_mem;
+ uint64_t used_emer;
uint64_t low_mem;
uint64_t high_mem;
-
+ uint64_t emer_mem;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
@@ -477,7 +478,7 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n");
}
- drm_query_memctl(&used_mem, &low_mem, &high_mem);
+ drm_query_memctl(&used_mem, &used_emer, &low_mem, &high_mem, &emer_mem);
if (used_mem > 16*PAGE_SIZE) {
DRM_PROC_PRINT("Used object memory is %lu pages.\n",
@@ -486,10 +487,19 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("Used object memory is %lu bytes.\n",
(unsigned long) used_mem);
}
+ if (used_emer > 16*PAGE_SIZE) {
+ DRM_PROC_PRINT("Used emergency memory is %lu pages.\n",
+ (unsigned long) (used_emer >> PAGE_SHIFT));
+ } else {
+ DRM_PROC_PRINT("Used emergency memory is %lu bytes.\n\n",
+ (unsigned long) used_emer);
+ }
DRM_PROC_PRINT("Soft object memory usage threshold is %lu pages.\n",
(unsigned long) (low_mem >> PAGE_SHIFT));
DRM_PROC_PRINT("Hard object memory usage threshold is %lu pages.\n",
(unsigned long) (high_mem >> PAGE_SHIFT));
+ DRM_PROC_PRINT("Emergency root only memory usage threshold is %lu pages.\n",
+ (unsigned long) (emer_mem >> PAGE_SHIFT));
DRM_PROC_PRINT("\n");
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index cc80b132..e991254f 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -299,13 +299,13 @@ int drm_ttm_populate(struct drm_ttm *ttm)
return 0;
be = ttm->be;
- if (ttm->page_flags & DRM_TTM_PAGE_WRITE) {
- for (i = 0; i < ttm->num_pages; ++i) {
- page = drm_ttm_get_page(ttm, i);
- if (!page)
- return -ENOMEM;
- }
+
+ for (i = 0; i < ttm->num_pages; ++i) {
+ page = drm_ttm_get_page(ttm, i);
+ if (!page)
+ return -ENOMEM;
}
+
be->func->populate(be, ttm->num_pages, ttm->pages, ttm->dummy_read_page);
ttm->state = ttm_unbound;
return 0;