[PATCH 32/34] drm: Apply tight eviction scanning to color_adjust
Chris Wilson
chris at chris-wilson.co.uk
Mon Dec 12 11:53:48 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 | 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(-)
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index ba1a244fe6e5..b061066066d8 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -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
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 09ead31a094d..73353f87f46a 100644
--- a/drivers/gpu/drm/selftests/test-drm_mm.c
+++ b/drivers/gpu/drm/selftests/test-drm_mm.c
@@ -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,
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 4ff76d0ab849..884166b91e90 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -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
--
2.11.0
More information about the dri-devel
mailing list