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.paneersel...@amd.com>
>> ---
>>   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);
>>

Reply via email to