diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
index 11bb59399471..6c795e1b3247 100644
--- a/drivers/gpu/drm/drm_buddy.c
+++ b/drivers/gpu/drm/drm_buddy.c
@@ -386,6 +386,140 @@ alloc_range_bias(struct drm_buddy *mm,
 	return ERR_PTR(err);
 }
 
+static void __continuous_block_in_tree(struct drm_buddy_block *top_block,
+				       struct list_head *fbl,
+				       int left,
+				       int min_order)
+{
+	/*
+	 * Look for continuous memory of
+	 * [top_block) when left is true or (top_block] when left is false.
+	 * The list of fbl looks like (top_block1][free_block][...][top_blockX).
+	 * Memory offset is in ascending order.
+	 */
+	while (top_block) {
+		struct drm_buddy_block *block = top_block;
+		int order;
+
+		while (drm_buddy_block_is_split(block))
+			block = left ? block->left : block->right;
+
+		order = drm_buddy_block_order(block);
+		if (order < min_order || !drm_buddy_block_is_free(block))
+			return;
+
+		if (left)
+			list_add_tail(&block->tmp_link, fbl);
+		else
+			list_add(&block->tmp_link, fbl);
+
+		if (order == min_order)
+			return;
+		top_block = __get_buddy(block);
+	}
+}
+
+static bool __free_block_in_order(struct list_head *fbl,
+				  struct drm_buddy_block *cur,
+				  int order,
+				  struct drm_buddy_block **first,
+				  struct drm_buddy_block **last)
+{
+	struct drm_buddy_block *fb = cur, *lb = list_next_entry(cur, tmp_link);
+	u64 pages = BIT(order);
+	u64 cur_pages = 0;
+
+	/*
+	 * Look for continuous memory which satisfy requested order.
+	 * Memory in list fbl are already in below order.
+	 * 1) Memory offset are in ascending order.
+	 * 2) Memory size are in ascending order from left to middle and
+	 * descending order from middle to right.
+	 * So walk through the list of fbl from middle to both sides to
+	 * choose the bigger memory.
+	 * This is because one memory with order X are composed with 2 of order X-1
+	 * or 1 of order X-1 and 2 of order X-2, etc. Looks like below.
+	 *      n
+	 *    {∑(X - y)} + {2 * (X-n-1))}
+	 *      1
+	 * And the last 2 memory of order (X-n-1) are at the two sides of list.
+	 */
+	list_for_each_entry_from_reverse(fb, fbl, tmp_link) {
+		int prev_order = drm_buddy_block_order(fb);
+
+		list_for_each_entry_from(lb, fbl, tmp_link) {
+			int next_order = drm_buddy_block_order(lb);
+
+			if (prev_order <= next_order)
+				cur_pages += BIT(next_order);
+			else
+				break;
+		}
+
+		cur_pages += BIT(prev_order);
+		if (pages == cur_pages) {
+			*first = fb;
+			*last = list_prev_entry(lb, tmp_link);
+			return true;
+		}
+		BUG_ON(pages < cur_pages);
+	}
+
+	*first = *last = NULL;
+	return false;
+}
+
+static struct drm_buddy_block *
+find_continuous_blocks(struct drm_buddy *mm,
+		       int order,
+		       unsigned long flags,
+		       struct drm_buddy_block **lb)
+{
+	struct list_head *head = &mm->free_list[order - 1];
+	struct drm_buddy_block *free_block, *first = NULL, *last = NULL;
+
+	/*
+	 * Look for continuous free memory in buddy and buddy-in-law.
+	 * IOW, the most left blocks at right of free block and the most right
+	 * blocks at left of free block.
+	 */
+
+	list_for_each_entry(free_block, head, link) {
+		struct drm_buddy_block *buddy, *parent, *block;
+		int left, min_order = 0;
+		LIST_HEAD(fbl);
+
+		parent = free_block->parent;
+		if (!parent)
+			continue;
+
+		left = parent->left == free_block;
+		list_add(&free_block->tmp_link, &fbl);
+		buddy = __get_buddy(free_block);
+		__continuous_block_in_tree(buddy, &fbl, left, min_order);
+
+		while (parent && !((parent->left == block) ^ left)) {
+			block = parent;
+			parent = parent->parent;
+		}
+
+		if (!parent)
+			continue;
+
+		buddy = __get_buddy(block);
+		__continuous_block_in_tree(buddy, &fbl, !left, min_order);
+
+		/* list head of fbl is invalid outside.
+		 * Walk through list from first fo last only.
+		 */
+		if (__free_block_in_order(&fbl, free_block, order, &first, &last))
+			break;
+	}
+
+	*lb = last;
+	return first;
+}
+
 static struct drm_buddy_block *
 get_maxblock(struct list_head *head)
 {
@@ -637,7 +771,7 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm,
 			   struct list_head *blocks,
 			   unsigned long flags)
 {
-	struct drm_buddy_block *block = NULL;
+	struct drm_buddy_block *block = NULL, *last_block = NULL;
 	unsigned int min_order, order;
 	unsigned long pages;
 	LIST_HEAD(allocated);
@@ -689,17 +823,30 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm,
 				break;
 
 			if (order-- == min_order) {
+				if (!(flags & DRM_BUDDY_RANGE_ALLOCATION) &&
+				    min_order != 0 && pages == BIT(min_order)) {
+					block = find_continuous_blocks(mm,
+								       min_order,
+								       flags,
+								       &last_block);
+					if (block)
+						break;
+				}
 				err = -ENOSPC;
 				goto err_free;
 			}
 		} while (1);
 
-		mark_allocated(block);
-		mm->avail -= drm_buddy_block_size(mm, block);
-		kmemleak_update_trace(block);
-		list_add_tail(&block->link, &allocated);
-
-		pages -= BIT(order);
+		do {
+			mark_allocated(block);
+			mm->avail -= drm_buddy_block_size(mm, block);
+			kmemleak_update_trace(block);
+			list_add_tail(&block->link, &allocated);
+			pages -= BIT(drm_buddy_block_order(block));
+			if (block == last_block || !last_block)
+				break;
+			block = list_next_entry(block, tmp_link);
+		} while (block);
 
 		if (!pages)
 			break;
