[PATCH] drm/mm: Support 4 GiB and larger ranges

Alex Deucher alexdeucher at gmail.com
Wed Mar 4 08:20:15 PST 2015


On Fri, Jan 23, 2015 at 3:05 AM, Thierry Reding
<thierry.reding at gmail.com> wrote:
> From: Thierry Reding <treding at nvidia.com>
>
> The current implementation is limited by the number of addresses that
> fit into an unsigned long. This causes problems on 32-bit Tegra where
> unsigned long is 32-bit but drm_mm is used to manage an IOVA space of
> 4 GiB. Given the 32-bit limitation, the range is limited to 4 GiB - 1
> (or 4 GiB - 4 KiB for page granularity).
>
> This commit changes the start and size of the range to be an unsigned
> 64-bit integer, thus allowing much larger ranges to be supported.
>
> Signed-off-by: Thierry Reding <treding at nvidia.com>

Did this land yet?  I think we need this for for the full fix for the
case when device address space does not match CPU address space.
E.g., radeons have 40 or 48 bit internal address spaces.  On radeon's
with 4GB or more vram, the gart aperture ends up above that in the
GPU's address space which ends up getting truncated on 32 bit.  See
the discussion here:
http://lists.freedesktop.org/archives/dri-devel/2015-March/078614.html

Alex

