[PATCH 46/48] drm: Optionally create mm blocks from top-to-bottom

David Herrmann dh.herrmann at gmail.com
Sun Dec 8 06:28:04 PST 2013


Hi

On Fri, Dec 6, 2013 at 11:11 PM, Ben Widawsky
<benjamin.widawsky at intel.com> wrote:
> From: Chris Wilson <chris at chris-wilson.co.uk>
>
> Clients like i915 needs to segregate cache domains within the GTT which
> can lead to small amounts of fragmentation. By allocating the uncached
> buffers from the bottom and the cacheable buffers from the top, we can
> reduce the amount of wasted space and also optimize allocation of the
> mappable portion of the GTT to only those buffers that require CPU
> access through the GTT.
>
> v2 by Ben:
> Update callers in i915_gem_object_bind_to_gtt()
> Turn search flags and allocation flags into separate enums
> Make checkpatch happy where logical/easy
>
> v3 by Ben:
> Rebased on top of the many drm_mm changes since the original patches
> Remove ATOMIC from allocator flags (Chris)
> Reverse order of TOPDOWN and BOTTOMUP

CC'ing dri-devel as I'm not subscribed to intel-gfx.

> Cc: David Herrmann <dh.herrmann at gmail.com>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
> ---
>  drivers/gpu/drm/drm_mm.c            | 56 +++++++++++++++++++++++++++----------
>  drivers/gpu/drm/i915/i915_gem.c     |  3 +-
>  drivers/gpu/drm/i915/i915_gem_gtt.c |  2 +-
>  include/drm/drm_mm.h                | 29 ++++++++++++++++---
>  4 files changed, 69 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
> index af93cc5..4f5e4f6 100644
> --- a/drivers/gpu/drm/drm_mm.c
> +++ b/drivers/gpu/drm/drm_mm.c
> @@ -65,7 +65,8 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
>  static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
>                                  struct drm_mm_node *node,
>                                  unsigned long size, unsigned alignment,
> -                                unsigned long color)
> +                                unsigned long color,
> +                                enum drm_mm_allocator_flags flags)
>  {
>         struct drm_mm *mm = hole_node->mm;
>         unsigned long hole_start = drm_mm_hole_node_start(hole_node);
> @@ -78,12 +79,22 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
>         if (mm->color_adjust)
>                 mm->color_adjust(hole_node, color, &adj_start, &adj_end);
>
> +       if (flags & DRM_MM_CREATE_TOP)
> +               adj_start = adj_end - size;
> +

That should be above the call to mm->color_adjust(), imo. But I'm not
entirely sure what kind of adjustments drivers do. At least you should
be consistend with the range-helper below where you call it *before*
the color-adjustment.

>         if (alignment) {
>                 unsigned tmp = adj_start % alignment;
> -               if (tmp)
> -                       adj_start += alignment - tmp;
> +               if (tmp) {
> +                       if (flags & DRM_MM_CREATE_TOP)
> +                               adj_start -= tmp;
> +                       else
> +                               adj_start += alignment - tmp;
> +               }
>         }
>
> +       BUG_ON(adj_start < hole_start);
> +       BUG_ON(adj_end > hole_end);
> +
>         if (adj_start == hole_start) {
>                 hole_node->hole_follows = 0;
>                 list_del(&hole_node->hole_stack);
> @@ -155,16 +166,17 @@ EXPORT_SYMBOL(drm_mm_reserve_node);
>  int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
>                                unsigned long size, unsigned alignment,
>                                unsigned long color,
> -                              enum drm_mm_search_flags flags)
> +                              enum drm_mm_search_flags sflags,
> +                              enum drm_mm_allocator_flags aflags)
>  {
>         struct drm_mm_node *hole_node;
>
>         hole_node = drm_mm_search_free_generic(mm, size, alignment,
> -                                              color, flags);
> +                                              color, sflags);
>         if (!hole_node)
>                 return -ENOSPC;
>
> -       drm_mm_insert_helper(hole_node, node, size, alignment, color);
> +       drm_mm_insert_helper(hole_node, node, size, alignment, color, aflags);
>         return 0;
>  }
>  EXPORT_SYMBOL(drm_mm_insert_node_generic);
> @@ -173,7 +185,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>                                        struct drm_mm_node *node,
>                                        unsigned long size, unsigned alignment,
>                                        unsigned long color,
> -                                      unsigned long start, unsigned long end)
> +                                      unsigned long start, unsigned long end,
> +                                      enum drm_mm_allocator_flags flags)
>  {
>         struct drm_mm *mm = hole_node->mm;
>         unsigned long hole_start = drm_mm_hole_node_start(hole_node);
> @@ -188,13 +201,20 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>         if (adj_end > end)
>                 adj_end = end;
>
> +       if (flags & DRM_MM_CREATE_TOP)
> +               adj_start = adj_end - size;
> +
>         if (mm->color_adjust)
>                 mm->color_adjust(hole_node, color, &adj_start, &adj_end);
>
>         if (alignment) {
>                 unsigned tmp = adj_start % alignment;
> -               if (tmp)
> -                       adj_start += alignment - tmp;
> +               if (tmp) {
> +                       if (flags & DRM_MM_CREATE_TOP)
> +                               adj_start -= tmp;
> +                       else
> +                               adj_start += alignment - tmp;
> +               }
>         }
>
>         if (adj_start == hole_start) {
> @@ -211,6 +231,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>         INIT_LIST_HEAD(&node->hole_stack);
>         list_add(&node->node_list, &hole_node->node_list);
>
> +       BUG_ON(node->start < start);
> +       BUG_ON(node->start < adj_start);
>         BUG_ON(node->start + node->size > adj_end);
>         BUG_ON(node->start + node->size > end);
>
> @@ -227,21 +249,23 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>   * restricted allocations. The preallocated memory node must be cleared.
>   */
>  int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
> -                                       unsigned long size, unsigned alignment, unsigned long color,
> +                                       unsigned long size, unsigned alignment,
> +                                       unsigned long color,
>                                         unsigned long start, unsigned long end,
> -                                       enum drm_mm_search_flags flags)
> +                                       enum drm_mm_search_flags sflags,
> +                                       enum drm_mm_allocator_flags aflags)
>  {
>         struct drm_mm_node *hole_node;
>
>         hole_node = drm_mm_search_free_in_range_generic(mm,
>                                                         size, alignment, color,
> -                                                       start, end, flags);
> +                                                       start, end, sflags);
>         if (!hole_node)
>                 return -ENOSPC;
>
>         drm_mm_insert_helper_range(hole_node, node,
>                                    size, alignment, color,
> -                                  start, end);
> +                                  start, end, aflags);
>         return 0;
>  }
>  EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic);
> @@ -315,7 +339,8 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
>         best = NULL;
>         best_size = ~0UL;
>
> -       drm_mm_for_each_hole(entry, mm, adj_start, adj_end) {
> +       __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
> +                              flags & DRM_MM_SEARCH_BELOW) {
>                 if (mm->color_adjust) {
>                         mm->color_adjust(entry, color, &adj_start, &adj_end);
>                         if (adj_end <= adj_start)
> @@ -356,7 +381,8 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
>         best = NULL;
>         best_size = ~0UL;
>
> -       drm_mm_for_each_hole(entry, mm, adj_start, adj_end) {
> +       __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
> +                              flags & DRM_MM_SEARCH_BELOW) {
>                 if (adj_start < start)
>                         adj_start = start;
>                 if (adj_end > end)
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index a03c262..1360f89 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -3280,7 +3280,8 @@ search_free:
>         ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
>                                                   size, alignment,
>                                                   obj->cache_level, 1, gtt_max,
> -                                                 DRM_MM_SEARCH_DEFAULT);
> +                                                 DRM_MM_SEARCH_DEFAULT,
> +                                                 DRM_MM_CREATE_DEFAULT);
>         if (ret) {
>                 ret = i915_gem_evict_something(dev, vm, size, alignment,
>                                                obj->cache_level,
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 998f9a0..37832e4 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -861,7 +861,7 @@ alloc:
>                                                   &ppgtt->node, GEN6_PD_SIZE,
>                                                   GEN6_PD_ALIGN, 0,
>                                                   0, dev_priv->gtt.base.total,
> -                                                 DRM_MM_SEARCH_DEFAULT);
> +                                                 DRM_MM_BOTTOMUP);
>         if (ret == -ENOSPC && !retried) {
>                 ret = i915_gem_evict_something(dev, &dev_priv->gtt.base,
>                                                GEN6_PD_SIZE, GEN6_PD_ALIGN,
> diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
> index cba6786..36c1d8f 100644
> --- a/include/drm/drm_mm.h
> +++ b/include/drm/drm_mm.h
> @@ -47,8 +47,17 @@
>  enum drm_mm_search_flags {
>         DRM_MM_SEARCH_DEFAULT =         0,
>         DRM_MM_SEARCH_BEST =            1 << 0,
> +       DRM_MM_SEARCH_BELOW =           1 << 1,

SEARCH_BEST and SEARCH_BELOW are (almost) mutually exclusive, right?
Hm, but doesn't really hurt if someone specifies both so should be
fine.

Regarding the names: Something like DRM_MM_SEARCH_FROM_TOP sounds
better to my German ears, but what do I know.. (same below for
CREATE_TOP->CREATE_FROM_TOP).

>  };
>
> +enum drm_mm_allocator_flags {
> +       DRM_MM_CREATE_DEFAULT =         0,
> +       DRM_MM_CREATE_TOP =             1 << 0,
> +};
> +
> +#define DRM_MM_BOTTOMUP DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT
> +#define DRM_MM_TOPDOWN DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP
> +

That is ugly. Is that really needed? The drm_mm calls already have a
lot of arguments, I don't think we should hide the extra flag just to
save one. If it's about the more obvious name, why not add "static
inline" helpers? debuggers hate pre-processor magic..

Apart from the adjust_color() thing, I'm fine with this patch whether
you change names/arguments or not. So with that fixed:
Reviewed-by: David Herrmann <dh.herrmann at gmail.com>

Thanks
David

>  struct drm_mm_node {
>         struct list_head node_list;
>         struct list_head hole_stack;
> @@ -133,6 +142,14 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
>              1 : 0; \
>              entry = list_entry(entry->hole_stack.next, struct drm_mm_node, hole_stack))
>
> +#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \
> +       for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
> +            &entry->hole_stack != &(mm)->hole_stack ? \
> +            hole_start = drm_mm_hole_node_start(entry), \
> +            hole_end = drm_mm_hole_node_end(entry), \
> +            1 : 0; \
> +            entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack))
> +
>  /*
>   * Basic range manager support (drm_mm.c)
>   */
> @@ -143,14 +160,16 @@ extern int drm_mm_insert_node_generic(struct drm_mm *mm,
>                                       unsigned long size,
>                                       unsigned alignment,
>                                       unsigned long color,
> -                                     enum drm_mm_search_flags flags);
> +                                     enum drm_mm_search_flags sflags,
> +                                     enum drm_mm_allocator_flags aflags);
>  static inline int drm_mm_insert_node(struct drm_mm *mm,
>                                      struct drm_mm_node *node,
>                                      unsigned long size,
>                                      unsigned alignment,
>                                      enum drm_mm_search_flags flags)
>  {
> -       return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags);
> +       return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags,
> +                                         DRM_MM_CREATE_DEFAULT);
>  }
>
>  extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
> @@ -160,7 +179,8 @@ extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
>                                        unsigned long color,
>                                        unsigned long start,
>                                        unsigned long end,
> -                                      enum drm_mm_search_flags flags);
> +                                      enum drm_mm_search_flags sflags,
> +                                      enum drm_mm_allocator_flags aflags);
>  static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
>                                               struct drm_mm_node *node,
>                                               unsigned long size,
> @@ -170,7 +190,8 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
>                                               enum drm_mm_search_flags flags)
>  {
>         return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
> -                                                  0, start, end, flags);
> +                                                  0, start, end, flags,
> +                                                  DRM_MM_CREATE_DEFAULT);
>  }
>
>  extern void drm_mm_remove_node(struct drm_mm_node *node);
> --
> 1.8.4.2
>


More information about the dri-devel mailing list