Re: [PATCH v3 2/6] drm: improve drm_buddy_alloc function
On 23/11/2021 22:39, Arunpravin wrote: On 18/11/21 12:09 am, Matthew Auld wrote: On 16/11/2021 20:18, Arunpravin wrote: - Make drm_buddy_alloc a single function to handle range allocation and non-range allocation demands - Implemented a new function alloc_range() which allocates the requested power-of-two block comply with range limitations - Moved order computation and memory alignment logic from i915 driver to drm buddy v2: merged below changes to keep the build unbroken - drm_buddy_alloc_range() becomes obsolete and may be removed - enable ttm range allocation (fpfn / lpfn) support in i915 driver - apply enhanced drm_buddy_alloc() function to i915 driver v3(Matthew Auld): - Fix alignment issues and remove unnecessary list_empty check - add more validation checks for input arguments - make alloc_range() block allocations as bottom-up - optimize order computation logic - replace uint64_t with u64, which is preferred in the kernel Signed-off-by: Arunpravin --- drivers/gpu/drm/drm_buddy.c | 259 ++ drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 69 ++--- drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 2 + include/drm/drm_buddy.h | 22 +- 4 files changed, 203 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 39eb1d224bec..c9b18a29f8d1 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -274,63 +274,6 @@ void drm_buddy_free_list(struct drm_buddy_mm *mm, struct 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; @@ -341,52 +284,22 @@ 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) +static struct drm_buddy_block * +alloc_range(struct drm_buddy_mm *mm, + u64 start, u64 end, + unsigned int order) { 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; + end = end - 1; for (i = 0; i < mm->n_roots; ++i) list_
Re: [PATCH v3 2/6] drm: improve drm_buddy_alloc function
On 18/11/21 12:09 am, Matthew Auld wrote: > On 16/11/2021 20:18, Arunpravin wrote: >> - Make drm_buddy_alloc a single function to handle >>range allocation and non-range allocation demands >> >> - Implemented a new function alloc_range() which allocates >>the requested power-of-two block comply with range limitations >> >> - Moved order computation and memory alignment logic from >>i915 driver to drm buddy >> >> v2: >>merged below changes to keep the build unbroken >> - drm_buddy_alloc_range() becomes obsolete and may be removed >> - enable ttm range allocation (fpfn / lpfn) support in i915 driver >> - apply enhanced drm_buddy_alloc() function to i915 driver >> >> v3(Matthew Auld): >>- Fix alignment issues and remove unnecessary list_empty check >>- add more validation checks for input arguments >>- make alloc_range() block allocations as bottom-up >>- optimize order computation logic >>- replace uint64_t with u64, which is preferred in the kernel >> >> Signed-off-by: Arunpravin >> --- >> drivers/gpu/drm/drm_buddy.c | 259 ++ >> drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 69 ++--- >> drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 2 + >> include/drm/drm_buddy.h | 22 +- >> 4 files changed, 203 insertions(+), 149 deletions(-) >> >> diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c >> index 39eb1d224bec..c9b18a29f8d1 100644 >> --- a/drivers/gpu/drm/drm_buddy.c >> +++ b/drivers/gpu/drm/drm_buddy.c >> @@ -274,63 +274,6 @@ void drm_buddy_free_list(struct drm_buddy_mm *mm, >> struct 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; >> @@ -341,52 +284,22 @@ 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) >> +static struct drm_buddy_block * >> +alloc_range(struct drm_buddy_mm *mm, >> +u64 start, u64 end, >> +unsigned int order) >> { >> 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_ALIGNE
Re: [PATCH v3 2/6] drm: improve drm_buddy_alloc function
On 16/11/2021 20:18, Arunpravin wrote: - Make drm_buddy_alloc a single function to handle range allocation and non-range allocation demands - Implemented a new function alloc_range() which allocates the requested power-of-two block comply with range limitations - Moved order computation and memory alignment logic from i915 driver to drm buddy v2: merged below changes to keep the build unbroken - drm_buddy_alloc_range() becomes obsolete and may be removed - enable ttm range allocation (fpfn / lpfn) support in i915 driver - apply enhanced drm_buddy_alloc() function to i915 driver v3(Matthew Auld): - Fix alignment issues and remove unnecessary list_empty check - add more validation checks for input arguments - make alloc_range() block allocations as bottom-up - optimize order computation logic - replace uint64_t with u64, which is preferred in the kernel Signed-off-by: Arunpravin --- drivers/gpu/drm/drm_buddy.c | 259 ++ drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 69 ++--- drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 2 + include/drm/drm_buddy.h | 22 +- 4 files changed, 203 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 39eb1d224bec..c9b18a29f8d1 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -274,63 +274,6 @@ void drm_buddy_free_list(struct drm_buddy_mm *mm, struct 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; @@ -341,52 +284,22 @@ 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) +static struct drm_buddy_block * +alloc_range(struct drm_buddy_mm *mm, + u64 start, u64 end, + unsigned int order) { 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; + end = end - 1; for (i = 0; i < mm->n_roots; ++i) list_add_tail(&mm->roots[i]->tmp_link, &dfs); - end = start + size - 1; - do { u64 block_s
[PATCH v3 2/6] drm: improve drm_buddy_alloc function
- Make drm_buddy_alloc a single function to handle range allocation and non-range allocation demands - Implemented a new function alloc_range() which allocates the requested power-of-two block comply with range limitations - Moved order computation and memory alignment logic from i915 driver to drm buddy v2: merged below changes to keep the build unbroken - drm_buddy_alloc_range() becomes obsolete and may be removed - enable ttm range allocation (fpfn / lpfn) support in i915 driver - apply enhanced drm_buddy_alloc() function to i915 driver v3(Matthew Auld): - Fix alignment issues and remove unnecessary list_empty check - add more validation checks for input arguments - make alloc_range() block allocations as bottom-up - optimize order computation logic - replace uint64_t with u64, which is preferred in the kernel Signed-off-by: Arunpravin --- drivers/gpu/drm/drm_buddy.c | 259 ++ drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 69 ++--- drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 2 + include/drm/drm_buddy.h | 22 +- 4 files changed, 203 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 39eb1d224bec..c9b18a29f8d1 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -274,63 +274,6 @@ void drm_buddy_free_list(struct drm_buddy_mm *mm, struct 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; @@ -341,52 +284,22 @@ 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) +static struct drm_buddy_block * +alloc_range(struct drm_buddy_mm *mm, + u64 start, u64 end, + unsigned int order) { 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; + end = end - 1; 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; @@ -399,26 +312,26 @