On 04/01/22 7:41 pm, Matthew Auld wrote: > On 26/12/2021 22:24, Arunpravin wrote: >> On contiguous allocation, we round up the size >> to the *next* power of 2, implement a function >> to free the unused pages after the newly allocate block. >> >> v2(Matthew Auld): >> - replace function name 'drm_buddy_free_unused_pages' with >> drm_buddy_block_trim >> - replace input argument name 'actual_size' with 'new_size' >> - add more validation checks for input arguments >> - add overlaps check to avoid needless searching and splitting >> - merged the below patch to see the feature in action >> - add free unused pages support to i915 driver >> - lock drm_buddy_block_trim() function as it calls mark_free/mark_split >> are all globally visible >> >> v3(Matthew Auld): >> - remove trim method error handling as we address the failure case >> at drm_buddy_block_trim() function >> >> v4: >> - in case of trim, at __alloc_range() split_block failure path >> marks the block as free and removes it from the original list, >> potentially also freeing it, to overcome this problem, we turn >> the drm_buddy_block_trim() input node into a temporary node to >> prevent recursively freeing itself, but still retain the >> un-splitting/freeing of the other nodes(Matthew Auld) >> >> - modify the drm_buddy_block_trim() function return type >> >> Signed-off-by: Arunpravin <Arunpravin.PaneerSelvam@xxxxxxx> >> --- >> drivers/gpu/drm/drm_buddy.c | 61 +++++++++++++++++++ >> drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 8 +++ >> include/drm/drm_buddy.h | 4 ++ >> 3 files changed, 73 insertions(+) >> >> diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c >> index eddc1eeda02e..855afcaf7edd 100644 >> --- a/drivers/gpu/drm/drm_buddy.c >> +++ b/drivers/gpu/drm/drm_buddy.c >> @@ -538,6 +538,67 @@ static int __drm_buddy_alloc_range(struct drm_buddy_mm *mm, >> 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: output list head to add allocated blocks >> + * >> + * 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 it can be freed. >> + */ >> +void drm_buddy_block_trim(struct drm_buddy_mm *mm, >> + u64 new_size, >> + struct list_head *blocks) > > It might be better to just return the error, and let the user decide if > they want to ignore it? Also we might want some kind of unit test for > this, so having an actual return value might be useful there. > sure will revert it >> +{ >> + struct drm_buddy_block *parent; >> + struct drm_buddy_block *block; >> + LIST_HEAD(dfs); >> + u64 new_start; >> + int err; >> + >> + if (!list_is_singular(blocks)) >> + return; >> + >> + block = list_first_entry(blocks, >> + struct drm_buddy_block, >> + link); >> + >> + if (!drm_buddy_block_is_allocated(block)) >> + return; >> + >> + if (new_size > drm_buddy_block_size(mm, block)) >> + return; >> + >> + if (!new_size && !IS_ALIGNED(new_size, mm->chunk_size)) >> + return; >> + >> + if (new_size == drm_buddy_block_size(mm, block)) >> + return; >> + >> + 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; >> +} >> +EXPORT_SYMBOL(drm_buddy_block_trim); >> + >> /** >> * drm_buddy_alloc - allocate power-of-two blocks >> * >> diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> index 7c58efb60dba..05f924f32e96 100644 >> --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> @@ -97,6 +97,14 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, >> if (unlikely(err)) >> goto err_free_blocks; >> >> + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { >> + mutex_lock(&bman->lock); >> + drm_buddy_block_trim(mm, >> + (u64)n_pages << PAGE_SHIFT, > > AFAIK, n_pages has already been rounded up to the next power-of-two > here, so this becomes a noop. I assume we need to use the "original" > size here? > ah yes..missed it, will change as below u64 original_size = (u64)bman_res->base.num_pages << PAGE_SHIFT; mutex_lock(&bman->lock); drm_buddy_block_trim(mm, original_size, &bman_res->blocks); >> + &bman_res->blocks); >> + mutex_unlock(&bman->lock); >> + } >> + >> *res = &bman_res->base; >> return 0; >> >> diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h >> index f573b02304f4..703866a87939 100644 >> --- a/include/drm/drm_buddy.h >> +++ b/include/drm/drm_buddy.h >> @@ -146,6 +146,10 @@ int drm_buddy_alloc(struct drm_buddy_mm *mm, >> struct list_head *blocks, >> unsigned long flags); >> >> +void drm_buddy_block_trim(struct drm_buddy_mm *mm, >> + u64 new_size, >> + struct list_head *blocks); >> + >> 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); >>