Re: [PATCH v6 4/6] drm: implement a method to free unused pages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

+{
+	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?

+				&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);




[Index of Archives]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux