Commit 6b9d89b4 authored by Chris Wilson's avatar Chris Wilson Committed by Dave Airlie

drm: Add colouring to the range allocator

In order to support snoopable memory on non-LLC architectures (so that
we can bind vgem objects into the i915 GATT for example), we have to
avoid the prefetcher on the GPU from crossing memory domains and so
prevent allocation of a snoopable PTE immediately following an uncached
PTE. To do that, we need to extend the range allocator with support for
tracking and segregating different node colours.

This will be used by i915 to segregate memory domains within the GTT.

v2: Now with more drm_mm helpers and less driver interference.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Dave Airlie <airlied@redhat.com
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Jerome Glisse <jglisse@redhat.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarDave Airlie <airlied@gmail.com>
parent 49099c49
...@@ -354,7 +354,7 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj) ...@@ -354,7 +354,7 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj)
/* Get a DRM GEM mmap offset allocated... */ /* Get a DRM GEM mmap offset allocated... */
list->file_offset_node = drm_mm_search_free(&mm->offset_manager, list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
obj->size / PAGE_SIZE, 0, 0); obj->size / PAGE_SIZE, 0, false);
if (!list->file_offset_node) { if (!list->file_offset_node) {
DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
......
This diff is collapsed.
...@@ -2748,8 +2748,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, ...@@ -2748,8 +2748,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
if (map_and_fenceable) if (map_and_fenceable)
free_space = free_space =
drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
size, alignment, 0, size, alignment,
dev_priv->mm.gtt_mappable_end, 0, dev_priv->mm.gtt_mappable_end,
0); 0);
else else
free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
...@@ -2760,7 +2760,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, ...@@ -2760,7 +2760,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
obj->gtt_space = obj->gtt_space =
drm_mm_get_block_range_generic(free_space, drm_mm_get_block_range_generic(free_space,
size, alignment, 0, size, alignment, 0,
dev_priv->mm.gtt_mappable_end, 0, dev_priv->mm.gtt_mappable_end,
0); 0);
else else
obj->gtt_space = obj->gtt_space =
......
...@@ -78,11 +78,12 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, ...@@ -78,11 +78,12 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
INIT_LIST_HEAD(&unwind_list); INIT_LIST_HEAD(&unwind_list);
if (mappable) if (mappable)
drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size, drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space,
alignment, 0, min_size, alignment, 0,
dev_priv->mm.gtt_mappable_end); 0, dev_priv->mm.gtt_mappable_end);
else else
drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); drm_mm_init_scan(&dev_priv->mm.gtt_space,
min_size, alignment, 0);
/* First see if there is a large enough contiguous idle region... */ /* First see if there is a large enough contiguous idle region... */
list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
......
...@@ -50,6 +50,7 @@ struct drm_mm_node { ...@@ -50,6 +50,7 @@ struct drm_mm_node {
unsigned scanned_next_free : 1; unsigned scanned_next_free : 1;
unsigned scanned_preceeds_hole : 1; unsigned scanned_preceeds_hole : 1;
unsigned allocated : 1; unsigned allocated : 1;
unsigned long color;
unsigned long start; unsigned long start;
unsigned long size; unsigned long size;
struct drm_mm *mm; struct drm_mm *mm;
...@@ -66,6 +67,7 @@ struct drm_mm { ...@@ -66,6 +67,7 @@ struct drm_mm {
spinlock_t unused_lock; spinlock_t unused_lock;
unsigned int scan_check_range : 1; unsigned int scan_check_range : 1;
unsigned scan_alignment; unsigned scan_alignment;
unsigned long scan_color;
unsigned long scan_size; unsigned long scan_size;
unsigned long scan_hit_start; unsigned long scan_hit_start;
unsigned scan_hit_size; unsigned scan_hit_size;
...@@ -73,6 +75,9 @@ struct drm_mm { ...@@ -73,6 +75,9 @@ struct drm_mm {
unsigned long scan_start; unsigned long scan_start;
unsigned long scan_end; unsigned long scan_end;
struct drm_mm_node *prev_scanned_node; struct drm_mm_node *prev_scanned_node;
void (*color_adjust)(struct drm_mm_node *node, unsigned long color,
unsigned long *start, unsigned long *end);
}; };
static inline bool drm_mm_node_allocated(struct drm_mm_node *node) static inline bool drm_mm_node_allocated(struct drm_mm_node *node)
...@@ -100,11 +105,13 @@ static inline bool drm_mm_initialized(struct drm_mm *mm) ...@@ -100,11 +105,13 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
unsigned long size, unsigned long size,
unsigned alignment, unsigned alignment,
unsigned long color,
int atomic); int atomic);
extern struct drm_mm_node *drm_mm_get_block_range_generic( extern struct drm_mm_node *drm_mm_get_block_range_generic(
struct drm_mm_node *node, struct drm_mm_node *node,
unsigned long size, unsigned long size,
unsigned alignment, unsigned alignment,
unsigned long color,
unsigned long start, unsigned long start,
unsigned long end, unsigned long end,
int atomic); int atomic);
...@@ -112,13 +119,13 @@ static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, ...@@ -112,13 +119,13 @@ static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
unsigned long size, unsigned long size,
unsigned alignment) unsigned alignment)
{ {
return drm_mm_get_block_generic(parent, size, alignment, 0); return drm_mm_get_block_generic(parent, size, alignment, 0, 0);
} }
static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent, static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
unsigned long size, unsigned long size,
unsigned alignment) unsigned alignment)
{ {
return drm_mm_get_block_generic(parent, size, alignment, 1); return drm_mm_get_block_generic(parent, size, alignment, 0, 1);
} }
static inline struct drm_mm_node *drm_mm_get_block_range( static inline struct drm_mm_node *drm_mm_get_block_range(
struct drm_mm_node *parent, struct drm_mm_node *parent,
...@@ -127,8 +134,19 @@ static inline struct drm_mm_node *drm_mm_get_block_range( ...@@ -127,8 +134,19 @@ static inline struct drm_mm_node *drm_mm_get_block_range(
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
{ {
return drm_mm_get_block_range_generic(parent, size, alignment, return drm_mm_get_block_range_generic(parent, size, alignment, 0,
start, end, 0); start, end, 0);
}
static inline struct drm_mm_node *drm_mm_get_color_block_range(
struct drm_mm_node *parent,
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end)
{
return drm_mm_get_block_range_generic(parent, size, alignment, color,
start, end, 0);
} }
static inline struct drm_mm_node *drm_mm_get_block_atomic_range( static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
struct drm_mm_node *parent, struct drm_mm_node *parent,
...@@ -137,7 +155,7 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range( ...@@ -137,7 +155,7 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
{ {
return drm_mm_get_block_range_generic(parent, size, alignment, return drm_mm_get_block_range_generic(parent, size, alignment, 0,
start, end, 1); start, end, 1);
} }
extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
...@@ -149,18 +167,59 @@ extern int drm_mm_insert_node_in_range(struct drm_mm *mm, ...@@ -149,18 +167,59 @@ extern int drm_mm_insert_node_in_range(struct drm_mm *mm,
extern void drm_mm_put_block(struct drm_mm_node *cur); extern void drm_mm_put_block(struct drm_mm_node *cur);
extern void drm_mm_remove_node(struct drm_mm_node *node); extern void drm_mm_remove_node(struct drm_mm_node *node);
extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, extern struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
unsigned long size, unsigned long size,
unsigned alignment, unsigned alignment,
int best_match); unsigned long color,
extern struct drm_mm_node *drm_mm_search_free_in_range( bool best_match);
extern struct drm_mm_node *drm_mm_search_free_in_range_generic(
const struct drm_mm *mm,
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end,
bool best_match);
static inline struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
unsigned long size,
unsigned alignment,
bool best_match)
{
return drm_mm_search_free_generic(mm,size, alignment, 0, best_match);
}
static inline struct drm_mm_node *drm_mm_search_free_in_range(
const struct drm_mm *mm, const struct drm_mm *mm,
unsigned long size, unsigned long size,
unsigned alignment, unsigned alignment,
unsigned long start, unsigned long start,
unsigned long end, unsigned long end,
int best_match); bool best_match)
extern int drm_mm_init(struct drm_mm *mm, unsigned long start, {
return drm_mm_search_free_in_range_generic(mm, size, alignment, 0,
start, end, best_match);
}
static inline struct drm_mm_node *drm_mm_search_free_color(const struct drm_mm *mm,
unsigned long size,
unsigned alignment,
unsigned long color,
bool best_match)
{
return drm_mm_search_free_generic(mm,size, alignment, color, best_match);
}
static inline struct drm_mm_node *drm_mm_search_free_in_range_color(
const struct drm_mm *mm,
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end,
bool best_match)
{
return drm_mm_search_free_in_range_generic(mm, size, alignment, color,
start, end, best_match);
}
extern int drm_mm_init(struct drm_mm *mm,
unsigned long start,
unsigned long size); unsigned long size);
extern void drm_mm_takedown(struct drm_mm *mm); extern void drm_mm_takedown(struct drm_mm *mm);
extern int drm_mm_clean(struct drm_mm *mm); extern int drm_mm_clean(struct drm_mm *mm);
...@@ -171,10 +230,14 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) ...@@ -171,10 +230,14 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
return block->mm; return block->mm;
} }
void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, void drm_mm_init_scan(struct drm_mm *mm,
unsigned alignment); unsigned long size,
void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size, unsigned alignment,
unsigned long color);
void drm_mm_init_scan_with_range(struct drm_mm *mm,
unsigned long size,
unsigned alignment, unsigned alignment,
unsigned long color,
unsigned long start, unsigned long start,
unsigned long end); unsigned long end);
int drm_mm_scan_add_block(struct drm_mm_node *node); int drm_mm_scan_add_block(struct drm_mm_node *node);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment