@@ -26,6 +26,7 @@
#include <linux/dma-direction.h>
#include <drm/gpu_scheduler.h>
+#include <drm/drm_buddy.h>
#include "amdgpu.h"
#define AMDGPU_PL_GDS (TTM_PL_PRIV + 0)
@@ -40,12 +41,13 @@
struct amdgpu_vram_mgr {
struct ttm_resource_manager manager;
- struct drm_mm mm;
+ struct drm_buddy_mm mm;
spinlock_t lock;
struct list_head reservations_pending;
struct list_head reserved_pages;
atomic64_t usage;
atomic64_t vis_usage;
+ uint64_t default_page_size;
};
struct amdgpu_gtt_mgr {
@@ -180,10 +180,10 @@ const struct attribute_group amdgpu_vram_mgr_attr_group = {
* Calculate how many bytes of the MM node are inside visible VRAM
*/
static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
- struct drm_mm_node *node)
+ struct drm_buddy_block *block)
{
- uint64_t start = node->start << PAGE_SHIFT;
- uint64_t end = (node->size + node->start) << PAGE_SHIFT;
+ uint64_t start = node_start(block);
+ uint64_t end = start + node_size(block);
if (start >= adev->gmc.visible_vram_size)
return 0;
@@ -204,9 +204,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct ttm_resource *res = bo->tbo.resource;
- unsigned pages = res->num_pages;
- struct drm_mm_node *mm;
- u64 usage;
+ struct amdgpu_vram_mgr_node *node = to_amdgpu_vram_mgr_node(res);
+ struct drm_buddy_block *block;
+ u64 usage = 0;
if (amdgpu_gmc_vram_full_visible(&adev->gmc))
return amdgpu_bo_size(bo);
@@ -214,9 +214,8 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
return 0;
- mm = &container_of(res, struct ttm_range_mgr_node, base)->mm_nodes[0];
- for (usage = 0; pages; pages -= mm->size, mm++)
- usage += amdgpu_vram_mgr_vis_size(adev, mm);
+ list_for_each_entry(block, &node->blocks, link)
+ usage += amdgpu_vram_mgr_vis_size(adev, block);
return usage;
}
@@ -226,21 +225,30 @@ static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man)
{
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
- struct drm_mm *mm = &mgr->mm;
+ struct drm_buddy_mm *mm = &mgr->mm;
struct amdgpu_vram_reservation *rsv, *temp;
+ struct drm_buddy_block *block;
uint64_t vis_usage;
list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
- if (drm_mm_reserve_node(mm, &rsv->mm_node))
+ if (drm_buddy_alloc(mm, rsv->start, rsv->start + rsv->size,
+ rsv->size, rsv->min_size, &rsv->block,
+ rsv->flags))
continue;
- dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n",
- rsv->mm_node.start, rsv->mm_node.size);
+ block = list_first_entry_or_null(&rsv->block,
+ struct drm_buddy_block,
+ link);
- vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
- atomic64_add(vis_usage, &mgr->vis_usage);
- atomic64_add(rsv->mm_node.size << PAGE_SHIFT, &mgr->usage);
- list_move(&rsv->node, &mgr->reserved_pages);
+ if (block) {
+ dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n",
+ rsv->start, rsv->size);
+
+ vis_usage = amdgpu_vram_mgr_vis_size(adev, block);
+ atomic64_add(vis_usage, &mgr->vis_usage);
+ atomic64_add(rsv->size, &mgr->usage);
+ list_move(&rsv->node, &mgr->reserved_pages);
+ }
}
}
@@ -264,11 +272,15 @@ int amdgpu_vram_mgr_reserve_range(struct ttm_resource_manager *man,
return -ENOMEM;
INIT_LIST_HEAD(&rsv->node);
- rsv->mm_node.start = start >> PAGE_SHIFT;
- rsv->mm_node.size = size >> PAGE_SHIFT;
+ INIT_LIST_HEAD(&rsv->block);
+
+ rsv->start = start;
+ rsv->size = size;
+ rsv->min_size = size;
+ rsv->flags |= DRM_BUDDY_RANGE_ALLOCATION;
spin_lock(&mgr->lock);
- list_add_tail(&mgr->reservations_pending, &rsv->node);
+ list_add_tail(&rsv->node, &mgr->reservations_pending);
amdgpu_vram_mgr_do_reserve(man);
spin_unlock(&mgr->lock);
@@ -296,16 +308,16 @@ int amdgpu_vram_mgr_query_page_status(struct ttm_resource_manager *man,
spin_lock(&mgr->lock);
list_for_each_entry(rsv, &mgr->reservations_pending, node) {
- if ((rsv->mm_node.start <= start) &&
- (start < (rsv->mm_node.start + rsv->mm_node.size))) {
+ if ((rsv->start <= start) &&
+ (start < (rsv->start + rsv->size))) {
ret = -EBUSY;
goto out;
}
}
list_for_each_entry(rsv, &mgr->reserved_pages, node) {
- if ((rsv->mm_node.start <= start) &&
- (start < (rsv->mm_node.start + rsv->mm_node.size))) {
+ if ((rsv->start <= start) &&
+ (start < (rsv->start + rsv->size))) {
ret = 0;
goto out;
}
@@ -317,28 +329,6 @@ int amdgpu_vram_mgr_query_page_status(struct ttm_resource_manager *man,
return ret;
}
-/**
- * amdgpu_vram_mgr_virt_start - update virtual start address
- *
- * @mem: ttm_resource to update
- * @node: just allocated node
- *
- * Calculate a virtual BO start address to easily check if everything is CPU
- * accessible.
- */
-static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
- struct drm_mm_node *node)
-{
- unsigned long start;
-
- start = node->start + node->size;
- if (start > mem->num_pages)
- start -= mem->num_pages;
- else
- start = 0;
- mem->start = max(mem->start, start);
-}
-
/**
* amdgpu_vram_mgr_new - allocate new ranges
*
@@ -354,13 +344,13 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
const struct ttm_place *place,
struct ttm_resource **res)
{
- unsigned long lpfn, num_nodes, pages_per_node, pages_left, pages;
+ unsigned long lpfn, pages_per_node, pages_left, pages, n_pages;
+ uint64_t vis_usage = 0, mem_bytes, max_bytes, min_page_size;
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
- uint64_t vis_usage = 0, mem_bytes, max_bytes;
- struct ttm_range_mgr_node *node;
- struct drm_mm *mm = &mgr->mm;
- enum drm_mm_insert_mode mode;
+ struct amdgpu_vram_mgr_node *node;
+ struct drm_buddy_mm *mm = &mgr->mm;
+ struct drm_buddy_block *block;
unsigned i;
int r;
@@ -379,10 +369,9 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
goto error_sub;
}
- if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
+ if (place->flags & TTM_PL_FLAG_CONTIGUOUS)
pages_per_node = ~0ul;
- num_nodes = 1;
- } else {
+ else {
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
pages_per_node = HPAGE_PMD_NR;
#else
@@ -391,11 +380,10 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
#endif
pages_per_node = max_t(uint32_t, pages_per_node,
tbo->page_alignment);
- num_nodes = DIV_ROUND_UP_ULL(PFN_UP(mem_bytes), pages_per_node);
}
- node = kvmalloc(struct_size(node, mm_nodes, num_nodes),
- GFP_KERNEL | __GFP_ZERO);
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+
if (!node) {
r = -ENOMEM;
goto error_sub;
@@ -403,9 +391,17 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
ttm_resource_init(tbo, place, &node->base);
- mode = DRM_MM_INSERT_BEST;
+ INIT_LIST_HEAD(&node->blocks);
+
if (place->flags & TTM_PL_FLAG_TOPDOWN)
- mode = DRM_MM_INSERT_HIGH;
+ node->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
+
+ if (place->fpfn || lpfn != man->size)
+ /* Allocate blocks in desired range */
+ node->flags |= DRM_BUDDY_RANGE_ALLOCATION;
+
+ min_page_size = mgr->default_page_size;
+ BUG_ON(min_page_size < mm->chunk_size);
pages_left = node->base.num_pages;
@@ -413,36 +409,63 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
pages = min(pages_left, 2UL << (30 - PAGE_SHIFT));
i = 0;
- spin_lock(&mgr->lock);
while (pages_left) {
- uint32_t alignment = tbo->page_alignment;
-
if (pages >= pages_per_node)
- alignment = pages_per_node;
-
- r = drm_mm_insert_node_in_range(mm, &node->mm_nodes[i], pages,
- alignment, 0, place->fpfn,
- lpfn, mode);
- if (unlikely(r)) {
- if (pages > pages_per_node) {
- if (is_power_of_2(pages))
- pages = pages / 2;
- else
- pages = rounddown_pow_of_two(pages);
- continue;
- }
- goto error_free;
+ pages = pages_per_node;
+
+ n_pages = pages;
+
+ if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
+ n_pages = roundup_pow_of_two(n_pages);
+ min_page_size = (uint64_t)n_pages << PAGE_SHIFT;
+
+ if (n_pages > lpfn)
+ lpfn = n_pages;
}
- vis_usage += amdgpu_vram_mgr_vis_size(adev, &node->mm_nodes[i]);
- amdgpu_vram_mgr_virt_start(&node->base, &node->mm_nodes[i]);
+ spin_lock(&mgr->lock);
+ r = drm_buddy_alloc(mm, (uint64_t)place->fpfn << PAGE_SHIFT,
+ (uint64_t)lpfn << PAGE_SHIFT,
+ (uint64_t)n_pages << PAGE_SHIFT,
+ min_page_size, &node->blocks,
+ node->flags);
+ spin_unlock(&mgr->lock);
+
+ if (unlikely(r))
+ goto error_free_blocks;
+
pages_left -= pages;
++i;
if (pages > pages_left)
pages = pages_left;
}
- spin_unlock(&mgr->lock);
+
+ /* Free unused pages for contiguous allocation */
+ if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
+ uint64_t actual_size = (uint64_t)node->base.num_pages << PAGE_SHIFT;
+
+ r = drm_buddy_free_unused_pages(mm,
+ actual_size,
+ &node->blocks);
+
+ if (unlikely(r))
+ goto error_free_blocks;
+ }
+
+ list_for_each_entry(block, &node->blocks, link)
+ vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
+
+ block = list_first_entry_or_null(&node->blocks,
+ struct drm_buddy_block,
+ link);
+
+ if (!block) {
+ r = -ENOSPC;
+ goto error_free_res;
+ }
+
+ node->base.start = node_start(block) >> PAGE_SHIFT;
if (i == 1)
node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
@@ -456,12 +479,12 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
*res = &node->base;
return 0;
-error_free:
- while (i--)
- drm_mm_remove_node(&node->mm_nodes[i]);
+error_free_blocks:
+ spin_lock(&mgr->lock);
+ drm_buddy_free_list(mm, &node->blocks);
spin_unlock(&mgr->lock);
- kvfree(node);
-
+error_free_res:
+ kfree(node);
error_sub:
atomic64_sub(mem_bytes, &mgr->usage);
return r;
@@ -478,28 +501,28 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
struct ttm_resource *res)
{
- struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
+ struct amdgpu_vram_mgr_node *node = to_amdgpu_vram_mgr_node(res);
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
+ struct drm_buddy_mm *mm = &mgr->mm;
+ struct drm_buddy_block *block;
uint64_t usage = 0, vis_usage = 0;
- unsigned i, pages;
spin_lock(&mgr->lock);
- for (i = 0, pages = res->num_pages; pages;
- pages -= node->mm_nodes[i].size, ++i) {
- struct drm_mm_node *mm = &node->mm_nodes[i];
-
- drm_mm_remove_node(mm);
- usage += mm->size << PAGE_SHIFT;
- vis_usage += amdgpu_vram_mgr_vis_size(adev, mm);
+ list_for_each_entry(block, &node->blocks, link) {
+ usage += node_size(block);
+ vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
}
+
amdgpu_vram_mgr_do_reserve(man);
+
+ drm_buddy_free_list(mm, &node->blocks);
spin_unlock(&mgr->lock);
atomic64_sub(usage, &mgr->usage);
atomic64_sub(vis_usage, &mgr->vis_usage);
- kvfree(node);
+ kfree(node);
}
/**
@@ -653,9 +676,18 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
struct drm_printer *printer)
{
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+ struct drm_buddy_mm *mm = &mgr->mm;
+ struct drm_buddy_block *block;
spin_lock(&mgr->lock);
- drm_mm_print(&mgr->mm, printer);
+ drm_printf(printer, "default_page_size: %lluKiB\n",
+ mgr->default_page_size >> 10);
+
+ drm_buddy_print(mm, printer);
+
+ drm_printf(printer, "reserved:\n");
+ list_for_each_entry(block, &mgr->reserved_pages, link)
+ drm_buddy_block_print(mm, block, printer);
spin_unlock(&mgr->lock);
drm_printf(printer, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n",
@@ -680,15 +712,20 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{
struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
struct ttm_resource_manager *man = &mgr->manager;
+ int err;
ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT);
man->func = &amdgpu_vram_mgr_func;
- drm_mm_init(&mgr->mm, 0, man->size);
+ err = drm_buddy_init(&mgr->mm, man->size << PAGE_SHIFT, PAGE_SIZE);
+ if (err)
+ return err;
+
spin_lock_init(&mgr->lock);
INIT_LIST_HEAD(&mgr->reservations_pending);
INIT_LIST_HEAD(&mgr->reserved_pages);
+ mgr->default_page_size = PAGE_SIZE;
ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
ttm_resource_manager_set_used(man, true);
@@ -721,10 +758,10 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
kfree(rsv);
list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
- drm_mm_remove_node(&rsv->mm_node);
+ drm_buddy_free_list(&mgr->mm, &rsv->block);
kfree(rsv);
}
- drm_mm_takedown(&mgr->mm);
+ drm_buddy_fini(&mgr->mm);
spin_unlock(&mgr->lock);
ttm_resource_manager_cleanup(man);
Remove drm_mm references and add DRM buddy functions Signed-off-by: Arunpravin <Arunpravin.PaneerSelvam@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 4 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 233 +++++++++++-------- 2 files changed, 138 insertions(+), 99 deletions(-)