Hi Christian,
I will make this a separate module.

Thanks,
Arun

On 17/11/21 1:33 pm, Christian König wrote:
> I've looked a bit more into this and I think we should just follow 
> Thomas Zimmermann's idea to make this a separate module.
> 
> Otherwise we just have the code around all the time even if it is unused 
> and implementing this should be trivial.
> 
> See how DRM_GEM_CMA_HELPER or DRM_VRAM_HELPER are done in 
> drivers/gpu/drm/Kconfig and then have the desired effect in 
> drivers/gpu/drm/Makefile
> 
> Should be something like ~15 lines of additional configuration which 
> saves a bit of memory on embedded systems which just need a fbdev 
> replacement.
> 
> Thanks,
> Christian.
> 
> Am 16.11.21 um 21:18 schrieb Arunpravin:
>> Move the base i915 buddy allocator code into drm
>> - Move i915_buddy.h to include/drm
>> - Move i915_buddy.c to drm root folder
>> - Rename "i915" string with "drm" string wherever applicable
>> - Rename "I915" string with "DRM" string wherever applicable
>> - Fix header file dependencies
>> - Fix alignment issues
>> - add Makefile support for drm buddy
>> - export functions and write kerneldoc description
>> - Remove i915 selftest config check condition as buddy selftest
>>    will be moved to drm selftest folder
>>
>> cleanup i915 buddy references in i915 driver module
>> and replace with drm buddy
>>
>> v2:
>>    - include header file in alphabetical order (Thomas)
>>    - merged changes listed in the body section into a single patch
>>      to keep the build intact (Christian, Jani)
>>
>> Signed-off-by: Arunpravin <arunpravin.paneersel...@amd.com>
>> ---
>>   drivers/gpu/drm/Makefile                      |   2 +-
>>   drivers/gpu/drm/drm_buddy.c                   | 521 ++++++++++++++++++
>>   drivers/gpu/drm/drm_drv.c                     |   3 +
>>   drivers/gpu/drm/i915/Makefile                 |   1 -
>>   drivers/gpu/drm/i915/i915_buddy.c             | 466 ----------------
>>   drivers/gpu/drm/i915/i915_buddy.h             | 143 -----
>>   drivers/gpu/drm/i915/i915_module.c            |   3 -
>>   drivers/gpu/drm/i915/i915_scatterlist.c       |  11 +-
>>   drivers/gpu/drm/i915/i915_ttm_buddy_manager.c |  33 +-
>>   drivers/gpu/drm/i915/i915_ttm_buddy_manager.h |   4 +-
>>   include/drm/drm_buddy.h                       | 153 +++++
>>   11 files changed, 702 insertions(+), 638 deletions(-)
>>   create mode 100644 drivers/gpu/drm/drm_buddy.c
>>   delete mode 100644 drivers/gpu/drm/i915/i915_buddy.c
>>   delete mode 100644 drivers/gpu/drm/i915/i915_buddy.h
>>   create mode 100644 include/drm/drm_buddy.h
>>
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 0dff40bb863c..dc61e91a3154 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -18,7 +18,7 @@ drm-y       :=     drm_aperture.o drm_auth.o drm_cache.o \
>>              drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
>>              drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
>>              drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \
>> -            drm_managed.o drm_vblank_work.o
>> +            drm_managed.o drm_vblank_work.o drm_buddy.o
>>   
>>   drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o 
>> drm_dma.o \
>>                          drm_legacy_misc.o drm_lock.o drm_memory.o 
>> drm_scatter.o \
>> diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
>> new file mode 100644
>> index 000000000000..39eb1d224bec
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_buddy.c
>> @@ -0,0 +1,521 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright © 2021 Intel Corporation
>> + */
>> +
>> +#include <linux/kmemleak.h>
>> +#include <linux/sizes.h>
>> +
>> +#include <drm/drm_buddy.h>
>> +
>> +static struct kmem_cache *slab_blocks;
>> +
>> +static struct drm_buddy_block *drm_block_alloc(struct drm_buddy_mm *mm,
>> +                                           struct drm_buddy_block *parent,
>> +                                           unsigned int order,
>> +                                           u64 offset)
>> +{
>> +    struct drm_buddy_block *block;
>> +
>> +    BUG_ON(order > DRM_BUDDY_MAX_ORDER);
>> +
>> +    block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL);
>> +    if (!block)
>> +            return NULL;
>> +
>> +    block->header = offset;
>> +    block->header |= order;
>> +    block->parent = parent;
>> +
>> +    BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED);
>> +    return block;
>> +}
>> +
>> +static void drm_block_free(struct drm_buddy_mm *mm,
>> +                       struct drm_buddy_block *block)
>> +{
>> +    kmem_cache_free(slab_blocks, block);
>> +}
>> +
>> +static void mark_allocated(struct drm_buddy_block *block)
>> +{
>> +    block->header &= ~DRM_BUDDY_HEADER_STATE;
>> +    block->header |= DRM_BUDDY_ALLOCATED;
>> +
>> +    list_del(&block->link);
>> +}
>> +
>> +static void mark_free(struct drm_buddy_mm *mm,
>> +                  struct drm_buddy_block *block)
>> +{
>> +    block->header &= ~DRM_BUDDY_HEADER_STATE;
>> +    block->header |= DRM_BUDDY_FREE;
>> +
>> +    list_add(&block->link,
>> +             &mm->free_list[drm_buddy_block_order(block)]);
>> +}
>> +
>> +static void mark_split(struct drm_buddy_block *block)
>> +{
>> +    block->header &= ~DRM_BUDDY_HEADER_STATE;
>> +    block->header |= DRM_BUDDY_SPLIT;
>> +
>> +    list_del(&block->link);
>> +}
>> +
>> +/**
>> + * drm_buddy_init - init memory manager
>> + *
>> + * @mm: DRM buddy manager to initialize
>> + * @size: size in bytes to manage
>> + * @chunk_size: minimum page size in bytes for our allocations
>> + *
>> + * Initializes the memory manager and its resources.
>> + *
>> + * Returns:
>> + * 0 on success, error code on failure.
>> + */
>> +int drm_buddy_init(struct drm_buddy_mm *mm, u64 size, u64 chunk_size)
>> +{
>> +    unsigned int i;
>> +    u64 offset;
>> +
>> +    if (size < chunk_size)
>> +            return -EINVAL;
>> +
>> +    if (chunk_size < PAGE_SIZE)
>> +            return -EINVAL;
>> +
>> +    if (!is_power_of_2(chunk_size))
>> +            return -EINVAL;
>> +
>> +    size = round_down(size, chunk_size);
>> +
>> +    mm->size = size;
>> +    mm->avail = size;
>> +    mm->chunk_size = chunk_size;
>> +    mm->max_order = ilog2(size) - ilog2(chunk_size);
>> +
>> +    BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER);
>> +
>> +    mm->free_list = kmalloc_array(mm->max_order + 1,
>> +                                  sizeof(struct list_head),
>> +                                  GFP_KERNEL);
>> +    if (!mm->free_list)
>> +            return -ENOMEM;
>> +
>> +    for (i = 0; i <= mm->max_order; ++i)
>> +            INIT_LIST_HEAD(&mm->free_list[i]);
>> +
>> +    mm->n_roots = hweight64(size);
>> +
>> +    mm->roots = kmalloc_array(mm->n_roots,
>> +                              sizeof(struct drm_buddy_block *),
>> +                              GFP_KERNEL);
>> +    if (!mm->roots)
>> +            goto out_free_list;
>> +
>> +    offset = 0;
>> +    i = 0;
>> +
>> +    /*
>> +     * Split into power-of-two blocks, in case we are given a size that is
>> +     * not itself a power-of-two.
>> +     */
>> +    do {
>> +            struct drm_buddy_block *root;
>> +            unsigned int order;
>> +            u64 root_size;
>> +
>> +            root_size = rounddown_pow_of_two(size);
>> +            order = ilog2(root_size) - ilog2(chunk_size);
>> +
>> +            root = drm_block_alloc(mm, NULL, order, offset);
>> +            if (!root)
>> +                    goto out_free_roots;
>> +
>> +            mark_free(mm, root);
>> +
>> +            BUG_ON(i > mm->max_order);
>> +            BUG_ON(drm_buddy_block_size(mm, root) < chunk_size);
>> +
>> +            mm->roots[i] = root;
>> +
>> +            offset += root_size;
>> +            size -= root_size;
>> +            i++;
>> +    } while (size);
>> +
>> +    return 0;
>> +
>> +out_free_roots:
>> +    while (i--)
>> +            drm_block_free(mm, mm->roots[i]);
>> +    kfree(mm->roots);
>> +out_free_list:
>> +    kfree(mm->free_list);
>> +    return -ENOMEM;
>> +}
>> +EXPORT_SYMBOL(drm_buddy_init);
>> +
>> +/**
>> + * drm_buddy_fini - tear down the memory manager
>> + *
>> + * @mm: DRM buddy manager to free
>> + *
>> + * Cleanup memory manager resources and the freelist
>> + */
>> +void drm_buddy_fini(struct drm_buddy_mm *mm)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < mm->n_roots; ++i) {
>> +            WARN_ON(!drm_buddy_block_is_free(mm->roots[i]));
>> +            drm_block_free(mm, mm->roots[i]);
>> +    }
>> +
>> +    WARN_ON(mm->avail != mm->size);
>> +
>> +    kfree(mm->roots);
>> +    kfree(mm->free_list);
>> +}
>> +EXPORT_SYMBOL(drm_buddy_fini);
>> +
>> +static int split_block(struct drm_buddy_mm *mm,
>> +                   struct drm_buddy_block *block)
>> +{
>> +    unsigned int block_order = drm_buddy_block_order(block) - 1;
>> +    u64 offset = drm_buddy_block_offset(block);
>> +
>> +    BUG_ON(!drm_buddy_block_is_free(block));
>> +    BUG_ON(!drm_buddy_block_order(block));
>> +
>> +    block->left = drm_block_alloc(mm, block, block_order, offset);
>> +    if (!block->left)
>> +            return -ENOMEM;
>> +
>> +    block->right = drm_block_alloc(mm, block, block_order,
>> +                                    offset + (mm->chunk_size << 
>> block_order));
>> +    if (!block->right) {
>> +            drm_block_free(mm, block->left);
>> +            return -ENOMEM;
>> +    }
>> +
>> +    mark_free(mm, block->left);
>> +    mark_free(mm, block->right);
>> +
>> +    mark_split(block);
>> +
>> +    return 0;
>> +}
>> +
>> +static struct drm_buddy_block *
>> +get_buddy(struct drm_buddy_block *block)
>> +{
>> +    struct drm_buddy_block *parent;
>> +
>> +    parent = block->parent;
>> +    if (!parent)
>> +            return NULL;
>> +
>> +    if (parent->left == block)
>> +            return parent->right;
>> +
>> +    return parent->left;
>> +}
>> +
>> +static void __drm_buddy_free(struct drm_buddy_mm *mm,
>> +                         struct drm_buddy_block *block)
>> +{
>> +    struct drm_buddy_block *parent;
>> +
>> +    while ((parent = block->parent)) {
>> +            struct drm_buddy_block *buddy;
>> +
>> +            buddy = get_buddy(block);
>> +
>> +            if (!drm_buddy_block_is_free(buddy))
>> +                    break;
>> +
>> +            list_del(&buddy->link);
>> +
>> +            drm_block_free(mm, block);
>> +            drm_block_free(mm, buddy);
>> +
>> +            block = parent;
>> +    }
>> +
>> +    mark_free(mm, block);
>> +}
>> +
>> +void drm_buddy_free(struct drm_buddy_mm *mm,
>> +                struct drm_buddy_block *block)
>> +{
>> +    BUG_ON(!drm_buddy_block_is_allocated(block));
>> +    mm->avail += drm_buddy_block_size(mm, block);
>> +    __drm_buddy_free(mm, block);
>> +}
>> +
>> +/**
>> + * drm_buddy_free_list - free blocks
>> + *
>> + * @mm: DRM buddy manager
>> + * @objects: input list head to free blocks
>> + */
>> +void drm_buddy_free_list(struct drm_buddy_mm *mm, struct list_head *objects)
>> +{
>> +    struct drm_buddy_block *block, *on;
>> +
>> +    list_for_each_entry_safe(block, on, objects, link) {
>> +            drm_buddy_free(mm, block);
>> +            cond_resched();
>> +    }
>> +    INIT_LIST_HEAD(objects);
>> +}
>> +EXPORT_SYMBOL(drm_buddy_free_list);
>> +
>> +/**
>> + * drm_buddy_alloc - allocate power-of-two blocks
>> + *
>> + * @mm: DRM buddy manager to allocate from
>> + * @order: size of the allocation
>> + *
>> + * The order value here translates to:
>> + *
>> + * 0 = 2^0 * mm->chunk_size
>> + * 1 = 2^1 * mm->chunk_size
>> + * 2 = 2^2 * mm->chunk_size
>> + *
>> + * Returns:
>> + * allocated ptr to the &drm_buddy_block on success
>> + */
>> +struct drm_buddy_block *
>> +drm_buddy_alloc(struct drm_buddy_mm *mm, unsigned int order)
>> +{
>> +    struct drm_buddy_block *block = NULL;
>> +    unsigned int i;
>> +    int err;
>> +
>> +    for (i = order; i <= mm->max_order; ++i) {
>> +            block = list_first_entry_or_null(&mm->free_list[i],
>> +                                             struct drm_buddy_block,
>> +                                             link);
>> +            if (block)
>> +                    break;
>> +    }
>> +
>> +    if (!block)
>> +            return ERR_PTR(-ENOSPC);
>> +
>> +    BUG_ON(!drm_buddy_block_is_free(block));
>> +
>> +    while (i != order) {
>> +            err = split_block(mm, block);
>> +            if (unlikely(err))
>> +                    goto out_free;
>> +
>> +            /* Go low */
>> +            block = block->left;
>> +            i--;
>> +    }
>> +
>> +    mark_allocated(block);
>> +    mm->avail -= drm_buddy_block_size(mm, block);
>> +    kmemleak_update_trace(block);
>> +    return block;
>> +
>> +out_free:
>> +    if (i != order)
>> +            __drm_buddy_free(mm, block);
>> +    return ERR_PTR(err);
>> +}
>> +EXPORT_SYMBOL(drm_buddy_alloc);
>> +
>> +static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
>> +{
>> +    return s1 <= e2 && e1 >= s2;
>> +}
>> +
>> +static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
>> +{
>> +    return s1 <= s2 && e1 >= e2;
>> +}
>> +
>> +/**
>> + * drm_buddy_alloc_range - allocate range
>> + *
>> + * @mm: DRM buddy manager to allocate from
>> + * @blocks: output list head to add allocated blocks
>> + * @start: start of the allowed range for this block
>> + * @size: size of the allocation
>> + *
>> + * Intended for pre-allocating portions of the address space, for example to
>> + * reserve a block for the initial framebuffer or similar, hence the 
>> expectation
>> + * here is that drm_buddy_alloc() is still the main vehicle for
>> + * allocations, so if that's not the case then the drm_mm range allocator is
>> + * probably a much better fit, and so you should probably go use that 
>> instead.
>> + *
>> + * Note that it's safe to chain together multiple alloc_ranges
>> + * with the same blocks list
>> + *
>> + * Returns:
>> + * 0 on success, error code on failure.
>> + */
>> +int drm_buddy_alloc_range(struct drm_buddy_mm *mm,
>> +                      struct list_head *blocks,
>> +                      u64 start, u64 size)
>> +{
>> +    struct drm_buddy_block *block;
>> +    struct drm_buddy_block *buddy;
>> +    LIST_HEAD(allocated);
>> +    LIST_HEAD(dfs);
>> +    u64 end;
>> +    int err;
>> +    int i;
>> +
>> +    if (size < mm->chunk_size)
>> +            return -EINVAL;
>> +
>> +    if (!IS_ALIGNED(size | start, mm->chunk_size))
>> +            return -EINVAL;
>> +
>> +    if (range_overflows(start, size, mm->size))
>> +            return -EINVAL;
>> +
>> +    for (i = 0; i < mm->n_roots; ++i)
>> +            list_add_tail(&mm->roots[i]->tmp_link, &dfs);
>> +
>> +    end = start + size - 1;
>> +
>> +    do {
>> +            u64 block_start;
>> +            u64 block_end;
>> +
>> +            block = list_first_entry_or_null(&dfs,
>> +                                             struct drm_buddy_block,
>> +                                             tmp_link);
>> +            if (!block)
>> +                    break;
>> +
>> +            list_del(&block->tmp_link);
>> +
>> +            block_start = drm_buddy_block_offset(block);
>> +            block_end = block_start + drm_buddy_block_size(mm, block) - 1;
>> +
>> +            if (!overlaps(start, end, block_start, block_end))
>> +                    continue;
>> +
>> +            if (drm_buddy_block_is_allocated(block)) {
>> +                    err = -ENOSPC;
>> +                    goto err_free;
>> +            }
>> +
>> +            if (contains(start, end, block_start, block_end)) {
>> +                    if (!drm_buddy_block_is_free(block)) {
>> +                            err = -ENOSPC;
>> +                            goto err_free;
>> +                    }
>> +
>> +                    mark_allocated(block);
>> +                    mm->avail -= drm_buddy_block_size(mm, block);
>> +                    list_add_tail(&block->link, &allocated);
>> +                    continue;
>> +            }
>> +
>> +            if (!drm_buddy_block_is_split(block)) {
>> +                    err = split_block(mm, block);
>> +                    if (unlikely(err))
>> +                            goto err_undo;
>> +            }
>> +
>> +            list_add(&block->right->tmp_link, &dfs);
>> +            list_add(&block->left->tmp_link, &dfs);
>> +    } while (1);
>> +
>> +    list_splice_tail(&allocated, blocks);
>> +    return 0;
>> +
>> +err_undo:
>> +    /*
>> +     * We really don't want to leave around a bunch of split blocks, since
>> +     * bigger is better, so make sure we merge everything back before we
>> +     * free the allocated blocks.
>> +     */
>> +    buddy = get_buddy(block);
>> +    if (buddy &&
>> +        (drm_buddy_block_is_free(block) &&
>> +         drm_buddy_block_is_free(buddy)))
>> +            __drm_buddy_free(mm, block);
>> +
>> +err_free:
>> +    drm_buddy_free_list(mm, &allocated);
>> +    return err;
>> +}
>> +EXPORT_SYMBOL(drm_buddy_alloc_range);
>> +
>> +/**
>> + * drm_buddy_block_print - print block information
>> + *
>> + * @mm: DRM buddy manager
>> + * @block: DRM buddy block
>> + * @p: DRM printer to use
>> + */
>> +void drm_buddy_block_print(struct drm_buddy_mm *mm,
>> +                       struct drm_buddy_block *block,
>> +                       struct drm_printer *p)
>> +{
>> +    u64 start = drm_buddy_block_offset(block);
>> +    u64 size = drm_buddy_block_size(mm, block);
>> +
>> +    drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size);
>> +}
>> +EXPORT_SYMBOL(drm_buddy_block_print);
>> +
>> +/**
>> + * drm_buddy_print - print allocator state
>> + *
>> + * @mm: DRM buddy manager
>> + * @p: DRM printer to use
>> + */
>> +void drm_buddy_print(struct drm_buddy_mm *mm, struct drm_printer *p)
>> +{
>> +    int order;
>> +
>> +    drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n",
>> +               mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20);
>> +
>> +    for (order = mm->max_order; order >= 0; order--) {
>> +            struct drm_buddy_block *block;
>> +            u64 count = 0, free;
>> +
>> +            list_for_each_entry(block, &mm->free_list[order], link) {
>> +                    BUG_ON(!drm_buddy_block_is_free(block));
>> +                    count++;
>> +            }
>> +
>> +            drm_printf(p, "order-%d ", order);
>> +
>> +            free = count * (mm->chunk_size << order);
>> +            if (free < SZ_1M)
>> +                    drm_printf(p, "free: %lluKiB", free >> 10);
>> +            else
>> +                    drm_printf(p, "free: %lluMiB", free >> 20);
>> +
>> +            drm_printf(p, ", pages: %llu\n", count);
>> +    }
>> +}
>> +EXPORT_SYMBOL(drm_buddy_print);
>> +
>> +void drm_buddy_module_exit(void)
>> +{
>> +    kmem_cache_destroy(slab_blocks);
>> +}
>> +
>> +int __init drm_buddy_module_init(void)
>> +{
>> +    slab_blocks = KMEM_CACHE(drm_buddy_block, 0);
>> +    if (!slab_blocks)
>> +            return -ENOMEM;
>> +
>> +    return 0;
>> +}
>> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> index 7a5097467ba5..5d5e46e60586 100644
>> --- a/drivers/gpu/drm/drm_drv.c
>> +++ b/drivers/gpu/drm/drm_drv.c
>> @@ -35,6 +35,7 @@
>>   #include <linux/slab.h>
>>   #include <linux/srcu.h>
>>   
>> +#include <drm/drm_buddy.h>
>>   #include <drm/drm_cache.h>
>>   #include <drm/drm_client.h>
>>   #include <drm/drm_color_mgmt.h>
>> @@ -1034,6 +1035,7 @@ static void drm_core_exit(void)
>>      drm_sysfs_destroy();
>>      idr_destroy(&drm_minors_idr);
>>      drm_connector_ida_destroy();
>> +    drm_buddy_module_exit();
>>   }
>>   
>>   static int __init drm_core_init(void)
>> @@ -1043,6 +1045,7 @@ static int __init drm_core_init(void)
>>      drm_connector_ida_init();
>>      idr_init(&drm_minors_idr);
>>      drm_memcpy_init_early();
>> +    drm_buddy_module_init();
>>   
>>      ret = drm_sysfs_init();
>>      if (ret < 0) {
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index 467872cca027..fc5ca8c4ccb2 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -161,7 +161,6 @@ gem-y += \
>>   i915-y += \
>>        $(gem-y) \
>>        i915_active.o \
>> -      i915_buddy.o \
>>        i915_cmd_parser.o \
>>        i915_gem_evict.o \
>>        i915_gem_gtt.o \
>> diff --git a/drivers/gpu/drm/i915/i915_buddy.c 
>> b/drivers/gpu/drm/i915/i915_buddy.c
>> deleted file mode 100644
>> index 6e2ad68f8f3f..000000000000
>> --- a/drivers/gpu/drm/i915/i915_buddy.c
>> +++ /dev/null
>> @@ -1,466 +0,0 @@
>> -// SPDX-License-Identifier: MIT
>> -/*
>> - * Copyright © 2021 Intel Corporation
>> - */
>> -
>> -#include <linux/kmemleak.h>
>> -#include <linux/sizes.h>
>> -
>> -#include "i915_buddy.h"
>> -
>> -#include "i915_gem.h"
>> -#include "i915_utils.h"
>> -
>> -static struct kmem_cache *slab_blocks;
>> -
>> -static struct i915_buddy_block *i915_block_alloc(struct i915_buddy_mm *mm,
>> -                                             struct i915_buddy_block 
>> *parent,
>> -                                             unsigned int order,
>> -                                             u64 offset)
>> -{
>> -    struct i915_buddy_block *block;
>> -
>> -    GEM_BUG_ON(order > I915_BUDDY_MAX_ORDER);
>> -
>> -    block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL);
>> -    if (!block)
>> -            return NULL;
>> -
>> -    block->header = offset;
>> -    block->header |= order;
>> -    block->parent = parent;
>> -
>> -    GEM_BUG_ON(block->header & I915_BUDDY_HEADER_UNUSED);
>> -    return block;
>> -}
>> -
>> -static void i915_block_free(struct i915_buddy_mm *mm,
>> -                        struct i915_buddy_block *block)
>> -{
>> -    kmem_cache_free(slab_blocks, block);
>> -}
>> -
>> -static void mark_allocated(struct i915_buddy_block *block)
>> -{
>> -    block->header &= ~I915_BUDDY_HEADER_STATE;
>> -    block->header |= I915_BUDDY_ALLOCATED;
>> -
>> -    list_del(&block->link);
>> -}
>> -
>> -static void mark_free(struct i915_buddy_mm *mm,
>> -                  struct i915_buddy_block *block)
>> -{
>> -    block->header &= ~I915_BUDDY_HEADER_STATE;
>> -    block->header |= I915_BUDDY_FREE;
>> -
>> -    list_add(&block->link,
>> -             &mm->free_list[i915_buddy_block_order(block)]);
>> -}
>> -
>> -static void mark_split(struct i915_buddy_block *block)
>> -{
>> -    block->header &= ~I915_BUDDY_HEADER_STATE;
>> -    block->header |= I915_BUDDY_SPLIT;
>> -
>> -    list_del(&block->link);
>> -}
>> -
>> -int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size)
>> -{
>> -    unsigned int i;
>> -    u64 offset;
>> -
>> -    if (size < chunk_size)
>> -            return -EINVAL;
>> -
>> -    if (chunk_size < PAGE_SIZE)
>> -            return -EINVAL;
>> -
>> -    if (!is_power_of_2(chunk_size))
>> -            return -EINVAL;
>> -
>> -    size = round_down(size, chunk_size);
>> -
>> -    mm->size = size;
>> -    mm->avail = size;
>> -    mm->chunk_size = chunk_size;
>> -    mm->max_order = ilog2(size) - ilog2(chunk_size);
>> -
>> -    GEM_BUG_ON(mm->max_order > I915_BUDDY_MAX_ORDER);
>> -
>> -    mm->free_list = kmalloc_array(mm->max_order + 1,
>> -                                  sizeof(struct list_head),
>> -                                  GFP_KERNEL);
>> -    if (!mm->free_list)
>> -            return -ENOMEM;
>> -
>> -    for (i = 0; i <= mm->max_order; ++i)
>> -            INIT_LIST_HEAD(&mm->free_list[i]);
>> -
>> -    mm->n_roots = hweight64(size);
>> -
>> -    mm->roots = kmalloc_array(mm->n_roots,
>> -                              sizeof(struct i915_buddy_block *),
>> -                              GFP_KERNEL);
>> -    if (!mm->roots)
>> -            goto out_free_list;
>> -
>> -    offset = 0;
>> -    i = 0;
>> -
>> -    /*
>> -     * Split into power-of-two blocks, in case we are given a size that is
>> -     * not itself a power-of-two.
>> -     */
>> -    do {
>> -            struct i915_buddy_block *root;
>> -            unsigned int order;
>> -            u64 root_size;
>> -
>> -            root_size = rounddown_pow_of_two(size);
>> -            order = ilog2(root_size) - ilog2(chunk_size);
>> -
>> -            root = i915_block_alloc(mm, NULL, order, offset);
>> -            if (!root)
>> -                    goto out_free_roots;
>> -
>> -            mark_free(mm, root);
>> -
>> -            GEM_BUG_ON(i > mm->max_order);
>> -            GEM_BUG_ON(i915_buddy_block_size(mm, root) < chunk_size);
>> -
>> -            mm->roots[i] = root;
>> -
>> -            offset += root_size;
>> -            size -= root_size;
>> -            i++;
>> -    } while (size);
>> -
>> -    return 0;
>> -
>> -out_free_roots:
>> -    while (i--)
>> -            i915_block_free(mm, mm->roots[i]);
>> -    kfree(mm->roots);
>> -out_free_list:
>> -    kfree(mm->free_list);
>> -    return -ENOMEM;
>> -}
>> -
>> -void i915_buddy_fini(struct i915_buddy_mm *mm)
>> -{
>> -    int i;
>> -
>> -    for (i = 0; i < mm->n_roots; ++i) {
>> -            GEM_WARN_ON(!i915_buddy_block_is_free(mm->roots[i]));
>> -            i915_block_free(mm, mm->roots[i]);
>> -    }
>> -
>> -    GEM_WARN_ON(mm->avail != mm->size);
>> -
>> -    kfree(mm->roots);
>> -    kfree(mm->free_list);
>> -}
>> -
>> -static int split_block(struct i915_buddy_mm *mm,
>> -                   struct i915_buddy_block *block)
>> -{
>> -    unsigned int block_order = i915_buddy_block_order(block) - 1;
>> -    u64 offset = i915_buddy_block_offset(block);
>> -
>> -    GEM_BUG_ON(!i915_buddy_block_is_free(block));
>> -    GEM_BUG_ON(!i915_buddy_block_order(block));
>> -
>> -    block->left = i915_block_alloc(mm, block, block_order, offset);
>> -    if (!block->left)
>> -            return -ENOMEM;
>> -
>> -    block->right = i915_block_alloc(mm, block, block_order,
>> -                                    offset + (mm->chunk_size << 
>> block_order));
>> -    if (!block->right) {
>> -            i915_block_free(mm, block->left);
>> -            return -ENOMEM;
>> -    }
>> -
>> -    mark_free(mm, block->left);
>> -    mark_free(mm, block->right);
>> -
>> -    mark_split(block);
>> -
>> -    return 0;
>> -}
>> -
>> -static struct i915_buddy_block *
>> -get_buddy(struct i915_buddy_block *block)
>> -{
>> -    struct i915_buddy_block *parent;
>> -
>> -    parent = block->parent;
>> -    if (!parent)
>> -            return NULL;
>> -
>> -    if (parent->left == block)
>> -            return parent->right;
>> -
>> -    return parent->left;
>> -}
>> -
>> -static void __i915_buddy_free(struct i915_buddy_mm *mm,
>> -                          struct i915_buddy_block *block)
>> -{
>> -    struct i915_buddy_block *parent;
>> -
>> -    while ((parent = block->parent)) {
>> -            struct i915_buddy_block *buddy;
>> -
>> -            buddy = get_buddy(block);
>> -
>> -            if (!i915_buddy_block_is_free(buddy))
>> -                    break;
>> -
>> -            list_del(&buddy->link);
>> -
>> -            i915_block_free(mm, block);
>> -            i915_block_free(mm, buddy);
>> -
>> -            block = parent;
>> -    }
>> -
>> -    mark_free(mm, block);
>> -}
>> -
>> -void i915_buddy_free(struct i915_buddy_mm *mm,
>> -                 struct i915_buddy_block *block)
>> -{
>> -    GEM_BUG_ON(!i915_buddy_block_is_allocated(block));
>> -    mm->avail += i915_buddy_block_size(mm, block);
>> -    __i915_buddy_free(mm, block);
>> -}
>> -
>> -void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head 
>> *objects)
>> -{
>> -    struct i915_buddy_block *block, *on;
>> -
>> -    list_for_each_entry_safe(block, on, objects, link) {
>> -            i915_buddy_free(mm, block);
>> -            cond_resched();
>> -    }
>> -    INIT_LIST_HEAD(objects);
>> -}
>> -
>> -/*
>> - * Allocate power-of-two block. The order value here translates to:
>> - *
>> - *   0 = 2^0 * mm->chunk_size
>> - *   1 = 2^1 * mm->chunk_size
>> - *   2 = 2^2 * mm->chunk_size
>> - *   ...
>> - */
>> -struct i915_buddy_block *
>> -i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order)
>> -{
>> -    struct i915_buddy_block *block = NULL;
>> -    unsigned int i;
>> -    int err;
>> -
>> -    for (i = order; i <= mm->max_order; ++i) {
>> -            block = list_first_entry_or_null(&mm->free_list[i],
>> -                                             struct i915_buddy_block,
>> -                                             link);
>> -            if (block)
>> -                    break;
>> -    }
>> -
>> -    if (!block)
>> -            return ERR_PTR(-ENOSPC);
>> -
>> -    GEM_BUG_ON(!i915_buddy_block_is_free(block));
>> -
>> -    while (i != order) {
>> -            err = split_block(mm, block);
>> -            if (unlikely(err))
>> -                    goto out_free;
>> -
>> -            /* Go low */
>> -            block = block->left;
>> -            i--;
>> -    }
>> -
>> -    mark_allocated(block);
>> -    mm->avail -= i915_buddy_block_size(mm, block);
>> -    kmemleak_update_trace(block);
>> -    return block;
>> -
>> -out_free:
>> -    if (i != order)
>> -            __i915_buddy_free(mm, block);
>> -    return ERR_PTR(err);
>> -}
>> -
>> -static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
>> -{
>> -    return s1 <= e2 && e1 >= s2;
>> -}
>> -
>> -static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
>> -{
>> -    return s1 <= s2 && e1 >= e2;
>> -}
>> -
>> -/*
>> - * Allocate range. Note that it's safe to chain together multiple 
>> alloc_ranges
>> - * with the same blocks list.
>> - *
>> - * Intended for pre-allocating portions of the address space, for example to
>> - * reserve a block for the initial framebuffer or similar, hence the 
>> expectation
>> - * here is that i915_buddy_alloc() is still the main vehicle for
>> - * allocations, so if that's not the case then the drm_mm range allocator is
>> - * probably a much better fit, and so you should probably go use that 
>> instead.
>> - */
>> -int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
>> -                       struct list_head *blocks,
>> -                       u64 start, u64 size)
>> -{
>> -    struct i915_buddy_block *block;
>> -    struct i915_buddy_block *buddy;
>> -    LIST_HEAD(allocated);
>> -    LIST_HEAD(dfs);
>> -    u64 end;
>> -    int err;
>> -    int i;
>> -
>> -    if (size < mm->chunk_size)
>> -            return -EINVAL;
>> -
>> -    if (!IS_ALIGNED(size | start, mm->chunk_size))
>> -            return -EINVAL;
>> -
>> -    if (range_overflows(start, size, mm->size))
>> -            return -EINVAL;
>> -
>> -    for (i = 0; i < mm->n_roots; ++i)
>> -            list_add_tail(&mm->roots[i]->tmp_link, &dfs);
>> -
>> -    end = start + size - 1;
>> -
>> -    do {
>> -            u64 block_start;
>> -            u64 block_end;
>> -
>> -            block = list_first_entry_or_null(&dfs,
>> -                                             struct i915_buddy_block,
>> -                                             tmp_link);
>> -            if (!block)
>> -                    break;
>> -
>> -            list_del(&block->tmp_link);
>> -
>> -            block_start = i915_buddy_block_offset(block);
>> -            block_end = block_start + i915_buddy_block_size(mm, block) - 1;
>> -
>> -            if (!overlaps(start, end, block_start, block_end))
>> -                    continue;
>> -
>> -            if (i915_buddy_block_is_allocated(block)) {
>> -                    err = -ENOSPC;
>> -                    goto err_free;
>> -            }
>> -
>> -            if (contains(start, end, block_start, block_end)) {
>> -                    if (!i915_buddy_block_is_free(block)) {
>> -                            err = -ENOSPC;
>> -                            goto err_free;
>> -                    }
>> -
>> -                    mark_allocated(block);
>> -                    mm->avail -= i915_buddy_block_size(mm, block);
>> -                    list_add_tail(&block->link, &allocated);
>> -                    continue;
>> -            }
>> -
>> -            if (!i915_buddy_block_is_split(block)) {
>> -                    err = split_block(mm, block);
>> -                    if (unlikely(err))
>> -                            goto err_undo;
>> -            }
>> -
>> -            list_add(&block->right->tmp_link, &dfs);
>> -            list_add(&block->left->tmp_link, &dfs);
>> -    } while (1);
>> -
>> -    list_splice_tail(&allocated, blocks);
>> -    return 0;
>> -
>> -err_undo:
>> -    /*
>> -     * We really don't want to leave around a bunch of split blocks, since
>> -     * bigger is better, so make sure we merge everything back before we
>> -     * free the allocated blocks.
>> -     */
>> -    buddy = get_buddy(block);
>> -    if (buddy &&
>> -        (i915_buddy_block_is_free(block) &&
>> -         i915_buddy_block_is_free(buddy)))
>> -            __i915_buddy_free(mm, block);
>> -
>> -err_free:
>> -    i915_buddy_free_list(mm, &allocated);
>> -    return err;
>> -}
>> -
>> -void i915_buddy_block_print(struct i915_buddy_mm *mm,
>> -                        struct i915_buddy_block *block,
>> -                        struct drm_printer *p)
>> -{
>> -    u64 start = i915_buddy_block_offset(block);
>> -    u64 size = i915_buddy_block_size(mm, block);
>> -
>> -    drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size);
>> -}
>> -
>> -void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p)
>> -{
>> -    int order;
>> -
>> -    drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n",
>> -               mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20);
>> -
>> -    for (order = mm->max_order; order >= 0; order--) {
>> -            struct i915_buddy_block *block;
>> -            u64 count = 0, free;
>> -
>> -            list_for_each_entry(block, &mm->free_list[order], link) {
>> -                    GEM_BUG_ON(!i915_buddy_block_is_free(block));
>> -                    count++;
>> -            }
>> -
>> -            drm_printf(p, "order-%d ", order);
>> -
>> -            free = count * (mm->chunk_size << order);
>> -            if (free < SZ_1M)
>> -                    drm_printf(p, "free: %lluKiB", free >> 10);
>> -            else
>> -                    drm_printf(p, "free: %lluMiB", free >> 20);
>> -
>> -            drm_printf(p, ", pages: %llu\n", count);
>> -    }
>> -}
>> -
>> -#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
>> -#include "selftests/i915_buddy.c"
>> -#endif
>> -
>> -void i915_buddy_module_exit(void)
>> -{
>> -    kmem_cache_destroy(slab_blocks);
>> -}
>> -
>> -int __init i915_buddy_module_init(void)
>> -{
>> -    slab_blocks = KMEM_CACHE(i915_buddy_block, 0);
>> -    if (!slab_blocks)
>> -            return -ENOMEM;
>> -
>> -    return 0;
>> -}
>> diff --git a/drivers/gpu/drm/i915/i915_buddy.h 
>> b/drivers/gpu/drm/i915/i915_buddy.h
>> deleted file mode 100644
>> index 7077742112ac..000000000000
>> --- a/drivers/gpu/drm/i915/i915_buddy.h
>> +++ /dev/null
>> @@ -1,143 +0,0 @@
>> -/* SPDX-License-Identifier: MIT */
>> -/*
>> - * Copyright © 2021 Intel Corporation
>> - */
>> -
>> -#ifndef __I915_BUDDY_H__
>> -#define __I915_BUDDY_H__
>> -
>> -#include <linux/bitops.h>
>> -#include <linux/list.h>
>> -#include <linux/slab.h>
>> -
>> -#include <drm/drm_print.h>
>> -
>> -struct i915_buddy_block {
>> -#define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
>> -#define I915_BUDDY_HEADER_STATE  GENMASK_ULL(11, 10)
>> -#define   I915_BUDDY_ALLOCATED         (1 << 10)
>> -#define   I915_BUDDY_FREE      (2 << 10)
>> -#define   I915_BUDDY_SPLIT     (3 << 10)
>> -/* Free to be used, if needed in the future */
>> -#define I915_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6)
>> -#define I915_BUDDY_HEADER_ORDER  GENMASK_ULL(5, 0)
>> -    u64 header;
>> -
>> -    struct i915_buddy_block *left;
>> -    struct i915_buddy_block *right;
>> -    struct i915_buddy_block *parent;
>> -
>> -    void *private; /* owned by creator */
>> -
>> -    /*
>> -     * While the block is allocated by the user through i915_buddy_alloc*,
>> -     * the user has ownership of the link, for example to maintain within
>> -     * a list, if so desired. As soon as the block is freed with
>> -     * i915_buddy_free* ownership is given back to the mm.
>> -     */
>> -    struct list_head link;
>> -    struct list_head tmp_link;
>> -};
>> -
>> -/* Order-zero must be at least PAGE_SIZE */
>> -#define I915_BUDDY_MAX_ORDER (63 - PAGE_SHIFT)
>> -
>> -/*
>> - * Binary Buddy System.
>> - *
>> - * Locking should be handled by the user, a simple mutex around
>> - * i915_buddy_alloc* and i915_buddy_free* should suffice.
>> - */
>> -struct i915_buddy_mm {
>> -    /* Maintain a free list for each order. */
>> -    struct list_head *free_list;
>> -
>> -    /*
>> -     * Maintain explicit binary tree(s) to track the allocation of the
>> -     * address space. This gives us a simple way of finding a buddy block
>> -     * and performing the potentially recursive merge step when freeing a
>> -     * block.  Nodes are either allocated or free, in which case they will
>> -     * also exist on the respective free list.
>> -     */
>> -    struct i915_buddy_block **roots;
>> -
>> -    /*
>> -     * Anything from here is public, and remains static for the lifetime of
>> -     * the mm. Everything above is considered do-not-touch.
>> -     */
>> -    unsigned int n_roots;
>> -    unsigned int max_order;
>> -
>> -    /* Must be at least PAGE_SIZE */
>> -    u64 chunk_size;
>> -    u64 size;
>> -    u64 avail;
>> -};
>> -
>> -static inline u64
>> -i915_buddy_block_offset(struct i915_buddy_block *block)
>> -{
>> -    return block->header & I915_BUDDY_HEADER_OFFSET;
>> -}
>> -
>> -static inline unsigned int
>> -i915_buddy_block_order(struct i915_buddy_block *block)
>> -{
>> -    return block->header & I915_BUDDY_HEADER_ORDER;
>> -}
>> -
>> -static inline unsigned int
>> -i915_buddy_block_state(struct i915_buddy_block *block)
>> -{
>> -    return block->header & I915_BUDDY_HEADER_STATE;
>> -}
>> -
>> -static inline bool
>> -i915_buddy_block_is_allocated(struct i915_buddy_block *block)
>> -{
>> -    return i915_buddy_block_state(block) == I915_BUDDY_ALLOCATED;
>> -}
>> -
>> -static inline bool
>> -i915_buddy_block_is_free(struct i915_buddy_block *block)
>> -{
>> -    return i915_buddy_block_state(block) == I915_BUDDY_FREE;
>> -}
>> -
>> -static inline bool
>> -i915_buddy_block_is_split(struct i915_buddy_block *block)
>> -{
>> -    return i915_buddy_block_state(block) == I915_BUDDY_SPLIT;
>> -}
>> -
>> -static inline u64
>> -i915_buddy_block_size(struct i915_buddy_mm *mm,
>> -                  struct i915_buddy_block *block)
>> -{
>> -    return mm->chunk_size << i915_buddy_block_order(block);
>> -}
>> -
>> -int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size);
>> -
>> -void i915_buddy_fini(struct i915_buddy_mm *mm);
>> -
>> -struct i915_buddy_block *
>> -i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order);
>> -
>> -int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
>> -                       struct list_head *blocks,
>> -                       u64 start, u64 size);
>> -
>> -void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block 
>> *block);
>> -
>> -void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head 
>> *objects);
>> -
>> -void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p);
>> -void i915_buddy_block_print(struct i915_buddy_mm *mm,
>> -                        struct i915_buddy_block *block,
>> -                        struct drm_printer *p);
>> -
>> -void i915_buddy_module_exit(void);
>> -int i915_buddy_module_init(void);
>> -
>> -#endif
>> diff --git a/drivers/gpu/drm/i915/i915_module.c 
>> b/drivers/gpu/drm/i915/i915_module.c
>> index c7507266aa83..355681dbd7a8 100644
>> --- a/drivers/gpu/drm/i915/i915_module.c
>> +++ b/drivers/gpu/drm/i915/i915_module.c
>> @@ -9,7 +9,6 @@
>>   #include "gem/i915_gem_context.h"
>>   #include "gem/i915_gem_object.h"
>>   #include "i915_active.h"
>> -#include "i915_buddy.h"
>>   #include "i915_params.h"
>>   #include "i915_pci.h"
>>   #include "i915_perf.h"
>> @@ -50,8 +49,6 @@ static const struct {
>>      { .init = i915_check_nomodeset },
>>      { .init = i915_active_module_init,
>>        .exit = i915_active_module_exit },
>> -    { .init = i915_buddy_module_init,
>> -      .exit = i915_buddy_module_exit },
>>      { .init = i915_context_module_init,
>>        .exit = i915_context_module_exit },
>>      { .init = i915_gem_context_module_init,
>> diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c 
>> b/drivers/gpu/drm/i915/i915_scatterlist.c
>> index 4a6712dca838..84d622aa32d2 100644
>> --- a/drivers/gpu/drm/i915/i915_scatterlist.c
>> +++ b/drivers/gpu/drm/i915/i915_scatterlist.c
>> @@ -5,10 +5,9 @@
>>    */
>>   
>>   #include "i915_scatterlist.h"
>> -
>> -#include "i915_buddy.h"
>>   #include "i915_ttm_buddy_manager.h"
>>   
>> +#include <drm/drm_buddy.h>
>>   #include <drm/drm_mm.h>
>>   
>>   #include <linux/slab.h>
>> @@ -126,9 +125,9 @@ struct sg_table *i915_sg_from_buddy_resource(struct 
>> ttm_resource *res,
>>      struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
>>      const u64 size = res->num_pages << PAGE_SHIFT;
>>      const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
>> -    struct i915_buddy_mm *mm = bman_res->mm;
>> +    struct drm_buddy_mm *mm = bman_res->mm;
>>      struct list_head *blocks = &bman_res->blocks;
>> -    struct i915_buddy_block *block;
>> +    struct drm_buddy_block *block;
>>      struct scatterlist *sg;
>>      struct sg_table *st;
>>      resource_size_t prev_end;
>> @@ -151,8 +150,8 @@ struct sg_table *i915_sg_from_buddy_resource(struct 
>> ttm_resource *res,
>>      list_for_each_entry(block, blocks, link) {
>>              u64 block_size, offset;
>>   
>> -            block_size = min_t(u64, size, i915_buddy_block_size(mm, block));
>> -            offset = i915_buddy_block_offset(block);
>> +            block_size = min_t(u64, size, drm_buddy_block_size(mm, block));
>> +            offset = drm_buddy_block_offset(block);
>>   
>>              while (block_size) {
>>                      u64 len;
>> diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c 
>> b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
>> index d59fbb019032..c4b70cb8c248 100644
>> --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
>> +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
>> @@ -8,14 +8,15 @@
>>   #include <drm/ttm/ttm_bo_driver.h>
>>   #include <drm/ttm/ttm_placement.h>
>>   
>> +#include <drm/drm_buddy.h>
>> +
>>   #include "i915_ttm_buddy_manager.h"
>>   
>> -#include "i915_buddy.h"
>>   #include "i915_gem.h"
>>   
>>   struct i915_ttm_buddy_manager {
>>      struct ttm_resource_manager manager;
>> -    struct i915_buddy_mm mm;
>> +    struct drm_buddy_mm mm;
>>      struct list_head reserved;
>>      struct mutex lock;
>>      u64 default_page_size;
>> @@ -34,7 +35,7 @@ static int i915_ttm_buddy_man_alloc(struct 
>> ttm_resource_manager *man,
>>   {
>>      struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
>>      struct i915_ttm_buddy_resource *bman_res;
>> -    struct i915_buddy_mm *mm = &bman->mm;
>> +    struct drm_buddy_mm *mm = &bman->mm;
>>      unsigned long n_pages;
>>      unsigned int min_order;
>>      u64 min_page_size;
>> @@ -73,7 +74,7 @@ static int i915_ttm_buddy_man_alloc(struct 
>> ttm_resource_manager *man,
>>      n_pages = size >> ilog2(mm->chunk_size);
>>   
>>      do {
>> -            struct i915_buddy_block *block;
>> +            struct drm_buddy_block *block;
>>              unsigned int order;
>>   
>>              order = fls(n_pages) - 1;
>> @@ -82,7 +83,7 @@ static int i915_ttm_buddy_man_alloc(struct 
>> ttm_resource_manager *man,
>>   
>>              do {
>>                      mutex_lock(&bman->lock);
>> -                    block = i915_buddy_alloc(mm, order);
>> +                    block = drm_buddy_alloc(mm, order);
>>                      mutex_unlock(&bman->lock);
>>                      if (!IS_ERR(block))
>>                              break;
>> @@ -106,7 +107,7 @@ static int i915_ttm_buddy_man_alloc(struct 
>> ttm_resource_manager *man,
>>   
>>   err_free_blocks:
>>      mutex_lock(&bman->lock);
>> -    i915_buddy_free_list(mm, &bman_res->blocks);
>> +    drm_buddy_free_list(mm, &bman_res->blocks);
>>      mutex_unlock(&bman->lock);
>>   err_free_res:
>>      kfree(bman_res);
>> @@ -120,7 +121,7 @@ static void i915_ttm_buddy_man_free(struct 
>> ttm_resource_manager *man,
>>      struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
>>   
>>      mutex_lock(&bman->lock);
>> -    i915_buddy_free_list(&bman->mm, &bman_res->blocks);
>> +    drm_buddy_free_list(&bman->mm, &bman_res->blocks);
>>      mutex_unlock(&bman->lock);
>>   
>>      kfree(bman_res);
>> @@ -130,17 +131,17 @@ static void i915_ttm_buddy_man_debug(struct 
>> ttm_resource_manager *man,
>>                                   struct drm_printer *printer)
>>   {
>>      struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
>> -    struct i915_buddy_block *block;
>> +    struct drm_buddy_block *block;
>>   
>>      mutex_lock(&bman->lock);
>>      drm_printf(printer, "default_page_size: %lluKiB\n",
>>                 bman->default_page_size >> 10);
>>   
>> -    i915_buddy_print(&bman->mm, printer);
>> +    drm_buddy_print(&bman->mm, printer);
>>   
>>      drm_printf(printer, "reserved:\n");
>>      list_for_each_entry(block, &bman->reserved, link)
>> -            i915_buddy_block_print(&bman->mm, block, printer);
>> +            drm_buddy_block_print(&bman->mm, block, printer);
>>      mutex_unlock(&bman->lock);
>>   }
>>   
>> @@ -190,7 +191,7 @@ int i915_ttm_buddy_man_init(struct ttm_device *bdev,
>>      if (!bman)
>>              return -ENOMEM;
>>   
>> -    err = i915_buddy_init(&bman->mm, size, chunk_size);
>> +    err = drm_buddy_init(&bman->mm, size, chunk_size);
>>      if (err)
>>              goto err_free_bman;
>>   
>> @@ -228,7 +229,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, 
>> unsigned int type)
>>   {
>>      struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
>>      struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
>> -    struct i915_buddy_mm *mm = &bman->mm;
>> +    struct drm_buddy_mm *mm = &bman->mm;
>>      int ret;
>>   
>>      ttm_resource_manager_set_used(man, false);
>> @@ -240,8 +241,8 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, 
>> unsigned int type)
>>      ttm_set_driver_manager(bdev, type, NULL);
>>   
>>      mutex_lock(&bman->lock);
>> -    i915_buddy_free_list(mm, &bman->reserved);
>> -    i915_buddy_fini(mm);
>> +    drm_buddy_free_list(mm, &bman->reserved);
>> +    drm_buddy_fini(mm);
>>      mutex_unlock(&bman->lock);
>>   
>>      ttm_resource_manager_cleanup(man);
>> @@ -264,11 +265,11 @@ int i915_ttm_buddy_man_reserve(struct 
>> ttm_resource_manager *man,
>>                             u64 start, u64 size)
>>   {
>>      struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
>> -    struct i915_buddy_mm *mm = &bman->mm;
>> +    struct drm_buddy_mm *mm = &bman->mm;
>>      int ret;
>>   
>>      mutex_lock(&bman->lock);
>> -    ret = i915_buddy_alloc_range(mm, &bman->reserved, start, size);
>> +    ret = drm_buddy_alloc_range(mm, &bman->reserved, start, size);
>>      mutex_unlock(&bman->lock);
>>   
>>      return ret;
>> diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h 
>> b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h
>> index 0722d33f3e14..fa644b512c2e 100644
>> --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h
>> +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h
>> @@ -13,7 +13,7 @@
>>   
>>   struct ttm_device;
>>   struct ttm_resource_manager;
>> -struct i915_buddy_mm;
>> +struct drm_buddy_mm;
>>   
>>   /**
>>    * struct i915_ttm_buddy_resource
>> @@ -28,7 +28,7 @@ struct i915_buddy_mm;
>>   struct i915_ttm_buddy_resource {
>>      struct ttm_resource base;
>>      struct list_head blocks;
>> -    struct i915_buddy_mm *mm;
>> +    struct drm_buddy_mm *mm;
>>   };
>>   
>>   /**
>> diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h
>> new file mode 100644
>> index 000000000000..5ce3fc702f80
>> --- /dev/null
>> +++ b/include/drm/drm_buddy.h
>> @@ -0,0 +1,153 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright © 2021 Intel Corporation
>> + */
>> +
>> +#ifndef __DRM_BUDDY_H__
>> +#define __DRM_BUDDY_H__
>> +
>> +#include <linux/bitops.h>
>> +#include <linux/list.h>
>> +#include <linux/slab.h>
>> +#include <linux/sched.h>
>> +
>> +#include <drm/drm_print.h>
>> +
>> +#define range_overflows(start, size, max) ({ \
>> +    typeof(start) start__ = (start); \
>> +    typeof(size) size__ = (size); \
>> +    typeof(max) max__ = (max); \
>> +    (void)(&start__ == &size__); \
>> +    (void)(&start__ == &max__); \
>> +    start__ >= max__ || size__ > max__ - start__; \
>> +})
>> +
>> +struct drm_buddy_block {
>> +#define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
>> +#define DRM_BUDDY_HEADER_STATE  GENMASK_ULL(11, 10)
>> +#define   DRM_BUDDY_ALLOCATED          (1 << 10)
>> +#define   DRM_BUDDY_FREE       (2 << 10)
>> +#define   DRM_BUDDY_SPLIT      (3 << 10)
>> +/* Free to be used, if needed in the future */
>> +#define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6)
>> +#define DRM_BUDDY_HEADER_ORDER  GENMASK_ULL(5, 0)
>> +    u64 header;
>> +
>> +    struct drm_buddy_block *left;
>> +    struct drm_buddy_block *right;
>> +    struct drm_buddy_block *parent;
>> +
>> +    void *private; /* owned by creator */
>> +
>> +    /*
>> +     * While the block is allocated by the user through drm_buddy_alloc*,
>> +     * the user has ownership of the link, for example to maintain within
>> +     * a list, if so desired. As soon as the block is freed with
>> +     * drm_buddy_free* ownership is given back to the mm.
>> +     */
>> +    struct list_head link;
>> +    struct list_head tmp_link;
>> +};
>> +
>> +/* Order-zero must be at least PAGE_SIZE */
>> +#define DRM_BUDDY_MAX_ORDER (63 - PAGE_SHIFT)
>> +
>> +/*
>> + * Binary Buddy System.
>> + *
>> + * Locking should be handled by the user, a simple mutex around
>> + * drm_buddy_alloc* and drm_buddy_free* should suffice.
>> + */
>> +struct drm_buddy_mm {
>> +    /* Maintain a free list for each order. */
>> +    struct list_head *free_list;
>> +
>> +    /*
>> +     * Maintain explicit binary tree(s) to track the allocation of the
>> +     * address space. This gives us a simple way of finding a buddy block
>> +     * and performing the potentially recursive merge step when freeing a
>> +     * block.  Nodes are either allocated or free, in which case they will
>> +     * also exist on the respective free list.
>> +     */
>> +    struct drm_buddy_block **roots;
>> +
>> +    /*
>> +     * Anything from here is public, and remains static for the lifetime of
>> +     * the mm. Everything above is considered do-not-touch.
>> +     */
>> +    unsigned int n_roots;
>> +    unsigned int max_order;
>> +
>> +    /* Must be at least PAGE_SIZE */
>> +    u64 chunk_size;
>> +    u64 size;
>> +    u64 avail;
>> +};
>> +
>> +static inline u64
>> +drm_buddy_block_offset(struct drm_buddy_block *block)
>> +{
>> +    return block->header & DRM_BUDDY_HEADER_OFFSET;
>> +}
>> +
>> +static inline unsigned int
>> +drm_buddy_block_order(struct drm_buddy_block *block)
>> +{
>> +    return block->header & DRM_BUDDY_HEADER_ORDER;
>> +}
>> +
>> +static inline unsigned int
>> +drm_buddy_block_state(struct drm_buddy_block *block)
>> +{
>> +    return block->header & DRM_BUDDY_HEADER_STATE;
>> +}
>> +
>> +static inline bool
>> +drm_buddy_block_is_allocated(struct drm_buddy_block *block)
>> +{
>> +    return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED;
>> +}
>> +
>> +static inline bool
>> +drm_buddy_block_is_free(struct drm_buddy_block *block)
>> +{
>> +    return drm_buddy_block_state(block) == DRM_BUDDY_FREE;
>> +}
>> +
>> +static inline bool
>> +drm_buddy_block_is_split(struct drm_buddy_block *block)
>> +{
>> +    return drm_buddy_block_state(block) == DRM_BUDDY_SPLIT;
>> +}
>> +
>> +static inline u64
>> +drm_buddy_block_size(struct drm_buddy_mm *mm,
>> +                 struct drm_buddy_block *block)
>> +{
>> +    return mm->chunk_size << drm_buddy_block_order(block);
>> +}
>> +
>> +int drm_buddy_init(struct drm_buddy_mm *mm, u64 size, u64 chunk_size);
>> +
>> +void drm_buddy_fini(struct drm_buddy_mm *mm);
>> +
>> +struct drm_buddy_block *
>> +drm_buddy_alloc(struct drm_buddy_mm *mm, unsigned int order);
>> +
>> +int drm_buddy_alloc_range(struct drm_buddy_mm *mm,
>> +                      struct list_head *blocks,
>> +                      u64 start, u64 size);
>> +
>> +void drm_buddy_free(struct drm_buddy_mm *mm, struct drm_buddy_block *block);
>> +
>> +void drm_buddy_free_list(struct drm_buddy_mm *mm, struct list_head 
>> *objects);
>> +
>> +void drm_buddy_print(struct drm_buddy_mm *mm, struct drm_printer *p);
>> +void drm_buddy_block_print(struct drm_buddy_mm *mm,
>> +                       struct drm_buddy_block *block,
>> +                       struct drm_printer *p);
>> +
>> +void drm_buddy_module_exit(void);
>> +int drm_buddy_module_init(void);
>> +
>> +#endif
> 

Reply via email to