return __alloc_range(mm, &dfs, start, size, blocks);
 }
 
+/**
+ * drm_buddy_block_trim - free unused pages
+ *
+ * @mm: DRM buddy manager
+ * @new_size: original size requested
+ * @blocks: Input and output list of allocated blocks.
+ * MUST contain single block as input to be trimmed.
+ * On success will contain the newly allocated blocks
+ * making up the @new_size. Blocks always appear in
+ * ascending order
+ *
+ * For contiguous allocation, we round up the size to the nearest
+ * power of two value, drivers consume *actual* size, so remaining
+ * portions are unused and can be optionally freed with this function
+ *
+ * Returns:
+ * 0 on success, error code on failure.
+ */
+int drm_buddy_block_trim(struct drm_buddy *mm,
+                        u64 new_size,
+                        struct list_head *blocks)
+{
+       struct drm_buddy_block *parent;
+       struct drm_buddy_block *block;
+       LIST_HEAD(dfs);
+       u64 new_start;
+       int err;
+
+       if (!list_is_singular(blocks))
+               return -EINVAL;
+
+       block = list_first_entry(blocks,
+                                struct drm_buddy_block,
+                                link);
+
+       if (WARN_ON(!drm_buddy_block_is_allocated(block)))
+               return -EINVAL;
+
+       if (new_size > drm_buddy_block_size(mm, block))
+               return -EINVAL;
+
+       if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size))
+               return -EINVAL;
+
+       if (new_size == drm_buddy_block_size(mm, block))
+               return 0;
+
+       list_del(&block->link);
+       mark_free(mm, block);
+       mm->avail += drm_buddy_block_size(mm, block);
+
+       /* Prevent recursively freeing this node */
+       parent = block->parent;
+       block->parent = NULL;
+
+       new_start = drm_buddy_block_offset(block);
+       list_add(&block->tmp_link, &dfs);
+       err =  __alloc_range(mm, &dfs, new_start, new_size, blocks);
+       if (err) {
+               mark_allocated(block);
+               mm->avail -= drm_buddy_block_size(mm, block);
+               list_add(&block->link, blocks);
+       }
+
+       block->parent = parent;
+       return err;
+}
+EXPORT_SYMBOL(drm_buddy_block_trim);
+
 /**
  * drm_buddy_alloc_blocks - allocate power-of-two blocks
  *