@@ -823,23 +823,8 @@ bool drm_mm_scan_add_block(struct drm_mm_scan *scan,
}
}
- if (mm->color_adjust) {
- /* If allocations need adjusting due to neighbouring colours,
- * we do not have enough information to decide if we need
- * to evict nodes on either side of [adj_start, adj_end].
- * What almost works is
- * hit_start = adj_start + (hole_start - col_start);
- * hit_end = adj_start + scan->size + (hole_end - col_end);
- * but because the decision is only made on the final hole,
- * we may underestimate the required adjustments for an
- * interior allocation.
- */
- scan->hit_start = hole_start;
- scan->hit_end = hole_end;
- } else {
- scan->hit_start = adj_start;
- scan->hit_end = adj_start + scan->size;
- }
+ scan->hit_start = adj_start;
+ scan->hit_end = adj_start + scan->size;
DRM_MM_BUG_ON(scan->hit_start >= scan->hit_end);
DRM_MM_BUG_ON(scan->hit_start < hole_start);
@@ -887,6 +872,33 @@ bool drm_mm_scan_remove_block(struct drm_mm_scan *scan,
}
EXPORT_SYMBOL(drm_mm_scan_remove_block);
+struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)
+{
+ struct drm_mm *mm = scan->mm;
+ struct drm_mm_node *hole;
+ u64 hole_start, hole_end;
+
+ if (!mm->color_adjust)
+ return NULL;
+
+ hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack);
+
+ hole_start = __drm_mm_hole_node_start(hole);
+ hole_end = __drm_mm_hole_node_end(hole);
+
+ DRM_MM_BUG_ON(hole_start > scan->hit_start);
+ DRM_MM_BUG_ON(hole_end < scan->hit_end);
+
+ mm->color_adjust(hole, scan->color, &hole_start, &hole_end);
+ if (hole_start > scan->hit_start)
+ return hole;
+ if (hole_end < scan->hit_end)
+ return list_next_entry(hole, node_list);
+
+ return NULL;
+}
+EXPORT_SYMBOL(drm_mm_scan_color_evict);
+
/**
* drm_mm_init - initialize a drm-mm allocator
* @mm: the drm_mm structure to initialize
@@ -108,6 +108,7 @@ i915_gem_evict_something(struct i915_address_space *vm,
NULL,
}, **phase;
struct i915_vma *vma, *next;
+ struct drm_mm_node *node;
int ret;
lockdep_assert_held(&vm->i915->drm.struct_mutex);
@@ -212,6 +213,11 @@ i915_gem_evict_something(struct i915_address_space *vm,
ret = i915_vma_unbind(vma);
}
+ while (ret == 0 && (node = drm_mm_scan_color_evict(&scan))) {
+ vma = container_of(node, struct i915_vma, node);
+ ret = i915_vma_unbind(vma);
+ }
+
return ret;
}
@@ -1662,6 +1662,11 @@ static int igt_color_evict(void *ignored)
list_for_each_entry(e, &evict_list, link)
drm_mm_remove_node(&e->node);
+ while ((node = drm_mm_scan_color_evict(&scan))) {
+ e = container_of(node, struct evict_node, node);
+ drm_mm_remove_node(&e->node);
+ list_add(&e->link, &evict_list);
+ }
memset(&tmp, 0, sizeof(tmp));
err = drm_mm_insert_node_generic(&mm, &tmp, nsize, n, c,
@@ -1735,6 +1740,11 @@ static int igt_color_evict(void *ignored)
list_for_each_entry(e, &evict_list, link)
drm_mm_remove_node(&e->node);
+ while ((node = drm_mm_scan_color_evict(&scan))) {
+ e = container_of(node, struct evict_node, node);
+ drm_mm_remove_node(&e->node);
+ list_add(&e->link, &evict_list);
+ }
memset(&tmp, 0, sizeof(tmp));
err = drm_mm_insert_node_generic(&mm, &tmp, nsize, n, c,
@@ -1867,6 +1877,11 @@ static int igt_color_evict_range(void *ignored)
list_for_each_entry(e, &evict_list, link)
drm_mm_remove_node(&e->node);
+ while ((node = drm_mm_scan_color_evict(&scan))) {
+ e = container_of(node, struct evict_node, node);
+ drm_mm_remove_node(&e->node);
+ list_add(&e->link, &evict_list);
+ }
memset(&tmp, 0, sizeof(tmp));
err = drm_mm_insert_node_in_range_generic(&mm, &tmp, nsize, n, c,
@@ -1943,6 +1958,11 @@ static int igt_color_evict_range(void *ignored)
list_for_each_entry(e, &evict_list, link)
drm_mm_remove_node(&e->node);
+ while ((node = drm_mm_scan_color_evict(&scan))) {
+ e = container_of(node, struct evict_node, node);
+ drm_mm_remove_node(&e->node);
+ list_add(&e->link, &evict_list);
+ }
memset(&tmp, 0, sizeof(tmp));
err = drm_mm_insert_node_in_range_generic(&mm, &tmp, nsize, n, c,
@@ -403,6 +403,7 @@ bool drm_mm_scan_add_block(struct drm_mm_scan *scan,
struct drm_mm_node *node);
bool drm_mm_scan_remove_block(struct drm_mm_scan *scan,
struct drm_mm_node *node);
+struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan);
void drm_mm_debug_table(const struct drm_mm *mm, const char *prefix);
#ifdef CONFIG_DEBUG_FS
Using mm->color_adjust makes the eviction scanner much tricker since we don't know the actual neighbours of the target hole until after it is created (after scanning is complete). To work out whether we need to evict the neighbours because they impact upon the hole, we have to then check the hole afterwards - requiring an extra step in the user of the eviction scanner when they apply color_adjust. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/drm_mm.c | 46 +++++++++++++++++++++------------ drivers/gpu/drm/i915/i915_gem_evict.c | 6 +++++ drivers/gpu/drm/selftests/test-drm_mm.c | 20 ++++++++++++++ include/drm/drm_mm.h | 1 + 4 files changed, 56 insertions(+), 17 deletions(-)