#define HOLE_SIZE(NODE) ((NODE)->hole_size)
 #define HOLE_ADDR(NODE) (__drm_mm_hole_node_start(NODE))
 
+static u64 rb_to_hole_size(struct rb_node *rb)
+{
+       return rb_entry(rb, struct drm_mm_node, rb_hole_size)->hole_size;
+}
+
+static void insert_hole_size(struct rb_root_cached *root,
+                            struct drm_mm_node *node)
+{
+       struct rb_node **link = &root->rb_root.rb_node, *rb = NULL;
+       u64 x = node->hole_size;
+       bool first = true;
+
+       while (*link) {
+               rb = *link;
+               if (x > rb_to_hole_size(rb)) {
+                       link = &rb->rb_left;
+               } else {
+                       link = &rb->rb_right;
+                       first = false;
+               }
+       }
+
+       rb_link_node(&node->rb_hole_size, rb, link);
+       rb_insert_color_cached(&node->rb_hole_size, root, first);
+}
+
 static void add_hole(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
                __drm_mm_hole_node_end(node) - __drm_mm_hole_node_start(node);
        DRM_MM_BUG_ON(!drm_mm_hole_follows(node));
 
-       RB_INSERT(mm->holes_size, rb_hole_size, HOLE_SIZE);
+       insert_hole_size(&mm->holes_size, node);
        RB_INSERT(mm->holes_addr, rb_hole_addr, HOLE_ADDR);
 
        list_add(&node->hole_stack, &mm->hole_stack);
        DRM_MM_BUG_ON(!drm_mm_hole_follows(node));
 
        list_del(&node->hole_stack);
-       rb_erase(&node->rb_hole_size, &node->mm->holes_size);
+       rb_erase_cached(&node->rb_hole_size, &node->mm->holes_size);
        rb_erase(&node->rb_hole_addr, &node->mm->holes_addr);
        node->hole_size = 0;
 
 
 static struct drm_mm_node *best_hole(struct drm_mm *mm, u64 size)
 {
-       struct rb_node *best = NULL;
-       struct rb_node **link = &mm->holes_size.rb_node;
+       struct rb_node *rb = mm->holes_size.rb_root.rb_node;
+       struct drm_mm_node *best = NULL;
 
-       while (*link) {
-               struct rb_node *rb = *link;
+       do {
+               struct drm_mm_node *node =
+                       rb_entry(rb, struct drm_mm_node, rb_hole_size);
 
-               if (size <= rb_hole_size(rb)) {
-                       link = &rb->rb_left;
-                       best = rb;
+               if (size <= node->hole_size) {
+                       best = node;
+                       rb = rb->rb_right;
                } else {
-                       link = &rb->rb_right;
+                       rb = rb->rb_left;
                }
-       }
+       } while (rb);
 
-       return rb_hole_size_to_node(best);
+       return best;
 }
 
 static struct drm_mm_node *find_hole(struct drm_mm *mm, u64 addr)
 {
+       struct rb_node *rb = mm->holes_addr.rb_node;
        struct drm_mm_node *node = NULL;
-       struct rb_node **link = &mm->holes_addr.rb_node;
 
-       while (*link) {
+       while (rb) {
                u64 hole_start;
 
-               node = rb_hole_addr_to_node(*link);
+               node = rb_hole_addr_to_node(rb);
                hole_start = __drm_mm_hole_node_start(node);
 
                if (addr < hole_start)
-                       link = &node->rb_hole_addr.rb_left;
+                       rb = node->rb_hole_addr.rb_left;
                else if (addr > hole_start + node->hole_size)
-                       link = &node->rb_hole_addr.rb_right;
+                       rb = node->rb_hole_addr.rb_right;
                else
                        break;
        }
           u64 start, u64 end, u64 size,
           enum drm_mm_insert_mode mode)
 {
-       if (RB_EMPTY_ROOT(&mm->holes_size))
-               return NULL;
-
        switch (mode) {
        default:
        case DRM_MM_INSERT_BEST:
        switch (mode) {
        default:
        case DRM_MM_INSERT_BEST:
-               return rb_hole_size_to_node(rb_next(&node->rb_hole_size));
+               return rb_hole_size_to_node(rb_prev(&node->rb_hole_size));
 
        case DRM_MM_INSERT_LOW:
                return rb_hole_addr_to_node(rb_next(&node->rb_hole_addr));
 }
 EXPORT_SYMBOL(drm_mm_reserve_node);
 
+static u64 rb_to_hole_size_or_zero(struct rb_node *rb)
+{
+       return rb ? rb_to_hole_size(rb) : 0;
+}
+
 /**
  * drm_mm_insert_node_in_range - ranged search for space and insert @node
  * @mm: drm_mm to allocate from
        if (unlikely(size == 0 || range_end - range_start < size))
                return -ENOSPC;
 
+       if (rb_to_hole_size_or_zero(rb_first_cached(&mm->holes_size)) < size)
+               return -ENOSPC;
+
        if (alignment <= 1)
                alignment = 0;
 
 
        if (drm_mm_hole_follows(old)) {
                list_replace(&old->hole_stack, &new->hole_stack);
-               rb_replace_node(&old->rb_hole_size,
-                               &new->rb_hole_size,
-                               &mm->holes_size);
+               rb_replace_node_cached(&old->rb_hole_size,
+                                      &new->rb_hole_size,
+                                      &mm->holes_size);
                rb_replace_node(&old->rb_hole_addr,
                                &new->rb_hole_addr,
                                &mm->holes_addr);
 
        INIT_LIST_HEAD(&mm->hole_stack);
        mm->interval_tree = RB_ROOT_CACHED;
-       mm->holes_size = RB_ROOT;
+       mm->holes_size = RB_ROOT_CACHED;
        mm->holes_addr = RB_ROOT;
 
        /* Clever trick to avoid a special case in the free hole tracking. */