[PATCH 30/31] drm: Apply tight eviction scanning to color_adjust

Chris Wilson chris at chris-wilson.co.uk
Mon Dec 12 08:42:00 UTC 2016


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 at chris-wilson.co.uk>
---
 drivers/gpu/drm/drm_mm.c                | 48 +++++++++++++++++++++------------
 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, 58 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 4eab82f2a1ef..10d0aceaeb1b 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -824,26 +824,13 @@ 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;
+
 	MM_BUG_ON(scan->hit_start >= scan->hit_end);
 	MM_BUG_ON(scan->hit_start < hole_start);
 	MM_BUG_ON(scan->hit_end > hole_end);
+
 	return true;
 }
 EXPORT_SYMBOL(drm_mm_scan_add_block);
@@ -879,6 +866,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);
+
+	MM_BUG_ON(hole_start > scan->hit_start);
+	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
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 89da9225043f..e4987e354311 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -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;
 }
 
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c
index 19a370a66100..cb8c0c026179 100644
--- a/drivers/gpu/drm/selftests/test-drm_mm.c
+++ b/drivers/gpu/drm/selftests/test-drm_mm.c
@@ -1663,6 +1663,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,
@@ -1736,6 +1741,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,
@@ -1868,6 +1878,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,
@@ -1944,6 +1959,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,
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index c6844d153783..6bd942613c5a 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -396,6 +396,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
-- 
2.11.0



More information about the Intel-gfx-trybot mailing list