> ---
>  drivers/gpu/drm/drm_mm.c | 152 ++++++++++++++++++++++++-----------------------
>  include/drm/drm_mm.h     |  52 ++++++++--------
>  2 files changed, 105 insertions(+), 99 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
> index 04a209e2b66d..7fc6f8bd4821 100644
> --- a/drivers/gpu/drm/drm_mm.c
> +++ b/drivers/gpu/drm/drm_mm.c
> @@ -91,29 +91,29 @@
>   */
>
>  static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
> -                                               unsigned long size,
> +                                               u64 size,
>                                                 unsigned alignment,
>                                                 unsigned long color,
>                                                 enum drm_mm_search_flags flags);
>  static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
> -                                               unsigned long size,
> +                                               u64 size,
>                                                 unsigned alignment,
>                                                 unsigned long color,
> -                                               unsigned long start,
> -                                               unsigned long end,
> +                                               u64 start,
> +                                               u64 end,
>                                                 enum drm_mm_search_flags flags);
>
>  static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
>                                  struct drm_mm_node *node,
> -                                unsigned long size, unsigned alignment,
> +                                u64 size, unsigned alignment,
>                                  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);
> -       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
> -       unsigned long adj_start = hole_start;
> -       unsigned long adj_end = hole_end;
> +       u64 hole_start = drm_mm_hole_node_start(hole_node);
> +       u64 hole_end = drm_mm_hole_node_end(hole_node);
> +       u64 adj_start = hole_start;
> +       u64 adj_end = hole_end;
>
>         BUG_ON(node->allocated);
>
> @@ -124,12 +124,15 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
>                 adj_start = adj_end - size;
>
>         if (alignment) {
> -               unsigned tmp = adj_start % alignment;
> -               if (tmp) {
> +               u64 tmp = adj_start;
> +               unsigned rem;
> +
> +               rem = do_div(tmp, alignment);
> +               if (rem) {
>                         if (flags & DRM_MM_CREATE_TOP)
> -                               adj_start -= tmp;
> +                               adj_start -= rem;
>                         else
> -                               adj_start += alignment - tmp;
> +                               adj_start += alignment - rem;
>                 }
>         }
>
> @@ -176,9 +179,9 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
>  int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
>  {
>         struct drm_mm_node *hole;
> -       unsigned long end = node->start + node->size;
> -       unsigned long hole_start;
> -       unsigned long hole_end;
> +       u64 end = node->start + node->size;
> +       u64 hole_start;
> +       u64 hole_end;
>
>         BUG_ON(node == NULL);
>
> @@ -227,7 +230,7 @@ EXPORT_SYMBOL(drm_mm_reserve_node);
>   * 0 on success, -ENOSPC if there's no suitable hole.
>   */
>  int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
> -                              unsigned long size, unsigned alignment,
> +                              u64 size, unsigned alignment,
>                                unsigned long color,
>                                enum drm_mm_search_flags sflags,
>                                enum drm_mm_allocator_flags aflags)
> @@ -246,16 +249,16 @@ EXPORT_SYMBOL(drm_mm_insert_node_generic);
>
>  static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>                                        struct drm_mm_node *node,
> -                                      unsigned long size, unsigned alignment,
> +                                      u64 size, unsigned alignment,
>                                        unsigned long color,
> -                                      unsigned long start, unsigned long end,
> +                                      u64 start, u64 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);
> -       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
> -       unsigned long adj_start = hole_start;
> -       unsigned long adj_end = hole_end;
> +       u64 hole_start = drm_mm_hole_node_start(hole_node);
> +       u64 hole_end = drm_mm_hole_node_end(hole_node);
> +       u64 adj_start = hole_start;
> +       u64 adj_end = hole_end;
>
>         BUG_ON(!hole_node->hole_follows || node->allocated);
>
> @@ -271,12 +274,15 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>                 mm->color_adjust(hole_node, color, &adj_start, &adj_end);
>
>         if (alignment) {
> -               unsigned tmp = adj_start % alignment;
> -               if (tmp) {
> +               u64 tmp = adj_start;
> +               unsigned rem;
> +
> +               rem = do_div(tmp, alignment);
> +               if (rem) {
>                         if (flags & DRM_MM_CREATE_TOP)
> -                               adj_start -= tmp;
> +                               adj_start -= rem;
>                         else
> -                               adj_start += alignment - tmp;
> +                               adj_start += alignment - rem;
>                 }
>         }
>
> @@ -324,9 +330,9 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
>   * 0 on success, -ENOSPC if there's no suitable hole.
>   */
>  int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
> -                                       unsigned long size, unsigned alignment,
> +                                       u64 size, unsigned alignment,
>                                         unsigned long color,
> -                                       unsigned long start, unsigned long end,
> +                                       u64 start, u64 end,
>                                         enum drm_mm_search_flags sflags,
>                                         enum drm_mm_allocator_flags aflags)
>  {
> @@ -387,32 +393,34 @@ void drm_mm_remove_node(struct drm_mm_node *node)
>  }
>  EXPORT_SYMBOL(drm_mm_remove_node);
>
> -static int check_free_hole(unsigned long start, unsigned long end,
> -                          unsigned long size, unsigned alignment)
> +static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
>  {
>         if (end - start < size)
>                 return 0;
>
>         if (alignment) {
> -               unsigned tmp = start % alignment;
> +               u64 tmp = start;
> +               unsigned rem;
> +
> +               rem = do_div(tmp, alignment);
>                 if (tmp)
> -                       start += alignment - tmp;
> +                       start += alignment - rem;
>         }
>
>         return end >= start + size;
>  }
>
>  static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
> -                                                     unsigned long size,
> +                                                     u64 size,
>                                                       unsigned alignment,
>                                                       unsigned long color,
>                                                       enum drm_mm_search_flags flags)
>  {
>         struct drm_mm_node *entry;
>         struct drm_mm_node *best;
> -       unsigned long adj_start;
> -       unsigned long adj_end;
> -       unsigned long best_size;
> +       u64 adj_start;
> +       u64 adj_end;
> +       u64 best_size;
>
>         BUG_ON(mm->scanned_blocks);
>
> @@ -421,7 +429,7 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
>
>         __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
>                                flags & DRM_MM_SEARCH_BELOW) {
> -               unsigned long hole_size = adj_end - adj_start;
> +               u64 hole_size = adj_end - adj_start;
>
>                 if (mm->color_adjust) {
>                         mm->color_adjust(entry, color, &adj_start, &adj_end);
> @@ -445,18 +453,18 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
>  }
>
>  static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
> -                                                       unsigned long size,
> +                                                       u64 size,
>                                                         unsigned alignment,
>                                                         unsigned long color,
> -                                                       unsigned long start,
> -                                                       unsigned long end,
> +                                                       u64 start,
> +                                                       u64 end,
>                                                         enum drm_mm_search_flags flags)
>  {
>         struct drm_mm_node *entry;
>         struct drm_mm_node *best;
> -       unsigned long adj_start;
> -       unsigned long adj_end;
> -       unsigned long best_size;
> +       u64 adj_start;
> +       u64 adj_end;
> +       u64 best_size;
>
>         BUG_ON(mm->scanned_blocks);
>
> @@ -465,7 +473,7 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
>
>         __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
>                                flags & DRM_MM_SEARCH_BELOW) {
> -               unsigned long hole_size = adj_end - adj_start;
> +               u64 hole_size = adj_end - adj_start;
>
>                 if (adj_start < start)
>                         adj_start = start;
> @@ -561,7 +569,7 @@ EXPORT_SYMBOL(drm_mm_replace_node);
>   * adding/removing nodes to/from the scan list are allowed.
>   */
>  void drm_mm_init_scan(struct drm_mm *mm,
> -                     unsigned long size,
> +                     u64 size,
>                       unsigned alignment,
>                       unsigned long color)
>  {
> @@ -594,11 +602,11 @@ EXPORT_SYMBOL(drm_mm_init_scan);
>   * adding/removing nodes to/from the scan list are allowed.
>   */
>  void drm_mm_init_scan_with_range(struct drm_mm *mm,
> -                                unsigned long size,
> +                                u64 size,
>                                  unsigned alignment,
>                                  unsigned long color,
> -                                unsigned long start,
> -                                unsigned long end)
> +                                u64 start,
> +                                u64 end)
>  {
>         mm->scan_color = color;
>         mm->scan_alignment = alignment;
> @@ -627,8 +635,8 @@ bool drm_mm_scan_add_block(struct drm_mm_node *node)
>  {
>         struct drm_mm *mm = node->mm;
>         struct drm_mm_node *prev_node;
> -       unsigned long hole_start, hole_end;
> -       unsigned long adj_start, adj_end;
> +       u64 hole_start, hole_end;
> +       u64 adj_start, adj_end;
>
>         mm->scanned_blocks++;
>
> @@ -731,7 +739,7 @@ EXPORT_SYMBOL(drm_mm_clean);
>   *
>   * Note that @mm must be cleared to 0 before calling this function.
>   */
> -void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
> +void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
>  {
>         INIT_LIST_HEAD(&mm->hole_stack);
>         mm->scanned_blocks = 0;
> @@ -766,18 +774,17 @@ void drm_mm_takedown(struct drm_mm * mm)
>  }
>  EXPORT_SYMBOL(drm_mm_takedown);
>
> -static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
> -                                      const char *prefix)
> +static u64 drm_mm_debug_hole(struct drm_mm_node *entry,
> +                                    const char *prefix)
>  {
> -       unsigned long hole_start, hole_end, hole_size;
> +       u64 hole_start, hole_end, hole_size;
>
>         if (entry->hole_follows) {
>                 hole_start = drm_mm_hole_node_start(entry);
>                 hole_end = drm_mm_hole_node_end(entry);
>                 hole_size = hole_end - hole_start;
> -               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
> -                       prefix, hole_start, hole_end,
> -                       hole_size);
> +               pr_debug("%s %#llx-%#llx: %llu: free\n", prefix, hole_start,
> +                        hole_end, hole_size);
>                 return hole_size;
>         }
>
> @@ -792,35 +799,34 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
>  void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
>  {
>         struct drm_mm_node *entry;
> -       unsigned long total_used = 0, total_free = 0, total = 0;
> +       u64 total_used = 0, total_free = 0, total = 0;
>
>         total_free += drm_mm_debug_hole(&mm->head_node, prefix);
>
>         drm_mm_for_each_node(entry, mm) {
> -               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
> -                       prefix, entry->start, entry->start + entry->size,
> -                       entry->size);
> +               pr_debug("%s %#llx-%#llx: %llu: used\n", prefix, entry->start,
> +                        entry->start + entry->size, entry->size);
>                 total_used += entry->size;
>                 total_free += drm_mm_debug_hole(entry, prefix);
>         }
>         total = total_free + total_used;
>
> -       printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
> -               total_used, total_free);
> +       pr_debug("%s total: %llu, used %llu free %llu\n", prefix, total,
> +                total_used, total_free);
>  }
>  EXPORT_SYMBOL(drm_mm_debug_table);
>
>  #if defined(CONFIG_DEBUG_FS)
> -static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
> +static u64 drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
>  {
> -       unsigned long hole_start, hole_end, hole_size;
> +       u64 hole_start, hole_end, hole_size;
>
>         if (entry->hole_follows) {
>                 hole_start = drm_mm_hole_node_start(entry);
>                 hole_end = drm_mm_hole_node_end(entry);
>                 hole_size = hole_end - hole_start;
> -               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
> -                               hole_start, hole_end, hole_size);
> +               seq_printf(m, "%#llx-%#llx: %llu: free\n", hole_start,
> +                          hole_end, hole_size);
>                 return hole_size;
>         }
>
> @@ -835,20 +841,20 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en
>  int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
>  {
>         struct drm_mm_node *entry;
> -       unsigned long total_used = 0, total_free = 0, total = 0;
> +       u64 total_used = 0, total_free = 0, total = 0;
>
>         total_free += drm_mm_dump_hole(m, &mm->head_node);
>
>         drm_mm_for_each_node(entry, mm) {
> -               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
> -                               entry->start, entry->start + entry->size,
> -                               entry->size);
> +               seq_printf(m, "%#016llx-%#016llx: %llu: used\n", entry->start,
> +                          entry->start + entry->size, entry->size);
>                 total_used += entry->size;
>                 total_free += drm_mm_dump_hole(m, entry);
>         }
>         total = total_free + total_used;
>
> -       seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
> +       seq_printf(m, "total: %llu, used %llu free %llu\n", total,
> +                  total_used, total_free);
>         return 0;
>  }
>  EXPORT_SYMBOL(drm_mm_dump_table);
> diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
> index a24addfdfcec..0de6290df4da 100644
> --- a/include/drm/drm_mm.h
> +++ b/include/drm/drm_mm.h
> @@ -68,8 +68,8 @@ struct drm_mm_node {
>         unsigned scanned_preceeds_hole : 1;
>         unsigned allocated : 1;
>         unsigned long color;
> -       unsigned long start;
> -       unsigned long size;
> +       u64 start;
> +       u64 size;
>         struct drm_mm *mm;
>  };
>
> @@ -82,16 +82,16 @@ struct drm_mm {
>         unsigned int scan_check_range : 1;
>         unsigned scan_alignment;
>         unsigned long scan_color;
> -       unsigned long scan_size;
> -       unsigned long scan_hit_start;
> -       unsigned long scan_hit_end;
> +       u64 scan_size;
> +       u64 scan_hit_start;
> +       u64 scan_hit_end;
>         unsigned scanned_blocks;
> -       unsigned long scan_start;
> -       unsigned long scan_end;
> +       u64 scan_start;
> +       u64 scan_end;
>         struct drm_mm_node *prev_scanned_node;
>
>         void (*color_adjust)(struct drm_mm_node *node, unsigned long color,
> -                            unsigned long *start, unsigned long *end);
> +                            u64 *start, u64 *end);
>  };
>
>  /**
> @@ -124,7 +124,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
>         return mm->hole_stack.next;
>  }
>
> -static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
> +static inline u64 __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
>  {
>         return hole_node->start + hole_node->size;
>  }
> @@ -140,13 +140,13 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no
>   * Returns:
>   * Start of the subsequent hole.
>   */
> -static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
> +static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node)
>  {
>         BUG_ON(!hole_node->hole_follows);
>         return __drm_mm_hole_node_start(hole_node);
>  }
>
> -static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
> +static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
>  {
>         return list_entry(hole_node->node_list.next,
>                           struct drm_mm_node, node_list)->start;
> @@ -163,7 +163,7 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node
>   * Returns:
>   * End of the subsequent hole.
>   */
> -static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
> +static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
>  {
>         return __drm_mm_hole_node_end(hole_node);
>  }
> @@ -222,7 +222,7 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
>
>  int drm_mm_insert_node_generic(struct drm_mm *mm,
>                                struct drm_mm_node *node,
> -                              unsigned long size,
> +                              u64 size,
>                                unsigned alignment,
>                                unsigned long color,
>                                enum drm_mm_search_flags sflags,
> @@ -245,7 +245,7 @@ int drm_mm_insert_node_generic(struct drm_mm *mm,
>   */
>  static inline int drm_mm_insert_node(struct drm_mm *mm,
>                                      struct drm_mm_node *node,
> -                                    unsigned long size,
> +                                    u64 size,
>                                      unsigned alignment,
>                                      enum drm_mm_search_flags flags)
>  {
> @@ -255,11 +255,11 @@ static inline int drm_mm_insert_node(struct drm_mm *mm,
>
>  int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
>                                         struct drm_mm_node *node,
> -                                       unsigned long size,
> +                                       u64 size,
>                                         unsigned alignment,
>                                         unsigned long color,
> -                                       unsigned long start,
> -                                       unsigned long end,
> +                                       u64 start,
> +                                       u64 end,
>                                         enum drm_mm_search_flags sflags,
>                                         enum drm_mm_allocator_flags aflags);
>  /**
> @@ -282,10 +282,10 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
>   */
>  static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
>                                               struct drm_mm_node *node,
> -                                             unsigned long size,
> +                                             u64 size,
>                                               unsigned alignment,
> -                                             unsigned long start,
> -                                             unsigned long end,
> +                                             u64 start,
> +                                             u64 end,
>                                               enum drm_mm_search_flags flags)
>  {
>         return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
> @@ -296,21 +296,21 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
>  void drm_mm_remove_node(struct drm_mm_node *node);
>  void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
>  void drm_mm_init(struct drm_mm *mm,
> -                unsigned long start,
> -                unsigned long size);
> +                u64 start,
> +                u64 size);
>  void drm_mm_takedown(struct drm_mm *mm);
>  bool drm_mm_clean(struct drm_mm *mm);
>
>  void drm_mm_init_scan(struct drm_mm *mm,
> -                     unsigned long size,
> +                     u64 size,
>                       unsigned alignment,
>                       unsigned long color);
>  void drm_mm_init_scan_with_range(struct drm_mm *mm,
> -                                unsigned long size,
> +                                u64 size,
>                                  unsigned alignment,
>                                  unsigned long color,
> -                                unsigned long start,
> -                                unsigned long end);
> +                                u64 start,
> +                                u64 end);
>  bool drm_mm_scan_add_block(struct drm_mm_node *node);
>  bool drm_mm_scan_remove_block(struct drm_mm_node *node);
>
> --
> 2.1.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list